From 49035929fb03cab75c7888be171d110d516c6e59 Mon Sep 17 00:00:00 2001 From: Mark Moser Date: Tue, 18 Apr 2017 10:39:49 -0500 Subject: [PATCH 1/5] bug: resolve false positive "oops" redirect --- app/controllers/candidate_controller.rb | 1 + app/models/candidate.rb | 11 +++++++++++ test/models/candidate_test.rb | 19 +++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/app/controllers/candidate_controller.rb b/app/controllers/candidate_controller.rb index 0cd4f4c..e052666 100644 --- a/app/controllers/candidate_controller.rb +++ b/app/controllers/candidate_controller.rb @@ -45,6 +45,7 @@ class CandidateController < ApplicationController end def send_to_oops + redirect_to welcome_path and return if current_candidate && current_candidate.stale? redirect_to oops_path if current_candidate end end diff --git a/app/models/candidate.rb b/app/models/candidate.rb index 56083a1..8587779 100644 --- a/app/models/candidate.rb +++ b/app/models/candidate.rb @@ -48,6 +48,17 @@ class Candidate < ApplicationRecord answers.where(submitted: true) end + def last_answered_at + return Time.current unless submitted_answers.count.positive? + submitted_answers.order(updated_at: :desc).first.updated_at + end + + def stale? + return true unless answers.count.positive? + minutes_since_answered = (Time.current.minus_with_coercion(last_answered_at) / 60).round + minutes_since_answered > 45 + end + def answered_questions answers.where.not(answer: nil) .where("answers.answer not like '%later:%'") diff --git a/test/models/candidate_test.rb b/test/models/candidate_test.rb index 5b9ea44..4d5154e 100644 --- a/test/models/candidate_test.rb +++ b/test/models/candidate_test.rb @@ -34,4 +34,23 @@ class CandidateTest < ActiveSupport::TestCase candidate.build_reviews assert_equal 3, candidate.votes.count end + + test 'can get last answer timestamp' do + candidate = candidates(:roy) + roy_last = answers(:roy2).updated_at + + assert_equal roy_last, candidate.last_answered_at + end + + test 'gillian is stale with no answers' do + candidate = candidates(:gillian) + + assert candidate.stale? + end + + test 'roy is stale with answers' do + candidate = candidates(:roy) + + assert candidate.stale? + end end From 255e430abd6480e2f0a65cc8f502f863fa2e3fa4 Mon Sep 17 00:00:00 2001 From: Mark Moser Date: Wed, 3 May 2017 16:25:32 -0500 Subject: [PATCH 2/5] limit quiz and results scopes to current_user access now managers and reviewers can only see quizzes and completed results for those quizzes they have been assigned to. --- Gemfile | 1 + Gemfile.lock | 2 ++ app/controllers/admin/result_controller.rb | 8 ++++---- app/policies/quiz_policy.rb | 6 +++--- erd.pdf | Bin 40769 -> 39157 bytes test/policies/quiz_policy_test.rb | 2 +- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Gemfile b/Gemfile index d8447a6..90f6e82 100644 --- a/Gemfile +++ b/Gemfile @@ -54,6 +54,7 @@ group :development, :test do gem 'byebug', platform: :mri gem 'pry-byebug' gem 'pry-rails' + gem 'table_print' gem 'faker' gem 'brakeman' diff --git a/Gemfile.lock b/Gemfile.lock index bbe87c3..a9e6a8f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -280,6 +280,7 @@ GEM actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) + table_print (1.5.6) thor (0.19.4) thread_safe (0.3.5) tilt (2.0.5) @@ -348,6 +349,7 @@ DEPENDENCIES simplecov spring spring-watcher-listen (~> 2.0.0) + table_print turbolinks (~> 5) tzinfo-data uglifier (>= 1.3.0) diff --git a/app/controllers/admin/result_controller.rb b/app/controllers/admin/result_controller.rb index 48bb2b5..64e0fea 100644 --- a/app/controllers/admin/result_controller.rb +++ b/app/controllers/admin/result_controller.rb @@ -11,10 +11,10 @@ module Admin def index sort_case = "(case when review_status = 0 then '' else name end)" sort_with_case = sort_column == 'name' ? sort_case : sort_column - @candidates = Candidate.where(completed: true) - .includes(:recruiter) - .order("#{sort_with_case} #{sort_direction}") - .page(params[:page]) + @candidates = current_user.reviewees.where(completed: true) + .includes(:recruiter) + .order("#{sort_with_case} #{sort_direction}") + .page(params[:page]) end def view diff --git a/app/policies/quiz_policy.rb b/app/policies/quiz_policy.rb index 6f80113..f70114d 100644 --- a/app/policies/quiz_policy.rb +++ b/app/policies/quiz_policy.rb @@ -25,10 +25,10 @@ class QuizPolicy < ApplicationPolicy class Scope < Scope def resolve - if user.reviewer? - scope.joins(:reviewers).where('reviewer_to_quizzes.user_id = ?', user.id) - else + if user.acts_as_recruiter? scope + else + scope.joins(:reviewers).where('reviewer_to_quizzes.user_id = ?', user.id) end end end diff --git a/erd.pdf b/erd.pdf index 35d725dc84e7b2b0780c0e2830824c41ce38fd23..306fb65fadae92affe09c8f0092ed4aa7aa5bd4a 100644 GIT binary patch delta 23488 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 rFO=U94l?G4fel5lg#J$x+P~t*)x diff --git a/test/policies/quiz_policy_test.rb b/test/policies/quiz_policy_test.rb index e5eb7be..505f9f0 100644 --- a/test/policies/quiz_policy_test.rb +++ b/test/policies/quiz_policy_test.rb @@ -15,7 +15,7 @@ class QuizPolicyTest < PolicyAssertions::Test test 'should allow manager to scope' do scope = QuizPolicy::Scope.new(users(:manager), Quiz).resolve - assert_equal Quiz.count, scope.count + assert_equal users(:manager).quizzes.count, scope.count end test 'should allow reviewer to scope' do From 47054265c8393c1bd061a7e8cbea3342b59a40be Mon Sep 17 00:00:00 2001 From: Mark Moser Date: Thu, 4 May 2017 07:49:10 -0500 Subject: [PATCH 3/5] update fixtures and tests to include second department/quiz --- .../admin/candidate_controller/index_test.rb | 2 +- test/fixtures/answers.yml | 88 ++++++++++++++++++- test/fixtures/candidates.yml | 39 ++++++++ test/fixtures/questions.yml | 29 ++++++ test/fixtures/quizzes.yml | 11 ++- test/fixtures/reviewer_to_quizzes.yml | 8 ++ test/fixtures/reviewer_votes.yml | 26 ++++++ test/fixtures/users.yml | 13 +++ test/models/reviewer_vote_test.rb | 2 +- test/workers/reviewer_reminder_test.rb | 2 +- 10 files changed, 212 insertions(+), 8 deletions(-) diff --git a/test/controllers/admin/candidate_controller/index_test.rb b/test/controllers/admin/candidate_controller/index_test.rb index cd6ebe0..d14ef40 100644 --- a/test/controllers/admin/candidate_controller/index_test.rb +++ b/test/controllers/admin/candidate_controller/index_test.rb @@ -25,7 +25,7 @@ module Admin auth_recruiter get admin_candidates_url assert_response :success - assert_select "a[href='#{admin_edit_candidate_path(candidates(:martha))}']" + assert_select "a[href='#{admin_edit_candidate_path(candidates(:gillian))}']" end end end diff --git a/test/fixtures/answers.yml b/test/fixtures/answers.yml index 69019e2..de1b7be 100644 --- a/test/fixtures/answers.yml +++ b/test/fixtures/answers.yml @@ -698,8 +698,8 @@ wade10: jorge1: candidate: jorge - question: Cras justo odio, dapibus ac facilisis in, egestas eget quam. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. - answer: option 3 + question: fed1 + answer: Cras justo odio, dapibus ac facilisis in, egestas eget quam. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. saved: 0 submitted: true created_at: <%= DateTime.now() - 36.hours - 22.minutes %> @@ -890,3 +890,87 @@ elsie10: created_at: <%= DateTime.now() - 36.hours - 40.minutes %> updated_at: <%= DateTime.now() - 36.hours - 20.minutes %> + +########################## +############# Studio Quiz +ethan1: + candidate: ethan + question: studio1 + answer: Cras justo odio, dapibus ac facilisis in, egestas eget quam. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. + saved: 0 + submitted: true + created_at: <%= DateTime.now() - 36.hours - 22.minutes %> + updated_at: <%= DateTime.now() - 36.hours - 22.minutes %> + +ethan2: + candidate: ethan + question: studio2 + answer: Vestibulum id ligula porta felis euismod semper. + saved: 0 + submitted: true + created_at: <%= DateTime.now() - 36.hours - 24.minutes %> + updated_at: <%= DateTime.now() - 36.hours - 4.minutes %> + +ethan3: + candidate: ethan + question: studio3 + answer: Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nulla vitae elit libero, a pharetra augue. + saved: 0 + submitted: true + created_at: <%= DateTime.now() - 36.hours - 26.minutes %> + updated_at: <%= DateTime.now() - 36.hours - 6.minutes %> + +adele1: + candidate: adele + question: studio1 + answer: Cras justo odio, dapibus ac facilisis in, egestas eget quam. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. + saved: 0 + submitted: true + created_at: <%= DateTime.now() - 16.hours - 22.minutes %> + updated_at: <%= DateTime.now() - 16.hours - 22.minutes %> + +adele2: + candidate: adele + question: studio2 + answer: Vestibulum id ligula porta felis euismod semper. + saved: 0 + submitted: true + created_at: <%= DateTime.now() - 16.hours - 24.minutes %> + updated_at: <%= DateTime.now() - 16.hours - 4.minutes %> + +adele3: + candidate: adele + question: studio3 + answer: Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nulla vitae elit libero, a pharetra augue. + saved: 0 + submitted: true + created_at: <%= DateTime.now() - 16.hours - 26.minutes %> + updated_at: <%= DateTime.now() - 16.hours - 6.minutes %> + +carl1: + candidate: carl + question: studio1 + answer: Cras justo odio, dapibus ac facilisis in, egestas eget quam. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. + saved: 0 + submitted: true + created_at: <%= DateTime.now() - 22.minutes %> + updated_at: <%= DateTime.now() - 22.minutes %> + +carl2: + candidate: carl + question: studio2 + answer: Vestibulum id ligula porta felis euismod semper. + saved: 0 + submitted: true + created_at: <%= DateTime.now() - 24.minutes %> + updated_at: <%= DateTime.now() - 4.minutes %> + +carl3: + candidate: carl + question: studio3 + answer: Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nulla vitae elit libero, a pharetra augue. + saved: 0 + submitted: true + created_at: <%= DateTime.now() - 26.minutes %> + updated_at: <%= DateTime.now() - 6.minutes %> + diff --git a/test/fixtures/candidates.yml b/test/fixtures/candidates.yml index d298cc5..0e70cec 100644 --- a/test/fixtures/candidates.yml +++ b/test/fixtures/candidates.yml @@ -179,3 +179,42 @@ gustov: # Gustov is NOT for FED reminded: false test_hash: kp6tfghjyapJnkz2N +ethan: # Completed quiz for studio + name: Ethan Woodward + email: <%= CryptSerializer.dump 'ethan.woodward@mailinator.com' %> + experience: 0-3 + project: Studio Client + position: 'full-time' + skill_needs: 'Angular, HTML' + recruiter: recruiter + quiz: studio + completed: true + reminded: false + test_hash: vNgQo2c5/HZL2CN + +adele: # Completed quiz for studio + name: Adele Kearney + email: <%= CryptSerializer.dump 'adele.kearney@mailinator.com' %> + experience: 0-3 + project: Studio Client + position: 'full-time' + skill_needs: 'Angular, HTML' + recruiter: recruiter + quiz: studio + completed: true + reminded: false + test_hash: 37GmHL0Odjwv + +carl: # Completed quiz for studio + name: Carl Mitchell + email: <%= CryptSerializer.dump 'carle.mitchell@mailinator.com' %> + experience: 0-3 + project: Studio Client + position: 'full-time' + skill_needs: 'Angular, HTML' + recruiter: recruiter + quiz: studio + completed: true + reminded: false + test_hash: hANPsTL1XHcmi + diff --git a/test/fixtures/questions.yml b/test/fixtures/questions.yml index 4380750..33a23f7 100644 --- a/test/fixtures/questions.yml +++ b/test/fixtures/questions.yml @@ -150,3 +150,32 @@ admin1: sort: 0 active: true + +studio1: + quiz: studio + question: 'Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Maecenas faucibus mollis interdum.' + category: Ipsum + input_type: text + input_options: + sort: 0 + active: true + +studio2: + quiz: studio + question: 'Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Maecenas faucibus mollis interdum.' + category: Magna + input_type: text + input_options: + sort: 0 + active: true + + +studio3: + quiz: studio + question: 'Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Maecenas faucibus mollis interdum.' + category: Commodo + input_type: text + input_options: + sort: 0 + active: true + diff --git a/test/fixtures/quizzes.yml b/test/fixtures/quizzes.yml index f4bd5fa..5f4aa1d 100644 --- a/test/fixtures/quizzes.yml +++ b/test/fixtures/quizzes.yml @@ -1,11 +1,16 @@ # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html fed: - name: PDR Standard FED Screening - unit: PDR + name: PDA Standard FED Screening + unit: PD Agency dept: FED admin: name: An extra quiz not assigned to anyone - unit: PDR + unit: PD dept: NOPE + +studio: + name: Studio Screening One + unit: PD Studio + dept: FED diff --git a/test/fixtures/reviewer_to_quizzes.yml b/test/fixtures/reviewer_to_quizzes.yml index cb91027..45b4b22 100644 --- a/test/fixtures/reviewer_to_quizzes.yml +++ b/test/fixtures/reviewer_to_quizzes.yml @@ -11,3 +11,11 @@ two: three: user: manager quiz: fed + +four: + user: studio_manager + quiz: studio + +five: + user: studio_reviewer + quiz: studio diff --git a/test/fixtures/reviewer_votes.yml b/test/fixtures/reviewer_votes.yml index a8ab4c1..440ac4b 100644 --- a/test/fixtures/reviewer_votes.yml +++ b/test/fixtures/reviewer_votes.yml @@ -93,3 +93,29 @@ reviewer2_elsie: candidate: elsie user: reviewer2 + +studio_reviewer_carle: + candidate: carle + user: studio_reviewer + +studio_reviewer_ethan: + candidate: ethan + user: studio_reviewer + +studio_reviewer_adele: + candidate: adele + user: studio_reviewer + + +studio_manager_carle: + candidate: carle + user: studio_manager + +studio_manager_ethan: + candidate: ethan + user: studio_manager + +studio_manager_adele: + user: studio_manager + candidate: adele + diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml index 94e21e3..9e55556 100644 --- a/test/fixtures/users.yml +++ b/test/fixtures/users.yml @@ -29,3 +29,16 @@ admin: email: alan.admin@mailinator.com password_digest: <%= BCrypt::Password.create("password", cost: 4) %> role: admin + +studio_manager: + name: Studio Manager + email: studio.manager@mailinator.com + password_digest: <%= BCrypt::Password.create("password", cost: 4) %> + role: manager + +studio_reviewer: + name: Studio Reviewer + email: studio.reviewer@mailinator.com + password_digest: <%= BCrypt::Password.create("password", cost: 4) %> + role: reviewer + diff --git a/test/models/reviewer_vote_test.rb b/test/models/reviewer_vote_test.rb index d5a9ef3..2ea670c 100644 --- a/test/models/reviewer_vote_test.rb +++ b/test/models/reviewer_vote_test.rb @@ -14,7 +14,7 @@ class ReviewerVoteTest < ActiveSupport::TestCase test "manager has a vote for every completed quiz" do manager = users(:manager) - completed_count = Candidate.where(completed: true).count + completed_count = 6 assert_equal completed_count, manager.votes.size end diff --git a/test/workers/reviewer_reminder_test.rb b/test/workers/reviewer_reminder_test.rb index c4399dd..5a6cbf0 100644 --- a/test/workers/reviewer_reminder_test.rb +++ b/test/workers/reviewer_reminder_test.rb @@ -4,7 +4,7 @@ require 'test_helper' class ReviewerReminderTest < ActiveSupport::TestCase test "collection is created with results" do reminders = ReviewerReminder.new - assert_equal 6, reminders.size + assert_equal 8, reminders.size end test "each reminder has needed attributes" do From e009fc33305713c88457652095e90f4cf392fdf0 Mon Sep 17 00:00:00 2001 From: Mark Moser Date: Thu, 4 May 2017 13:01:02 -0500 Subject: [PATCH 4/5] We are PDA --- db/seeds.rb | 6 +++--- test/controllers/admin/auth_controller_test.rb | 2 +- test/fixtures/users.yml | 2 +- test/test_helpers/auth_test_helper.rb | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/db/seeds.rb b/db/seeds.rb index e1186d7..fe97609 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -8,13 +8,13 @@ User.create( name: 'admin', - email: 'pdr.admin@mailinator.com', + email: 'pda.admin@mailinator.com', password_digest: BCrypt::Password.create("this is the admin password"), role: 'admin' ) Quiz.create( - name: 'PDR Standard FED Screening', + name: 'PDA Standard FED Screening', unit: 'FED', - dept: 'PDR' + dept: 'PDA' ) diff --git a/test/controllers/admin/auth_controller_test.rb b/test/controllers/admin/auth_controller_test.rb index 477200c..73f5299 100644 --- a/test/controllers/admin/auth_controller_test.rb +++ b/test/controllers/admin/auth_controller_test.rb @@ -47,7 +47,7 @@ module Admin test "recruiter should auth to dashboard" do post admin_auth_url, params: { auth: - { email: 'pdr.recruiter@mailinator.com', password: 'password' } } + { email: 'pda.recruiter@mailinator.com', password: 'password' } } assert_redirected_to admin_url end diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml index 9e55556..ef8fbdf 100644 --- a/test/fixtures/users.yml +++ b/test/fixtures/users.yml @@ -2,7 +2,7 @@ recruiter: name: Sam Recruiter - email: pdr.recruiter@mailinator.com + email: pda.recruiter@mailinator.com password_digest: <%= BCrypt::Password.create("password", cost: 4) %> role: recruiter diff --git a/test/test_helpers/auth_test_helper.rb b/test/test_helpers/auth_test_helper.rb index 152a7b6..03f6ace 100644 --- a/test/test_helpers/auth_test_helper.rb +++ b/test/test_helpers/auth_test_helper.rb @@ -21,7 +21,7 @@ module AuthTestHelper def auth_recruiter post admin_auth_url, params: { auth: - { email: 'pdr.recruiter@mailinator.com', password: 'password' } } + { email: 'pda.recruiter@mailinator.com', password: 'password' } } end def auth_reviewer From 3ebb79857e7fbb51ffa44a91dea51432457c4fca Mon Sep 17 00:00:00 2001 From: Mark Moser Date: Thu, 4 May 2017 14:02:11 -0500 Subject: [PATCH 5/5] starting a result policy --- app/controllers/admin/result_controller.rb | 14 +++----- app/policies/result_policy.rb | 41 ++++++++++++++++++++++ test/policies/result_policy_test.rb | 27 ++++++++++++++ 3 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 app/policies/result_policy.rb create mode 100644 test/policies/result_policy_test.rb diff --git a/app/controllers/admin/result_controller.rb b/app/controllers/admin/result_controller.rb index 64e0fea..c3eeee0 100644 --- a/app/controllers/admin/result_controller.rb +++ b/app/controllers/admin/result_controller.rb @@ -1,20 +1,16 @@ # frozen_string_literal: true module Admin class ResultController < AdminController - # TODO: change context from Candidate to Quiz - # bypass pundit lockdowns until completed - after_action :skip_policy_scope + # TODO: bypass pundit authorization until a result wrapper class if sorted after_action :skip_authorization - # + # needed for :view - # TODO: Limit results to the quizzes current_user has access to def index sort_case = "(case when review_status = 0 then '' else name end)" sort_with_case = sort_column == 'name' ? sort_case : sort_column - @candidates = current_user.reviewees.where(completed: true) - .includes(:recruiter) - .order("#{sort_with_case} #{sort_direction}") - .page(params[:page]) + @candidates = policy_scope(:result).includes(:recruiter) + .order("#{sort_with_case} #{sort_direction}") + .page(params[:page]) end def view diff --git a/app/policies/result_policy.rb b/app/policies/result_policy.rb new file mode 100644 index 0000000..60934df --- /dev/null +++ b/app/policies/result_policy.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true +class ResultPolicy < Struct.new(:user, :result) + # Result Access Policy + # + # Only Admins and Recruiters can view all results + # Managers and Reviewers can view any completed quiz they are linked to + + attr_reader :user, :record + + def initialize(user, record) + raise Pundit::NotAuthorizedError, "Must be logged in." unless user + @user = user + @record = record + end + + def index? + true + end + + # def view? + # return true if user.acts_as_recruiter? + # user.reviewees.include? record + # end + + class Scope + attr_reader :user, :scope + + def initialize(user, scope) + @user = user + @scope = scope + end + + def resolve + if user.acts_as_recruiter? + Candidate.where(completed: true) + else + user.reviewees.where(completed: true) + end + end + end +end diff --git a/test/policies/result_policy_test.rb b/test/policies/result_policy_test.rb new file mode 100644 index 0000000..fdccb60 --- /dev/null +++ b/test/policies/result_policy_test.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +require 'test_helper' + +class ResultPolicyTest < PolicyAssertions::Test + def test_index + assert_permit users(:admin), :result + assert_permit users(:recruiter), :result + assert_permit users(:manager), :result + assert_permit users(:reviewer), :result + end + + test 'should allow admin to scope' do + scope = ResultPolicy::Scope.new(users(:admin), Candidate).resolve + assert_equal Candidate.where(completed: true).count, scope.count + end + + test 'should allow recruiter to scope' do + scope = ResultPolicy::Scope.new(users(:recruiter), Candidate).resolve + assert_equal Candidate.where(completed: true).count, scope.count + end + + test 'should not allow fed.reviewer to scope studio results' do + reviewer = users(:reviewer) + scope = ResultPolicy::Scope.new(reviewer, Candidate).resolve + assert_equal reviewer.reviewees.where(completed: true).count, scope.count + end +end