From 854fe4cc4640ef36b75d8857227172c2deff7ca8 Mon Sep 17 00:00:00 2001 From: philipkukulak Date: Fri, 22 May 2026 16:42:01 -0400 Subject: [PATCH] Implement GET and PATCH /overall_comment API routes, closes #7708 --- app/controllers/api/groups_controller.rb | 23 ++++ config/routes.rb | 6 ++ .../controllers/api/groups_controller_spec.rb | 100 ++++++++++++++++++ 3 files changed, 129 insertions(+) diff --git a/app/controllers/api/groups_controller.rb b/app/controllers/api/groups_controller.rb index 538f5e444d..3eba711911 100644 --- a/app/controllers/api/groups_controller.rb +++ b/app/controllers/api/groups_controller.rb @@ -466,6 +466,29 @@ def add_test_run end end + def overall_comment + result = grouping&.current_result + return page_not_found('No submission exists for that group') if result.nil? + + case request.method + when 'GET' + respond_to do |format| + format.xml do + render xml: { overall_comment: result.overall_comment }.to_xml(root: 'result', skip_types: 'true') + end + format.json { render json: { overall_comment: result.overall_comment } } + end + when 'PATCH' + if result.update(overall_comment: params[:overall_comment]) + head :ok + else + render 'shared/http_status', + locals: { code: '422', message: result.errors.full_messages.first }, + status: :unprocessable_content + end + end + end + private def assignment diff --git a/config/routes.rb b/config/routes.rb index 51c1de0ca1..2f922e2f43 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -50,6 +50,8 @@ # PATCH /api/courses/:course_id/assignments/:assignment_id/groups/:group_id/feedback_files/:id(.:format) api/feedback_files#update # PUT /api/courses/:course_id/assignments/:assignment_id/groups/:group_id/feedback_files/:id(.:format) api/feedback_files#update # DELETE /api/courses/:course_id/assignments/:assignment_id/groups/:group_id/feedback_files/:id(.:format) api/feedback_files#destroy +# overall_comment_api_course_assignment_group GET /api/courses/:course_id/assignments/:assignment_id/groups/:id/overall_comment(.:format) api/groups#overall_comment +# PATCH /api/courses/:course_id/assignments/:assignment_id/groups/:id/overall_comment(.:format) api/groups#overall_comment # annotations_api_course_assignment_group GET /api/courses/:course_id/assignments/:assignment_id/groups/:id/annotations(.:format) api/groups#annotations # add_annotations_api_course_assignment_group POST /api/courses/:course_id/assignments/:assignment_id/groups/:id/add_annotations(.:format) api/groups#add_annotations # add_members_api_course_assignment_group POST /api/courses/:course_id/assignments/:assignment_id/groups/:id/add_members(.:format) api/groups#add_members @@ -620,6 +622,10 @@ patch 'extension' delete 'extension' end + member do + get 'overall_comment' + patch 'overall_comment' + end end resources :starter_file_groups, only: [:index, :create] member do diff --git a/spec/controllers/api/groups_controller_spec.rb b/spec/controllers/api/groups_controller_spec.rb index 1a043a6389..90fb249afe 100644 --- a/spec/controllers/api/groups_controller_spec.rb +++ b/spec/controllers/api/groups_controller_spec.rb @@ -52,6 +52,16 @@ params: { assignment_id: assignment.id, course_id: course.id, id: group.id, extension: extension_params } expect(response).to have_http_status(:forbidden) end + + it 'should fail to authenticate a GET overall_comment request' do + get :overall_comment, params: { assignment_id: assignment.id, id: group.id, course_id: course.id } + expect(response).to have_http_status(:forbidden) + end + + it 'should fail to authenticate a PATCH overall_comment request' do + patch :overall_comment, params: { assignment_id: assignment.id, id: group.id, course_id: course.id } + expect(response).to have_http_status(:forbidden) + end end context 'An authenticated request requesting' do @@ -1460,5 +1470,95 @@ end end end + + context 'Overall Comment' do + let!(:grouping) { create(:grouping, group: group, assignment: assignment) } + + before { request.env['HTTP_ACCEPT'] = 'application/json' } + + context 'when no submission/result exists' do + it 'GET returns 404' do + get :overall_comment, params: { course_id: course.id, assignment_id: assignment.id, id: group.id } + expect(response).to have_http_status(:not_found) + end + + it 'PATCH returns 404' do + patch :overall_comment, params: { course_id: course.id, assignment_id: assignment.id, + id: group.id, overall_comment: 'hello' } + expect(response).to have_http_status(:not_found) + end + end + + context 'when a result exists' do + let(:submission) { create(:version_used_submission, grouping: grouping) } + + before { submission } + + context 'expecting a json response' do + it 'GET returns 200 with the overall_comment' do + grouping.current_result.update!(overall_comment: 'existing comment') + get :overall_comment, params: { course_id: course.id, assignment_id: assignment.id, id: group.id } + expect(response).to have_http_status(:ok) + expect(response.parsed_body['overall_comment']).to eq('existing comment') + end + + it 'GET returns 200 with null overall_comment when none set' do + get :overall_comment, params: { course_id: course.id, assignment_id: assignment.id, id: group.id } + expect(response).to have_http_status(:ok) + expect(response.parsed_body['overall_comment']).to be_nil + end + + it_behaves_like 'for a different course' do + before do + get :overall_comment, params: { course_id: course.id, assignment_id: assignment.id, id: group.id } + end + end + end + + context 'expecting an xml response' do + before { request.env['HTTP_ACCEPT'] = 'application/xml' } + + it 'GET returns 200' do + get :overall_comment, params: { course_id: course.id, assignment_id: assignment.id, id: group.id } + expect(response).to have_http_status(:ok) + end + + it 'GET returns overall_comment nested under a result root element' do + grouping.current_result.update!(overall_comment: 'xml comment') + get :overall_comment, params: { course_id: course.id, assignment_id: assignment.id, id: group.id } + parsed = Hash.from_xml(response.body) + expect(parsed.dig('result', 'overall_comment')).to eq('xml comment') + end + + it 'GET returns null overall_comment as empty element when none set' do + get :overall_comment, params: { course_id: course.id, assignment_id: assignment.id, id: group.id } + parsed = Hash.from_xml(response.body) + expect(parsed.dig('result', 'overall_comment')).to be_nil + end + end + + it 'PATCH updates overall_comment and returns 200' do + patch :overall_comment, params: { course_id: course.id, assignment_id: assignment.id, + id: group.id, overall_comment: 'new comment' } + expect(response).to have_http_status(:ok) + expect(grouping.current_result.reload.overall_comment).to eq('new comment') + end + + it 'PATCH can clear overall_comment to nil' do + grouping.current_result.update!(overall_comment: 'existing') + patch :overall_comment, params: { course_id: course.id, assignment_id: assignment.id, + id: group.id, overall_comment: nil } + expect(response).to have_http_status(:ok) + expect(grouping.current_result.reload.overall_comment).to be_nil + end + + it_behaves_like 'for a different course' do + before do + patch :overall_comment, params: { course_id: course.id, assignment_id: assignment.id, + id: group.id, overall_comment: 'hello' } + end + end + end + end end end