Use author_in_programming_group? policy for files & RfCs

* Allow all members of a programming group to list and solve RfCs
* Also adjust policy specs to respect programming groups
This commit is contained in:
kiragrammel
2023-08-22 09:23:20 +02:00
committed by Sebastian Serth
parent 9d1be1eeff
commit 01accdae58
7 changed files with 101 additions and 19 deletions

View File

@ -44,7 +44,11 @@ class RequestForCommentsController < ApplicationController
# GET /my_request_for_comments # GET /my_request_for_comments
def my_comment_requests def my_comment_requests
@search = policy_scope(RequestForComment) @search = policy_scope(RequestForComment)
.joins(:submission)
.where(user: current_user) .where(user: current_user)
.or(policy_scope(RequestForComment)
.joins(:submission)
.where(submission: {contributor: current_user.programming_groups}))
.order(created_at: :desc) # Order for the LIMIT part of the query .order(created_at: :desc) # Order for the LIMIT part of the query
.ransack(params[:q]) .ransack(params[:q])

View File

@ -124,8 +124,8 @@ class Submission < ApplicationRecord
(contributor_id + exercise.created_at.to_i) % 10 == 1 (contributor_id + exercise.created_at.to_i) % 10 == 1
end end
def own_unsolved_rfc(user = self.user) def own_unsolved_rfc(user)
Pundit.policy_scope(user, RequestForComment).unsolved.find_by(exercise:, user:) Pundit.policy_scope(user, RequestForComment).joins(:submission).where(submission: {contributor:}).unsolved.find_by(exercise:)
end end
def unsolved_rfc(user = self.user) def unsolved_rfc(user = self.user)

View File

@ -50,9 +50,21 @@ class ApplicationPolicy
private :teacher_in_study_group? private :teacher_in_study_group?
def author_in_programming_group? def author_in_programming_group?
return false unless @record.contributor.programming_group? if @record.respond_to? :contributor # e.g. submission
possible_programming_group = @record.contributor
@record.contributor.users.include?(@user) elsif @record.respond_to? :context # e.g. file
possible_programming_group = @record.context.contributor
elsif @record.respond_to? :submission # e.g. request_for_comment
possible_programming_group = @record.submission.contributor
else
return false
end
return false unless possible_programming_group.programming_group?
possible_programming_group.users.include?(@user)
end end
private :author_in_programming_group? private :author_in_programming_group?

View File

@ -38,7 +38,7 @@ module CodeOcean
if @record.context.is_a?(Exercise) if @record.context.is_a?(Exercise)
admin? || author? admin? || author?
elsif @record.context.is_a?(Submission) && @record.context.exercise.allow_file_creation elsif @record.context.is_a?(Submission) && @record.context.exercise.allow_file_creation
author? author? || author_in_programming_group?
else else
no_one no_one
end end

View File

@ -6,7 +6,7 @@ class RequestForCommentPolicy < ApplicationPolicy
end end
def show? def show?
admin? || author? || rfc_visibility admin? || author? || author_in_programming_group? || rfc_visibility
end end
def destroy? def destroy?
@ -14,11 +14,11 @@ class RequestForCommentPolicy < ApplicationPolicy
end end
def mark_as_solved? def mark_as_solved?
admin? || author? admin? || author? || author_in_programming_group?
end end
def set_thank_you_note? def set_thank_you_note?
admin? || author? admin? || author? || author_in_programming_group?
end end
def clear_question? def clear_question?

View File

