diff --git a/app/controllers/admin/vote_controller.rb b/app/controllers/admin/vote_controller.rb new file mode 100644 index 0000000..63a2fdc --- /dev/null +++ b/app/controllers/admin/vote_controller.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true +module Admin + class VoteController < AdminController + def up + authorize ReviewerVote + @candidate = Candidate.find_by(test_hash: params[:test_hash]) + current_user.cast_yea_on(@candidate) + + results = { + message: "Vote tallied!", + upCount: @candidate.votes.yea.count, + downCount: @candidate.votes.nay.count + } + render json: results.to_json + end + + def down + authorize ReviewerVote + @candidate = Candidate.find_by(test_hash: params[:test_hash]) + current_user.cast_nay_on(@candidate) + + results = { + message: "Vote tallied!", + upCount: @candidate.votes.yea.count, + downCount: @candidate.votes.nay.count + } + render json: results.to_json + end + + def approve + authorize ReviewerVote + @candidate = Candidate.find_by(test_hash: params[:test_hash]) + current_user.approve_candidate(@candidate) + + results = { message: "Interview requested!" } + render json: results.to_json + end + + def decline + authorize ReviewerVote + @candidate = Candidate.find_by(test_hash: params[:test_hash]) + current_user.decline_candidate(@candidate) + + results = { message: "Interview declined." } + render json: results.to_json + end + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 9d601e3..7db5e31 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -16,6 +16,35 @@ class User < ApplicationRecord save end + # Voting + def cast_yea_on candidate + vote = votes.find_or_create_by(candidate_id: candidate.to_i) + vote.vote = :yea + vote.save + end + + def cast_nay_on candidate + vote = votes.find_or_create_by(candidate_id: candidate.to_i) + vote.vote = :nay + vote.save + end + + def approve_candidate candidate + candidate = Candidate.find(candidate.to_i) + + vote = votes.find_or_create_by(candidate_id: candidate.to_i) + vote.veto = :approved + candidate.update_attribute(:review_status, :approved) if vote.save + end + + def decline_candidate candidate + candidate = Candidate.find(candidate.to_i) + + vote = votes.find_or_create_by(candidate_id: candidate.to_i) + vote.veto = :rejected + candidate.update_attribute(:review_status, :declined) if vote.save + end + # Roles def admin? 'admin' == role diff --git a/app/policies/reviewer_vote_policy.rb b/app/policies/reviewer_vote_policy.rb new file mode 100644 index 0000000..78de734 --- /dev/null +++ b/app/policies/reviewer_vote_policy.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true +class ReviewerVotePolicy < ApplicationPolicy + # Voting Policy + # + # Only Reviewers, Managers, and Admins, can cast a vote on a quiz result + # + # Reviewers can vote any quiz they are linked to + # Only Managers, and Admins, can veto a quiz result + + def up? + # return true if user.acts_as_admin? + # user.quizzes.include? record.candidate.quiz + true + end + + def down? + # return true if user.acts_as_manager? + # user.quizzes.include? record + true + end + + def approve? + user.acts_as_manager? + end + + def decline? + user.acts_as_manager? + end + + class Scope < Scope + def resolve + return ReviewerVote.none if user.recruiter? + + if user.reviewer? + scope.where(user_id: user.id) + else + scope + end + end + end +end diff --git a/config/routes.rb b/config/routes.rb index c5356dd..691f4c5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -50,6 +50,11 @@ Rails.application.routes.draw do get "/admin/results", to: "admin/result#index", as: :admin_results get "/admin/result/:test_hash", to: "admin/result#view", as: :admin_result + get "admin/vote/:test_hash/up", to: "admin/vote#up", as: :admin_up_vote + get "admin/vote/:test_hash/down", to: "admin/vote#down", as: :admin_down_vote + get "admin/vote/:test_hash/approve", to: "admin/vote#approve", as: :admin_approve_vote + get "admin/vote/:test_hash/decline", to: "admin/vote#decline", as: :admin_decline_vote + get "/admin", to: "admin/dashboard#show", as: :admin ######################################################################################### diff --git a/erd.pdf b/erd.pdf index d662d8d..2a66978 100644 Binary files a/erd.pdf and b/erd.pdf differ diff --git a/test/controllers/admin/user_controller_test.rb b/test/controllers/admin/user_controller_test.rb index 8498ffc..be8c9a9 100644 --- a/test/controllers/admin/user_controller_test.rb +++ b/test/controllers/admin/user_controller_test.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: true +# frozen_string_literal: true() require 'test_helper' module Admin diff --git a/test/controllers/admin/vote_controller_test.rb b/test/controllers/admin/vote_controller_test.rb new file mode 100644 index 0000000..093a9f2 --- /dev/null +++ b/test/controllers/admin/vote_controller_test.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true +require 'test_helper' + +module Admin + class VoteControllerTest < ActionDispatch::IntegrationTest + test "reviewer can up vote henry" do + auth_user users(:reviewer) + henry = candidates(:henry) + + assert_difference("Candidate.find(#{henry.id}).votes.yea.count", 1) do + get admin_up_vote_url(henry.test_hash) + end + assert_response :success + end + + test "reviewer can down vote henry" do + auth_user users(:reviewer) + henry = candidates(:henry) + + assert_difference("Candidate.find(#{henry.id}).votes.nay.count", 1) do + get admin_down_vote_url(henry.test_hash) + end + assert_response :success + end + + test "reviewer can change vote on henry" do + auth_user users(:reviewer) + henry = candidates(:henry) + get admin_up_vote_url(henry.test_hash) + + assert_difference("Candidate.find(#{henry.id}).votes.nay.count", 1) do + get admin_down_vote_url(henry.test_hash) + end + assert_response :success + end + + test "manager can approve henry" do + auth_user users(:manager) + henry = candidates(:henry) + get admin_approve_vote_url(henry.test_hash) + + assert_equal 1, henry.votes.approved.count + assert_equal 'approved', Candidate.find(henry.to_i).review_status + assert_response :success + end + + test "manager can decline henry" do + auth_user users(:manager) + henry = candidates(:henry) + get admin_decline_vote_url(henry.test_hash) + + assert_equal 1, henry.votes.rejected.count + assert_equal 'declined', Candidate.find(henry.to_i).review_status + assert_response :success + end + end +end diff --git a/test/fixtures/candidates.yml b/test/fixtures/candidates.yml index 7a22bfd..4def21b 100644 --- a/test/fixtures/candidates.yml +++ b/test/fixtures/candidates.yml @@ -102,3 +102,13 @@ wade: # Wade has completed AND submitted the test reminded: false test_hash: BkSkpapJnkz2N +gustov: # Gustov is NOT for FED + name: Gustov + email: <%= CryptSerializer.dump 'gustov@mailinator.com' %> + experience: 0-3 + recruiter: recruiter + quiz: admin + completed: false + reminded: false + test_hash: kp6tfghjyapJnkz2N + diff --git a/test/policies/reviewer_vote_policy_test.rb b/test/policies/reviewer_vote_policy_test.rb new file mode 100644 index 0000000..8dc05a8 --- /dev/null +++ b/test/policies/reviewer_vote_policy_test.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true +require 'test_helper' + +class ReviewerVotePolicyTest < PolicyAssertions::Test + test 'should require current_user' do + assert_raise Pundit::NotAuthorizedError do + ReviewerVotePolicy.new(nil, ReviewerVote.first).view? + end + end + + test 'should allow admin to scope' do + scope = ReviewerVotePolicy::Scope.new(users(:admin), ReviewerVote).resolve + assert_equal ReviewerVote.count, scope.count + end + + test 'should allow manager to scope' do + scope = ReviewerVotePolicy::Scope.new(users(:manager), ReviewerVote).resolve + assert_equal ReviewerVote.count, scope.count + end + + test 'should allow reviewer to scope' do + scope = ReviewerVotePolicy::Scope.new(users(:reviewer), ReviewerVote).resolve + assert_equal users(:reviewer).votes.count, scope.count + end + + test 'should NOT allow recruiter to scope' do + scope = ReviewerVotePolicy::Scope.new(users(:recruiter), ReviewerVote).resolve + assert_equal 0, scope.count + end + + def test_up + skip + # assert_permit users(:admin), candidates(:richard) + # assert_permit users(:admin), candidates(:gustov) + # assert_permit users(:manager), candidates(:richard) + # assert_permit users(:reviewer), candidates(:richard) + # + # refute_permit users(:reviewer), candidates(:gustov) + # refute_permit users(:recruiter), candidates(:richard) + end + + # def test_create_and_update + # assert_permit users(:admin), Vote + # assert_permit users(:manager), Vote + # + # refute_permit users(:recruiter), Vote + # refute_permit users(:reviewer), Vote + # end +end diff --git a/test/test_helpers/README.txt b/test/test_helpers/README.md similarity index 100% rename from test/test_helpers/README.txt rename to test/test_helpers/README.md