diff --git a/Makefile b/Makefile index 9931fb46..0cd41d79 100644 --- a/Makefile +++ b/Makefile @@ -1,44 +1,28 @@ -RAILS_CONTAINER := web -DOCKER := docker -DOCKER_COMPOSE := docker-compose +include Makefile.in .PHONY: all all: run -.PHONY: nuke -nuke: - ${DOCKER} system prune -a --volumes - -.PHONY: minty-fresh -minty-fresh: - ${DOCKER_COMPOSE} down --rmi all --volumes - -.PHONY: rmi -rmi: - ${DOCKER} images -q | xargs docker rmi -f - -.PHONY: rmdi -rmdi: - ${DOCKER} images -a --filter=dangling=true -q | xargs ${DOCKER} rmi - -.PHONY: rm-exited-containers -rm-exited-containers: - ${DOCKER} ps -a -q -f status=exited | xargs ${DOCKER} rm -v +.PHONY: setup +setup: build db_create db_migrate -.PHONY: fresh-restart -fresh-restart: minty-fresh setup test run +.PHONY: console +console: + $(DOCKER_COMPOSE) run $(RAILS_CONTAINER) rails console .PHONY: console-sandbox console-sandbox: - docker-compose run ${RAILS_CONTAINER} rails console --sandbox + $(DOCKER_COMPOSE) run $(RAILS_CONTAINER) rails console --sandbox + +#### Utility .PHONY: run run: - docker-compose up --build + $(DOCKER_COMPOSE) up --build .PHONY: bg bg: - docker-compose up --build -d + $(DOCKER_COMPOSE) up --build -d .PHONY: open open: @@ -46,55 +30,79 @@ open: .PHONY: build build: - docker-compose build - -.PHONY: console -console: - docker-compose run ${RAILS_CONTAINER} rails console + $(DOCKER_COMPOSE) build .PHONY: routes routes: - docker-compose run ${RAILS_CONTAINER} rake routes + $(DOCKER_COMPOSE) run $(RAILS_CONTAINER) rake routes +.PHONY: bundle +bundle: + $(DOCKER_COMPOSE) run $(RAILS_CONTAINER) bash -c 'cd /app && bundle' + +#### Database .PHONY: db_create db_create: - docker-compose run ${RAILS_CONTAINER} rake db:create + $(DOCKER_COMPOSE) run $(RAILS_CONTAINER) rake db:create .PHONY: db_migrate db_migrate: - docker-compose run ${RAILS_CONTAINER} rake db:migrate + $(DOCKER_COMPOSE) run $(RAILS_CONTAINER) rake db:migrate .PHONY: db_status db_status: - docker-compose run ${RAILS_CONTAINER} rake db:migrate:status + $(DOCKER_COMPOSE) run $(RAILS_CONTAINER) rake db:migrate:status .PHONY: db_rollback db_rollback: - docker-compose run ${RAILS_CONTAINER} rake db:rollback + $(DOCKER_COMPOSE) run $(RAILS_CONTAINER) rake db:rollback .PHONY: db_seed db_seed: - docker-compose run ${RAILS_CONTAINER} rake db:seed + $(DOCKER_COMPOSE) run $(RAILS_CONTAINER) rake db:seed +#### Tests and Linting .PHONY: test test: bg - docker-compose run operationcode-psql bash -c "while ! psql --host=operationcode-psql --username=postgres -c 'SELECT 1'; do sleep 5; done;" - docker-compose run ${RAILS_CONTAINER} bash -c 'export RAILS_ENV=test && rake db:test:prepare && rake test && rubocop' + $(DOCKER_COMPOSE) run operationcode-psql bash -c "while ! psql --host=operationcode-psql --username=postgres -c 'SELECT 1'; do sleep 5; done;" + $(DOCKER_COMPOSE) run $(RAILS_CONTAINER) bash -c 'export RAILS_ENV=test && rake db:test:prepare && rake test || echo -e "$(RED)Unit tests have failed$(NC)" ' + $(DOCKER_COMPOSE) run $(RAILS_CONTAINER) bash -c 'rubocop' || echo -e "$(RED)Linting has failed$(NC)" .PHONY: rubocop rubocop: - docker-compose run ${RAILS_CONTAINER} rubocop + $(DOCKER_COMPOSE) run $(RAILS_CONTAINER) rubocop .PHONY: rubocop_auto_correct rubocop_auto_correct: - docker-compose run ${RAILS_CONTAINER} rubocop -a --auto-correct + $(DOCKER_COMPOSE) run $(RAILS_CONTAINER) rubocop -a --auto-correct -.PHONY: bundle -bundle: - docker-compose run ${RAILS_CONTAINER} bash -c 'cd /app && bundle' -setup: build db_create db_migrate +#### Cleanup +.PHONY: nuke +nuke: + $(DOCKER) system prune -a --volumes + +.PHONY: minty-fresh +minty-fresh: + $(DOCKER_COMPOSE) down --rmi all --volumes + +.PHONY: rmi +rmi: + $(DOCKER) images -q | xargs docker rmi -f + +.PHONY: rmdi +rmdi: + $(DOCKER) images -a --filter=dangling=true -q | xargs $(DOCKER) rmi + +.PHONY: rm-exited-containers +rm-exited-containers: + $(DOCKER) ps -a -q -f status=exited | xargs $(DOCKER) rm -v + +.PHONY: fresh-restart +fresh-restart: minty-fresh setup test run + +#### Deployment publish: build bin/publish diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 00000000..49f66a6d --- /dev/null +++ b/Makefile.in @@ -0,0 +1,10 @@ +RAILS_CONTAINER:= web +DOCKER_COMPOSE:= docker-compose +DOCKER:= docker +RED=\033[0;31m +GREEN=\032[0;32m +NC=\033[0m + + +.DELETE_ON_ERROR: +.SILENT: diff --git a/apiary.apib b/apiary.apib index 5155068b..705e0ca7 100644 --- a/apiary.apib +++ b/apiary.apib @@ -435,6 +435,35 @@ API endpoints that Operation Code's Rails backend makes available to its React f errors: "Some error message" } +## Jobs | Collection [/api/v1/jobs] + +## List all Jobs [GET] + ++ Response 200 (application/json) + + [ + { + "id": 1, + "title": "A great job", + "source_url": "www.applyhere.com", + "source": "Company A", + "city": "Virginia Beach", + "state": "VA", + "country": "USA", + "description": "Our job is fun!", + "is_open": false, + "remote": false, + "created_at": "2018-06-01T16:21:59.462Z", + "updated_at": "2018-06-01T16:21:59.462Z" + } + ] + ++ Response 422 (application/json) + + { + errors: "Some error message" + } + ## Location | Create [/api/v1/code_schools/:code_school_id/locations{?code_school_id,va_accepted,address1,address2,city,state,zip}] diff --git a/app/admin/job.rb b/app/admin/job.rb new file mode 100644 index 00000000..07de9d85 --- /dev/null +++ b/app/admin/job.rb @@ -0,0 +1,36 @@ +ActiveAdmin.register Job do + permit_params :title, :source_url, :source, :city, :state, :country, :description, :is_open, :remote + + index do + selectable_column + id_column + + column :title + column :source_url + column :source + column :city + column :state + column :country + column :description + column :is_open + column :remote + + actions + end + + form do |f| + f.inputs do + f.input :title + f.input :source_url + f.input :source + f.input :city + f.input :state + f.input :country + f.input :description + f.input :is_open + f.input :remote + end + + f.actions + end +end diff --git a/app/controllers/api/v1/jobs_controller.rb b/app/controllers/api/v1/jobs_controller.rb new file mode 100644 index 00000000..291311ef --- /dev/null +++ b/app/controllers/api/v1/jobs_controller.rb @@ -0,0 +1,11 @@ +module Api + module V1 + class JobsController < ApiController + def index + render json: Job.is_open, status: :ok + rescue StandardError => e + render json: { errors: e.message }, status: :unprocessable_entity + end + end + end +end diff --git a/app/models/job.rb b/app/models/job.rb new file mode 100644 index 00000000..b521d688 --- /dev/null +++ b/app/models/job.rb @@ -0,0 +1,18 @@ +class Job < ApplicationRecord + acts_as_taggable + + scope :is_open, -> { where(closed_at: nil) } + scope :is_closed, -> { where.not(closed_at: nil) } + + def open? + closed_at.nil? + end + + def closed? + !open? + end + + def self.with_tags(*args) + tagged_with(args, any: true) + end +end diff --git a/config/routes.rb b/config/routes.rb index e410d4c7..b9a6d911 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -30,6 +30,7 @@ end resources :email_list_recipients, only: :create resources :events, only: :index + resources :jobs, only: :index resources :mentors, only: [:index, :create, :show] resources :requests, only: [:index, :create, :show, :update] resources :resources, only: [:index, :create, :show, :update, :destroy] do diff --git a/db/migrate/20180531004341_create_jobs.rb b/db/migrate/20180531004341_create_jobs.rb new file mode 100644 index 00000000..af096024 --- /dev/null +++ b/db/migrate/20180531004341_create_jobs.rb @@ -0,0 +1,17 @@ +class CreateJobs < ActiveRecord::Migration[5.0] + def change + create_table :jobs do |t| + t.string :title + t.string :source_url + t.string :source + t.string :city + t.string :state + t.string :country + t.text :description + t.datetime :closed_at, default: nil + t.boolean :remote, default: false + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index b8fbd982..6a7dca95 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -116,6 +116,20 @@ t.index ["user_id"], name: "index_git_hub_users_on_user_id", using: :btree end + create_table "jobs", force: :cascade do |t| + t.string "title" + t.string "source_url" + t.string "source" + t.string "city" + t.string "state" + t.string "country" + t.text "description" + t.datetime "closed_at", default: nil + t.boolean "remote", default: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "locations", force: :cascade do |t| t.boolean "va_accepted" t.string "address1" diff --git a/db/seeds.rb b/db/seeds.rb index c60ddfcc..d4bcfdec 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -14,6 +14,7 @@ TeamMember.destroy_all AdminUser.destroy_all Role.destroy_all +Job.destroy_all FactoryGirl.create(:user) FactoryGirl.create(:user) @@ -31,6 +32,9 @@ Service.create!(:name => service) end +# Create jobs +Job.create!(title: "A great job", source_url: "www.applyhere.com", source: "Company A", city: "Virginia Beach", state: "VA", country: "USA", description: "Our job is fun!", is_open: true, remote: false) + # Create team members SeedTeamMembers.seed_all @@ -53,6 +57,7 @@ admin_users = AdminUser.count scholarship_count = Scholarship.count scholarship_app = ScholarshipApplication.count +jobs = Job.count puts 'Seeding complete. Created:' p "#{users} users" @@ -62,3 +67,4 @@ p "#{admin_users} admin users" p "#{scholarship_count} scholarships" p "#{scholarship_app} scholarship applications" +p "#{jobs} jobs" diff --git a/test/controllers/api/v1/jobs_controller_test.rb b/test/controllers/api/v1/jobs_controller_test.rb new file mode 100644 index 00000000..53340175 --- /dev/null +++ b/test/controllers/api/v1/jobs_controller_test.rb @@ -0,0 +1,16 @@ +require 'test_helper' + +class Api::V1::JobsControllerTest < ActionDispatch::IntegrationTest + test 'index endpoint should return job parameters in JSON format' do + jobs = [] + 5.times do + jobs << create(:job) + end + get api_v1_jobs_url, as: :json + i = 0 + response.parsed_body.each do |response| + assert_equal true, response['title'] == jobs[i].title + i += 1 + end + end +end diff --git a/test/factories/jobs.rb b/test/factories/jobs.rb new file mode 100644 index 00000000..9f9ae1db --- /dev/null +++ b/test/factories/jobs.rb @@ -0,0 +1,13 @@ +FactoryGirl.define do + factory :job do + title { Faker::Lorem.characters(7) } + source_url { Faker::Internet.url } + source { Faker::Lorem.characters(7) } + city { Faker::Address.city } + state { Faker::Address.state } + country { Faker::Address.country } + description { Faker::Lorem.paragraph } + closed_at nil + remote false + end +end diff --git a/test/models/job_test.rb b/test/models/job_test.rb new file mode 100644 index 00000000..17f144ca --- /dev/null +++ b/test/models/job_test.rb @@ -0,0 +1,17 @@ +require 'test_helper' + +class JobTest < ActiveSupport::TestCase + setup do + @job = create :job + end + + test 'should be valid' do + assert @job.valid? + end + + test '.with_tags returns job with tag' do + @job.tag_list.add('front-end') + @job.save! + assert_equal Job.with_tags('front-end'), [@job] + end +end