@ -30,32 +30,82 @@ describe CodeOcean::FilePolicy do
context 'when being part of a submission' do context 'when being part of a submission' do
let(:file) { submission.files.first } let(:file) { submission.files.first }
context 'when file creation is allowed' do shared_context 'when file creation is allowed' do
before do before do
submission.exercise.update(allow_file_creation: true) submission.exercise.update(allow_file_creation: true)
end end
it 'grants access to authors' do
expect(policy).to permit(submission.author, file)
end
end end
context 'when file creation is not allowed' do shared_context 'when file creation is not allowed' do
before do before do
submission.exercise.update(allow_file_creation: false) submission.exercise.update(allow_file_creation: false)
end end
it 'grants access to authors' do
expect(policy).not_to permit(submission.author, file)
end
end end
shared_examples 'no other user allowed to access' do
it 'does not grant access to all other users' do it 'does not grant access to all other users' do
%i[admin external_user teacher].each do |factory_name| %i[admin external_user teacher].each do |factory_name|
expect(policy).not_to permit(create(factory_name), file) expect(policy).not_to permit(create(factory_name), file)
end end
end end
end end
context 'when a single user authored' do
context 'when file creation is allowed' do
include_context 'when file creation is allowed'
it 'grants access to authors' do
expect(policy).to permit(submission.author, file)
end
it_behaves_like 'no other user allowed to access'
end
context 'when file creation is not allowed' do
include_context 'when file creation is not allowed'
it 'does not grant access to authors' do
expect(policy).not_to permit(submission.author, file)
end
it_behaves_like 'no other user allowed to access'
end
end
context 'when a programming group authored' do
let(:group_author) { create(:external_user) }
let(:other_group_author) { create(:external_user) }
let(:programming_group) { create(:programming_group, exercise: submission.exercise, users: [group_author, other_group_author]) }
before do
submission.update(contributor: programming_group)
end
context 'when file creation is allowed' do
include_context 'when file creation is allowed'
it 'grants access to authors' do
expect(policy).to permit(group_author, file)
expect(policy).to permit(other_group_author, file)
end
it_behaves_like 'no other user allowed to access'
end
context 'when file creation is not allowed' do
include_context 'when file creation is not allowed'
it 'does not grant access to authors' do
expect(policy).not_to permit(group_author, file)
expect(policy).not_to permit(other_group_author, file)
end
it_behaves_like 'no other user allowed to access'
end
end
it_behaves_like 'no other user allowed to access'
end
end end
permissions :destroy? do permissions :destroy? do

View File

@ -59,6 +59,12 @@ describe RequestForCommentPolicy do
it 'grants access to authors' do it 'grants access to authors' do
expect(policy).to permit(rfc.author, rfc) expect(policy).to permit(rfc.author, rfc)
end end
it 'grant access to other authors of the programming group' do
rfc.submission.update(contributor: programming_group)
expect(policy).to permit(author_other_group_member, rfc)
expect(policy).to permit(viewer_other_group_member, rfc)
end
end end
shared_examples 'grants access to admins and authors only' do shared_examples 'grants access to admins and authors only' do
@ -70,6 +76,12 @@ describe RequestForCommentPolicy do
expect(policy).to permit(rfc.author, rfc) expect(policy).to permit(rfc.author, rfc)
end end
it 'grant access to other authors of the programming group' do
rfc.submission.update(contributor: programming_group)
expect(policy).to permit(author_other_group_member, rfc)
expect(policy).to permit(viewer_other_group_member, rfc)
end
it 'does not grant access to all other users' do it 'does not grant access to all other users' do
%i[external_user teacher].each do |factory_name| %i[external_user teacher].each do |factory_name|
expect(policy).not_to permit(create(factory_name, consumer: viewer_consumer, study_groups: viewer_study_groups), rfc) expect(policy).not_to permit(create(factory_name, consumer: viewer_consumer, study_groups: viewer_study_groups), rfc)
@ -81,6 +93,10 @@ describe RequestForCommentPolicy do
let(:author_study_groups) { create_list(:study_group, 1, consumer: author_consumer) } let(:author_study_groups) { create_list(:study_group, 1, consumer: author_consumer) }
let(:rfc) { create(:rfc, user: rfc_author) } let(:rfc) { create(:rfc, user: rfc_author) }
let(:author_other_group_member) { create(:external_user, consumer: author_consumer) }
let(:viewer_other_group_member) { create(:external_user, consumer: viewer_consumer) }
let(:programming_group) { create(:programming_group, exercise: rfc.submission.exercise, users: [rfc.author, author_other_group_member, viewer_other_group_member]) }
context "when the author's rfc_visibility is set to all" do context "when the author's rfc_visibility is set to all" do
let(:author_consumer) { create(:consumer, rfc_visibility: 'all') } let(:author_consumer) { create(:consumer, rfc_visibility: 'all') }