diff --git a/Changelog.md b/Changelog.md index 38b832c82a..e1c07963bb 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,6 +10,7 @@ - Scanned exams and Jupyter notebook rendering are now controlled by the `scanned_exams.enabled` (renamed from `scanned_exams.enable`) and `nbconvert_enabled` settings (both enabled by default) (#8208) ### ✨ New features and improvements +- Added a new toggle to display assignment averages to students when viewing their grade summary (#8243) - Implemented new model, `GroupingsTags`, and added corresponding tests (#8233) - Added optional OpenTelemetry tracing of requests and background jobs, controlled by the new `telemetry` settings, and a `telemetry` Docker Compose profile that runs a local Grafana for viewing traces in development (#8223) - Courses created through the API (`POST /api/courses`) are now connected to the autotester given by the `autotest.default_url` setting, unless the request includes its own `autotest_url` parameter (#8222) diff --git a/app/controllers/assignments_controller.rb b/app/controllers/assignments_controller.rb index 1099e02bdd..d558038d63 100644 --- a/app/controllers/assignments_controller.rb +++ b/app/controllers/assignments_controller.rb @@ -1027,6 +1027,7 @@ def assignment_params :vcs_submit, :url_submit, :api_submit, + :display_average_to_students, :display_median_to_students, :display_grader_names_to_students, :group_min, diff --git a/app/controllers/course_summaries_controller.rb b/app/controllers/course_summaries_controller.rb index 788e689cba..7026c4006c 100644 --- a/app/controllers/course_summaries_controller.rb +++ b/app/controllers/course_summaries_controller.rb @@ -142,7 +142,9 @@ def assessment_overview(assessment) median: nil } if current_role.instructor? || (current_role.student? && current_role.released_result_for?(assessment)) - data[:average] = get_assessment_data(assessment, :average) + if current_role.instructor? || assessment.display_average_to_students + data[:average] = get_assessment_data(assessment, :average) + end if current_role.instructor? || assessment.display_median_to_students data[:median] = get_assessment_data(assessment, :median) end diff --git a/app/models/assignment.rb b/app/models/assignment.rb index 2fec99fe5f..ba783e9e71 100644 --- a/app/models/assignment.rb +++ b/app/models/assignment.rb @@ -154,7 +154,8 @@ class Assignment < Assessment :enable_student_tests, :allow_remarks, :display_grader_names_to_students, :display_median_to_students, :group_name_autogenerated, - :is_hidden, :visible_on, :visible_until, :vcs_submit, :has_peer_review].freeze + :is_hidden, :visible_on, :visible_until, :vcs_submit, :has_peer_review, + :display_average_to_students].freeze ASSESSMENT_FIELDS = [:short_identifier, :description, :due_date, :message, :is_hidden, :visible_on, :visible_until].freeze @@ -164,7 +165,7 @@ class Assignment < Assessment :remark_message, :assign_graders_to_criteria, :enable_test, :enable_student_tests, :allow_remarks, :display_grader_names_to_students, - :display_median_to_students, :group_name_autogenerated, + :display_average_to_students, :display_median_to_students, :group_name_autogenerated, :vcs_submit, :has_peer_review].freeze STARTER_FILES_DIR = ( diff --git a/app/models/assignment_properties.rb b/app/models/assignment_properties.rb index 681f30a89e..391bbc9492 100644 --- a/app/models/assignment_properties.rb +++ b/app/models/assignment_properties.rb @@ -11,6 +11,7 @@ # api_submit :boolean default(FALSE), not null # assign_graders_to_criteria :boolean default(FALSE), not null # autotest_settings :json +# display_average_to_students :boolean default(TRUE), not null # display_grader_names_to_students :boolean default(FALSE), not null # display_median_to_students :boolean default(FALSE), not null # duration :interval @@ -78,6 +79,7 @@ class AssignmentProperties < ApplicationRecord validates :allow_web_submits, inclusion: { in: [true, false] } validates :vcs_submit, inclusion: { in: [true, false] } validates :display_grader_names_to_students, inclusion: { in: [true, false] } + validates :display_average_to_students, inclusion: { in: [true, false] } validates :display_median_to_students, inclusion: { in: [true, false] } validates :has_peer_review, inclusion: { in: [true, false] } validates :assign_graders_to_criteria, inclusion: { in: [true, false] } diff --git a/app/models/grade_entry_form.rb b/app/models/grade_entry_form.rb index 377fe65c5d..d55a84235c 100644 --- a/app/models/grade_entry_form.rb +++ b/app/models/grade_entry_form.rb @@ -271,6 +271,10 @@ def update_grade_entry_items(names, totals, overwrite) self.grade_entry_items.reload end + def display_average_to_students + true + end + def display_median_to_students false end diff --git a/app/views/assignments/_form.html.erb b/app/views/assignments/_form.html.erb index 99ddd2b691..596bb9a782 100644 --- a/app/views/assignments/_form.html.erb +++ b/app/views/assignments/_form.html.erb @@ -320,6 +320,10 @@ <%= ap_f.check_box :api_submit %> <% end %> + <%= ap_f.label :display_average_to_students, + Assignment.human_attribute_name(:display_average_to_students) %> + <%= ap_f.check_box :display_average_to_students %> + <%= ap_f.label :display_median_to_students, Assignment.human_attribute_name(:display_median_to_students) %> <%= ap_f.check_box :display_median_to_students %> diff --git a/config/locales/models/assignments/en.yml b/config/locales/models/assignments/en.yml index 47b565df7b..d3565d9f34 100644 --- a/config/locales/models/assignments/en.yml +++ b/config/locales/models/assignments/en.yml @@ -10,6 +10,7 @@ en: assignment_files: Required files collection_date: Due date including maximum late penalty (if any) description: Assignment description + display_average_to_students: Display assignment average to students display_grader_names_to_students: Display grader names to students display_median_to_students: Display assignment median to students due_date: Due date diff --git a/db/migrate/20261106010918_add_display_average_to_students_to_assignment_properties.rb b/db/migrate/20261106010918_add_display_average_to_students_to_assignment_properties.rb new file mode 100644 index 0000000000..0e694f5170 --- /dev/null +++ b/db/migrate/20261106010918_add_display_average_to_students_to_assignment_properties.rb @@ -0,0 +1,5 @@ +class AddDisplayAverageToStudentsToAssignmentProperties < ActiveRecord::Migration[8.1] + def change + add_column :assignment_properties, :display_average_to_students, :boolean, default: true, null: false + end +end diff --git a/db/structure.sql b/db/structure.sql index 8961a56030..ef3525a33e 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -436,7 +436,8 @@ CREATE TABLE public.assignment_properties ( autotest_settings json, api_submit boolean DEFAULT false NOT NULL, release_with_urls boolean DEFAULT false NOT NULL, - token_end_date timestamp(6) without time zone + token_end_date timestamp(6) without time zone, + display_average_to_students boolean DEFAULT true NOT NULL ); @@ -4823,6 +4824,7 @@ ALTER TABLE ONLY public.submission_files SET search_path TO "$user", public; INSERT INTO "schema_migrations" (version) VALUES +('20261106010918'), ('20261030000000'), ('20260926233000'), ('20260703000001'), diff --git a/doc/import_samples/assignments.yml b/doc/import_samples/assignments.yml index 2808cee052..7c99d7ff9a 100644 --- a/doc/import_samples/assignments.yml +++ b/doc/import_samples/assignments.yml @@ -16,6 +16,7 @@ assignments: enable_student_tests: false allow_remarks: false display_grader_names_to_students: false + display_average_to_students: true display_median_to_students: false group_name_autogenerated: true is_hidden: false diff --git a/docs/docs/instructors/importing-and-exporting-data.md b/docs/docs/instructors/importing-and-exporting-data.md index 58557fe030..2491f9a5d5 100644 --- a/docs/docs/instructors/importing-and-exporting-data.md +++ b/docs/docs/instructors/importing-and-exporting-data.md @@ -104,6 +104,7 @@ The remaining fields are optional. - `enable_student_tests` - `allow_remarks` - `display_grader_names_to_students` +- `display_average_to_students` - `display_median_to_students` - `group_name_autogenerated` - `is_hidden` diff --git a/spec/controllers/assignments_controller_spec.rb b/spec/controllers/assignments_controller_spec.rb index d78d9c45ae..e321f2b5f7 100644 --- a/spec/controllers/assignments_controller_spec.rb +++ b/spec/controllers/assignments_controller_spec.rb @@ -14,7 +14,7 @@ assignment: { assignment_properties_attributes: { scanned_exam: false, section_due_dates_type: 0, allow_web_submits: 0, vcs_submit: 0, - display_median_to_students: 0, display_grader_names_to_students: 0, + display_average_to_students: 0, display_median_to_students: 0, display_grader_names_to_students: 0, student_form_groups: 0, group_min: 1, group_max: 1, group_name_autogenerated: 1, allow_remarks: 0 }, submission_rule_attributes: { @@ -822,6 +822,7 @@ it_behaves_like 'update assignment_properties', :section_due_dates_type, false, true it_behaves_like 'update assignment_properties', :allow_web_submits, false, true it_behaves_like 'update assignment_properties', :vcs_submit, false, true + it_behaves_like 'update assignment_properties', :display_average_to_students, false, true it_behaves_like 'update assignment_properties', :display_median_to_students, false, true it_behaves_like 'update assignment_properties', :display_grader_names_to_students, false, true it_behaves_like 'update assignment_properties', :has_peer_review, false, true @@ -957,6 +958,7 @@ it_behaves_like 'create assignment_properties', :section_due_dates_type, true it_behaves_like 'create assignment_properties', :allow_web_submits, true it_behaves_like 'create assignment_properties', :vcs_submit, true + it_behaves_like 'create assignment_properties', :display_average_to_students, true it_behaves_like 'create assignment_properties', :display_median_to_students, true it_behaves_like 'create assignment_properties', :display_grader_names_to_students, true it_behaves_like 'create assignment_properties', :has_peer_review, true @@ -1010,7 +1012,7 @@ short_identifier: assignment.short_identifier, assignment_properties_attributes: { scanned_exam: false, section_due_dates_type: 0, allow_web_submits: 0, vcs_submit: 0, - display_median_to_students: 0, display_grader_names_to_students: 0, + display_average_to_students: 0, display_median_to_students: 0, display_grader_names_to_students: 0, student_form_groups: 0, group_min: 1, group_max: 1, group_name_autogenerated: 1, allow_remarks: 0 }, submission_rule_attributes: { diff --git a/spec/controllers/course_summaries_controller_spec.rb b/spec/controllers/course_summaries_controller_spec.rb index 34e8c0b1bc..a76b0c92e9 100644 --- a/spec/controllers/course_summaries_controller_spec.rb +++ b/spec/controllers/course_summaries_controller_spec.rb @@ -335,7 +335,7 @@ returned_averages = response_data[:graph_data][:average] returned_medians = response_data[:graph_data][:median] Assessment.order(id: :asc).each do |a| - averages << a.results_average&.round(2) + averages << (a.display_average_to_students ? a.results_average&.round(2) : nil) medians << (a.display_median_to_students ? a.results_median&.round(2) : nil) end expect(returned_medians.compact).to be_empty @@ -359,7 +359,13 @@ end end - context 'when display_median_to_students not set for any assignment' do + context 'when display_average_to_students set for some assignments' do + before { Assignment.order(id: :asc).first.assignment_properties.update(display_average_to_students: true) } + + it_behaves_like 'check_graph_data' + end + + context 'when display_median_to_students and display_average_to_students not set for any assignment' do it_behaves_like 'check_graph_data' end diff --git a/spec/fixtures/files/assignments/sample-timed-assessment-good/properties.yml b/spec/fixtures/files/assignments/sample-timed-assessment-good/properties.yml index 0276b5b44f..ad2de42656 100644 --- a/spec/fixtures/files/assignments/sample-timed-assessment-good/properties.yml +++ b/spec/fixtures/files/assignments/sample-timed-assessment-good/properties.yml @@ -20,6 +20,7 @@ assignment_properties_attributes: enable_student_tests: true allow_remarks: false display_grader_names_to_students: false + display_average_to_students: true display_median_to_students: false group_name_autogenerated: false vcs_submit: true diff --git a/spec/models/course_spec.rb b/spec/models/course_spec.rb index bca11c1234..9264d1c58d 100644 --- a/spec/models/course_spec.rb +++ b/spec/models/course_spec.rb @@ -265,7 +265,7 @@ let(:desired_attributes) do ['short_identifier', 'description', 1.day.from_now.at_beginning_of_minute, 'message', 1, 2, 1, true, true, 2.days.from_now.at_beginning_of_minute, 'remark_message', - true, true, false, true, true, true, true, false, nil, nil, true, true] + true, true, false, true, true, true, true, false, nil, nil, true, true, false] end let(:assignment) do csv = desired_attributes.to_csv @@ -385,7 +385,7 @@ let(:desired_attributes) do ['short_identifier', 'description', 1.day.from_now.at_beginning_of_minute, 'message', 1, 2, 1, true, true, 2.days.from_now.at_beginning_of_minute, 'remark_message', - true, true, false, true, true, true, true, false, nil, nil, true, true] + true, true, false, true, true, true, true, false, nil, nil, true, true, false] end let(:assignment) do desired_attribute_value_hash = Assignment::DEFAULT_FIELDS.zip(desired_attributes).to_h @@ -417,7 +417,7 @@ let!(:new_assignment_attr) do ['new', 'abc', 1.day.from_now.at_beginning_of_minute, 'message', 1, 2, 1, true, true, 2.days.from_now.at_beginning_of_minute, 'remark_message', - true, true, false, true, true, true, true, false, nil, nil, true, false] + true, true, false, true, true, true, true, false, nil, nil, true, false, false] end let!(:returned) do # create the old assignment @@ -802,7 +802,7 @@ def create_assignment_csv_string(assignment) assignment.assign_graders_to_criteria, assignment.enable_test, assignment.enable_student_tests, assignment.allow_remarks, assignment.display_grader_names_to_students, assignment.display_median_to_students, assignment.group_name_autogenerated, assignment.is_hidden, assignment.visible_on, assignment.visible_until, - assignment.vcs_submit, assignment.has_peer_review].to_csv + assignment.vcs_submit, assignment.has_peer_review, assignment.display_average_to_students].to_csv end def create_assignment_symbol_to_value_map(assignment) @@ -828,6 +828,7 @@ def create_assignment_symbol_to_value_map(assignment) enable_student_tests: assignment.enable_student_tests, allow_remarks: assignment.allow_remarks, display_grader_names_to_students: assignment.display_grader_names_to_students, + display_average_to_students: assignment.display_average_to_students, display_median_to_students: assignment.display_median_to_students, group_name_autogenerated: assignment.group_name_autogenerated, vcs_submit: assignment.vcs_submit,