diff --git a/app/controllers/admin/question_controller.rb b/app/controllers/admin/question_controller.rb index c3b74f4..1dfbb84 100644 --- a/app/controllers/admin/question_controller.rb +++ b/app/controllers/admin/question_controller.rb @@ -2,16 +2,20 @@ module Admin class QuestionController < AdminController def index - @questions = Question.includes(:quiz).order("quizzes.name", { active: :desc }, :sort) + @questions = policy_scope Question.includes(:quiz).order("quizzes.name", { active: :desc }, :sort) end def new + authorize Question + @question = Question.new(active: true) - @quizzes = Quiz.all + @quizzes = policy_scope Quiz.all end def create - @quizzes = Quiz.all + authorize Quiz + + @quizzes = policy_scope Quiz.all @question = Question.create(process_question_params) if @question.persisted? @@ -24,16 +28,20 @@ module Admin def view @question = Question.includes(:quiz).find(params[:question_id]) + authorize @question end def edit - @quizzes = Quiz.all + @quizzes = policy_scope Quiz.all @question = Question.includes(:quiz).find(params[:question_id]) + + authorize @question end def update - @quizzes = Quiz.all + @quizzes = policy_scope Quiz.all @question = Question.find(params[:question_id]) + authorize @question if @question.update_attributes(process_question_params) redirect_to admin_question_path(@question.to_i), @@ -46,6 +54,7 @@ module Admin def options @question = params[:question_id].present? ? Question.find(params[:question_id]) : Question.new + authorize @question render layout: false end diff --git a/app/controllers/admin/quiz_controller.rb b/app/controllers/admin/quiz_controller.rb index 4ca5fbb..9d1d5ef 100644 --- a/app/controllers/admin/quiz_controller.rb +++ b/app/controllers/admin/quiz_controller.rb @@ -6,8 +6,8 @@ module Admin end def new + authorize Quiz @quiz = Quiz.new - authorize @quiz end def create diff --git a/app/policies/question_policy.rb b/app/policies/question_policy.rb new file mode 100644 index 0000000..2c64165 --- /dev/null +++ b/app/policies/question_policy.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true +class QuestionPolicy < ApplicationPolicy + # Question Access Policy + # + # Only Admins and Managers can create or update a quiz (and its questions) + # Reviewers can view any quiz they are linked to + # Recruiters can NOT list or view questions + + def view? + return false if user.recruiter? + return true if user.admin? || user.manager? + user.quizzes.include? record.quiz + end + + def create? + user.manager? || user.admin? + end + + def update? + user.manager? || user.admin? + end + + def options? + !user.recruiter? + end + + class Scope < Scope + def resolve + raise(Pundit::NotAuthorizedError, 'No Access to resource.') if user.recruiter? + + if user.admin? || user.manager? + scope + else + scope.where(quiz_id: user.quizzes.map(&:id)) + end + end + end +end diff --git a/test/fixtures/questions.yml b/test/fixtures/questions.yml index 6460c5f..b498ff2 100644 --- a/test/fixtures/questions.yml +++ b/test/fixtures/questions.yml @@ -111,3 +111,13 @@ fed10: - "wibbly wobbly, timey wimey" sort: 9 active: true + +admin1: + quiz: admin + question: 'You have a question you want to ask.' + category: Admin + input_type: text + input_options: + sort: 0 + active: true + diff --git a/test/policies/question_policy_test.rb b/test/policies/question_policy_test.rb new file mode 100644 index 0000000..28d63c8 --- /dev/null +++ b/test/policies/question_policy_test.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true +require 'test_helper' + +class QuestionPolicyTest < PolicyAssertions::Test + test 'should require current_user' do + assert_raise Pundit::NotAuthorizedError do + QuestionPolicy.new(nil, Question.first).view? + end + end + + test 'should allow admin to scope' do + scope = QuestionPolicy::Scope.new(users(:admin), Question).resolve + assert_equal Question.count, scope.count + end + + test 'should allow manager to scope' do + scope = QuestionPolicy::Scope.new(users(:manager), Question).resolve + assert_equal Question.count, scope.count + end + + test 'should allow reviewer to scope' do + quiz_ids = users(:reviewer).quizzes.map(&:id) + + scope = QuestionPolicy::Scope.new(users(:reviewer), Question).resolve + assert_equal Question.where(quiz_id: quiz_ids).count, scope.count + end + + test 'should NOT allow recruiter to scope' do + assert_raise Pundit::NotAuthorizedError do + QuestionPolicy::Scope.new(users(:recruiter), Question).resolve + end + end + + def test_view + assert_permit users(:admin), questions(:fed1) + assert_permit users(:manager), questions(:fed1) + assert_permit users(:reviewer), questions(:fed1) + + refute_permit users(:reviewer), questions(:admin1) + refute_permit users(:recruiter), questions(:fed1) + end + + def test_create_and_update + assert_permit users(:admin), Question + assert_permit users(:manager), Question + + refute_permit users(:recruiter), Question + refute_permit users(:reviewer), Question + end +end diff --git a/test/policies/user_policy_test.rb b/test/policies/user_policy_test.rb index 4a9096c..e2514d4 100644 --- a/test/policies/user_policy_test.rb +++ b/test/policies/user_policy_test.rb @@ -2,6 +2,12 @@ require 'test_helper' class UserPolicyTest < PolicyAssertions::Test + test 'should require current_user' do + assert_raise Pundit::NotAuthorizedError do + UserPolicy.new(nil, User.first).view? + end + end + test 'should allow admin to scope' do scope = UserPolicy::Scope.new(users(:admin), User).resolve assert_equal User.count, scope.count @@ -13,12 +19,6 @@ class UserPolicyTest < PolicyAssertions::Test end end - test 'should require current_user' do - assert_raise Pundit::NotAuthorizedError do - UserPolicy.new(nil, User.first).view? - end - end - def test_view assert_permit users(:admin), User.first