From cbde9529aa400cf05ad80aa646b2aa09dcf92528 Mon Sep 17 00:00:00 2001 From: Hauke Klement Date: Thu, 29 Jan 2015 17:13:22 +0100 Subject: [PATCH] implemented team-dependent exercise policy --- app/policies/exercise_policy.rb | 13 ++++++++++--- spec/policies/exercise_policy_spec.rb | 24 ++++++++++++++++++------ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/app/policies/exercise_policy.rb b/app/policies/exercise_policy.rb index 1d3863b0..3ba765ca 100644 --- a/app/policies/exercise_policy.rb +++ b/app/policies/exercise_policy.rb @@ -4,20 +4,27 @@ class ExercisePolicy < AdminOrAuthorPolicy end private :author? - [:clone?, :statistics?].each do |action| - define_method(action) { admin? || author? } + [:clone?, :destroy?, :edit?, :show?, :statistics?, :update?].each do |action| + define_method(action) { admin? || author? || team_member? } end [:implement?, :submit?].each do |action| define_method(action) { everyone } end + def team_member? + @record.team.try(:members, []).include?(@user) + end + private :team_member? + class Scope < Scope def resolve if @user.admin? @scope.all + elsif @user.internal? + @scope.where("user_id = #{@user.id} OR public = TRUE OR (team_id IS NOT NULL AND team_id IN (SELECT t.id FROM teams t JOIN internal_users_teams iut ON t.id = iut.team_id WHERE iut.internal_user_id = #{@user.id}))") else - @scope.where("user_id = #{@user.id} OR public = TRUE") + @scope.none end end end diff --git a/spec/policies/exercise_policy_spec.rb b/spec/policies/exercise_policy_spec.rb index 4b1dc521..6b4e0966 100644 --- a/spec/policies/exercise_policy_spec.rb +++ b/spec/policies/exercise_policy_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe ExercisePolicy do subject { ExercisePolicy } - let(:exercise) { FactoryGirl.build(:fibonacci) } + let(:exercise) { FactoryGirl.build(:fibonacci, team: FactoryGirl.create(:team)) } [:create?, :index?, :new?].each do |action| permissions(action) do @@ -21,7 +21,7 @@ describe ExercisePolicy do end end - [:destroy?, :edit?, :show?, :update?].each do |action| + [:clone?, :destroy?, :edit?, :show?, :statistics?, :update?].each do |action| permissions(action) do it 'grants access to admins' do expect(subject).to permit(FactoryGirl.build(:admin), exercise) @@ -31,6 +31,10 @@ describe ExercisePolicy do expect(subject).to permit(exercise.author, exercise) end + it 'grants access to team members' do + expect(subject).to permit(exercise.team.members.first, exercise) + end + it 'does not grant access to all other users' do [:external_user, :teacher].each do |factory_name| expect(subject).not_to permit(FactoryGirl.build(factory_name), exercise) @@ -54,11 +58,15 @@ describe ExercisePolicy do let(:admin) { FactoryGirl.create(:admin) } let(:external_user) { FactoryGirl.create(:external_user) } let(:teacher) { FactoryGirl.create(:teacher) } + let(:team) { FactoryGirl.create(:team) } before(:each) do [admin, teacher].each do |user| [true, false].each do |public| - FactoryGirl.create(:fibonacci, public: public, user_id: user.id, user_type: InternalUser.class.name) + team.members << teacher + [team, nil].each do |team| + FactoryGirl.create(:fibonacci, public: public, team: team, user_id: user.id, user_type: InternalUser.class.name) + end end end end @@ -74,8 +82,8 @@ describe ExercisePolicy do context 'for external users' do let(:scope) { Pundit.policy_scope!(external_user, Exercise) } - it 'returns only public exercises' do - expect(scope.map(&:id)).to include(*Exercise.where(public: true).map(&:id)) + it 'returns nothing' do + expect(scope.count).to be 0 end end @@ -90,8 +98,12 @@ describe ExercisePolicy do expect(scope.map(&:id)).to include(*Exercise.where(public: false, user_id: teacher.id).map(&:id)) end + it "includes all of team members' non-public exercises" do + expect(scope.map(&:id)).to include(*Exercise.where(public: false, team_id: teacher.teams.first.id).map(&:id)) + end + it "does not include other authors' non-public exercises" do - expect(scope.map(&:id)).not_to include(*Exercise.where(public: false).where("user_id <> #{teacher.id}").map(&:id)) + expect(scope.map(&:id)).not_to include(*Exercise.where(public: false).where("team_id <> #{teacher.teams.first.id} AND user_id <> #{teacher.id}").map(&:id)) end end end