From e0f5e482bea6145601d76e07b109152c377b1259 Mon Sep 17 00:00:00 2001 From: Mark Moser Date: Sat, 19 Nov 2016 16:34:48 -0600 Subject: [PATCH] vote/veto processing --- app/controllers/admin/vote_controller.rb | 48 +++++++++++++++ app/models/user.rb | 29 +++++++++ app/policies/reviewer_vote_policy.rb | 41 +++++++++++++ config/routes.rb | 5 ++ erd.pdf | Bin 40602 -> 40760 bytes .../controllers/admin/user_controller_test.rb | 2 +- .../controllers/admin/vote_controller_test.rb | 57 ++++++++++++++++++ test/fixtures/candidates.yml | 10 +++ test/policies/reviewer_vote_policy_test.rb | 49 +++++++++++++++ test/test_helpers/{README.txt => README.md} | 0 10 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 app/controllers/admin/vote_controller.rb create mode 100644 app/policies/reviewer_vote_policy.rb create mode 100644 test/controllers/admin/vote_controller_test.rb create mode 100644 test/policies/reviewer_vote_policy_test.rb rename test/test_helpers/{README.txt => README.md} (100%) 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 d662d8da1d17a9b13d3099b6b072843ab6167ae3..2a669781946763f830f13918b19bb1002e71f052 100644 GIT binary patch delta 22224 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 Bt=a$p 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