From 5a8b74a1b0aca74dd4627bd728d4605e76e1a3b0 Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Tue, 20 May 2025 00:13:58 -0400 Subject: [PATCH 01/18] created test cases for assignment marks, edit and update --- spec/controllers/criteria_controller_spec.rb | 95 +++++++++++++++++--- 1 file changed, 83 insertions(+), 12 deletions(-) diff --git a/spec/controllers/criteria_controller_spec.rb b/spec/controllers/criteria_controller_spec.rb index 61b830a765..20decd3a70 100644 --- a/spec/controllers/criteria_controller_spec.rb +++ b/spec/controllers/criteria_controller_spec.rb @@ -220,23 +220,59 @@ end describe '#edit' do - before do - get_as instructor, - :edit, - params: { course_id: course.id, id: flexible_criterion.id }, - format: :js - end + context 'when assignment marks have not been released' do + before do + get_as instructor, + :edit, + params: { course_id: course.id, id: flexible_criterion.id }, + format: :js + end - it 'should respond with appropriate content' do - expect(assigns(:criterion)).to be_truthy - end + it 'should respond with appropriate content' do + expect(assigns(:criterion)).to be_truthy + end - it 'should render edit template' do - expect(subject).to render_template(:edit) + it 'should render edit template' do + expect(subject).to render_template(:edit) + end + + it 'should respond with success' do + expect(subject).to respond_with(:success) + end end - it 'should respond with success' do + # there should not be a bad request expectation because it was not implemented. + context 'when assignment marks have been released' do + let!(:released_assignment) do + create(:assignment, course: course).tap do |assignment| + # create one criterion *before* release + create(:flexible_criterion, assignment: assignment, name: 'Pre-release Criterion') + + grouping = create(:grouping, assignment: assignment) + submission = create(:submission, grouping: grouping) + submission.get_latest_result.update!(released_to_students: true) + end + end + + let(:flexible_criterion) do + released_assignment.criteria.find_by(type: 'FlexibleCriterion') + end + + before do + get_as instructor, + :edit, + params: { course_id: released_assignment.course_id, id: flexible_criterion.id }, + format: :js + end + + it 'flashes message with error' do + expect(flash[:notice]).to have_message(I18n.t('criteria.errors.released_marks')) + end + + it 'responds with success' do expect(subject).to respond_with(:success) + end + end end @@ -376,6 +412,41 @@ end end + describe '#update' do + context 'when assignment marks have been released' do + let!(:released_assignment) do + create(:assignment, course: course).tap do |assignment| + # create one criterion *before* release + create(:flexible_criterion, assignment: assignment, name: 'Pre-release Criterion') + + grouping = create(:grouping, assignment: assignment) + submission = create(:submission, grouping: grouping) + submission.get_latest_result.update!(released_to_students: true) + end + end + + let(:flexible_criterion) do + released_assignment.criteria.find_by(type: 'FlexibleCriterion') + end + + before do + post_as instructor, + :update, + params: { course_id: released_assignment.course_id, id: flexible_criterion.id }, + format: :js + end + + it 'flashes message with error' do + expect(flash[:error]).to have_message(I18n.t('criteria.errors.released_marks')) + end + + it 'responds with :bad_request status' do + expect(response).to have_http_status(:bad_request) + end + + end + end + describe '#edit' do before do post_as instructor, From f1636e69eefb9aebb905ca1e577442c40e1e4717 Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Tue, 20 May 2025 00:17:18 -0400 Subject: [PATCH 02/18] removed unnecessary comments --- spec/controllers/criteria_controller_spec.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/controllers/criteria_controller_spec.rb b/spec/controllers/criteria_controller_spec.rb index 9a50a8f04f..c0f138acd1 100644 --- a/spec/controllers/criteria_controller_spec.rb +++ b/spec/controllers/criteria_controller_spec.rb @@ -271,7 +271,6 @@ context 'when assignment marks have been released' do let!(:released_assignment) do create(:assignment, course: course).tap do |assignment| - # create one criterion *before* release create(:flexible_criterion, assignment: assignment, name: 'Pre-release Criterion') grouping = create(:grouping, assignment: assignment) @@ -468,7 +467,6 @@ context 'when assignment marks have been released' do let!(:released_assignment) do create(:assignment, course: course).tap do |assignment| - # create one criterion *before* release create(:flexible_criterion, assignment: assignment, name: 'Pre-release Criterion') grouping = create(:grouping, assignment: assignment) From 36c16d3195077bc40ebc1e253b2ec535cc612bee Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Tue, 20 May 2025 00:22:58 -0400 Subject: [PATCH 03/18] added myself to list of contributors --- doc/markus-contributors.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/markus-contributors.txt b/doc/markus-contributors.txt index 4dfe1fcdaa..ff85bd1d77 100644 --- a/doc/markus-contributors.txt +++ b/doc/markus-contributors.txt @@ -192,6 +192,7 @@ Shion Kashimura Simon Lavigne-Giroux Sohee Goo Stephen Tsimicalis +Steven Lin Su Zhang Tanveer Gill Tara Clark From f4bea093553d6b65f213fca275452d40adcb260b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 04:25:11 +0000 Subject: [PATCH 04/18] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- spec/controllers/criteria_controller_spec.rb | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/spec/controllers/criteria_controller_spec.rb b/spec/controllers/criteria_controller_spec.rb index c0f138acd1..af16f23c57 100644 --- a/spec/controllers/criteria_controller_spec.rb +++ b/spec/controllers/criteria_controller_spec.rb @@ -273,7 +273,7 @@ create(:assignment, course: course).tap do |assignment| create(:flexible_criterion, assignment: assignment, name: 'Pre-release Criterion') - grouping = create(:grouping, assignment: assignment) + grouping = create(:grouping, assignment: assignment) submission = create(:submission, grouping: grouping) submission.get_latest_result.update!(released_to_students: true) end @@ -295,9 +295,8 @@ end it 'responds with success' do - expect(subject).to respond_with(:success) + expect(subject).to respond_with(:success) end - end end @@ -469,7 +468,7 @@ create(:assignment, course: course).tap do |assignment| create(:flexible_criterion, assignment: assignment, name: 'Pre-release Criterion') - grouping = create(:grouping, assignment: assignment) + grouping = create(:grouping, assignment: assignment) submission = create(:submission, grouping: grouping) submission.get_latest_result.update!(released_to_students: true) end @@ -481,9 +480,9 @@ before do post_as instructor, - :update, - params: { course_id: released_assignment.course_id, id: flexible_criterion.id }, - format: :js + :update, + params: { course_id: released_assignment.course_id, id: flexible_criterion.id }, + format: :js end it 'flashes message with error' do @@ -493,7 +492,6 @@ it 'responds with :bad_request status' do expect(response).to have_http_status(:bad_request) end - end end From 48b03038285d18421c4b2c021fa9d65b10d0f158 Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Tue, 20 May 2025 00:26:21 -0400 Subject: [PATCH 05/18] added my change to changelog --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index a88076dafe..5743b9a29a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -15,6 +15,7 @@ - Remove `activerecord-session_store` gem (#7517) - Upgrade to Rails 8 (#7504) - Add tests for `#new` and `#create` actions in `CriteriaController` (#7521) +- Add tests for `#edit` and `#update` when user is trying to change criteria in `CriteriaController` (#7526) ## [v2.7.0] From 26f5e6cc28f84a5cfac57bde95c109085c5e0478 Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Wed, 28 May 2025 14:38:36 -0400 Subject: [PATCH 06/18] Added changes from 1 to 5 --- Changelog.md.orig | 1075 ++++++++++++++ app/views/assignments/_read.html.erb | 66 +- app/views/assignments/show.html.erb | 2 +- config/locales/views/assignments/en.yml | 5 +- config/locales/views/groups/en.yml | 2 +- .../criteria_controller_spec.rb.orig | 1259 +++++++++++++++++ 6 files changed, 2369 insertions(+), 40 deletions(-) create mode 100644 Changelog.md.orig create mode 100644 spec/controllers/criteria_controller_spec.rb.orig diff --git a/Changelog.md.orig b/Changelog.md.orig new file mode 100644 index 0000000000..773c45644d --- /dev/null +++ b/Changelog.md.orig @@ -0,0 +1,1075 @@ +# Changelog + +## [unreleased] + +### 🚨 Breaking changes + +### ✨ New features and improvements + +### 🐛 Bug fixes + +- Fix bugs when assigning sections to starter file groups across multiple assignments (#7523) + +### 🔧 Internal changes + +- Remove `activerecord-session_store` gem (#7517) +- Upgrade to Rails 8 (#7504) +- Add tests for `#new` and `#create` actions in `CriteriaController` (#7521) +<<<<<<< HEAD +- Add tests for `#edit` and `#update` when user is trying to change criteria in `CriteriaController` (#7526) +======= +- Add tests for `#edit` and `#update` when user is trying to change criteria in `CriteriaController` (#7527) +>>>>>>> upstream/master + +## [v2.7.0] + +### 🚨 Breaking changes + +### ✨ New features and improvements + +- Fix front-end content shift when an input element is focused (#7384) +- Tooltip text for Package requirements file for Python autotester settings (#7383) +- Pass back tags and overall comments from Autotester to MarkUs (#7387) +- Render download test result button on assignment summary page only if the assignment has automated testing (#7417) +- Group test results by Test Groups id (#7422) +- Display HTML previews of RMarkdown files (#7394) +- Allow instructors to assign scans to inactive students (#7482) +- Added members parameter to add_group_api to support explicit member assignment during group creation (#7481) +- Modified add_group_api to use username as group name for individual assignments (#7481) +- Improved styling of markdown previews in `MarkdownPreview` component and annotation displays (#7487) +- Allow creating image annotations from a test run's outputs (#7486) +- Added an API that collects a single submission (#7494) +- Enable removal of a student from a course (#7480) +- Changed the PDF scanning job separate the student matching process into its own job. (#7499) + +### 🐛 Bug fixes + +- Ensures row selection for peer reviewer unassigning has the same validation checks as individual selections (#7274) +- Ensures mark levels on a rubric criterion are properly scaled when its max mark is updated (#7311) +- Refactor contributors list in About section to read from markus-contributors.txt (#7374) +- Optimized the querying of submissions when assigning graders (#7381) +- Update remote_autotest_settings_id validation to be unique to an autotester (#7393) +- Fix tag creation failing in tags table (#7426) +- Ensure tag names are unique within an assignment (#7430) +- Update flash style to "notice" for "setting up test env" message (#7445) +- Fixed bug in `ImageViewer` where image width was set to 0 on initial load (#7485) +- Fixed bug in `ImageViewer` where annotations did not disappear when moving the mouse out of the image (#7485) +- Ensured annotations appear in results view when in fullscreen mode (#7487) +- Fixed bug in `ImageViewer` where annotations did not always appear on initial image load (#7487) + +### 🔧 Internal changes + +- Reorganize Javascript files to separate Sprockets and Webpack compilation (#7345) +- Replace moment.js dependency with much smaller dayjs (#7346) +- Refactor `FileViewer`, `TextViewer`, `BinaryViewer` and `ImageViewer` components (#7270) +- Pin `mistune` Python dependency to preserve compatibility with `nbconvert` (#7371) +- Cache playwright's chromium installation on GitHub Actions (#7372) +- Fix broken link to the Vagrant installation guide in `README.md` (#7349) +- Fix `extra_hosts` configuration in `compose.yaml` (#7375) +- Add unit tests for `marks_graders_controller` (#7382) +- Convert front-end tests from enzyme to react testing library; add `@testing-library/user-event` (#7379) +- Refactor the `Result` component and its children to use React context API (#7380) +- Implement `contain_message` and `have_message` custom Rspec matchers to check for flash message content (#7386) +- Update Python version to 3.13 in seed autotest schemas (#7388) +- Rename jupyter notebook content functions and files to generalize to html content (#7391) +- Update to React v18 (#7392) +- Refactor querying on dashboard graph to query per-assignment rather than per-TA (#7420) +- Remove unused Javascript files (#7442) +- Refactor scanned test generation and test splitting from polling to websockets (#7428) +- Move Docker dependency updates into separate service (#7451) +- Fixed flaky test due to daylight savings time issue (#7452) +- Updated Python autotest seed file to illustrate pytest metadata custom markers (#7457) +- Updated to react-flatpickr v4.0.0 (#7478) +- Remove `mistune` Python explicit dependency (#7483) +- Applied pre-commit (specifically Rubocop) changes to use it_behaves_like over include_examples (#7492) +- Added explicit permissions to GitHub Actions workflow configuration (#7495) + +## [v2.6.1] + +### ✨ New features and improvements + +- Give instructors the ability to delete a TA from the Users Graders Tab (#7304) +- Added zoom and rotate functionality to PDF viewer (#7306) + +### 🐛 Bug fixes + +- Ensure we handle JSON parsing exceptions when converting Jupyter Notebooks (#7308) +- Fixed bug in grading context menu for editing/deleting annotations (#7314) +- Fixed bug in grading annotations table when deleting annotations (#7314) +- Ensure correct LTI version of lti_user_id is used on launch (#7335) + +## [v2.6.0] + +### ✨ New features and improvements + +- Prevent instructors from unassigning peer reviewers who have existing peer review data (#7263) +- Add visual indicator on a per-assignment basis for used grace credits (#7226) +- Change default disabled text area colour to ligher grey on light mode (#7269) +- Implement a limit on the file size rendered by the submission viewer (#7273) +- Add an option to retain old grading data when recollecting graded submissions (#7256) + +### 🐛 Bug fixes + +- Fix incorrect calculation of token penalties when submissions are on time (#7216) +- Ensured submissions that have been released cannot be recollected from the repo browser (#7254) +- Fix bug where renaming a group to an existing group in a different assignment resulted in incorrect repository mapping (#7224) +- Disable editable fields in assignment criterion when criterion is released (#7264) +- Fixed Download One Time Annotation 'Not Found' error (#7302) + +### 🔧 Internal changes + +- Fix test coverage for ExamTemplate.create_with_file method (#7213) +- Upgrade Docker environment to use Ruby v3.3 (#7185) +- Upgrade to Rails v7.2 (#7185) +- Move Exception message in student model to a localization file (#7218) +- Add test cases for the student model to cover Group or Grouping save method failure (#7218) +- Create tests for overtime messages of the submission rule classes (#7216) +- Fix flaky `check_repo_permissions` test (#7223) +- Move model validation error messages to respective localization files (#7229) +- Replace time-warp gem with newer, maintained timecop gem (#7234) +- Update pre-commit-hooks to v5.0 and add checks `check-illegal-windows-names`, `check-json`, and `check-merge-conflict` (#7259) +- Merge result.js and result_main.css build files into application.js/application.css (#7260) +- Simplify pdf.js configuration (#7260) +- Improve descriptions of the Group and Grouping models (#7262) +- Disable Rubocop Style/SafeNavigationChainLength check (#7301) +- Ignore faker translations in i18n-js compilation (#7305) + +## [v2.5.3] + +### 🐛 Bug fixes + +- Fix Marks Spreadsheet csv bug of showing incorrect marks (#7257) +- Fix incorrect inclusion of course parameter in LtiSyncJob (#7258) +- Fix Google Colab Jupyter Notebooks rendering by excluding widgets (#7271) + +## [v2.5.2] + +### ✨ New features and improvements + +- Improve textviewer rendering speed (#7211) +- Add periodic roster syncing via LTI (#7178) +- Allow instructors to assign graders by section (#7179) + +### 🐛 Bug fixes + +- Fix JSON/CSV summary of test results to always be inline with latest test run (#7214) +- Allow annotations to be added to results with released peer reviews (#7222) + +### 🔧 Internal changes + +- Manually specify chromedriver port number in Github actions (#7209) + +## [v2.5.1] + +### 🐛 Bug fixes + +- Fix bug in syntax highlighting caused by incorrect function call (#7187) + +## [v2.5.0] + +### ✨ New features and improvements + +- Allow deletion of assignments with no groups (#6880) +- Add new routes for `update`, `show`, and `index` actions of the Sections API Controller (#6955) +- Enable the deletion of Grade Entry Forms that have no grades (#6915) +- Allow instructors to configure an end date until which students can run automated tests (#6992) +- Gave TAs read-only access to starter file information under assignment settings (#6996) +- Allow inactive groups in the submissions table to be toggled for display (#7000) +- Display error message for student-run tests when no test groups are runnable (#7003) +- Added a confirmation check while renaming a file with a different extension (#7024) +- Allow inactive groups in the summary table to be toggled for display (#7029) +- Display error message for instructor-run tests when no test groups are runnable by instructors (#7038) +- Ensure user params are passed as keyword arguments to database queries (#7040) +- Added a progress bar for when a student uploads a file for submission (#7078) +- Added validations to the `TextAnnotation` model to ensure `line_start` and `line_end` are >= 1, and `column_start` and `column_end` are >= 0. (#7081) +- Calculate and display the exact future time for the next token generation to help students plan their test runs more effectively. (#7127) +- Set the default date for "Tokens available on" to the current time (#7173). +- Add setting to enable filtering of new course creation from LTI launch (#7151) + +### 🐛 Bug fixes + +- Ensure annotation previews are rendered on annotations page and in annotation category dropdown menus when grading (#7073) +- Ensure annotation rendering is updated in real-time for Jupyter notebooks (#7084) +- Fix MathJax rendering in annotations for Jupyter notebooks (#7084) +- Fix MathJax rendering of released overall comments (#7084) +- Fix rename confirmation check triggering even upon no rename input (#7124) +- Ensured that the assignment deadline is used as a placeholder if token_end_date is not present. (#7128) +- Fixed grader view rendering when a pre-defined annotation's content is blank (#7147) +- Fixed AJAX requests in grader view, which were missing CSRF token headers (#7174) +- Use jQuery `.find` method in `ModalMarkus` to guard against potential XSS attack (#7176) +- Sanitize LTI deployment course names when creating new courses (#7151) + +### 🔧 Internal changes + +- Fixed login_spec.rb flaky test on GitHub Actions run (#6966) +- Minor improvements in assignment association options (#6989) +- Update changelog and pull request template formats (#7041) +- Upgrade to MathJax version 3, with packaging from npm (#7073) +- Upgrade CI chromedriver to 125.0.6422.60 (#7082) +- Fix flaky `Assignment#summary_json` test (#7111) +- Upgrade pdfjs-dist to v4.3.136 (#7113) +- Fixed formatting of documentation repository on the PR template (#7120) +- Switch from rails-sassc to cssbundling-rails for CSS asset management (#7121) +- Fixed flaky test #creates groups for individual students in groups_controller_spec (#7145) +- Switch from SyntaxHighlighter to Prism for syntax highlighting (#7122) +- Move jquery-ui and ui-contextmenu dependencies to package.json and upgrade jquery-ui to v1.13.3 (#7149) +- Do not enforce secure cookies in development for LTI deployments (#7151) +- Remove CI chromedriver version and Chrome dependency (#7170) +- Update Jupyter notebook Javascript dependencies (require.js to v2.3.7, plotly.js to v2.34.0) (#7175) +- Do not require i18n-tasks in Gemfile (#7180) + +## [v2.4.12] + +### ✨ New features and improvements + +- Added a backend to check MIME type and file extension of uploaded files (#7083) + +### 🐛 Bug fixes + +- Fix bug in grade display for marks summary (#7125) +- Remove peer reviews from grade summary table (#7126) + +## [v2.4.11] + +### 🚨 Breaking changes + +- Disallow peer reviewers from printing results (#7114) + +## [v2.4.10] + +### ✨ New features and improvements + +- Allow restricting IP addresses for remote logins (#7072) + +## [v2.4.9] +- Peer review table bug fix to display total marks (#7034) +- Fix bug preventing deletion of autotest files (#7033) + +## [v2.4.8] +- Validate user-provided paths (#7025) + +## [v2.4.7] +- Support Jupyter notebooks for results printing (#6993) +- Enable bulk download of print PDFs for an assignments (#6998) +- Fixed long annotations being cut off in the annotation table (#7001) + +## [v2.4.6] +- Disallow students from uploading .git file and .git folder in their repository (#6963) + +## [v2.4.5] +- Add workaround for CSP in Safari < 16 (#6947) +- Improve add button labels on autotest settings page (#6948) +- Fix bug where grader distribution graph displays graders multiple times (#6950) +- Fixed bug where TA Summary table failed to display members (#6949) +- Make display of group member information consistent across submissions and summary table (#6917) + +## [v2.4.4] +- Fix websocket connection when logged in with remote auth (#6912) +- Fix bug where graders table failed to load when a group had no members (#6916) + +## [v2.4.3] +- Fix autotest settings criterion JSON schema validation (#6907) +- Ensure autotested criteria do not have marks set if tests time out (#6907) +- Fix import bug that prevents the peer review table from loading (#6908) + +## [v2.4.2] +- Fix feedback file API not returning feedback file IDs correctly (#6875) +- Allow inactive groups in the graders table to be toggled for display (#6778) +- Enable plotly rendering for jupyter notebooks (#6871) +- Bug Fix: Prevent assigning inactive graders to a group (#6801) +- Added new API routes for the `create` and `destroy` actions of SectionsController (#6873) +- Display error message in real-time when running automated tests, rather than waiting for page refresh (#6878) + +## [v2.4.1] +- Internal changes only + +## [v2.4.0] +- Display error message on file upload failure (#6703) +- Remark request grading: differentiate between old and new annotations using colour and remark flag (#6704) +- Display detailed messages about grace period deductions for an assignment on student interface (#6706) +- Moved create and edit tag modals to React (#6742) +- Added constraint for `Tag` name field: not empty and max 30 characters (#6742) +- Modified and moved helper methods from `CriteriaHelper` into static methods in the `Criterion` class (#6746) +- Convert helper methods of the module `app/helpers/annotations_categories_helper` into class methods of the + `AnnotationCategory` model. The refactored helper methods were `annotation_categories_to_yml` and + `upload_annotations_from_yaml` (#6747) +- Added tooltips to criteria type and visibility icons (#6753) +- Replace the function `tas` of the `Assignment` model with a `tas` "has_many" association for that model (#6764) +- Ensure starter files are passed to autotester in sorted order (#6771) +- Resolved issue 6677 by taking timed assessment's duration into account when determining when grading can begin (#6845) +- Fix loading results page when group is created after the due date (#6863) +- Autocomplete with active students only for matching process in 'assign scans' (#6844) +- Fix member filtering in Groups table (#6842) + +## [v2.3.4] +- Ensure the "Random Incomplete Submission" button takes into account criteria assignment for TAs (#6800) +- Ensure bonus marks are not included in assignment "out of" in submissions table (#6836) +- Ensure assignment "out of" in submissions table is rounded to two decimal places (#6836) +- Added POST API for Group Creation (#6834) + +## [v2.3.3] +- Fix bug where uploading scanned exam pages with overwriting option selected did not update submission files (#6768) +- Fix bug: "Download Submissions" download link was not being rendered from partial view (#6779) + +## [v2.3.2] +- Allow MathJAX to process environments (e.g., align) (#6762) + +## [v2.3.1] +- Add filter for empty/non-empty submissions in submissions table (#6711) +- Fix bug where autotest settings would not appear if there were no assignment criteria (#6718) +- Added API routes for Extensions API (#6743) +- Fix premature page reloading when autotest settings are saved (#6744) + +## [v2.3.0] +- Do not destroy pending group memberships if the group is given an extension (#6582) +- Add OCR for parsing scanned exam uploads (#6433) +- Move submission-specific results/ routes to be under submissions/ (#6434) +- Add option to allow Cross-Origin Resource Sharing (CORS) from JupyterHub (#6442) +- Fix error message when a file is submitted through the API that doesn't match the required file list (#6479) +- Improve syntax highlighting for C (#6513) +- Allow negative grades for bonus columns in marks spreadsheets (#6521) +- Clarify assignment submission rule configuration labels (#6529) +- Enable client-side validation of autotest settings page (#6568) +- Use web sockets instead of polling to update submissions table after collecting submissions (#6583) +- Order students by username when downloading the CSV grades breakdown for an assignment from Summary tab (#6589) +- Use web sockets to update TestRunTable for non-batch run tests when a test run is in progress or completed (#6591) +- Add button to allow students to cancel automated test runs (#6596) +- Use web sockets instead of polling to update submission collection status (#6597) +- Removed trailing spaces at end of every line when viewing a file (#6598) +- Modify MarkUs API to allow the CoursesController#index route to accept requests from all types of roles (#6619) +- Modify MarkUs API to allow the AssignmentsController#index route to accept requests from all types of roles (#6619) +- A user can't run tests with the same names / Single test error does not spoil the whole test batch (#6620) +- Refactored GET requests to use fetch API instead of jQuery (#6622) +- Change icon set to Font Awesome (Free) (#6627) +- Add feature to generate a PDF report of a result (PDF submission files only) (#6635) +- Add zoom feature to scanned exam template crop selection (#6640) +- Ensure Jupyter notebook HTML rendering does not require external CDNs (#6656) +- Prevent Jupyter notebook from reloading when an annotation is added (#6656) +- Added a button allowing graders to view a random incomplete submission (#6641) +- Added a filter modal allowing graders to specify filters and order when navigating submissions (#6642) +- Add icons to submission and result grading action buttons (#6666) +- Remove group name maximum length constraint (#6668) +- Fix bug where in some cases flash messages were not being rendered correctly (#6670) +- Enable duplicate pages when uploading scanned exams to overwrite existing pages or be ignored (#6674) +- Extended the filter modal to allow graders to order results by total mark and filter them by criteria (#6669) +- Validate copy and page number when fixing errors with scanned exams (#6695) +- Display due date and submission time in result "Submission Info" tab (#6698) +- Added "Help" link to the MarkUs page header dropdown (#6702) +- Prevent TAs that aren't assigned to grade a given criterion from assigning a grade to that criterion (#6699) +- Replace byebug gem with debug gem (#6705) +- Added persistence to the filter modal (#6697) + +## [v2.2.4] +- Add feature to generate a PDF report of a result (PDF submission files only) (#6635) + + +## [v2.2.3] +- Fix bug where in some circumstances the wrong result would be displayed to students (#6465) + +## [v2.2.2] +- Apply course maximum file size to feedback files (#6430) + +## [v2.2.1] +- Fix bug where error was raised when viewing jupyter notebooks if python is not available (#6418) +- Fix bug where peer reviewers could not view results they are assigned to review (#6439) +- Make fewer connections when connecting to redis (#6443) + +## [v2.2.0] +- Moved markdown text preview to new tab in the generic autosaving text form component (#6154) +- Simplify configuration options for storing files on disk (#6157) +- Replace yarn with npm as a package manager (#6159) +- Drop support for subversion repositories (#6160) +- Fix undefined prop type warnings when loading assessment charts (#6172) +- Allow graders and instructors to be set to hidden status (#6173) +- Prevent hidden roles from interacting with a course (#6173) +- Do not dynamically change the database schema which causes migration and installation issues (#6189) +- Make git hooks more portable by converting them to shell scripts (#6196) +- Don't start webpack docker service in development before the packages are fully installed (#6212) +- Added ability to download feedback files (#6215) +- Allow admins to set the autotester url for each course in the courses view (#6213) +- Allow admins to test and reset the connection to the autotester in the courses view and through the API (#6213) +- Fix bug where exam template was downloaded instead of copies with unique qr codes (#6219) +- Allow admin users to manage the maximum file size setting through the UI (#6195) +- Disable python features if python dependencies are not installed (#6232) +- Install system dependencies from a debian package (#6246) +- Fix bug where assignments could not be uploaded with unexpected properties in file upload content (#6224) +- Fix bug where tests group results associated with old test groups aren't displayed with test group information (#6285) +- Read the MarkUs version once at initialization instead of at every request (#6305) +- Allow spaces in file names (#6306) +- Fix bug where a request to cancel test runs failed if some test runs had already completed (#6320) +- Downloading files from a single repository no longer adds an additional subdirectory to the zip archive (#6323) +- Bulk submission collection: allow collecting the most recent revision and choosing whether to apply late penalties (#6341) +- Allow admins to role switch to instructors (#6353) +- Fix bug where rubric grades could not be selected with the return key (#6354) +- Allow admins to set the number of puma workers and threads from the settings files (#6348) +- Fix bug where a user who has switched roles could not view the about modal or log out (#6356) +- Fix bug where grades summary charts flicker in some browsers (#6352) +- Fix bug where emoji annotation options were available even when no text/region was selected (#6384) +- Fix bug where certain results attributes could not be updated if the result was incomplete (#6388) + +## [v2.1.7] +- Switch from jquery-ui-timepicker-addon to flatpickr for datetime inputs (#6158) +- Allow results to be made available only through unique tokens (#6244) + +## [v2.1.6] +- Fix bug where TAs were able to access urls for results they haven't been assigned to (#6321) +- Fix bug where the marking state was left as "complete" after a new criterion is created (#6303) +- Fix bug where writing starter files to repositories failed if the starter files contained a directory (#6294) +- Fix bug where csv summary download fails if criteria are created after marking (#6302) + +## [v2.1.5] +- Add admin users to the .access file so that they can be authenticated as having access to the git repos (#6237) +- Optionally log which user makes each request by tagging the log files with user_names (#6241) +- Allow users to upload and download csv files for marks spreadsheets in the same format (#6267) +- Hide manual submission collection button from users who don't have permission (#6282) +- Fix bug where gzipped binary feedback files were not unzipped correctly (#6283) +- Fix bug where remark request summary table wasn't being rendered correctly (#6284) +- Fix bug where test results were being associated with the wrong test runs (#6287) + +## [v2.1.4] +- Fix bug where git hooks are not run server side when symlinked (#6276/#6277) + +## [v2.1.3] +- Fix bug where automated test results were occasionally associated with the wrong grouping (#6238) + +## [v2.1.2] +- Fix bug preventing use of the update_grades API route (#6188) +- Fix overly restrictive policies for admin users (#6209) +- Add check for version format to ensure that Wiki links are well-formed (#6221) +- Fix bug where empty groups are hidden by default (#6222) +- Fix bug where test run table did not re-render when switching results (#6223) +- Allow admin users to manage the maximum file size setting through the UI (#6195) + +## [v2.1.1] +- Fix bug where files could not be uploaded using drag and drop if no files or folders previously existed. (#6117) +- Added drag and drop functionality to upload starter files and automated tests. (#6117) +- Added new summary statistics display for grade entry forms and grade entry column items (#6118) +- Moved markdown text preview to new tab in the modify/create annotation modal (#6138) +- Enable bulk removal of students from section in student table (#6145) +- Enable updating student active/inactive status in student edit form (#6145) + +## [v2.1.0] +- Remove unmaintained locales (#5727) +- Introduce standalone ruby script as an alternative method to checking for repository access (#5736) +- Added the ability to submit URLs (#5822) +- Switch Javascript bundling to jsbundling-rails gem, and update to webpack v5 (#5833) +- Remove group name displayed attribute from assignment properties table (#5834) +- Rework scanned exam page (#5839) +- Replace uses of first name and last name attributes with display name (#5844) +- Fix bug for rubric criteria level's mark update where one of the marks = an old mark (#5854) +- Upgrade to Rails 7 (#5885) +- Move footer and information in top right corner of navigation bar into a dropdown menu in the top right corner (#5886) +- Modified login to allow admin users to login via the UI (#5897) +- Fix bug where admins viewing the admin page were not redirected properly when timed out (#5909) +- Added a list of courses to manage for new markus administration view (#5907) +- Added a page in new markus administration view that allows admins to edit the attributes of a course (#5915) +- Added a page in new markus administration view that allows admins to create a new course (#5917) +- Added a list of users to manage for new markus administration view (#5918) +- Added Resque monitoring views for admin users (#5919) +- Added a page in new markus administration view that allows admins to edit user information (#5921) +- Added a page in new markus administration view that allows admins to create users (#5923) +- Added course visibility status to admin courses list (#5924) +- Added ability for instructors to edit course visibility (#5925) +- Fix bugs when handling remark requests with deductive annotations (#5926) +- Modified model associations so that a role belongs to a user (#5948) +- Fix display of flash messages when creating criteria and annotations (#5949) +- Display error messages on group csv upload when there are invalid group names (#5952) +- Created a new admin role (#5956) +- Added a bulk upload of end users to admin users page (#5959) +- Fix display of "Submit File" to "Upload File" for non submission views (#5960) +- Added an "Assign Scans" link to exam templates page (#5962) +- Added background job to clean tmp folder (#5963) +- Removed consideration of due date from scanned exam (#5964) +- Added Exception Notification Gem (#5965) +- Bug fixes for peer reviews (#5968) +- Added Rails Performance to Admin Dashboard (#5967) +- Added a detailed view for assignment statistics (#6000) +- Resolved issue 5905 by adding an explicit download icon to file manager, to differentiate from file preview action (#6001) +- Added student data such as user name, last name, first name, section, id number and email on grade reports for the whole course, individual assignments and grade entry forms (#6005) +- Update Groups API to return member role IDs instead of user IDs (#6006) +- Switch rendering of RMarkdown submission files to plaintext, rather than converting to HTML (#6008) +- Ensure consistent order when displaying test results (#6010) +- Added Capybara Gem (#6012) +- Enable students to rename files during submission (#6045) +- Separated peer review assignment upload/download from parent (#6048) +- Expanded summary stats UI (#6050) +- Fix bug for submission modal where students could submit files even if no file was chosen (#6052) +- Added ability to have a non-uniform group distribution when assigning graders (#6055) +- Added new "submit_file" API assignment route for students (#6057) +- Removed searchbar used to filter files on submissions page (#6058) +- Removed "outstanding_remark_request_count" attribute (#6059) +- Added checklist for required files on submissions page (#6061) +- Changed flash message that is displayed when students upload a file with an incorrect name. (#6062) +- Added emoji annotations for graders and removed `control+click` quick annotations. (#6093) +- Sorted courses on the dashboard. (#6099) +- Added summary statistics for criteria (#6100) +- Improved UI on 404 and 403 pages to match the style on MarkUs' dashboard. (#6101) +- Pass group name and starter files to the autotester when running tests (#6104) +- Handle multiple feedback files sent from the autotester (#6106) +- Added API CRUD requests for tags (#6107) +- Disabled admin editing of course name and allowed instructors to edit display name (#6111) +- Added explicit status and filtering for inactive students and groups in assignment groups page. (#6112) +- Fixed flaky automated test file tests by rearranging order of test file cleanup (#6114) +- Changed nav bar layout by moving the MarkUs logo beside the course name on the top bar (#6115) +- Replace standalone ruby script to check for repository access with database function (#6116) +- Update git over ssh scripts to optionally use the database function to check for repository access (#6116) +- Ensure each file viewer has independent syntax highlighting (#6139) +- Update git over ssh scripts to use the database function to check for authorized keys (#6142) +- Remove support for sqlite and mysql database types (#6143) +- Replace uglifier gem with terser gem to support ES6 syntax (#6146) +- Reorganize rake tasks to simplify steps required for asset precompilation in production (#6146) + +## [v2.0.10] +- Fix bug when sorting batch test runs where sorting by date was not working (#5906) +- Ensure tabs in result view do not reload when switching between them (#5910) +- Fix bug where penalty periods were sometimes incorrectly ordered (#5908) + +## [v2.0.9] +- Fix bug when downloading all automated test files where the files were saved to a sub directory (#5864) +- Fix bugs in assigning scanned exams and improve error message when assigning by name (#5895) +- Remove MarkUs logo from mobile view left navigation menu (#5899) +- Allow adding annotations to remark requests (#5900) + +## [v2.0.8] +- Fix bug where "run tests" grader permission was not working for submission table (#5860) +- Fix bug for replacing exam template files (#5863) + +## [v2.0.7] +- Fix bugs in starter files when assigning by section (#5846) + +## [v2.0.6] +- Fix bug for "Delete Group" button generating an invalid path (#5768) +- When role switched, 403 errors are displayed as flash messages after redirecting back to the previous page (#5785) +- Update wiki urls to point to https://github.com/MarkUsProject/Wiki (#5781) +- Allow TAs to download grades for students they've been assigned to grade (#5793) +- Fix bug for menu icon not working on mobile devices / smaller screens (#5818) +- Fix bugs when submitting and cancelling remark requests (#5838) +- Do not trigger starter file changed timestamp when only starter_files_after_due assignment setting is changed (#5845) + +## [v2.0.5] +- Add ability to annotate notebook (jupyter and Rmd) submissions (#5749) + +## [v2.0.4] +- Fix bug where "Create Note" button was displaying when a course had no noteables (#5745) +- Redesign login page for multiple authentication options (#5752) +- Do not timeout users who are logged in using remote authentication (#5738) +- Ensure users logged in using remote authentication have their session expired when logging out from remote authentication (#5738) +- Display error message for users logging in using remote authentication if they do not exist in MarkUs database (#5738) +- Fix bug where git hooks were not finding the correct file containing the maximum file size for a given course (#5744) +- Allow setting optional role attributes through the api (#5748) +- Allow students to populate their repositories with starter files (#5754) + +## [v2.0.3] +- Fix bug where repository access files were not taking multiple courses into account (#5734) +- Fix bug where sections and grace credits could not be updated from the student edit view (#5739) + +## [v2.0.2] +- Fix bug in displaying feedback files for test results (#5719) +- Require starter group names to be unique for an assignment (#5721) +- Fix bug in updating the autotester url for a given course (#5724) + +## [v2.0.1] +- Fix bug where a login with remote authentication failed to redirect to the landing page (#5690) +- Allow admin user to have a unique user name (#5691) + +## [v2.0.0] +- Support multiple courses in a single MarkUs instance (#5685) + +## [v1.14.1] +- Update wiki urls to point to https://github.com/MarkUsProject/Wiki (#5782) + +## [v1.14.0] +- Add the ability to hide assignments from individual sections (#5445) +- Display smaller error message when nbconvert fails to avoid a cookie overflow (#5510) +- Fix bug with run test button in grading view when marks are released (#5527) +- Update repository access permissions to take into account the Assignment + is_hidden and anonymize_groups attributes (#5547) +- Support syntax highlighting for R (#5558) +- Fixes in progress remark requests to display the remark request due date for students (#5562) +- Preserve exam template paper size and orientation when stamping with QR codes (#5573) +- Fix bugs in automatic parsing Python module (#5592) +- Fix exam template automatic parsing to only accept one crop box, and parse either + ID number or user name (#5592) +- Fix scanned exams when using automatic parsing with multiple exam templates (#5592) +- Fixes assignment graders checkbox settings text to avoid double negatives (#5600) +- Add test results download modal for assignment summary (#5561) +- Improve accessibility of exam templates page (#5607) +- Fix display bug with infinitely expanding chart in student results view for grade entry form (#5612) +- Added the ability to copy over entire assignments (#5616) +- Fix bug in User#visible_assessments for students in a section (#5634) +- Fixed bug where tag edit modal closed whenever it is clicked (#5652) +- Fix bug where the datetime selector wasn't being shown for peer review assessments (#5659) +- Fix bug in displaying associated feedback files when switching between results (#5676) + +## [v1.13.3] +- Display multiple feedback files returned by the autotester (#5524) +- Add workaround for CSP rules in Safari (#5526) +- Change level mark input field to accept change increments of 0.01 (#5546) +- Fix bug in annotation upload when updating categories not associated with a criterion (#5564) + +## [v1.13.2] +- Ensure "Create all groups" button uses existing repos if they already exist (#5504) +- Set criteria marks after autotest run (#5508) + +## [v1.13.1] +- Ensure that downloadable test specs file is portable between assignments and instances (#5469) +- Support rendering of Markdown in criterion descriptions (#5500) +- Ensure "Create all groups" button creates repositories for students usering their user name (#5499) + +## [v1.13.0] +- Modify Result.get_total_extra_marks to differentiate between having extra marks that sum to zero and + having no extra marks (#5220) +- Add copy to clipboard button for plaintext submission files in Results view (#5223) +- Add ability to associate feedback files to test group results (#5209) +- Communicate with autotester over http to support new autotesting configuration (#5225) +- Remove activerecord-import dependency (#5248) +- Combine all python dependencies (#5358) +- Rename "Tags/Notes" tab on grading page to "Submission Info", and move membership information to the tab (#5380) +- Respect referrer url when navigating between assignments (#5409) +- Remove delete link from TA table (#5407) +- Persist file size and rotation when navigating between text and image files (#5413) +- Improve student UI for timed assessments (#5417) +- When completing bulk actions, report errors instead of halting the whole process and rolling back (#5422) +- Add ability to download data from submissions table as csv file (#5418) +- Correctly update annotation category when creating annotation from "Did you mean" suggestion (#5448) +- Add route to download an example of the starter files that may be assigned to students (#5449) +- Validate a user's locale to ensure that it is set to a valid value (#5450) +- Display due date, collection date, and start time in repo browser view (#5462) +- Create dark mode versions of logo and favicon (#5463) +- Update UI for test results table (#5465) + +## [v1.12.5] +- Fix bugs in grading view when switching between submissions (#5400) + +## [v1.12.4] +- Symlink git repo hooks (#5283) + +## [v1.12.3] +- Add workaround for content security policy to allow loading blobs in Safari (#5273) + +## [v1.12.2] +- Require TestServer user to have a non-conflicting user name (#5268) + +## [v1.12.1] +- Remove counter caches (#5222) +- Delay grouping creation for working-alone timed assessments to when the student starts the assessment (#5224) +- Add option to hide starter files after collection date (#5226) + +## [v1.12.0] +- Remove annotations context menu from peer assignments view (#5116) +- Change 'Next' and 'Previous' submission button to use partial reloads (#5082) +- Add time zone validations (#5060) +- Add time zone to settings (#4938) +- Move configuration options to settings yaml files (#5061) +- Removed server_time information in submissions_controller.rb and server_time? from submission_policy.rb (#5071) +- Add rake tasks to un/archive all stateful files from a MarkUs instance (#5069) +- Fix bug where zip files with too many entries could not be uploaded (#5080) +- Add button to assignment's annotations tab to allow instructor to download one time annotations (#5088) +- Removed AssignmentStats table (#5089) +- Display assignment totals on the grade summary table rounded up to 2 decimal places (#5123) +- Removed results_average, results_median, results_fails, results_zeros cached stats (#5131) +- Do not allow users to set repo names by uploading csv files (#5132) +- Added a delete button to notes dialog under an results edit view and removed user_can_modify under note model, + removed Notes#user_can_modify and replaced instances of usage with NotePolicy (#5128) +- Support Markdown syntax for assessment messages (#5135) +- Remove controller-specific css files (#5136) +- Replace non-UTF8 characters in text file preview (#5156) +- Rollback group creation if error is raised when creating a group for a working-alone student (#5169) +- Prevent deletion/modification of annotation texts associated with a result with a pending remark request (#5170) +- Enhancing student submission log with required assignment file info, file size (fixes issue 5171) (#5188) +- Ensure that browsers cache the correct state of overall comments when marking (#5173) +- Ensure that graders are shown the correct annotation categories (#5181) +- Show informative error message if an uploaded criteria yaml file did not contain a "type" key (#5184) +- Enable content security policies (#5186) +- Allow for multiple custom validation messages (#5194) +- Add ability to hold shift to select a range of values in checkbox tables (#5182) +- Update ssh authorization to be more flexible, secure, and permit a single user to use the same public key for multiple instances (#5199) +- Fix bug where creating an annotation or switching results reset the selected file (#5200) +- Fix bug in Assignment#get_num_marked that caused it to double-count remark and original results (#5205) +- Update permission files in background jobs (#5207) +- Fix bug where graders can't see the tests that they run (#5210) +- Fix bug where graders can't release results on the results page (#5210) +- Use DOMpurify library to sanitize rendered markdown content (#5211) +- Add percentage extra marks when calculating total extra marks properly (#5213) + +## [v1.11.5] +- Account for percentage deductions when calculating total marks after deleting a criterion (#5176) +- Prevent students from downloading starter files early (#5189) + +## [v1.11.4] +- Override defaultSortMethod for react-table to put null/undefined values at bottom (#5159) +- Fix bug where groupings created before starter files were uploaded could not download starter files (#5160) + +## [v1.11.3] +- Fix easyModal overlay bug (#5117) + +## [v1.11.2] +- Fix bug where newlines were being added to files in zip archives (#5030) +- Fix bug where graders could be assigned to groups with empty submissions (#5031) +- Use Fullscreen API for grading in "fullscreen mode" (#5036) +- Render .ipynb submission files as html (#5032) +- Add option to view a binary file as plain text while grading (#5033) +- Fix bug where a remarked submission wasn't being shown in the course summary (#5063) +- Fix bug where the server user's api key was being regenerated after every test run creation (#5065) +- Fix bug where additional test tokens were added after every save (#5064) +- Fix bug where latex files were rendered with character escape sequences displayed (#5073) +- Fix bug where grader permission for creating annotations were not properly set (#5078) + +## [v1.11.1] +- Fix bug where duplicate marks can get created because of concurrent requests (#5018) +- Only display latest results for each test group to students viewing results from an released assignment (#5013) +- Remove localization path parameter (#4985) + +## [v1.11.0] +- Converts annotation modals from ERB into React (#4997) +- Refactor localization setting to settings page (#4996) +- Add admins to display name (#4994) +- Adds MathJax and Markdown support for remark requests (#4992) +- Use display name on top right corner (#4979) +- Add display name to settings (#4937) +- Create the required directory when uploading zip file with unzip is true (#4941) +- Remove preview of compressed archives in repo browser (#4920) +- Add singular annotation update feature when updating non-deductive categorized annotations (#4874) +- Replace Time.now and Time.zone.now with Time.current (#4896) +- Fix lingering annotation text displays when hovering (#4875) +- Add annotation completion to annotation modal (#4851) +- Introduce the ability to designate criteria as 'bonus' marks (#4804) +- Enable variable permissions for graders (#4601) +- UI for enable/disable variable permissions for graders (#4756) +- Image rotation tools added in marking UI (#4789) +- Image zooming tools added in marking UI (#4866) +- Fixed a bug preventing total marks from updating properly if one of the grades is nil (#4887) +- Group null/undefined values when sorting on dates using react-table (#4921) +- Add user settings page (#4922) +- Render .heic and .heif files properly in the file preview and feedback file views (#4926) +- Allow students to submit timed assessments after the collection date has passed even if they haven't started yet (#4935) +- No longer add starter files to group repositories when groupings are created (#4934) +- When starter files are updated, try to give students the updated version of the starter files they already have been assigned (#4934) +- Display an alert when students upload files without having downloaded the most up to date starter files first (#4934) +- Rename the parameter in get_file_info from id to assignment_id (#4936) +- Fix bug where maximum file size for an uploaded file was not enforced properly (#4939) +- Add counts of all/active/inactive students to students table (#4942) +- Allow feedback files to be updated by uploading a binary file object through the API (#4964) +- Fix a bug where some error messages reported by the API caused a json formatting error (#4964) +- Updated all authorization to use ActionPolicy (#4865) +- Fix bug where note creation form could be submitted before the form had finished updating (#4971) +- Move API key handling to user Settings page (#4967) +- Fix bug that prevented creation of scanned exams (#4968) +- Fix bug where subdirectories were not being created with the right path in the autotest file manager (#4969) +- Fix bug where penalty periods could have interval/hour values of zero (#4973) +- Add color theme settings (#4924) + +## [v1.10.4] +- Fix bug where students could see average and median marks when the results had not been released yet (#4976) +- Add email and id_number to user information returned by get requests to api user routes (#4974) + +## [v1.10.3] +- Allow for more concurrent access to git repositories (#4895) +- Fixed calculation bugs for grade summary (#4899) +- Fixed a bug where due dates in a flash message were incorrect for timed assessments (#4915) +- Allowed the difference between the start and end times of a timed assessment to be less than the duration (#4915) +- Fixed bug where negative total marks may be displayed when a negative extra mark exists (#4925) + +## [v1.10.2] +- Ensure that assignment subdirectories in repositories are maintained (#4893) +- Limit number of tests sent to the autotest server at one time (#4901) +- Restore the flash messages displayed when students submit files (#4903) +- Enable assignment only_required_files setting to work with subdirectories (#4903) +- Fix bug where checkbox marks are updated twice (#4908) +- Fixed the Assign Reviewers table loading issue (#4894) +- Fixed a bug where the progress bar in submissions and results page counts the not collected submissions (#4854) + +## [v1.10.1] +- Fix out of dates link to the wiki (#4843) +- Fixed a bug where the grade summary view was not being properly displayed if no criteria existed (#4855) +- Fixed an error preventing graders from viewing grade entry forms (#4857) +- Fixed an error which used unreleased results to calculate assignment statistics (#4862) + +## [v1.10.0] +- Issue #3670: Added API for adding and removing extra marks (#4499) +- Restrict confirmation dialog for annotation editing to annotations that belong to annotation categories (#4540) +- Fixed sorting in annotation table in results view (#4542) +- Enabled customization of rubric criterion level number and marks (#4535) +- Introduces automated email sending for submissions releases (#4432) +- Introduces automated email sending for spreadsheet releases (#4460) +- Introduces automated email sending for grouping invitations (#4470) +- Introduces student email settings (#4578) +- Assignment grader distribution graphs only show marks for assigned criteria when graders are assigned specific + criteria (#4656) +- Fixed bug preventing graders from creating new notes in results view (#4668) +- Fixed bug preventing new tags from being created from results view (#4669) +- Remove deprecated "detailed CSV" download link from submissions/browse (#4675) +- Introduces Deductive Annotations (#4693) +- Introduces annotation usage details panel to Annotations tab in admin settings (#4695) +- Fixed bug where bonuses and deductions were not displayed properly (#4699) +- Fixed bug where image annotations did not stay fixed relative to the image (#4706) +- Fixed bug where image annotations did not load properly (#4706) +- Fixed bug where downloading files in nested directories renamed the downloaded file (#4730) +- Introduces an option to unzip an uploaded zip file in place (#4731) +- Fixed bug where marking scheme weights were not displayed (#4735) +- Introduces timed assignments (#4665) +- Introduces uncategorized annotations grouping in Annotations settings tab (#4733) +- Introduces new grades summary chart, and makes student view of grades consistent with admin (#4740) +- Set SameSite=Lax on cookies (#4742) +- Introduces individual marks chart view for assessments (#4747) +- Fix annotation modal overflow issue (#4748) +- Introduce file viewer for student submission file manager and admin repo manager (#4754) +- Make skipping empty submissions the default behaviour when assigning graders (#4761) +- Introduce typing delay for entering flexible criterion mark (#4763) +- Fix UI overflow bug for large images in results file viewer (#4764) +- Add disabled delete button to submissions file manager when files unselected (#4765) +- Support syntax highlighting for html and css files (#4781) +- Add minutes field to non timed assessment extension modal (#4791) +- Add ability to check out git repositories over ssh using a public key uploaded in the new Key Pairs tab (#4598) +- Unify criterion tables using single table inheritance (refactoring change) (#4749) +- Add support for uploading multiple versions of starter files (#4751) +- Remove partially created annotation category data for failed upload (#4795) + +## [v1.9.3] +- Fixed inverse association bug with assignments (#4551) +- Fixed bug preventing graders from downloading submission files from multiple students (#4658) +- Fixed bug preventing downloading all submission files from git repo (#4658) + +## [v1.9.2] +- Fixed bug preventing all git hooks from being run in production (#4594) +- Fixed bug preventing folders from being deleted in file managers (#4605) +- Added support for displaying .heic and .heif files in the file viewer (#4607) +- Fixed bug preventing students from running tests and viewing student-run test settings properly (#4616) +- Fixed a bug preventing graders viewing the submissions page if they had specific criteria assigned to them (#4617) + +## [v1.9.1] +- Fixed bug where the output column was not shown in the test results table if the first row had no output (#4537) +- Fixed N+1 queries in Assignment repo list methods (#4543) +- Fixed submission download_repo_list file extension (#4543) +- Fixed bug preventing creation of assignments with submission rules (#4557) +- Fixed inverse association bug with assignments (#4551) +- Updated interface with the autotester so that files do not need to be copied when test are setup/enqueued (#4546) + +## [v1.9.0] +- Added option to anonymize group membership when viewed by graders (#4331) +- Added option to only display assigned criteria to graders as opposed to showing unassigned criteria but making them + ungradeable (#4331) +- Fixed bug where criteria were not expanded for grading (to both Admins and TAs) (#4380) +- Updated development docker image to connect to the development autotester docker image (#4389) +- Fixed bug where annotations were not removed when switching between PDF submission files (#4387) +- Fixed bug where annotations disappeared on window resize (#4387) +- Removed automatic saving of changes on the Autotesting Framework page and warn when redirecting instead (#4394) +- Added progress message when uploading changes on Automated Testing tab (#4395) +- Fixed bug where the error message is appearing when the instructor is trying to collect the submission of the student + who hasn't submitted anything (#4373) +- Ignore the "Total" column when uploading a csv file to a grade entry form. This makes the upload and download format + for the csv file consistent (#4425) +- Added git hook to limit the maximum file size committed and/or pushed to a git repository (#4421) +- Display newlines properly in flash messages (#4443) +- Api calls will now return the 'hidden' status of users when accessing user data (#4445) +- Make bulk submission file downloads a background job (#4463) +- Added option to download all test script files in the UI and through the API (#4494) +- Added syntax highlighting support for .tex files (#4505) +- Fixed annotation Markdown and MathJax rendering bug (#4506) +- Fixed bug where a grouping could be created even when the assignment subdirectory failed to be created (#4516) +- Progress messages for background jobs now are hidden once the job is completed (#4519) +- Fixed bug where a javascript submission/test/starter file can't be downloaded (#4520) +- Add ability to upload and download autotest settings as a json file/string through the UI and API (#4498) + +## [v1.8.4] +- Fixed bug where test output was not being properly hidden from students (#4379) +- Fixed bug where certain fonts were not rendered properly using pdfjs (#4382) + +## [v1.8.3] +- Fixed bug where grace credits were not displayed to Graders viewing the submissions table (#4332) +- Fixed filtering and sorting of grace credit column in students table. (#4327) +- Added feature to set multiple submissions to in/complete from the submissions table (#4336) +- Update pdfjs version and integrate with webpacker. (#4362) +- Fixed bug where tags could not be uploaded from a csv file (#4368) +- Fixed bug where marks were not being scaled properly after an update to a criterion's max_mark (#4369) +- Fixed bug where grade entry students were not being created if new students were created by csv upload (#4371) +- Fixed bug where the student interface page wasn't rendered if creating a single student grouping at the same time (#4372) + +## [v1.8.2] +- Fixed bug where all non-empty rows in a downloaded marks spreadsheet csv file were aligned to the left. (#4290) +- Updated the Changelog format. (#4292) +- Fix displayed number of graded assignments being larger than total allocated for TAs. (#4297) + +## [v1.0.0 - v1.8.1] +### Notes +- Due to a lapse in using the release system and this changelog, we do not have a detailed description of changes +- Future releases will continue to update this changelog +- For all changes since 1.0.0 release see: https://github.com/MarkUsProject/Markus/pulls?q=is%3Apr+created%3A2014-02-15..2019-12-11+is%3Aclosed + +## [v1.0.0] +- Using Rails to 3.0.x +- Add Support for Ruby 1.9.x +- Issue #1002: new REST API +- Fixed UI bugs +- Improved filename sanitization. +- Changed PDF conversion to Ghostscript for faster conversion +- Issue #1135: start to migrate from Prototype to jQuery +- Issue #1111: grader can dowload all files of a submission +- Issue #1073: possibility to import and export assignments +- Several improvements on sections +- Syntax Highlighter is now working with non utf-8 files +- Tests are not using fixtures anymore +### Notes +- For a list of all fixed issues see: https://github.com/MarkUsProject/Markus/issues?milestone=8 + +## [v0.10.0] +- Use of Bundler to manage Gems dependencies. +- Fixed UI bugs (marking state, released checkbox). +- Fixed bug with javascript cache. +- Fixed bug when uploading the same file twice. +- Improved filename sanitization. +- Added Review Board API scripts (developers only). +- Added Remark Request feature. +- Issue #355: Marking state icon on Submissions page is shifted. +- Issue #341: File name sanitation does not sanitize enough problematic + characters. +- Issue #321: Detailed CSV download for Flexible Grading Scheme is broken. +- Issue #306: Added Role Switching. +- Issue #302: Submit Remark Request Button should not be enabled/disabled, but + should stay always on. +- Issue #294: rake load:results not creating assignment_stat/ta_stat + associations. +- Issue #233: MySQL database issue with grade_distribution_percentage. +- Issue #200: Students have no UI for accessing their test results. +- Issue #199: Select all submissions for release is broken when student spread + across multiple pages. +- Issue #189: MarkusLogger needs to be adapted so that log files are unique to + each mongrel. +- Issue #156: Adding an extra mark doesn't show up until navigating away from + the page. +- Issue #151: REST api request to add users. +- Issue #122: Annotations with hex escape patterns stripped. +- Issue #107: Non-active students don't show up with the default "All" filter + during initialization. +- Issue #6: Results should not be able to be marked "complete" if one or more + of the criteria aren't filled in. +- Issue #3: Diplaying server's time on student view. + +## [v0.9.5] +- Fixed bug which prohibited removal of required assignment + files. + +## [v0.9.4] +- Fixed releasing and unreleasing marks for students using + select-all-across-pages feature in the submissions table. + +## [v0.9.3] +- Added UI for students to view their test results. + +## [v0.9.2] +- Issue #180: Infinite redirect loop caused by duplicate group records in the + database in turn possibly caused by races in a multi-mongrels-setup. + (commits: 6552f28bf7, 19933b7f65, e39c542a4d, c226371823, ac0e348bb6, + 3cee403b9d) +- Issue #158: Default for Students page shows all Students, and bulk actions + renamed. (commit: 1e13630914) +- Issue #143: Fixing penalty calculation for PenaltyPeriodSubmissionRule. + (commit: 537d6c3068) +- Issue #141: Fix replace file JavaScript check (commits: 7f395605a8, + e8150454b3) +- Issue #129: Uploaded criteria ordering preserved for flexible and rubric + criteria (commit: b76a9a896f) +- Issues #34, #133: Don't use i18n for MarkusLogger and + ensure_config_helper.rb (commits: a00a41e1a6, f652c919ed) +- Issue #693: Fixing confirm dialog for cloning groups (commit: 87e4d826f0) +- Issue #691: Adding Grace Credits using the bulk actions gets stuck + in "processing" (commit: e0f78dd873) +- Fixed INSTALL file due to switch to Github (commits: cfd72b09bb, c0bc922434) +- I18n fixes (commits: bc791a4f21, 232384e05a, 8e2fcb6d61, 95c27db874) + +## [v0.9.1] +- Submission collection problem due to erroneous eager loading + expression (commit: a1d380b60e). + +## [v0.9.0] +- Multiple bug fixes +- REMOTE_USER authentication support +- Redesigned manage groups and graders pages +- Added in-browser pdf display and annotation +- New batch submission collection +- Improved loading speed of submissions table +- Added ability to assign graders to individual criteria + +## [v0.8.0] +- Using Rails 2.3.8 +- MarkUs renders a 404 page error for mismatching routes +- Bug fixes on submission dates and grace period credits +- Python and Ruby Scripts using MarkUs API (see lib/tools) +- Displaying and annotating images + A lot of accessibility features have been implemented : + * Missing labels & Better focus on forms + * Adding annotations in downloaded code from students repository + * Re-arrange criteria using keyboard +- MarkUs is now completely internationalized +- Added new translation : french + +## [v0.7.1] +- Bugfix for svn permissions with web submissions + +## [v0.7.0] +- The notes system has been polished, and users can now add notes to groups, students, and submissions. +- Added the flexible criterion marking scheme type +- Added the marks spreadsheet feature +- The table of student submissions can now be bookmarked, and the back-button works correctly +- Minor bugfixes and usability fixes. + +## [v0.6.3] +- Added rake task to automatically regenerate svn_authz in the event of corruption +- MarkUs now ensures student read/write permissions on repositories after cloning groups + +## [v0.6.2] +- For now, students who work alone do not have their repositories named after them +- "Allow Web Submits?" in Assignment Properties page defaults to REPOSITORY_EXTERNAL_SUBMITS_ONLY setting now +- Annotation Category dropdowns no longer close prematurely on mouseover-ing a tooltip +- Added "Reset Mark" capability to grader view + +## [v0.6.1] +- Fixed trace on detailed CSV download for assignments (g9jerboa) +- Random TA assignment now applies only to selected groups (rburke) +- Next/Previous Submission links in grader view no longer skip submissions marked "completed" (c6conley) +- The student edit form now accepts input properly +- New UI in students editor and grader view to manage grace credit penalties +- Functional tests now all pass (c6conley) + +## [v0.6.0] +- Submissions table is now paginated (c6conley) +- It is now possible to push test results into MarkUs using the new REST API + (g9jerboa) +- TAs and Instructors can exchange notes via MarkUs now (tlclark, fgarces) +- Student is able to delete groups when there are no submitted files and the + studend is the inviter (g9jerboa) +- Subversion repositories are named after the Student's username, when students + work alone for an assignment (g9jerboa) +- Rubric criteria boot in expanded form (c6conley) +- Warning is given, when AJAX calls are working and grader navigates away from + Grader View (c6conley) +- MarkUs logs basic user actions (g9jerboa) + + +## [<= v0.5.10] +- MarkUs 0.5.10 corresponds to revision 1118 in release_0.5 branch (g9jerboa) +- Pump MARKUS_VERSION patch level to 10 (version is now 0.5.10) (g9jerboa) +- Added changelog file (g9jerboa) +- Changed has_submission? in grouping.rb to get rid of "dirty" records + (g9jerboa) +- Removed application of submission rule when manually collect submissions + (g9jerboa) +- Fixed Grader View bug when encountering binary files (g9jerboa) +- Fixed Submission's NoMethodErrors (fgarces) +- Closed CSRF bug of login screen (c6conley) +- Fix bug regarding Python docstrings in syntax highlighter (g9jerboa) +- Fixing bug that didn't highlight C code properly for students (c6conley) +- change $REPOSITORY_SVN_AUTHZ_FILE to REPOSITORY_PERMISSION_FILE in rake + task (g9jerboa) +- Use bulk permissions when creating a new Group (c6conley) +- Added bulk permission controls to Repository library (c6conley) +- Fixed GracePeriodSubmissionRule when students have 0 grace credits + (c6conley) +- Fixed typo in I18n variable (c6conley) +- Closed #419 - stack trace when downloading Subversion Export File (c6conley) +- Warnings are now given when assignments have due dates in the past + (c6conley) +- Changed/updated next/prev link behaviour (c6conley) +- Fixed annotation_category bug, and average calculation bug (c6conley) +- Closing #402 (c6conley) +- Add version and patch level information to MarkUs (g9jerboa) diff --git a/app/views/assignments/_read.html.erb b/app/views/assignments/_read.html.erb index 7037e4f12f..8a628834ed 100644 --- a/app/views/assignments/_read.html.erb +++ b/app/views/assignments/_read.html.erb @@ -1,8 +1,4 @@ -<% short_identifier = @assignment.is_peer_review? ? - "#{@assignment.parent_assignment.short_identifier} #{PeerReview.model_name.human}" : - @assignment.short_identifier %> - -

<%= "#{short_identifier}: #{@assignment.description}" %>

+

<%= t('assignments.assignment_information') %>

<% if @assignment.message %> @@ -134,6 +130,32 @@
<% end %> <% end %> + <% unless @assignment.starter_file_updated_at.nil? || @grouping.nil? %> + <% if allowed_to?(:download_starter_file?, @grouping) %> +

<%= I18n.t('assignments.starter_file.title') %>

+

<%= I18n.t('assignments.starter_file.provided') %>

+

<%= I18n.t('assignments.starter_file.changed_at', + changed_date: I18n.l(@assignment.starter_file_updated_at)) %>

+

+ <%= button_to t(:download_the, item: t('assignments.starter_file.title')), + download_starter_file_course_assignment_groups_path(@current_course, @assignment), + method: 'get' %> +

+ <% # Display the URL of this group's repository if applicable + if allowed_to?(:access_repo?, @grouping) %> +

+ <%= button_to t('assignments.starter_file.populate_repo'), + populate_repo_with_starter_files_course_assignment_groups_path( + course_id: @assignment.course_id, + assignment_id: @assignment.id + ), + { method: :patch, + data: { confirm: t('assignments.starter_file.populate_repo_confirm'), + disable_with: t(:please_wait) } } %> +

+ <% end %> + <% end %> + <% end %> <% if !peer_review && (!@assignment.is_timed || !@grouping&.start_time.nil? || @grouping&.past_collection_date?) %>

<%= Submission.model_name.human.pluralize %>

<% if @grouping.nil? %> @@ -146,19 +168,17 @@

<% end %>
    +
  • <%= link_to t('submissions.student.files_submitted', count: @num_submitted_files), "https://google.com" %>
  • <% if @num_submitted_files > 0 %>
  • <%= t('submissions.student.last_revision_date') %> <%= l(@last_modified_date) %>
  • <% end %> -
  • <%= t('submissions.student.files_submitted', count: @num_submitted_files) %>
-

<%= Assignment.human_attribute_name(:assignment_files) %>

- <% if @assignment.assignment_files.length == 0 %> -

<%= t('assignments.no_required_files') %>

- <% else %> + <% if @assignment.assignment_files.length > 0 %> +

<%= Assignment.human_attribute_name(:assignment_files) %>

    <% @assignment.assignment_files.each do |assignment_file| %>
  • <%= assignment_file.filename %>
  • @@ -175,30 +195,4 @@ <% end %> <% end %> <% end %> -<% unless @assignment.starter_file_updated_at.nil? || @grouping.nil? %> - <% if allowed_to?(:download_starter_file?, @grouping) %> -

    <%= I18n.t('assignments.starter_file.title') %>

    -

    <%= I18n.t('assignments.starter_file.provided') %>

    -

    <%= I18n.t('assignments.starter_file.changed_at', - changed_date: I18n.l(@assignment.starter_file_updated_at)) %>

    -

    - <%= button_to t(:download_the, item: t('assignments.starter_file.title')), - download_starter_file_course_assignment_groups_path(@current_course, @assignment), - method: 'get' %> -

    - <% # Display the URL of this group's repository if applicable - if allowed_to?(:access_repo?, @grouping) %> -

    - <%= button_to t('assignments.starter_file.populate_repo'), - populate_repo_with_starter_files_course_assignment_groups_path( - course_id: @assignment.course_id, - assignment_id: @assignment.id - ), - { method: :patch, - data: { confirm: t('assignments.starter_file.populate_repo_confirm'), - disable_with: t(:please_wait) } } %> -

    - <% end %> - <% end %> -<% end %> diff --git a/app/views/assignments/show.html.erb b/app/views/assignments/show.html.erb index 8c2a692e3a..8972d932f6 100644 --- a/app/views/assignments/show.html.erb +++ b/app/views/assignments/show.html.erb @@ -24,7 +24,7 @@ <% end %> <% end %> -<% content_for :title, "#{Assignment.model_name.human} #{@assignment.short_identifier}" %> +<% content_for :title, "#{@assignment.short_identifier}: #{Assignment.model_name.human}" %>
    diff --git a/config/locales/views/assignments/en.yml b/config/locales/views/assignments/en.yml index d84eb714c0..ed8b244052 100644 --- a/config/locales/views/assignments/en.yml +++ b/config/locales/views/assignments/en.yml @@ -1,6 +1,7 @@ --- en: assignments: + assignment_information: Assignment Information assignment_has_groupings: Assignment has groupings. average_annotations: "%{average_annotations} annotations per marked submission" configuration_zip_file: Configuration Zip File @@ -58,7 +59,7 @@ en: populate_repo_confirm: Are you sure you want to add the starter files to your repository? If they already exist in the repository, any changes will be overwritten. populate_repo_error: Unfortunately, the starter files could not be added to your repository. Please download them as a zip file instead. populate_repo_success: Starter files successfully added to your repository. - provided: Starter files have been provided for this assignment + provided: Starter files have been provided for this assignment. rename: Rename Selected File or Directory starter_file_rule: Starter File Assignment Rules starter_file_rule_types: @@ -66,7 +67,7 @@ en: sections: Assign starter file groups by section shuffle: Randomly select one top level file or directory from each starter file group simple: Assign the default starter file group to all students - title: Starter Files + title: Starter files upload_confirmation: The starter files for this assignment have changed since you last downloaded them. Are you sure you want to continue? use_original_filename: Use original filename successful_deletion: Assignment with id '%{invalid_id}' has been successfully deleted. diff --git a/config/locales/views/groups/en.yml b/config/locales/views/groups/en.yml index d7555b3b8b..5240f51fac 100644 --- a/config/locales/views/groups/en.yml +++ b/config/locales/views/groups/en.yml @@ -86,7 +86,7 @@ en: not_allowed_to_delete_group: If you would like to remove this group, you must contact your instructor. not_allowed_to_form_group: You are not allowed to form a group yourself. Please wait until your instructor forms your group. section_groups_only: You can only form a group with students in your section. - students_work_alone: Students work individually. + students_work_alone: You must complete this assignment individually. url_repository: Repository URL work_alone: Work alone working_alone: You have indicated you are working individually on this assignment. If you change your mind and want to create or join a group, first delete your group using the button below. diff --git a/spec/controllers/criteria_controller_spec.rb.orig b/spec/controllers/criteria_controller_spec.rb.orig new file mode 100644 index 0000000000..260f9e9f06 --- /dev/null +++ b/spec/controllers/criteria_controller_spec.rb.orig @@ -0,0 +1,1259 @@ +describe CriteriaController do + include UploadHelper + + # TODO: add 'role is from a different course' shared tests to each route test below + let(:instructor) { create(:instructor) } + let(:course) { instructor.course } + let(:assignment) { create(:assignment) } + let(:grouping) { create(:grouping, assignment: assignment) } + let(:submission) { create(:submission, grouping: grouping) } + + shared_examples 'callbacks' do + before do + @assignment = create(:assignment_with_criteria_and_results) + @crit = create(criterion, assignment: @assignment, max_mark: 3.0) + @assignment.groupings.each do |grouping| + create(:mark, result: grouping.current_result, mark: @crit.max_mark, criterion: @crit) + end + end + + describe 'An authenticated and authorized instructor doing a DELETE' do + it 'should update the relevant assignment\'s stats' do + old_average = @assignment.results_average + old_median = @assignment.results_median + delete_as instructor, + :destroy, + params: { course_id: course.id, id: @crit.id }, + format: :js + assignment.reload + expect(@assignment.results_median).to be >= old_median + expect(@assignment.results_average).to be >= old_average + end + end + + context 'when changing the bonus' do + it 'should be able to update the bonus value' do + get_as instructor, + :update, + params: { course_id: course.id, id: @crit.id, + criterion => { name: 'one', bonus: true } }, + format: :js + expect(@crit.reload.bonus).to be true + end + + it 'should update the relevant assignment\'s stats' do + old_average = @assignment.results_average + old_median = @assignment.results_median + get_as instructor, + :update, + params: { course_id: course.id, id: @crit.id, + criterion => { name: 'one', bonus: true } }, + format: :js + @assignment.reload + expect(@assignment.results_median).to be >= old_median + expect(@assignment.results_average).to be >= old_average + end + end + end + + describe 'Using Checkbox Criterion' do + let(:criterion) { :checkbox_criterion } + + it_behaves_like 'callbacks' + end + + describe 'Using Flexible Criteria' do + let(:criterion) { :flexible_criterion } + let(:flexible_criterion) do + create(:flexible_criterion, + assignment: assignment, + position: 1, + name: 'Flexible Criterion') + end + let(:flexible_criterion2) do + create(:flexible_criterion, + assignment: assignment, + position: 2, + name: 'Flexible Criterion 2') + end + + it_behaves_like 'callbacks' + + describe 'An unauthenticated and unauthorized user doing a GET' do + describe '#index' do + it 'should respond with redirect' do + get :index, params: { course_id: course.id, assignment_id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#new' do + it 'should respond with redirect' do + get :new, params: { course_id: course.id, assignment_id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#edit' do + it 'should respond with redirect' do + get :edit, params: { course_id: course.id, id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#update' do + it 'should respond with redirect' do + put :update, params: { course_id: course.id, id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#destroy' do + it 'should respond with redirect' do + delete :destroy, params: { course_id: course.id, id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#update_positions' do + it 'should respond with redirect' do + get :update_positions, params: { course_id: course.id, assignment_id: 1 } + expect(subject).to respond_with :redirect + end + end + + context 'with an assignment' do + context 'and a submission' do + describe '#edit' do + it 'should respond with redirect' do + get :edit, params: { course_id: course.id, id: 1 } + expect(subject).to respond_with :redirect + end + end + end + end + + describe '#download' do + it 'should respond with redirect' do + get :download, params: { course_id: course.id, assignment_id: 1 } + expect(subject).to respond_with :redirect + end + end + end + + describe 'An unauthenticated and unauthorized user doing a POST' do + describe '#index' do + it 'should respond with redirect' do + post :index, params: { course_id: course.id, assignment_id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#new' do + it 'should respond with redirect' do + post :new, params: { course_id: course.id, assignment_id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#update' do + it 'should respond with redirect' do + put :update, params: { course_id: course.id, id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#edit' do + it 'should respond with redirect' do + post :edit, params: { course_id: course.id, id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#destroy' do + it 'should respond with redirect' do + delete :destroy, params: { course_id: course.id, id: 1 } + expect(subject).to respond_with :redirect + end + end + end + + describe 'An authenticated and authorized instructor doing a GET' do + describe '#index' do + before do + get_as instructor, :index, params: { course_id: course.id, assignment_id: assignment.id } + end + + it 'should respond assign assignment and criteria' do + expect(assigns(:assignment)).to be_truthy + expect(assigns(:criteria)).to be_truthy + end + + it 'should render the edit template' do + expect(subject).to render_template(:index) + end + + it 'should respond with success' do + expect(subject).to respond_with(:success) + end + end + + describe '#new' do + context 'when assignment marks are not released' do + before do + get_as instructor, + :new, + params: { course_id: course.id, assignment_id: assignment.id }, + format: :js + end + + it 'should respond with appropriate content' do + expect(assigns(:assignment)).to be_truthy + end + + it 'should render the new template' do + expect(subject).to render_template(:new) + end + + it 'should respond with success' do + expect(subject).to respond_with(:success) + end + end + + context 'when assignment marks are released' do + let(:released_assignment) { create(:assignment) } + + before do + grouping = create(:grouping, assignment: released_assignment) + submission = create(:submission, grouping: grouping) + result = submission.get_latest_result + result.update!(released_to_students: true) + + get_as instructor, + :new, + params: { course_id: course.id, assignment_id: released_assignment.id }, + format: :js + end + + it 'displays an error message' do + expect(flash[:error]).to have_message(I18n.t('criteria.errors.released_marks')) + end + + it 'responds with :bad_request status' do + expect(response).to have_http_status(:bad_request) + end + end + end + + describe '#edit' do + context 'when assignment marks have not been released' do + before do + get_as instructor, + :edit, + params: { course_id: course.id, id: flexible_criterion.id }, + format: :js + end + + it 'should respond with appropriate content' do + expect(assigns(:criterion)).to be_truthy + end + + it 'should render edit template' do + expect(subject).to render_template(:edit) + end + + it 'should respond with success' do + expect(subject).to respond_with(:success) + end + end + +<<<<<<< HEAD + # there should not be a bad request expectation because it was not implemented. +======= +>>>>>>> upstream/master + context 'when assignment marks have been released' do + let!(:released_assignment) do + create(:assignment, course: course).tap do |assignment| + create(:flexible_criterion, assignment: assignment, name: 'Pre-release Criterion') + + grouping = create(:grouping, assignment: assignment) + submission = create(:submission, grouping: grouping) + submission.get_latest_result.update!(released_to_students: true) + end + end + + let(:flexible_criterion) do + released_assignment.criteria.find_by(type: 'FlexibleCriterion') + end + + before do + get_as instructor, + :edit, + params: { course_id: released_assignment.course_id, id: flexible_criterion.id }, + format: :js + end + + it 'flashes message with error' do + expect(flash[:notice]).to have_message(I18n.t('criteria.errors.released_marks')) + end + +<<<<<<< HEAD +======= + # there should not be a bad request expectation because the view renders successfully in read-only mode +>>>>>>> upstream/master + it 'responds with success' do + expect(subject).to respond_with(:success) + end + end + end + + describe '#update' do + context 'with errors' do + before do + allow_any_instance_of(FlexibleCriterion).to receive(:save).and_return(false) + allow_any_instance_of(FlexibleCriterion).to( + receive(:errors).and_return(ActiveModel::Errors.new(flexible_criterion)) + ) + + get_as instructor, + :update, + params: { course_id: course.id, id: flexible_criterion.id, + flexible_criterion: { name: 'one', max_mark: 10 } }, + format: :js + end + + it 'should respond with appropriate content' do + expect(assigns(:criterion)).to be_truthy + end + + it 'should respond with unprocessable entity' do + expect(subject).to respond_with(:unprocessable_entity) + end + end + + context 'without errors' do + before do + get_as instructor, + :update, + params: { course_id: course.id, id: flexible_criterion.id, + flexible_criterion: { name: 'one', max_mark: 10 } }, + format: :js + end + + it 'successfully assign criterion' do + expect(assigns(:criterion)).to be_truthy + end + + it 'should render the update template' do + expect(subject).to render_template(:update) + end + end + end + end + + describe 'An authenticated and authorized instructor doing a POST' do + describe '#index' do + before do + post_as instructor, :index, params: { course_id: course.id, assignment_id: assignment.id } + end + + it 'should respond with appropriate content' do + expect(assigns(:assignment)).to be_truthy + expect(assigns(:criteria)).to be_truthy + end + + it 'should render the index template' do + expect(subject).to render_template(:index) + end + + it 'should respond with success' do + expect(subject).to respond_with(:success) + end + end + + describe '#create' do + context 'with save error' do + before do + allow_any_instance_of(FlexibleCriterion).to receive(:save).and_return(false) + allow_any_instance_of(FlexibleCriterion).to receive(:errors).and_return(ActiveModel::Errors.new(self)) + post_as instructor, + :create, + params: { course_id: course.id, assignment_id: assignment.id, + flexible_criterion: { name: 'first', max_mark: 10 }, + new_criterion_prompt: 'first', criterion_type: 'FlexibleCriterion' }, + format: :js + end + + it 'should respond with appropriate content' do + expect(assigns(:criterion)).to be_truthy + expect(assigns(:assignment)).to be_truthy + end + + it 'should respond with unprocessable entity' do + expect(subject).to respond_with(:unprocessable_entity) + end + end + + context 'without error on an assignment as the first criterion' do + before do + post_as instructor, + :create, + params: { course_id: course.id, assignment_id: assignment.id, flexible_criterion: { name: 'first' }, + new_criterion_prompt: 'first', criterion_type: 'FlexibleCriterion', max_mark_prompt: 10 }, + format: :js + end + + it 'should respond with appropriate content' do + expect(assigns(:criterion)).to be_truthy + expect(assigns(:assignment)).to be_truthy + end + + it 'should render the create template' do + expect(subject).to render_template(:'criteria/create') + end + + it 'should respond with success' do + expect(subject).to respond_with(:success) + end + end + + context 'without error on an assignment that already has criteria' do + before do + create(:checkbox_criterion, assignment: assignment) + post_as instructor, + :create, + params: { course_id: course.id, assignment_id: assignment.id, + flexible_criterion: { name: 'second' }, new_criterion_prompt: 'second', + criterion_type: 'FlexibleCriterion', max_mark_prompt: 10 }, + format: :js + end + + it 'should respond with appropriate content' do + expect(assigns(:criterion)).to be_truthy + expect(assigns(:assignment)).to be_truthy + end + + it 'should render the create template' do + expect(subject).to render_template(:'criteria/create') + end + + it 'should respond with success' do + expect(subject).to respond_with(:success) + end + end + + context 'when assignment marks are released' do + let(:released_assignment) { create(:assignment) } + + before do + grouping = create(:grouping, assignment: released_assignment) + submission = create(:submission, grouping: grouping) + result = submission.get_latest_result + result.update!(released_to_students: true) + + post_as instructor, + :create, + params: { course_id: course.id, assignment_id: released_assignment.id, + flexible_criterion: { name: 'first', max_mark: 10 }, + new_criterion_prompt: 'first', criterion_type: 'RubricCriterion' }, + format: :js + end + + it 'displays an error message' do + expect(flash[:error]).to have_message(I18n.t('criteria.errors.released_marks')) + end + + it 'responds with :bad_request status' do + expect(response).to have_http_status(:bad_request) + end + end + end + + describe '#update' do + context 'when assignment marks have been released' do + let!(:released_assignment) do + create(:assignment, course: course).tap do |assignment| + create(:flexible_criterion, assignment: assignment, name: 'Pre-release Criterion') + + grouping = create(:grouping, assignment: assignment) + submission = create(:submission, grouping: grouping) + submission.get_latest_result.update!(released_to_students: true) + end + end + + let(:flexible_criterion) do + released_assignment.criteria.find_by(type: 'FlexibleCriterion') + end + + before do + post_as instructor, + :update, + params: { course_id: released_assignment.course_id, id: flexible_criterion.id }, + format: :js + end + + it 'flashes message with error' do + expect(flash[:error]).to have_message(I18n.t('criteria.errors.released_marks')) + end + + it 'responds with :bad_request status' do + expect(response).to have_http_status(:bad_request) + end + end + end + + describe '#edit' do + before do + post_as instructor, + :edit, + params: { course_id: course.id, id: flexible_criterion.id }, + format: :js + end + + it 'should respond with appropriate content' do + expect(assigns(:criterion)).to be_truthy + end + + it 'should render the edit template' do + expect(subject).to render_template(:edit) + end + + it 'should respond with success' do + expect(subject).to respond_with(:success) + end + end + + it 'should be able to update_positions' do + post_as instructor, + :update_positions, + params: { course_id: course.id, criterion: [flexible_criterion2.id, flexible_criterion.id], + assignment_id: assignment.id }, + format: :js + expect(subject).to render_template + expect(subject).to respond_with(:success) + + c1 = FlexibleCriterion.find(flexible_criterion.id) + expect(c1.position).to be(2) + c2 = FlexibleCriterion.find(flexible_criterion2.id) + expect(c2.position).to be(1) + end + end + + describe 'An authenticated and authorized instructor doing a DELETE' do + it 'should be able to delete the criterion' do + delete_as instructor, + :destroy, + params: { course_id: course.id, id: flexible_criterion.id }, + format: :js + expect(assigns(:criterion)).to be_truthy + expect(flash[:success]).to have_message(I18n.t('flash.criteria.destroy.success')) + expect(subject).to respond_with(:success) + + expect { FlexibleCriterion.find(flexible_criterion.id) }.to raise_error(ActiveRecord::RecordNotFound) + end + end + end + + describe 'Using Rubric Criteria' do + let(:criterion) { :rubric_criterion } + let(:rubric_criterion) do + create(:rubric_criterion, + assignment: assignment, + position: 1, + name: 'Rubric Criterion') + end + let(:rubric_criterion2) do + create(:rubric_criterion, + assignment: assignment, + position: 2, + name: 'Rubric Criterion 2') + end + + it_behaves_like 'callbacks' + + describe 'An unauthenticated and unauthorized user doing a GET' do + describe '#index' do + it 'should respond with redirect' do + get :index, params: { course_id: course.id, assignment_id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#new' do + it 'should respond with redirect' do + get :new, params: { course_id: course.id, assignment_id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#edit' do + it 'should respond with redirect' do + get :edit, params: { course_id: course.id, id: 1 } + expect(subject).to respond_with :redirect + end + + context 'with an assignment' do + context 'and a submission' do + describe '#edit' do + it 'should respond with redirect' do + get :edit, params: { course_id: course.id, assignment_id: assignment.id, id: 1 } + expect(subject).to respond_with :redirect + end + end + end + end + end + + describe '#destroy' do + it 'should respond with redirect' do + delete :destroy, params: { course_id: course.id, id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#update' do + it 'should respond with redirect' do + put :update, params: { course_id: course.id, id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#update_positions' do + it 'should respond with redirect' do + get :update_positions, params: { course_id: course.id, assignment_id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#download' do + it 'should respond with redirect' do + get :download, params: { course_id: course.id, assignment_id: 1 } + expect(subject).to respond_with :redirect + end + end + end + + describe 'An unauthenticated and unauthorized user doing a POST' do + describe '#index' do + it 'should respond with redirect' do + post :index, params: { course_id: course.id, assignment_id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#new' do + it 'should respond with redirect' do + post :new, params: { course_id: course.id, assignment_id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#edit' do + it 'should respond with redirect' do + post :edit, params: { course_id: course.id, id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#update' do + it 'should respond with redirect' do + put :update, params: { course_id: course.id, id: 1 } + expect(subject).to respond_with :redirect + end + end + + describe '#destroy' do + it 'should respond with redirect' do + delete :destroy, params: { course_id: course.id, id: 1 } + expect(subject).to respond_with :redirect + end + end + end + + describe 'An authenticated and authorized instructor doing a GET' do + describe '#index' do + before do + get_as instructor, :index, params: { course_id: course.id, assignment_id: assignment.id } + end + + it 'should respond assign assignment and criteria' do + expect(assigns(:assignment)).to be_truthy + expect(assigns(:criteria)).to be_truthy + end + + it 'should render the edit template' do + expect(subject).to render_template(:index) + end + + it 'should respond with success' do + expect(subject).to respond_with(:success) + end + end + + describe '#new' do + before do + get_as instructor, + :new, + params: { course_id: course.id, assignment_id: assignment.id }, + format: :js + end + + it 'should respond with appropriate content' do + expect(assigns(:assignment)).to be_truthy + end + + it 'should render the new template' do + expect(subject).to render_template(:new) + end + + it 'should respond with success' do + expect(subject).to respond_with(:success) + end + end + + describe '#edit' do + before do + get_as instructor, + :edit, + params: { course_id: course.id, id: rubric_criterion.id }, + format: :js + end + + it 'should respond with appropriate content' do + expect(assigns(:criterion)).to be_truthy + end + + it 'should render edit template' do + expect(subject).to render_template(:edit) + end + + it 'should respond with success' do + expect(subject).to respond_with(:success) + end + end + + describe '#update' do + context 'with errors' do + before do + allow_any_instance_of(RubricCriterion).to receive(:save).and_return(false) + allow_any_instance_of(RubricCriterion).to( + receive(:errors).and_return(ActiveModel::Errors.new(rubric_criterion)) + ) + get_as instructor, + :update, + params: { course_id: course.id, id: rubric_criterion.id, + rubric_criterion: { name: 'one', max_mark: 10 } }, + format: :js + end + + it 'should respond with appropriate content' do + expect(assigns(:criterion)).to be_truthy + end + + it 'should respond with unprocessable entity' do + expect(subject).to respond_with(:unprocessable_entity) + end + end + + context 'without errors' do + before do + get_as instructor, + :update, + params: { course_id: course.id, id: rubric_criterion.id, + rubric_criterion: { name: 'one', max_mark: 10 } }, + format: :js + end + + it 'successfully assign criterion' do + expect(assigns(:criterion)).to be_truthy + end + + it 'should render the update template' do + expect(subject).to render_template(:update) + end + end + end + end + + describe 'An authenticated and authorized instructor doing a POST' do + describe '#index' do + before do + post_as instructor, :index, params: { course_id: course.id, assignment_id: assignment.id } + end + + it 'should respond with appropriate content' do + expect(assigns(:assignment)).to be_truthy + expect(assigns(:criteria)).to be_truthy + end + + it 'should render the index template' do + expect(subject).to render_template(:index) + end + + it 'should respond with success' do + expect(subject).to respond_with(:success) + end + end + + describe '#create' do + context 'with save error' do + before do + allow_any_instance_of(RubricCriterion).to receive(:save).and_return(false) + allow_any_instance_of(RubricCriterion).to receive(:errors).and_return(ActiveModel::Errors.new(self)) + post_as instructor, + :create, + params: { course_id: course.id, assignment_id: assignment.id, max_mark_prompt: 10, + new_criterion_prompt: 'first', criterion_type: 'RubricCriterion' }, + format: :js + end + + it 'should respond with appropriate content' do + expect(assigns(:criterion)).to be_truthy + expect(assigns(:assignment)).to be_truthy + end + + it 'should respond with unprocessable entity' do + expect(subject).to respond_with(:unprocessable_entity) + end + end + + context 'without error on an assignment as the first criterion' do + before do + post_as instructor, + :create, + params: { course_id: course.id, assignment_id: assignment.id, + new_criterion_prompt: 'first', criterion_type: 'RubricCriterion', max_mark_prompt: 10 }, + format: :js + end + + it 'should respond with appropriate content' do + expect(assigns(:criterion)).to be_truthy + expect(assigns(:assignment)).to be_truthy + end + + it 'should render the create template' do + expect(subject).to render_template(:'criteria/create') + end + + it 'should respond with success' do + expect(subject).to respond_with(:success) + end + end + + context 'without error on an assignment that already has criteria' do + before do + post_as instructor, + :create, + params: { course_id: course.id, assignment_id: assignment.id, rubric_criterion: { name: 'first' }, + new_criterion_prompt: 'first', criterion_type: 'RubricCriterion', max_mark_prompt: 10 }, + format: :js + end + + it 'should respond with appropriate content' do + expect(assigns(:criterion)).to be_truthy + expect(assigns(:assignment)).to be_truthy + end + + it 'should render the create template' do + expect(subject).to render_template(:'criteria/create') + end + + it 'should respond with success' do + expect(subject).to respond_with(:success) + end + end + end + + describe '#edit' do + before do + post_as instructor, + :edit, + params: { course_id: course.id, id: rubric_criterion.id }, + format: :js + end + + it 'should respond with appropriate content' do + expect(assigns(:criterion)).to be_truthy + end + + it 'should render the edit template' do + expect(subject).to render_template(:edit) + end + + it 'should respond with success' do + expect(subject).to respond_with(:success) + end + end + + describe '#update_positions' do + context 'when all criteria id can be found under assignment' do + let(:rubric_criterion) do + create(:rubric_criterion, assignment: assignment, position: 1) + end + let(:rubric_criterion2) do + create(:rubric_criterion, assignment: assignment, position: 2) + end + + it 'should be able to update_positions' do + post_as instructor, + :update_positions, + params: { course_id: course.id, criterion: [rubric_criterion2.id, rubric_criterion.id], + assignment_id: assignment.id }, + format: :js + expect(subject).to render_template + expect(subject).to respond_with(:success) + + c1 = RubricCriterion.find(rubric_criterion.id) + expect(c1.position).to be(2) + c2 = RubricCriterion.find(rubric_criterion2.id) + expect(c2.position).to be(1) + end + end + + context 'when there exists criteria not under current assignment' do + let(:assignment2) { create(:assignment) } + let(:rubric_criterion) do + create(:rubric_criterion, assignment: assignment, position: 1) + end + let(:rubric_criterion2) do + create(:rubric_criterion, assignment: assignment, position: 2) + end + let(:rubric_criterion3) do + create(:rubric_criterion, assignment: assignment2, position: 3) + end + + before do + post_as instructor, + :update_positions, + params: { course_id: course.id, + criterion: [rubric_criterion3.id, + rubric_criterion2.id, + rubric_criterion.id], + assignment_id: assignment.id }, + format: :js + end + + it 'does not update position' do + c1 = RubricCriterion.find(rubric_criterion.id) + expect(c1.position).to be(1) + c2 = RubricCriterion.find(rubric_criterion2.id) + expect(c2.position).to be(2) + c3 = RubricCriterion.find(rubric_criterion3.id) + expect(c3.position).to be(3) + end + + it 'displays an error message' do + expect(flash[:error]).to have_message(I18n.t('criteria.errors.criteria_not_found')) + end + end + end + end + + describe 'An authenticated and authorized instructor doing a DELETE' do + it 'should be able to delete the criterion' do + delete_as instructor, + :destroy, + params: { course_id: course.id, id: rubric_criterion.id }, + format: :js + expect(assigns(:criterion)).to be_truthy + expect(flash[:success]).to have_message(I18n.t('flash.criteria.destroy.success')) + expect(subject).to respond_with(:success) + + expect { RubricCriterion.find(rubric_criterion.id) }.to raise_error(ActiveRecord::RecordNotFound) + end + end + end + + describe 'An authenticated and authorized instructor performing yml actions' do + let!(:rubric_criterion) do + create(:rubric_criterion, + assignment: assignment, + position: 1, + name: 'Rubric Criterion') + end + let!(:flexible_criterion) do + create(:flexible_criterion, + assignment: assignment, + position: 2, + name: 'Flexible Criterion') + end + let!(:checkbox_criterion) do + create(:checkbox_criterion, + assignment: assignment, + position: 3, + name: 'Checkbox Criterion') + end + let(:mixed_file) { fixture_file_upload('criteria/upload_yml_mixed.yaml', 'text/yaml') } + let(:mixed_file_no_ext) { fixture_file_upload('criteria/upload_yml_mixed', 'text/yaml') } + let(:mixed_file_wrong_ext) { fixture_file_upload('criteria/upload_yml_mixed.pdf', 'text/yaml') } + let(:invalid_mixed_file) { fixture_file_upload('criteria/upload_yml_mixed_invalid.yaml', 'text/yaml') } + let(:missing_levels_file) { fixture_file_upload('criteria/upload_yml_missing_levels.yaml', 'text/yaml') } + let(:empty_file) { fixture_file_upload('empty_file', 'text/yaml') } + let(:test_upload_download_file) { fixture_file_upload('criteria/criteria_upload_download.yaml', 'text/yaml') } + let(:expected_download) { fixture_file_upload('criteria/download_yml_output.yaml', 'text/yaml') } + let(:round_max_mark_file) { fixture_file_upload('criteria/round_max_mark.yaml', 'text/yaml') } + let(:partially_valid_file) { fixture_file_upload('criteria/partially_valid_file.yaml', 'text/yaml') } + let(:uploaded_file) { fixture_file_upload('criteria/upload_yml_mixed.yaml', 'text/yaml') } + let(:no_type_file) { fixture_file_upload('criteria/marking_criteria_no_type.yml', 'text/yaml') } + + context 'When a file containing a mixture of entries is uploaded' do + it 'raises an error if the file does not include any criteria' do + post_as instructor, :upload, + params: { course_id: course.id, assignment_id: assignment.id, upload_file: empty_file } + + expect(flash[:error]).to have_message(I18n.t('upload_errors.blank')) + end + + it 'deletes all criteria previously created' do + post_as instructor, :upload, + params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } + + expect(assignment.criteria.where(type: 'RubricCriterion').find_by(name: rubric_criterion.name)).to be_nil + expect(assignment.criteria.where(type: 'FlexibleCriterion').find_by(name: flexible_criterion.name)).to be_nil + expect(assignment.criteria.where(type: 'CheckboxCriterion').find_by(name: checkbox_criterion.name)).to be_nil + end + + it 'maintains the order between entries and positions for criteria' do + post_as instructor, :upload, + params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } + + expect(assignment.criteria.map { |cr| [cr.name, cr.position] }) + .to match_array([['cr30', 1], + ['cr20', 2], + ['cr100', 3], + ['cr40', 4], + ['cr80', 5], + ['cr50', 6], + ['cr60', 7], + ['cr90', 8]]) + end + + it 'creates all criteria with properly formatted entries' do + post_as instructor, :upload, + params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } + + expect(assignment.criteria.pluck(:name)).to contain_exactly('cr30', + 'cr20', + 'cr100', + 'cr80', + 'cr60', + 'cr90', + 'cr40', + 'cr50') + expect(flash[:success]).to have_message(I18n.t('upload_success', count: 8)) + end + + it 'creates rubric criteria with properly formatted entries' do + post_as instructor, :upload, + params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } + expect(assignment.criteria.where(type: 'RubricCriterion').pluck(:name)).to contain_exactly('cr30', 'cr90') + cr1 = assignment.criteria.where(type: 'RubricCriterion').find_by(name: 'cr30') + expect(cr1.levels.size).to eq(5) + expect(cr1.max_mark).to eq(5.0) + expect(cr1.bonus).to be true + expect(cr1.ta_visible).to be false + expect(cr1.peer_visible).to be true + # Since there are only 5 levels in this rubric criterion, if each of the following queries return an entity, + # then this rubric criterion is properly sat up. + expect(cr1.levels.find_by(name: 'Beginner', description: 'Fail', mark: 0)).not_to be_nil + expect(cr1.levels.find_by(name: 'Hmm', description: 'Almost fail', mark: 1)).not_to be_nil + expect(cr1.levels.find_by(name: 'Average', description: 'Not bad', mark: 2)).not_to be_nil + expect(cr1.levels.find_by(name: 'Good', description: 'Alright', mark: 3)).not_to be_nil + expect(cr1.levels.find_by(name: 'Excellent', description: 'Impressive', mark: 5)).not_to be_nil + + cr2 = assignment.criteria.where(type: 'RubricCriterion').find_by(name: 'cr90') + expect(cr2.max_mark).to eq(4.6) + expect(cr2.levels.size).to eq(5) + expect(cr2.ta_visible).to be true + expect(cr2.peer_visible).to be false + expect(cr2.bonus).to be false + end + + it 'creates flexible criteria with properly formatted entries' do + post_as instructor, :upload, + params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } + + expect(assignment.criteria.where(type: 'FlexibleCriterion').pluck(:name)) + .to contain_exactly('cr20', 'cr50', 'cr80', 'cr60') + + cr80 = assignment.criteria.where(type: 'FlexibleCriterion').find_by(name: 'cr80') + expect(cr80.max_mark).to eq(10.0) + expect(cr80.description).to eq('') + expect(cr80.ta_visible).to be true + expect(cr80.peer_visible).to be true + expect(cr80.bonus).to be false + + cr20 = assignment.criteria.where(type: 'FlexibleCriterion').find_by(name: 'cr20') + expect(cr20.max_mark).to eq(2.0) + expect(cr20.description).to eq('I am flexible') + expect(cr20.ta_visible).to be true + expect(cr20.peer_visible).to be true + expect(cr20.bonus).to be false + + cr50 = assignment.criteria.where(type: 'FlexibleCriterion').find_by(name: 'cr50') + expect(cr50.bonus).to be true + expect(cr50.max_mark).to eq(1.0) + expect(cr50.description).to eq('Another flexible.') + expect(cr50.ta_visible).to be true + expect(cr50.peer_visible).to be false + + cr60 = assignment.criteria.where(type: 'FlexibleCriterion').find_by(name: 'cr60') + expect(cr60.max_mark).to eq(10.0) + expect(cr60.description).to eq('') + expect(cr60.ta_visible).to be true + expect(cr60.peer_visible).to be false + expect(cr60.bonus).to be false + end + + it 'creates checkbox criteria with properly formatted entries' do + post_as instructor, :upload, + params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } + + expect(assignment.criteria.where(type: 'CheckboxCriterion').pluck(:name)).to contain_exactly('cr100', 'cr40') + cr1 = assignment.criteria.where(type: 'CheckboxCriterion').find_by(name: 'cr100') + expect(cr1.bonus).to be true + expect(cr1.max_mark).to eq(5.0) + expect(cr1.description).to eq('I am checkbox') + expect(cr1.ta_visible).to be true + expect(cr1.peer_visible).to be false + end + + it 'creates criteria being case insensitive with the type given' do + post_as instructor, :upload, + params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } + + expect(assignment.criteria.where(type: 'FlexibleCriterion').pluck(:name)) + .to contain_exactly('cr20', 'cr80', 'cr60', 'cr50') + end + + it 'creates criteria that lack a description' do + post_as instructor, :upload, + params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } + + expect(assignment.criteria.where(type: 'FlexibleCriterion').pluck(:name)).to include('cr80') + expect(assignment.criteria.where(type: 'FlexibleCriterion').find_by(name: 'cr80').description).to eq('') + end + + it 'creates criteria with the default visibility options if these are not given in the entries' do + post_as instructor, :upload, + params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } + expect(assignment.criteria.pluck(:name)).to include('cr100', 'cr60') + expect(assignment.criteria.where(type: 'CheckboxCriterion').find_by(name: 'cr100').ta_visible).to be true + expect(assignment.criteria.where(type: 'CheckboxCriterion').find_by(name: 'cr100').peer_visible).to be false + expect(assignment.criteria.where(type: 'FlexibleCriterion').find_by(name: 'cr60').ta_visible).to be true + expect(assignment.criteria.where(type: 'FlexibleCriterion').find_by(name: 'cr60').peer_visible).to be false + end + + it 'creates criteria with rounded (up to first digit after decimal point) maximum mark' do + post_as instructor, :upload, params: { course_id: course.id, assignment_id: assignment.id, + upload_file: round_max_mark_file } + expect(assignment.criteria.where(type: 'RubricCriterion').first.name).to eq('cr90') + + expect(assignment.criteria.where(type: 'RubricCriterion').first.max_mark).to eq(4.6) + end + + it 'creates criteria correctly when a valid yml file with no extension is uploaded' do + post_as instructor, :upload, + params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file_no_ext } + + expect(assignment.criteria.pluck(:name)).to contain_exactly('cr30', + 'cr20', + 'cr100', + 'cr80', + 'cr60', + 'cr90', + 'cr40', + 'cr50') + expect(flash[:success]).to have_message(I18n.t('upload_success', count: 8)) + end + + it 'creates criteria correctly when a valid yml file with the wrong extension is uploaded' do + post_as instructor, :upload, + params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file_wrong_ext } + + expect(assignment.criteria.pluck(:name)).to contain_exactly('cr30', + 'cr20', + 'cr100', + 'cr80', + 'cr60', + 'cr90', + 'cr40', + 'cr50') + expect(flash[:success]).to have_message(I18n.t('upload_success', count: 8)) + end + + it 'does not create criteria with format errors in entries' do + post_as instructor, :upload, params: { course_id: course.id, assignment_id: assignment.id, + upload_file: invalid_mixed_file } + + expect(assignment.criteria.pluck(:name)).not_to include('cr40', 'cr50', 'cr70') + expect(flash[:error]).to contain_message(I18n.t('criteria.errors.invalid_format')) + expect(flash[:error]).to contain_message(' cr40, cr70, cr50') + end + + it 'does not create criteria with an invalid mark' do + post_as instructor, :upload, params: { course_id: course.id, assignment_id: assignment.id, + upload_file: invalid_mixed_file } + + expect(assignment.criteria.pluck(:name)).not_to include('cr40', 'cr50') + end + + it 'does not create rubric criteria when levels are missing' do + post_as instructor, :upload, params: { course_id: course.id, assignment_id: assignment.id, + upload_file: missing_levels_file } + + expect(assignment.criteria.where(name: %w[no_levels empty_levels])).to be_empty + expect(flash[:error]).to contain_message(I18n.t('criteria.errors.invalid_format')) + expect(flash[:error]).to contain_message(' no_levels, empty_levels') + end + + it 'does not create criteria that have both visibility options set to false' do + post_as instructor, :upload, params: { course_id: course.id, assignment_id: assignment.id, + upload_file: invalid_mixed_file } + + expect(assignment.criteria.pluck(:name)).not_to include('cr70') + end + + it 'does not create criteria that have unmatched keys / more keys than required' do + expect(assignment.criteria.where(type: 'RubricCriterion').length).to eq(1) + post_as instructor, :upload, params: { course_id: course.id, assignment_id: assignment.id, + upload_file: partially_valid_file } + expect(assignment.criteria.where(type: 'RubricCriterion').length).to eq(1) + expect(flash[:error]).not_to be_nil + end + + context 'when there is no type specified for one of the criteria' do + it 'flashes an error message' do + post_as instructor, :upload, params: { course_id: course.id, assignment_id: assignment.id, + upload_file: no_type_file } + expect(flash[:error]).not_to be_nil + end + end + + context 'When some criteria have been previously uploaded and and instructor performs a download' do + before do + Criterion.upload_criteria_from_yaml(assignment, parse_yaml_content(test_upload_download_file.read)) + end + + it 'responds with appropriate status' do + get_as instructor, :download, params: { course_id: course.id, assignment_id: assignment.id } + + expect(response).to have_http_status(:ok) + end + + it 'sends the correct information' do + get_as instructor, :download, params: { course_id: course.id, assignment_id: assignment.id } + + expect(YAML.safe_load(response.body, permitted_classes: [Symbol], symbolize_names: true)) + .to eq(YAML.safe_load(expected_download.read, symbolize_names: true)) + end + end + end + end + + describe '#upload' do + it_behaves_like 'a controller supporting upload', formats: [:yml] do + let(:params) { { course_id: course.id, assignment_id: assignment.id } } + end + end +end From 16de70e2910fcac892e970dffb551a95b480090c Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Thu, 29 May 2025 02:24:27 -0400 Subject: [PATCH 07/18] Added routing to redirect tab to submissions --- app/views/assignments/_read.html.erb | 4 +++- config/locales/views/assignments/en.yml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/views/assignments/_read.html.erb b/app/views/assignments/_read.html.erb index 8a628834ed..77a7b86051 100644 --- a/app/views/assignments/_read.html.erb +++ b/app/views/assignments/_read.html.erb @@ -168,7 +168,9 @@

    <% end %>
      -
    • <%= link_to t('submissions.student.files_submitted', count: @num_submitted_files), "https://google.com" %>
    • +
    • <%= link_to t('submissions.student.files_submitted', count: @num_submitted_files), + file_manager_course_assignment_submissions_path(course_id: @assignment.course_id, + assignment_id: @assignment.id)%>
    • <% if @num_submitted_files > 0 %>
    • <%= t('submissions.student.last_revision_date') %> diff --git a/config/locales/views/assignments/en.yml b/config/locales/views/assignments/en.yml index ed8b244052..d0a5d28edf 100644 --- a/config/locales/views/assignments/en.yml +++ b/config/locales/views/assignments/en.yml @@ -1,9 +1,9 @@ --- en: assignments: - assignment_information: Assignment Information assignment_has_groupings: Assignment has groupings. average_annotations: "%{average_annotations} annotations per marked submission" + assignment_information: Assignment information configuration_zip_file: Configuration Zip File deadline_with_extension: You have an extension until %{extension_deadline}. deletion_confirmation: Are you sure you want to delete this assignment? From c82f105eb584fe55613917de5a0c739f836d2b05 Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Thu, 29 May 2025 02:37:33 -0400 Subject: [PATCH 08/18] Fixed previous commit for assignment description --- app/views/assignments/show.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/assignments/show.html.erb b/app/views/assignments/show.html.erb index 8972d932f6..5b8e8b9ed4 100644 --- a/app/views/assignments/show.html.erb +++ b/app/views/assignments/show.html.erb @@ -24,7 +24,7 @@ <% end %> <% end %> -<% content_for :title, "#{@assignment.short_identifier}: #{Assignment.model_name.human}" %> +<% content_for :title, "#{@assignment.short_identifier}: #{@assignment.description}" %>
      From 7d4ba25f76c30e6908eece4f0cb9753cf27b858e Mon Sep 17 00:00:00 2001 From: steven Date: Thu, 29 May 2025 02:43:54 -0400 Subject: [PATCH 09/18] Delete Changelog.md.orig Repeat --- Changelog.md.orig | 1075 --------------------------------------------- 1 file changed, 1075 deletions(-) delete mode 100644 Changelog.md.orig diff --git a/Changelog.md.orig b/Changelog.md.orig deleted file mode 100644 index 773c45644d..0000000000 --- a/Changelog.md.orig +++ /dev/null @@ -1,1075 +0,0 @@ -# Changelog - -## [unreleased] - -### 🚨 Breaking changes - -### ✨ New features and improvements - -### 🐛 Bug fixes - -- Fix bugs when assigning sections to starter file groups across multiple assignments (#7523) - -### 🔧 Internal changes - -- Remove `activerecord-session_store` gem (#7517) -- Upgrade to Rails 8 (#7504) -- Add tests for `#new` and `#create` actions in `CriteriaController` (#7521) -<<<<<<< HEAD -- Add tests for `#edit` and `#update` when user is trying to change criteria in `CriteriaController` (#7526) -======= -- Add tests for `#edit` and `#update` when user is trying to change criteria in `CriteriaController` (#7527) ->>>>>>> upstream/master - -## [v2.7.0] - -### 🚨 Breaking changes - -### ✨ New features and improvements - -- Fix front-end content shift when an input element is focused (#7384) -- Tooltip text for Package requirements file for Python autotester settings (#7383) -- Pass back tags and overall comments from Autotester to MarkUs (#7387) -- Render download test result button on assignment summary page only if the assignment has automated testing (#7417) -- Group test results by Test Groups id (#7422) -- Display HTML previews of RMarkdown files (#7394) -- Allow instructors to assign scans to inactive students (#7482) -- Added members parameter to add_group_api to support explicit member assignment during group creation (#7481) -- Modified add_group_api to use username as group name for individual assignments (#7481) -- Improved styling of markdown previews in `MarkdownPreview` component and annotation displays (#7487) -- Allow creating image annotations from a test run's outputs (#7486) -- Added an API that collects a single submission (#7494) -- Enable removal of a student from a course (#7480) -- Changed the PDF scanning job separate the student matching process into its own job. (#7499) - -### 🐛 Bug fixes - -- Ensures row selection for peer reviewer unassigning has the same validation checks as individual selections (#7274) -- Ensures mark levels on a rubric criterion are properly scaled when its max mark is updated (#7311) -- Refactor contributors list in About section to read from markus-contributors.txt (#7374) -- Optimized the querying of submissions when assigning graders (#7381) -- Update remote_autotest_settings_id validation to be unique to an autotester (#7393) -- Fix tag creation failing in tags table (#7426) -- Ensure tag names are unique within an assignment (#7430) -- Update flash style to "notice" for "setting up test env" message (#7445) -- Fixed bug in `ImageViewer` where image width was set to 0 on initial load (#7485) -- Fixed bug in `ImageViewer` where annotations did not disappear when moving the mouse out of the image (#7485) -- Ensured annotations appear in results view when in fullscreen mode (#7487) -- Fixed bug in `ImageViewer` where annotations did not always appear on initial image load (#7487) - -### 🔧 Internal changes - -- Reorganize Javascript files to separate Sprockets and Webpack compilation (#7345) -- Replace moment.js dependency with much smaller dayjs (#7346) -- Refactor `FileViewer`, `TextViewer`, `BinaryViewer` and `ImageViewer` components (#7270) -- Pin `mistune` Python dependency to preserve compatibility with `nbconvert` (#7371) -- Cache playwright's chromium installation on GitHub Actions (#7372) -- Fix broken link to the Vagrant installation guide in `README.md` (#7349) -- Fix `extra_hosts` configuration in `compose.yaml` (#7375) -- Add unit tests for `marks_graders_controller` (#7382) -- Convert front-end tests from enzyme to react testing library; add `@testing-library/user-event` (#7379) -- Refactor the `Result` component and its children to use React context API (#7380) -- Implement `contain_message` and `have_message` custom Rspec matchers to check for flash message content (#7386) -- Update Python version to 3.13 in seed autotest schemas (#7388) -- Rename jupyter notebook content functions and files to generalize to html content (#7391) -- Update to React v18 (#7392) -- Refactor querying on dashboard graph to query per-assignment rather than per-TA (#7420) -- Remove unused Javascript files (#7442) -- Refactor scanned test generation and test splitting from polling to websockets (#7428) -- Move Docker dependency updates into separate service (#7451) -- Fixed flaky test due to daylight savings time issue (#7452) -- Updated Python autotest seed file to illustrate pytest metadata custom markers (#7457) -- Updated to react-flatpickr v4.0.0 (#7478) -- Remove `mistune` Python explicit dependency (#7483) -- Applied pre-commit (specifically Rubocop) changes to use it_behaves_like over include_examples (#7492) -- Added explicit permissions to GitHub Actions workflow configuration (#7495) - -## [v2.6.1] - -### ✨ New features and improvements - -- Give instructors the ability to delete a TA from the Users Graders Tab (#7304) -- Added zoom and rotate functionality to PDF viewer (#7306) - -### 🐛 Bug fixes - -- Ensure we handle JSON parsing exceptions when converting Jupyter Notebooks (#7308) -- Fixed bug in grading context menu for editing/deleting annotations (#7314) -- Fixed bug in grading annotations table when deleting annotations (#7314) -- Ensure correct LTI version of lti_user_id is used on launch (#7335) - -## [v2.6.0] - -### ✨ New features and improvements - -- Prevent instructors from unassigning peer reviewers who have existing peer review data (#7263) -- Add visual indicator on a per-assignment basis for used grace credits (#7226) -- Change default disabled text area colour to ligher grey on light mode (#7269) -- Implement a limit on the file size rendered by the submission viewer (#7273) -- Add an option to retain old grading data when recollecting graded submissions (#7256) - -### 🐛 Bug fixes - -- Fix incorrect calculation of token penalties when submissions are on time (#7216) -- Ensured submissions that have been released cannot be recollected from the repo browser (#7254) -- Fix bug where renaming a group to an existing group in a different assignment resulted in incorrect repository mapping (#7224) -- Disable editable fields in assignment criterion when criterion is released (#7264) -- Fixed Download One Time Annotation 'Not Found' error (#7302) - -### 🔧 Internal changes - -- Fix test coverage for ExamTemplate.create_with_file method (#7213) -- Upgrade Docker environment to use Ruby v3.3 (#7185) -- Upgrade to Rails v7.2 (#7185) -- Move Exception message in student model to a localization file (#7218) -- Add test cases for the student model to cover Group or Grouping save method failure (#7218) -- Create tests for overtime messages of the submission rule classes (#7216) -- Fix flaky `check_repo_permissions` test (#7223) -- Move model validation error messages to respective localization files (#7229) -- Replace time-warp gem with newer, maintained timecop gem (#7234) -- Update pre-commit-hooks to v5.0 and add checks `check-illegal-windows-names`, `check-json`, and `check-merge-conflict` (#7259) -- Merge result.js and result_main.css build files into application.js/application.css (#7260) -- Simplify pdf.js configuration (#7260) -- Improve descriptions of the Group and Grouping models (#7262) -- Disable Rubocop Style/SafeNavigationChainLength check (#7301) -- Ignore faker translations in i18n-js compilation (#7305) - -## [v2.5.3] - -### 🐛 Bug fixes - -- Fix Marks Spreadsheet csv bug of showing incorrect marks (#7257) -- Fix incorrect inclusion of course parameter in LtiSyncJob (#7258) -- Fix Google Colab Jupyter Notebooks rendering by excluding widgets (#7271) - -## [v2.5.2] - -### ✨ New features and improvements - -- Improve textviewer rendering speed (#7211) -- Add periodic roster syncing via LTI (#7178) -- Allow instructors to assign graders by section (#7179) - -### 🐛 Bug fixes - -- Fix JSON/CSV summary of test results to always be inline with latest test run (#7214) -- Allow annotations to be added to results with released peer reviews (#7222) - -### 🔧 Internal changes - -- Manually specify chromedriver port number in Github actions (#7209) - -## [v2.5.1] - -### 🐛 Bug fixes - -- Fix bug in syntax highlighting caused by incorrect function call (#7187) - -## [v2.5.0] - -### ✨ New features and improvements - -- Allow deletion of assignments with no groups (#6880) -- Add new routes for `update`, `show`, and `index` actions of the Sections API Controller (#6955) -- Enable the deletion of Grade Entry Forms that have no grades (#6915) -- Allow instructors to configure an end date until which students can run automated tests (#6992) -- Gave TAs read-only access to starter file information under assignment settings (#6996) -- Allow inactive groups in the submissions table to be toggled for display (#7000) -- Display error message for student-run tests when no test groups are runnable (#7003) -- Added a confirmation check while renaming a file with a different extension (#7024) -- Allow inactive groups in the summary table to be toggled for display (#7029) -- Display error message for instructor-run tests when no test groups are runnable by instructors (#7038) -- Ensure user params are passed as keyword arguments to database queries (#7040) -- Added a progress bar for when a student uploads a file for submission (#7078) -- Added validations to the `TextAnnotation` model to ensure `line_start` and `line_end` are >= 1, and `column_start` and `column_end` are >= 0. (#7081) -- Calculate and display the exact future time for the next token generation to help students plan their test runs more effectively. (#7127) -- Set the default date for "Tokens available on" to the current time (#7173). -- Add setting to enable filtering of new course creation from LTI launch (#7151) - -### 🐛 Bug fixes - -- Ensure annotation previews are rendered on annotations page and in annotation category dropdown menus when grading (#7073) -- Ensure annotation rendering is updated in real-time for Jupyter notebooks (#7084) -- Fix MathJax rendering in annotations for Jupyter notebooks (#7084) -- Fix MathJax rendering of released overall comments (#7084) -- Fix rename confirmation check triggering even upon no rename input (#7124) -- Ensured that the assignment deadline is used as a placeholder if token_end_date is not present. (#7128) -- Fixed grader view rendering when a pre-defined annotation's content is blank (#7147) -- Fixed AJAX requests in grader view, which were missing CSRF token headers (#7174) -- Use jQuery `.find` method in `ModalMarkus` to guard against potential XSS attack (#7176) -- Sanitize LTI deployment course names when creating new courses (#7151) - -### 🔧 Internal changes - -- Fixed login_spec.rb flaky test on GitHub Actions run (#6966) -- Minor improvements in assignment association options (#6989) -- Update changelog and pull request template formats (#7041) -- Upgrade to MathJax version 3, with packaging from npm (#7073) -- Upgrade CI chromedriver to 125.0.6422.60 (#7082) -- Fix flaky `Assignment#summary_json` test (#7111) -- Upgrade pdfjs-dist to v4.3.136 (#7113) -- Fixed formatting of documentation repository on the PR template (#7120) -- Switch from rails-sassc to cssbundling-rails for CSS asset management (#7121) -- Fixed flaky test #creates groups for individual students in groups_controller_spec (#7145) -- Switch from SyntaxHighlighter to Prism for syntax highlighting (#7122) -- Move jquery-ui and ui-contextmenu dependencies to package.json and upgrade jquery-ui to v1.13.3 (#7149) -- Do not enforce secure cookies in development for LTI deployments (#7151) -- Remove CI chromedriver version and Chrome dependency (#7170) -- Update Jupyter notebook Javascript dependencies (require.js to v2.3.7, plotly.js to v2.34.0) (#7175) -- Do not require i18n-tasks in Gemfile (#7180) - -## [v2.4.12] - -### ✨ New features and improvements - -- Added a backend to check MIME type and file extension of uploaded files (#7083) - -### 🐛 Bug fixes - -- Fix bug in grade display for marks summary (#7125) -- Remove peer reviews from grade summary table (#7126) - -## [v2.4.11] - -### 🚨 Breaking changes - -- Disallow peer reviewers from printing results (#7114) - -## [v2.4.10] - -### ✨ New features and improvements - -- Allow restricting IP addresses for remote logins (#7072) - -## [v2.4.9] -- Peer review table bug fix to display total marks (#7034) -- Fix bug preventing deletion of autotest files (#7033) - -## [v2.4.8] -- Validate user-provided paths (#7025) - -## [v2.4.7] -- Support Jupyter notebooks for results printing (#6993) -- Enable bulk download of print PDFs for an assignments (#6998) -- Fixed long annotations being cut off in the annotation table (#7001) - -## [v2.4.6] -- Disallow students from uploading .git file and .git folder in their repository (#6963) - -## [v2.4.5] -- Add workaround for CSP in Safari < 16 (#6947) -- Improve add button labels on autotest settings page (#6948) -- Fix bug where grader distribution graph displays graders multiple times (#6950) -- Fixed bug where TA Summary table failed to display members (#6949) -- Make display of group member information consistent across submissions and summary table (#6917) - -## [v2.4.4] -- Fix websocket connection when logged in with remote auth (#6912) -- Fix bug where graders table failed to load when a group had no members (#6916) - -## [v2.4.3] -- Fix autotest settings criterion JSON schema validation (#6907) -- Ensure autotested criteria do not have marks set if tests time out (#6907) -- Fix import bug that prevents the peer review table from loading (#6908) - -## [v2.4.2] -- Fix feedback file API not returning feedback file IDs correctly (#6875) -- Allow inactive groups in the graders table to be toggled for display (#6778) -- Enable plotly rendering for jupyter notebooks (#6871) -- Bug Fix: Prevent assigning inactive graders to a group (#6801) -- Added new API routes for the `create` and `destroy` actions of SectionsController (#6873) -- Display error message in real-time when running automated tests, rather than waiting for page refresh (#6878) - -## [v2.4.1] -- Internal changes only - -## [v2.4.0] -- Display error message on file upload failure (#6703) -- Remark request grading: differentiate between old and new annotations using colour and remark flag (#6704) -- Display detailed messages about grace period deductions for an assignment on student interface (#6706) -- Moved create and edit tag modals to React (#6742) -- Added constraint for `Tag` name field: not empty and max 30 characters (#6742) -- Modified and moved helper methods from `CriteriaHelper` into static methods in the `Criterion` class (#6746) -- Convert helper methods of the module `app/helpers/annotations_categories_helper` into class methods of the - `AnnotationCategory` model. The refactored helper methods were `annotation_categories_to_yml` and - `upload_annotations_from_yaml` (#6747) -- Added tooltips to criteria type and visibility icons (#6753) -- Replace the function `tas` of the `Assignment` model with a `tas` "has_many" association for that model (#6764) -- Ensure starter files are passed to autotester in sorted order (#6771) -- Resolved issue 6677 by taking timed assessment's duration into account when determining when grading can begin (#6845) -- Fix loading results page when group is created after the due date (#6863) -- Autocomplete with active students only for matching process in 'assign scans' (#6844) -- Fix member filtering in Groups table (#6842) - -## [v2.3.4] -- Ensure the "Random Incomplete Submission" button takes into account criteria assignment for TAs (#6800) -- Ensure bonus marks are not included in assignment "out of" in submissions table (#6836) -- Ensure assignment "out of" in submissions table is rounded to two decimal places (#6836) -- Added POST API for Group Creation (#6834) - -## [v2.3.3] -- Fix bug where uploading scanned exam pages with overwriting option selected did not update submission files (#6768) -- Fix bug: "Download Submissions" download link was not being rendered from partial view (#6779) - -## [v2.3.2] -- Allow MathJAX to process environments (e.g., align) (#6762) - -## [v2.3.1] -- Add filter for empty/non-empty submissions in submissions table (#6711) -- Fix bug where autotest settings would not appear if there were no assignment criteria (#6718) -- Added API routes for Extensions API (#6743) -- Fix premature page reloading when autotest settings are saved (#6744) - -## [v2.3.0] -- Do not destroy pending group memberships if the group is given an extension (#6582) -- Add OCR for parsing scanned exam uploads (#6433) -- Move submission-specific results/ routes to be under submissions/ (#6434) -- Add option to allow Cross-Origin Resource Sharing (CORS) from JupyterHub (#6442) -- Fix error message when a file is submitted through the API that doesn't match the required file list (#6479) -- Improve syntax highlighting for C (#6513) -- Allow negative grades for bonus columns in marks spreadsheets (#6521) -- Clarify assignment submission rule configuration labels (#6529) -- Enable client-side validation of autotest settings page (#6568) -- Use web sockets instead of polling to update submissions table after collecting submissions (#6583) -- Order students by username when downloading the CSV grades breakdown for an assignment from Summary tab (#6589) -- Use web sockets to update TestRunTable for non-batch run tests when a test run is in progress or completed (#6591) -- Add button to allow students to cancel automated test runs (#6596) -- Use web sockets instead of polling to update submission collection status (#6597) -- Removed trailing spaces at end of every line when viewing a file (#6598) -- Modify MarkUs API to allow the CoursesController#index route to accept requests from all types of roles (#6619) -- Modify MarkUs API to allow the AssignmentsController#index route to accept requests from all types of roles (#6619) -- A user can't run tests with the same names / Single test error does not spoil the whole test batch (#6620) -- Refactored GET requests to use fetch API instead of jQuery (#6622) -- Change icon set to Font Awesome (Free) (#6627) -- Add feature to generate a PDF report of a result (PDF submission files only) (#6635) -- Add zoom feature to scanned exam template crop selection (#6640) -- Ensure Jupyter notebook HTML rendering does not require external CDNs (#6656) -- Prevent Jupyter notebook from reloading when an annotation is added (#6656) -- Added a button allowing graders to view a random incomplete submission (#6641) -- Added a filter modal allowing graders to specify filters and order when navigating submissions (#6642) -- Add icons to submission and result grading action buttons (#6666) -- Remove group name maximum length constraint (#6668) -- Fix bug where in some cases flash messages were not being rendered correctly (#6670) -- Enable duplicate pages when uploading scanned exams to overwrite existing pages or be ignored (#6674) -- Extended the filter modal to allow graders to order results by total mark and filter them by criteria (#6669) -- Validate copy and page number when fixing errors with scanned exams (#6695) -- Display due date and submission time in result "Submission Info" tab (#6698) -- Added "Help" link to the MarkUs page header dropdown (#6702) -- Prevent TAs that aren't assigned to grade a given criterion from assigning a grade to that criterion (#6699) -- Replace byebug gem with debug gem (#6705) -- Added persistence to the filter modal (#6697) - -## [v2.2.4] -- Add feature to generate a PDF report of a result (PDF submission files only) (#6635) - - -## [v2.2.3] -- Fix bug where in some circumstances the wrong result would be displayed to students (#6465) - -## [v2.2.2] -- Apply course maximum file size to feedback files (#6430) - -## [v2.2.1] -- Fix bug where error was raised when viewing jupyter notebooks if python is not available (#6418) -- Fix bug where peer reviewers could not view results they are assigned to review (#6439) -- Make fewer connections when connecting to redis (#6443) - -## [v2.2.0] -- Moved markdown text preview to new tab in the generic autosaving text form component (#6154) -- Simplify configuration options for storing files on disk (#6157) -- Replace yarn with npm as a package manager (#6159) -- Drop support for subversion repositories (#6160) -- Fix undefined prop type warnings when loading assessment charts (#6172) -- Allow graders and instructors to be set to hidden status (#6173) -- Prevent hidden roles from interacting with a course (#6173) -- Do not dynamically change the database schema which causes migration and installation issues (#6189) -- Make git hooks more portable by converting them to shell scripts (#6196) -- Don't start webpack docker service in development before the packages are fully installed (#6212) -- Added ability to download feedback files (#6215) -- Allow admins to set the autotester url for each course in the courses view (#6213) -- Allow admins to test and reset the connection to the autotester in the courses view and through the API (#6213) -- Fix bug where exam template was downloaded instead of copies with unique qr codes (#6219) -- Allow admin users to manage the maximum file size setting through the UI (#6195) -- Disable python features if python dependencies are not installed (#6232) -- Install system dependencies from a debian package (#6246) -- Fix bug where assignments could not be uploaded with unexpected properties in file upload content (#6224) -- Fix bug where tests group results associated with old test groups aren't displayed with test group information (#6285) -- Read the MarkUs version once at initialization instead of at every request (#6305) -- Allow spaces in file names (#6306) -- Fix bug where a request to cancel test runs failed if some test runs had already completed (#6320) -- Downloading files from a single repository no longer adds an additional subdirectory to the zip archive (#6323) -- Bulk submission collection: allow collecting the most recent revision and choosing whether to apply late penalties (#6341) -- Allow admins to role switch to instructors (#6353) -- Fix bug where rubric grades could not be selected with the return key (#6354) -- Allow admins to set the number of puma workers and threads from the settings files (#6348) -- Fix bug where a user who has switched roles could not view the about modal or log out (#6356) -- Fix bug where grades summary charts flicker in some browsers (#6352) -- Fix bug where emoji annotation options were available even when no text/region was selected (#6384) -- Fix bug where certain results attributes could not be updated if the result was incomplete (#6388) - -## [v2.1.7] -- Switch from jquery-ui-timepicker-addon to flatpickr for datetime inputs (#6158) -- Allow results to be made available only through unique tokens (#6244) - -## [v2.1.6] -- Fix bug where TAs were able to access urls for results they haven't been assigned to (#6321) -- Fix bug where the marking state was left as "complete" after a new criterion is created (#6303) -- Fix bug where writing starter files to repositories failed if the starter files contained a directory (#6294) -- Fix bug where csv summary download fails if criteria are created after marking (#6302) - -## [v2.1.5] -- Add admin users to the .access file so that they can be authenticated as having access to the git repos (#6237) -- Optionally log which user makes each request by tagging the log files with user_names (#6241) -- Allow users to upload and download csv files for marks spreadsheets in the same format (#6267) -- Hide manual submission collection button from users who don't have permission (#6282) -- Fix bug where gzipped binary feedback files were not unzipped correctly (#6283) -- Fix bug where remark request summary table wasn't being rendered correctly (#6284) -- Fix bug where test results were being associated with the wrong test runs (#6287) - -## [v2.1.4] -- Fix bug where git hooks are not run server side when symlinked (#6276/#6277) - -## [v2.1.3] -- Fix bug where automated test results were occasionally associated with the wrong grouping (#6238) - -## [v2.1.2] -- Fix bug preventing use of the update_grades API route (#6188) -- Fix overly restrictive policies for admin users (#6209) -- Add check for version format to ensure that Wiki links are well-formed (#6221) -- Fix bug where empty groups are hidden by default (#6222) -- Fix bug where test run table did not re-render when switching results (#6223) -- Allow admin users to manage the maximum file size setting through the UI (#6195) - -## [v2.1.1] -- Fix bug where files could not be uploaded using drag and drop if no files or folders previously existed. (#6117) -- Added drag and drop functionality to upload starter files and automated tests. (#6117) -- Added new summary statistics display for grade entry forms and grade entry column items (#6118) -- Moved markdown text preview to new tab in the modify/create annotation modal (#6138) -- Enable bulk removal of students from section in student table (#6145) -- Enable updating student active/inactive status in student edit form (#6145) - -## [v2.1.0] -- Remove unmaintained locales (#5727) -- Introduce standalone ruby script as an alternative method to checking for repository access (#5736) -- Added the ability to submit URLs (#5822) -- Switch Javascript bundling to jsbundling-rails gem, and update to webpack v5 (#5833) -- Remove group name displayed attribute from assignment properties table (#5834) -- Rework scanned exam page (#5839) -- Replace uses of first name and last name attributes with display name (#5844) -- Fix bug for rubric criteria level's mark update where one of the marks = an old mark (#5854) -- Upgrade to Rails 7 (#5885) -- Move footer and information in top right corner of navigation bar into a dropdown menu in the top right corner (#5886) -- Modified login to allow admin users to login via the UI (#5897) -- Fix bug where admins viewing the admin page were not redirected properly when timed out (#5909) -- Added a list of courses to manage for new markus administration view (#5907) -- Added a page in new markus administration view that allows admins to edit the attributes of a course (#5915) -- Added a page in new markus administration view that allows admins to create a new course (#5917) -- Added a list of users to manage for new markus administration view (#5918) -- Added Resque monitoring views for admin users (#5919) -- Added a page in new markus administration view that allows admins to edit user information (#5921) -- Added a page in new markus administration view that allows admins to create users (#5923) -- Added course visibility status to admin courses list (#5924) -- Added ability for instructors to edit course visibility (#5925) -- Fix bugs when handling remark requests with deductive annotations (#5926) -- Modified model associations so that a role belongs to a user (#5948) -- Fix display of flash messages when creating criteria and annotations (#5949) -- Display error messages on group csv upload when there are invalid group names (#5952) -- Created a new admin role (#5956) -- Added a bulk upload of end users to admin users page (#5959) -- Fix display of "Submit File" to "Upload File" for non submission views (#5960) -- Added an "Assign Scans" link to exam templates page (#5962) -- Added background job to clean tmp folder (#5963) -- Removed consideration of due date from scanned exam (#5964) -- Added Exception Notification Gem (#5965) -- Bug fixes for peer reviews (#5968) -- Added Rails Performance to Admin Dashboard (#5967) -- Added a detailed view for assignment statistics (#6000) -- Resolved issue 5905 by adding an explicit download icon to file manager, to differentiate from file preview action (#6001) -- Added student data such as user name, last name, first name, section, id number and email on grade reports for the whole course, individual assignments and grade entry forms (#6005) -- Update Groups API to return member role IDs instead of user IDs (#6006) -- Switch rendering of RMarkdown submission files to plaintext, rather than converting to HTML (#6008) -- Ensure consistent order when displaying test results (#6010) -- Added Capybara Gem (#6012) -- Enable students to rename files during submission (#6045) -- Separated peer review assignment upload/download from parent (#6048) -- Expanded summary stats UI (#6050) -- Fix bug for submission modal where students could submit files even if no file was chosen (#6052) -- Added ability to have a non-uniform group distribution when assigning graders (#6055) -- Added new "submit_file" API assignment route for students (#6057) -- Removed searchbar used to filter files on submissions page (#6058) -- Removed "outstanding_remark_request_count" attribute (#6059) -- Added checklist for required files on submissions page (#6061) -- Changed flash message that is displayed when students upload a file with an incorrect name. (#6062) -- Added emoji annotations for graders and removed `control+click` quick annotations. (#6093) -- Sorted courses on the dashboard. (#6099) -- Added summary statistics for criteria (#6100) -- Improved UI on 404 and 403 pages to match the style on MarkUs' dashboard. (#6101) -- Pass group name and starter files to the autotester when running tests (#6104) -- Handle multiple feedback files sent from the autotester (#6106) -- Added API CRUD requests for tags (#6107) -- Disabled admin editing of course name and allowed instructors to edit display name (#6111) -- Added explicit status and filtering for inactive students and groups in assignment groups page. (#6112) -- Fixed flaky automated test file tests by rearranging order of test file cleanup (#6114) -- Changed nav bar layout by moving the MarkUs logo beside the course name on the top bar (#6115) -- Replace standalone ruby script to check for repository access with database function (#6116) -- Update git over ssh scripts to optionally use the database function to check for repository access (#6116) -- Ensure each file viewer has independent syntax highlighting (#6139) -- Update git over ssh scripts to use the database function to check for authorized keys (#6142) -- Remove support for sqlite and mysql database types (#6143) -- Replace uglifier gem with terser gem to support ES6 syntax (#6146) -- Reorganize rake tasks to simplify steps required for asset precompilation in production (#6146) - -## [v2.0.10] -- Fix bug when sorting batch test runs where sorting by date was not working (#5906) -- Ensure tabs in result view do not reload when switching between them (#5910) -- Fix bug where penalty periods were sometimes incorrectly ordered (#5908) - -## [v2.0.9] -- Fix bug when downloading all automated test files where the files were saved to a sub directory (#5864) -- Fix bugs in assigning scanned exams and improve error message when assigning by name (#5895) -- Remove MarkUs logo from mobile view left navigation menu (#5899) -- Allow adding annotations to remark requests (#5900) - -## [v2.0.8] -- Fix bug where "run tests" grader permission was not working for submission table (#5860) -- Fix bug for replacing exam template files (#5863) - -## [v2.0.7] -- Fix bugs in starter files when assigning by section (#5846) - -## [v2.0.6] -- Fix bug for "Delete Group" button generating an invalid path (#5768) -- When role switched, 403 errors are displayed as flash messages after redirecting back to the previous page (#5785) -- Update wiki urls to point to https://github.com/MarkUsProject/Wiki (#5781) -- Allow TAs to download grades for students they've been assigned to grade (#5793) -- Fix bug for menu icon not working on mobile devices / smaller screens (#5818) -- Fix bugs when submitting and cancelling remark requests (#5838) -- Do not trigger starter file changed timestamp when only starter_files_after_due assignment setting is changed (#5845) - -## [v2.0.5] -- Add ability to annotate notebook (jupyter and Rmd) submissions (#5749) - -## [v2.0.4] -- Fix bug where "Create Note" button was displaying when a course had no noteables (#5745) -- Redesign login page for multiple authentication options (#5752) -- Do not timeout users who are logged in using remote authentication (#5738) -- Ensure users logged in using remote authentication have their session expired when logging out from remote authentication (#5738) -- Display error message for users logging in using remote authentication if they do not exist in MarkUs database (#5738) -- Fix bug where git hooks were not finding the correct file containing the maximum file size for a given course (#5744) -- Allow setting optional role attributes through the api (#5748) -- Allow students to populate their repositories with starter files (#5754) - -## [v2.0.3] -- Fix bug where repository access files were not taking multiple courses into account (#5734) -- Fix bug where sections and grace credits could not be updated from the student edit view (#5739) - -## [v2.0.2] -- Fix bug in displaying feedback files for test results (#5719) -- Require starter group names to be unique for an assignment (#5721) -- Fix bug in updating the autotester url for a given course (#5724) - -## [v2.0.1] -- Fix bug where a login with remote authentication failed to redirect to the landing page (#5690) -- Allow admin user to have a unique user name (#5691) - -## [v2.0.0] -- Support multiple courses in a single MarkUs instance (#5685) - -## [v1.14.1] -- Update wiki urls to point to https://github.com/MarkUsProject/Wiki (#5782) - -## [v1.14.0] -- Add the ability to hide assignments from individual sections (#5445) -- Display smaller error message when nbconvert fails to avoid a cookie overflow (#5510) -- Fix bug with run test button in grading view when marks are released (#5527) -- Update repository access permissions to take into account the Assignment - is_hidden and anonymize_groups attributes (#5547) -- Support syntax highlighting for R (#5558) -- Fixes in progress remark requests to display the remark request due date for students (#5562) -- Preserve exam template paper size and orientation when stamping with QR codes (#5573) -- Fix bugs in automatic parsing Python module (#5592) -- Fix exam template automatic parsing to only accept one crop box, and parse either - ID number or user name (#5592) -- Fix scanned exams when using automatic parsing with multiple exam templates (#5592) -- Fixes assignment graders checkbox settings text to avoid double negatives (#5600) -- Add test results download modal for assignment summary (#5561) -- Improve accessibility of exam templates page (#5607) -- Fix display bug with infinitely expanding chart in student results view for grade entry form (#5612) -- Added the ability to copy over entire assignments (#5616) -- Fix bug in User#visible_assessments for students in a section (#5634) -- Fixed bug where tag edit modal closed whenever it is clicked (#5652) -- Fix bug where the datetime selector wasn't being shown for peer review assessments (#5659) -- Fix bug in displaying associated feedback files when switching between results (#5676) - -## [v1.13.3] -- Display multiple feedback files returned by the autotester (#5524) -- Add workaround for CSP rules in Safari (#5526) -- Change level mark input field to accept change increments of 0.01 (#5546) -- Fix bug in annotation upload when updating categories not associated with a criterion (#5564) - -## [v1.13.2] -- Ensure "Create all groups" button uses existing repos if they already exist (#5504) -- Set criteria marks after autotest run (#5508) - -## [v1.13.1] -- Ensure that downloadable test specs file is portable between assignments and instances (#5469) -- Support rendering of Markdown in criterion descriptions (#5500) -- Ensure "Create all groups" button creates repositories for students usering their user name (#5499) - -## [v1.13.0] -- Modify Result.get_total_extra_marks to differentiate between having extra marks that sum to zero and - having no extra marks (#5220) -- Add copy to clipboard button for plaintext submission files in Results view (#5223) -- Add ability to associate feedback files to test group results (#5209) -- Communicate with autotester over http to support new autotesting configuration (#5225) -- Remove activerecord-import dependency (#5248) -- Combine all python dependencies (#5358) -- Rename "Tags/Notes" tab on grading page to "Submission Info", and move membership information to the tab (#5380) -- Respect referrer url when navigating between assignments (#5409) -- Remove delete link from TA table (#5407) -- Persist file size and rotation when navigating between text and image files (#5413) -- Improve student UI for timed assessments (#5417) -- When completing bulk actions, report errors instead of halting the whole process and rolling back (#5422) -- Add ability to download data from submissions table as csv file (#5418) -- Correctly update annotation category when creating annotation from "Did you mean" suggestion (#5448) -- Add route to download an example of the starter files that may be assigned to students (#5449) -- Validate a user's locale to ensure that it is set to a valid value (#5450) -- Display due date, collection date, and start time in repo browser view (#5462) -- Create dark mode versions of logo and favicon (#5463) -- Update UI for test results table (#5465) - -## [v1.12.5] -- Fix bugs in grading view when switching between submissions (#5400) - -## [v1.12.4] -- Symlink git repo hooks (#5283) - -## [v1.12.3] -- Add workaround for content security policy to allow loading blobs in Safari (#5273) - -## [v1.12.2] -- Require TestServer user to have a non-conflicting user name (#5268) - -## [v1.12.1] -- Remove counter caches (#5222) -- Delay grouping creation for working-alone timed assessments to when the student starts the assessment (#5224) -- Add option to hide starter files after collection date (#5226) - -## [v1.12.0] -- Remove annotations context menu from peer assignments view (#5116) -- Change 'Next' and 'Previous' submission button to use partial reloads (#5082) -- Add time zone validations (#5060) -- Add time zone to settings (#4938) -- Move configuration options to settings yaml files (#5061) -- Removed server_time information in submissions_controller.rb and server_time? from submission_policy.rb (#5071) -- Add rake tasks to un/archive all stateful files from a MarkUs instance (#5069) -- Fix bug where zip files with too many entries could not be uploaded (#5080) -- Add button to assignment's annotations tab to allow instructor to download one time annotations (#5088) -- Removed AssignmentStats table (#5089) -- Display assignment totals on the grade summary table rounded up to 2 decimal places (#5123) -- Removed results_average, results_median, results_fails, results_zeros cached stats (#5131) -- Do not allow users to set repo names by uploading csv files (#5132) -- Added a delete button to notes dialog under an results edit view and removed user_can_modify under note model, - removed Notes#user_can_modify and replaced instances of usage with NotePolicy (#5128) -- Support Markdown syntax for assessment messages (#5135) -- Remove controller-specific css files (#5136) -- Replace non-UTF8 characters in text file preview (#5156) -- Rollback group creation if error is raised when creating a group for a working-alone student (#5169) -- Prevent deletion/modification of annotation texts associated with a result with a pending remark request (#5170) -- Enhancing student submission log with required assignment file info, file size (fixes issue 5171) (#5188) -- Ensure that browsers cache the correct state of overall comments when marking (#5173) -- Ensure that graders are shown the correct annotation categories (#5181) -- Show informative error message if an uploaded criteria yaml file did not contain a "type" key (#5184) -- Enable content security policies (#5186) -- Allow for multiple custom validation messages (#5194) -- Add ability to hold shift to select a range of values in checkbox tables (#5182) -- Update ssh authorization to be more flexible, secure, and permit a single user to use the same public key for multiple instances (#5199) -- Fix bug where creating an annotation or switching results reset the selected file (#5200) -- Fix bug in Assignment#get_num_marked that caused it to double-count remark and original results (#5205) -- Update permission files in background jobs (#5207) -- Fix bug where graders can't see the tests that they run (#5210) -- Fix bug where graders can't release results on the results page (#5210) -- Use DOMpurify library to sanitize rendered markdown content (#5211) -- Add percentage extra marks when calculating total extra marks properly (#5213) - -## [v1.11.5] -- Account for percentage deductions when calculating total marks after deleting a criterion (#5176) -- Prevent students from downloading starter files early (#5189) - -## [v1.11.4] -- Override defaultSortMethod for react-table to put null/undefined values at bottom (#5159) -- Fix bug where groupings created before starter files were uploaded could not download starter files (#5160) - -## [v1.11.3] -- Fix easyModal overlay bug (#5117) - -## [v1.11.2] -- Fix bug where newlines were being added to files in zip archives (#5030) -- Fix bug where graders could be assigned to groups with empty submissions (#5031) -- Use Fullscreen API for grading in "fullscreen mode" (#5036) -- Render .ipynb submission files as html (#5032) -- Add option to view a binary file as plain text while grading (#5033) -- Fix bug where a remarked submission wasn't being shown in the course summary (#5063) -- Fix bug where the server user's api key was being regenerated after every test run creation (#5065) -- Fix bug where additional test tokens were added after every save (#5064) -- Fix bug where latex files were rendered with character escape sequences displayed (#5073) -- Fix bug where grader permission for creating annotations were not properly set (#5078) - -## [v1.11.1] -- Fix bug where duplicate marks can get created because of concurrent requests (#5018) -- Only display latest results for each test group to students viewing results from an released assignment (#5013) -- Remove localization path parameter (#4985) - -## [v1.11.0] -- Converts annotation modals from ERB into React (#4997) -- Refactor localization setting to settings page (#4996) -- Add admins to display name (#4994) -- Adds MathJax and Markdown support for remark requests (#4992) -- Use display name on top right corner (#4979) -- Add display name to settings (#4937) -- Create the required directory when uploading zip file with unzip is true (#4941) -- Remove preview of compressed archives in repo browser (#4920) -- Add singular annotation update feature when updating non-deductive categorized annotations (#4874) -- Replace Time.now and Time.zone.now with Time.current (#4896) -- Fix lingering annotation text displays when hovering (#4875) -- Add annotation completion to annotation modal (#4851) -- Introduce the ability to designate criteria as 'bonus' marks (#4804) -- Enable variable permissions for graders (#4601) -- UI for enable/disable variable permissions for graders (#4756) -- Image rotation tools added in marking UI (#4789) -- Image zooming tools added in marking UI (#4866) -- Fixed a bug preventing total marks from updating properly if one of the grades is nil (#4887) -- Group null/undefined values when sorting on dates using react-table (#4921) -- Add user settings page (#4922) -- Render .heic and .heif files properly in the file preview and feedback file views (#4926) -- Allow students to submit timed assessments after the collection date has passed even if they haven't started yet (#4935) -- No longer add starter files to group repositories when groupings are created (#4934) -- When starter files are updated, try to give students the updated version of the starter files they already have been assigned (#4934) -- Display an alert when students upload files without having downloaded the most up to date starter files first (#4934) -- Rename the parameter in get_file_info from id to assignment_id (#4936) -- Fix bug where maximum file size for an uploaded file was not enforced properly (#4939) -- Add counts of all/active/inactive students to students table (#4942) -- Allow feedback files to be updated by uploading a binary file object through the API (#4964) -- Fix a bug where some error messages reported by the API caused a json formatting error (#4964) -- Updated all authorization to use ActionPolicy (#4865) -- Fix bug where note creation form could be submitted before the form had finished updating (#4971) -- Move API key handling to user Settings page (#4967) -- Fix bug that prevented creation of scanned exams (#4968) -- Fix bug where subdirectories were not being created with the right path in the autotest file manager (#4969) -- Fix bug where penalty periods could have interval/hour values of zero (#4973) -- Add color theme settings (#4924) - -## [v1.10.4] -- Fix bug where students could see average and median marks when the results had not been released yet (#4976) -- Add email and id_number to user information returned by get requests to api user routes (#4974) - -## [v1.10.3] -- Allow for more concurrent access to git repositories (#4895) -- Fixed calculation bugs for grade summary (#4899) -- Fixed a bug where due dates in a flash message were incorrect for timed assessments (#4915) -- Allowed the difference between the start and end times of a timed assessment to be less than the duration (#4915) -- Fixed bug where negative total marks may be displayed when a negative extra mark exists (#4925) - -## [v1.10.2] -- Ensure that assignment subdirectories in repositories are maintained (#4893) -- Limit number of tests sent to the autotest server at one time (#4901) -- Restore the flash messages displayed when students submit files (#4903) -- Enable assignment only_required_files setting to work with subdirectories (#4903) -- Fix bug where checkbox marks are updated twice (#4908) -- Fixed the Assign Reviewers table loading issue (#4894) -- Fixed a bug where the progress bar in submissions and results page counts the not collected submissions (#4854) - -## [v1.10.1] -- Fix out of dates link to the wiki (#4843) -- Fixed a bug where the grade summary view was not being properly displayed if no criteria existed (#4855) -- Fixed an error preventing graders from viewing grade entry forms (#4857) -- Fixed an error which used unreleased results to calculate assignment statistics (#4862) - -## [v1.10.0] -- Issue #3670: Added API for adding and removing extra marks (#4499) -- Restrict confirmation dialog for annotation editing to annotations that belong to annotation categories (#4540) -- Fixed sorting in annotation table in results view (#4542) -- Enabled customization of rubric criterion level number and marks (#4535) -- Introduces automated email sending for submissions releases (#4432) -- Introduces automated email sending for spreadsheet releases (#4460) -- Introduces automated email sending for grouping invitations (#4470) -- Introduces student email settings (#4578) -- Assignment grader distribution graphs only show marks for assigned criteria when graders are assigned specific - criteria (#4656) -- Fixed bug preventing graders from creating new notes in results view (#4668) -- Fixed bug preventing new tags from being created from results view (#4669) -- Remove deprecated "detailed CSV" download link from submissions/browse (#4675) -- Introduces Deductive Annotations (#4693) -- Introduces annotation usage details panel to Annotations tab in admin settings (#4695) -- Fixed bug where bonuses and deductions were not displayed properly (#4699) -- Fixed bug where image annotations did not stay fixed relative to the image (#4706) -- Fixed bug where image annotations did not load properly (#4706) -- Fixed bug where downloading files in nested directories renamed the downloaded file (#4730) -- Introduces an option to unzip an uploaded zip file in place (#4731) -- Fixed bug where marking scheme weights were not displayed (#4735) -- Introduces timed assignments (#4665) -- Introduces uncategorized annotations grouping in Annotations settings tab (#4733) -- Introduces new grades summary chart, and makes student view of grades consistent with admin (#4740) -- Set SameSite=Lax on cookies (#4742) -- Introduces individual marks chart view for assessments (#4747) -- Fix annotation modal overflow issue (#4748) -- Introduce file viewer for student submission file manager and admin repo manager (#4754) -- Make skipping empty submissions the default behaviour when assigning graders (#4761) -- Introduce typing delay for entering flexible criterion mark (#4763) -- Fix UI overflow bug for large images in results file viewer (#4764) -- Add disabled delete button to submissions file manager when files unselected (#4765) -- Support syntax highlighting for html and css files (#4781) -- Add minutes field to non timed assessment extension modal (#4791) -- Add ability to check out git repositories over ssh using a public key uploaded in the new Key Pairs tab (#4598) -- Unify criterion tables using single table inheritance (refactoring change) (#4749) -- Add support for uploading multiple versions of starter files (#4751) -- Remove partially created annotation category data for failed upload (#4795) - -## [v1.9.3] -- Fixed inverse association bug with assignments (#4551) -- Fixed bug preventing graders from downloading submission files from multiple students (#4658) -- Fixed bug preventing downloading all submission files from git repo (#4658) - -## [v1.9.2] -- Fixed bug preventing all git hooks from being run in production (#4594) -- Fixed bug preventing folders from being deleted in file managers (#4605) -- Added support for displaying .heic and .heif files in the file viewer (#4607) -- Fixed bug preventing students from running tests and viewing student-run test settings properly (#4616) -- Fixed a bug preventing graders viewing the submissions page if they had specific criteria assigned to them (#4617) - -## [v1.9.1] -- Fixed bug where the output column was not shown in the test results table if the first row had no output (#4537) -- Fixed N+1 queries in Assignment repo list methods (#4543) -- Fixed submission download_repo_list file extension (#4543) -- Fixed bug preventing creation of assignments with submission rules (#4557) -- Fixed inverse association bug with assignments (#4551) -- Updated interface with the autotester so that files do not need to be copied when test are setup/enqueued (#4546) - -## [v1.9.0] -- Added option to anonymize group membership when viewed by graders (#4331) -- Added option to only display assigned criteria to graders as opposed to showing unassigned criteria but making them - ungradeable (#4331) -- Fixed bug where criteria were not expanded for grading (to both Admins and TAs) (#4380) -- Updated development docker image to connect to the development autotester docker image (#4389) -- Fixed bug where annotations were not removed when switching between PDF submission files (#4387) -- Fixed bug where annotations disappeared on window resize (#4387) -- Removed automatic saving of changes on the Autotesting Framework page and warn when redirecting instead (#4394) -- Added progress message when uploading changes on Automated Testing tab (#4395) -- Fixed bug where the error message is appearing when the instructor is trying to collect the submission of the student - who hasn't submitted anything (#4373) -- Ignore the "Total" column when uploading a csv file to a grade entry form. This makes the upload and download format - for the csv file consistent (#4425) -- Added git hook to limit the maximum file size committed and/or pushed to a git repository (#4421) -- Display newlines properly in flash messages (#4443) -- Api calls will now return the 'hidden' status of users when accessing user data (#4445) -- Make bulk submission file downloads a background job (#4463) -- Added option to download all test script files in the UI and through the API (#4494) -- Added syntax highlighting support for .tex files (#4505) -- Fixed annotation Markdown and MathJax rendering bug (#4506) -- Fixed bug where a grouping could be created even when the assignment subdirectory failed to be created (#4516) -- Progress messages for background jobs now are hidden once the job is completed (#4519) -- Fixed bug where a javascript submission/test/starter file can't be downloaded (#4520) -- Add ability to upload and download autotest settings as a json file/string through the UI and API (#4498) - -## [v1.8.4] -- Fixed bug where test output was not being properly hidden from students (#4379) -- Fixed bug where certain fonts were not rendered properly using pdfjs (#4382) - -## [v1.8.3] -- Fixed bug where grace credits were not displayed to Graders viewing the submissions table (#4332) -- Fixed filtering and sorting of grace credit column in students table. (#4327) -- Added feature to set multiple submissions to in/complete from the submissions table (#4336) -- Update pdfjs version and integrate with webpacker. (#4362) -- Fixed bug where tags could not be uploaded from a csv file (#4368) -- Fixed bug where marks were not being scaled properly after an update to a criterion's max_mark (#4369) -- Fixed bug where grade entry students were not being created if new students were created by csv upload (#4371) -- Fixed bug where the student interface page wasn't rendered if creating a single student grouping at the same time (#4372) - -## [v1.8.2] -- Fixed bug where all non-empty rows in a downloaded marks spreadsheet csv file were aligned to the left. (#4290) -- Updated the Changelog format. (#4292) -- Fix displayed number of graded assignments being larger than total allocated for TAs. (#4297) - -## [v1.0.0 - v1.8.1] -### Notes -- Due to a lapse in using the release system and this changelog, we do not have a detailed description of changes -- Future releases will continue to update this changelog -- For all changes since 1.0.0 release see: https://github.com/MarkUsProject/Markus/pulls?q=is%3Apr+created%3A2014-02-15..2019-12-11+is%3Aclosed - -## [v1.0.0] -- Using Rails to 3.0.x -- Add Support for Ruby 1.9.x -- Issue #1002: new REST API -- Fixed UI bugs -- Improved filename sanitization. -- Changed PDF conversion to Ghostscript for faster conversion -- Issue #1135: start to migrate from Prototype to jQuery -- Issue #1111: grader can dowload all files of a submission -- Issue #1073: possibility to import and export assignments -- Several improvements on sections -- Syntax Highlighter is now working with non utf-8 files -- Tests are not using fixtures anymore -### Notes -- For a list of all fixed issues see: https://github.com/MarkUsProject/Markus/issues?milestone=8 - -## [v0.10.0] -- Use of Bundler to manage Gems dependencies. -- Fixed UI bugs (marking state, released checkbox). -- Fixed bug with javascript cache. -- Fixed bug when uploading the same file twice. -- Improved filename sanitization. -- Added Review Board API scripts (developers only). -- Added Remark Request feature. -- Issue #355: Marking state icon on Submissions page is shifted. -- Issue #341: File name sanitation does not sanitize enough problematic - characters. -- Issue #321: Detailed CSV download for Flexible Grading Scheme is broken. -- Issue #306: Added Role Switching. -- Issue #302: Submit Remark Request Button should not be enabled/disabled, but - should stay always on. -- Issue #294: rake load:results not creating assignment_stat/ta_stat - associations. -- Issue #233: MySQL database issue with grade_distribution_percentage. -- Issue #200: Students have no UI for accessing their test results. -- Issue #199: Select all submissions for release is broken when student spread - across multiple pages. -- Issue #189: MarkusLogger needs to be adapted so that log files are unique to - each mongrel. -- Issue #156: Adding an extra mark doesn't show up until navigating away from - the page. -- Issue #151: REST api request to add users. -- Issue #122: Annotations with hex escape patterns stripped. -- Issue #107: Non-active students don't show up with the default "All" filter - during initialization. -- Issue #6: Results should not be able to be marked "complete" if one or more - of the criteria aren't filled in. -- Issue #3: Diplaying server's time on student view. - -## [v0.9.5] -- Fixed bug which prohibited removal of required assignment - files. - -## [v0.9.4] -- Fixed releasing and unreleasing marks for students using - select-all-across-pages feature in the submissions table. - -## [v0.9.3] -- Added UI for students to view their test results. - -## [v0.9.2] -- Issue #180: Infinite redirect loop caused by duplicate group records in the - database in turn possibly caused by races in a multi-mongrels-setup. - (commits: 6552f28bf7, 19933b7f65, e39c542a4d, c226371823, ac0e348bb6, - 3cee403b9d) -- Issue #158: Default for Students page shows all Students, and bulk actions - renamed. (commit: 1e13630914) -- Issue #143: Fixing penalty calculation for PenaltyPeriodSubmissionRule. - (commit: 537d6c3068) -- Issue #141: Fix replace file JavaScript check (commits: 7f395605a8, - e8150454b3) -- Issue #129: Uploaded criteria ordering preserved for flexible and rubric - criteria (commit: b76a9a896f) -- Issues #34, #133: Don't use i18n for MarkusLogger and - ensure_config_helper.rb (commits: a00a41e1a6, f652c919ed) -- Issue #693: Fixing confirm dialog for cloning groups (commit: 87e4d826f0) -- Issue #691: Adding Grace Credits using the bulk actions gets stuck - in "processing" (commit: e0f78dd873) -- Fixed INSTALL file due to switch to Github (commits: cfd72b09bb, c0bc922434) -- I18n fixes (commits: bc791a4f21, 232384e05a, 8e2fcb6d61, 95c27db874) - -## [v0.9.1] -- Submission collection problem due to erroneous eager loading - expression (commit: a1d380b60e). - -## [v0.9.0] -- Multiple bug fixes -- REMOTE_USER authentication support -- Redesigned manage groups and graders pages -- Added in-browser pdf display and annotation -- New batch submission collection -- Improved loading speed of submissions table -- Added ability to assign graders to individual criteria - -## [v0.8.0] -- Using Rails 2.3.8 -- MarkUs renders a 404 page error for mismatching routes -- Bug fixes on submission dates and grace period credits -- Python and Ruby Scripts using MarkUs API (see lib/tools) -- Displaying and annotating images - A lot of accessibility features have been implemented : - * Missing labels & Better focus on forms - * Adding annotations in downloaded code from students repository - * Re-arrange criteria using keyboard -- MarkUs is now completely internationalized -- Added new translation : french - -## [v0.7.1] -- Bugfix for svn permissions with web submissions - -## [v0.7.0] -- The notes system has been polished, and users can now add notes to groups, students, and submissions. -- Added the flexible criterion marking scheme type -- Added the marks spreadsheet feature -- The table of student submissions can now be bookmarked, and the back-button works correctly -- Minor bugfixes and usability fixes. - -## [v0.6.3] -- Added rake task to automatically regenerate svn_authz in the event of corruption -- MarkUs now ensures student read/write permissions on repositories after cloning groups - -## [v0.6.2] -- For now, students who work alone do not have their repositories named after them -- "Allow Web Submits?" in Assignment Properties page defaults to REPOSITORY_EXTERNAL_SUBMITS_ONLY setting now -- Annotation Category dropdowns no longer close prematurely on mouseover-ing a tooltip -- Added "Reset Mark" capability to grader view - -## [v0.6.1] -- Fixed trace on detailed CSV download for assignments (g9jerboa) -- Random TA assignment now applies only to selected groups (rburke) -- Next/Previous Submission links in grader view no longer skip submissions marked "completed" (c6conley) -- The student edit form now accepts input properly -- New UI in students editor and grader view to manage grace credit penalties -- Functional tests now all pass (c6conley) - -## [v0.6.0] -- Submissions table is now paginated (c6conley) -- It is now possible to push test results into MarkUs using the new REST API - (g9jerboa) -- TAs and Instructors can exchange notes via MarkUs now (tlclark, fgarces) -- Student is able to delete groups when there are no submitted files and the - studend is the inviter (g9jerboa) -- Subversion repositories are named after the Student's username, when students - work alone for an assignment (g9jerboa) -- Rubric criteria boot in expanded form (c6conley) -- Warning is given, when AJAX calls are working and grader navigates away from - Grader View (c6conley) -- MarkUs logs basic user actions (g9jerboa) - - -## [<= v0.5.10] -- MarkUs 0.5.10 corresponds to revision 1118 in release_0.5 branch (g9jerboa) -- Pump MARKUS_VERSION patch level to 10 (version is now 0.5.10) (g9jerboa) -- Added changelog file (g9jerboa) -- Changed has_submission? in grouping.rb to get rid of "dirty" records - (g9jerboa) -- Removed application of submission rule when manually collect submissions - (g9jerboa) -- Fixed Grader View bug when encountering binary files (g9jerboa) -- Fixed Submission's NoMethodErrors (fgarces) -- Closed CSRF bug of login screen (c6conley) -- Fix bug regarding Python docstrings in syntax highlighter (g9jerboa) -- Fixing bug that didn't highlight C code properly for students (c6conley) -- change $REPOSITORY_SVN_AUTHZ_FILE to REPOSITORY_PERMISSION_FILE in rake - task (g9jerboa) -- Use bulk permissions when creating a new Group (c6conley) -- Added bulk permission controls to Repository library (c6conley) -- Fixed GracePeriodSubmissionRule when students have 0 grace credits - (c6conley) -- Fixed typo in I18n variable (c6conley) -- Closed #419 - stack trace when downloading Subversion Export File (c6conley) -- Warnings are now given when assignments have due dates in the past - (c6conley) -- Changed/updated next/prev link behaviour (c6conley) -- Fixed annotation_category bug, and average calculation bug (c6conley) -- Closing #402 (c6conley) -- Add version and patch level information to MarkUs (g9jerboa) From fc3304b5b30bc28d44fb7cae65dfb27f712b4ac3 Mon Sep 17 00:00:00 2001 From: steven Date: Thu, 29 May 2025 02:44:30 -0400 Subject: [PATCH 10/18] Delete spec/controllers/criteria_controller_spec.rb.orig Repeat file, accidentally pressed sync on GitHub instead of using command-line --- .../criteria_controller_spec.rb.orig | 1259 ----------------- 1 file changed, 1259 deletions(-) delete mode 100644 spec/controllers/criteria_controller_spec.rb.orig diff --git a/spec/controllers/criteria_controller_spec.rb.orig b/spec/controllers/criteria_controller_spec.rb.orig deleted file mode 100644 index 260f9e9f06..0000000000 --- a/spec/controllers/criteria_controller_spec.rb.orig +++ /dev/null @@ -1,1259 +0,0 @@ -describe CriteriaController do - include UploadHelper - - # TODO: add 'role is from a different course' shared tests to each route test below - let(:instructor) { create(:instructor) } - let(:course) { instructor.course } - let(:assignment) { create(:assignment) } - let(:grouping) { create(:grouping, assignment: assignment) } - let(:submission) { create(:submission, grouping: grouping) } - - shared_examples 'callbacks' do - before do - @assignment = create(:assignment_with_criteria_and_results) - @crit = create(criterion, assignment: @assignment, max_mark: 3.0) - @assignment.groupings.each do |grouping| - create(:mark, result: grouping.current_result, mark: @crit.max_mark, criterion: @crit) - end - end - - describe 'An authenticated and authorized instructor doing a DELETE' do - it 'should update the relevant assignment\'s stats' do - old_average = @assignment.results_average - old_median = @assignment.results_median - delete_as instructor, - :destroy, - params: { course_id: course.id, id: @crit.id }, - format: :js - assignment.reload - expect(@assignment.results_median).to be >= old_median - expect(@assignment.results_average).to be >= old_average - end - end - - context 'when changing the bonus' do - it 'should be able to update the bonus value' do - get_as instructor, - :update, - params: { course_id: course.id, id: @crit.id, - criterion => { name: 'one', bonus: true } }, - format: :js - expect(@crit.reload.bonus).to be true - end - - it 'should update the relevant assignment\'s stats' do - old_average = @assignment.results_average - old_median = @assignment.results_median - get_as instructor, - :update, - params: { course_id: course.id, id: @crit.id, - criterion => { name: 'one', bonus: true } }, - format: :js - @assignment.reload - expect(@assignment.results_median).to be >= old_median - expect(@assignment.results_average).to be >= old_average - end - end - end - - describe 'Using Checkbox Criterion' do - let(:criterion) { :checkbox_criterion } - - it_behaves_like 'callbacks' - end - - describe 'Using Flexible Criteria' do - let(:criterion) { :flexible_criterion } - let(:flexible_criterion) do - create(:flexible_criterion, - assignment: assignment, - position: 1, - name: 'Flexible Criterion') - end - let(:flexible_criterion2) do - create(:flexible_criterion, - assignment: assignment, - position: 2, - name: 'Flexible Criterion 2') - end - - it_behaves_like 'callbacks' - - describe 'An unauthenticated and unauthorized user doing a GET' do - describe '#index' do - it 'should respond with redirect' do - get :index, params: { course_id: course.id, assignment_id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#new' do - it 'should respond with redirect' do - get :new, params: { course_id: course.id, assignment_id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#edit' do - it 'should respond with redirect' do - get :edit, params: { course_id: course.id, id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#update' do - it 'should respond with redirect' do - put :update, params: { course_id: course.id, id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#destroy' do - it 'should respond with redirect' do - delete :destroy, params: { course_id: course.id, id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#update_positions' do - it 'should respond with redirect' do - get :update_positions, params: { course_id: course.id, assignment_id: 1 } - expect(subject).to respond_with :redirect - end - end - - context 'with an assignment' do - context 'and a submission' do - describe '#edit' do - it 'should respond with redirect' do - get :edit, params: { course_id: course.id, id: 1 } - expect(subject).to respond_with :redirect - end - end - end - end - - describe '#download' do - it 'should respond with redirect' do - get :download, params: { course_id: course.id, assignment_id: 1 } - expect(subject).to respond_with :redirect - end - end - end - - describe 'An unauthenticated and unauthorized user doing a POST' do - describe '#index' do - it 'should respond with redirect' do - post :index, params: { course_id: course.id, assignment_id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#new' do - it 'should respond with redirect' do - post :new, params: { course_id: course.id, assignment_id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#update' do - it 'should respond with redirect' do - put :update, params: { course_id: course.id, id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#edit' do - it 'should respond with redirect' do - post :edit, params: { course_id: course.id, id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#destroy' do - it 'should respond with redirect' do - delete :destroy, params: { course_id: course.id, id: 1 } - expect(subject).to respond_with :redirect - end - end - end - - describe 'An authenticated and authorized instructor doing a GET' do - describe '#index' do - before do - get_as instructor, :index, params: { course_id: course.id, assignment_id: assignment.id } - end - - it 'should respond assign assignment and criteria' do - expect(assigns(:assignment)).to be_truthy - expect(assigns(:criteria)).to be_truthy - end - - it 'should render the edit template' do - expect(subject).to render_template(:index) - end - - it 'should respond with success' do - expect(subject).to respond_with(:success) - end - end - - describe '#new' do - context 'when assignment marks are not released' do - before do - get_as instructor, - :new, - params: { course_id: course.id, assignment_id: assignment.id }, - format: :js - end - - it 'should respond with appropriate content' do - expect(assigns(:assignment)).to be_truthy - end - - it 'should render the new template' do - expect(subject).to render_template(:new) - end - - it 'should respond with success' do - expect(subject).to respond_with(:success) - end - end - - context 'when assignment marks are released' do - let(:released_assignment) { create(:assignment) } - - before do - grouping = create(:grouping, assignment: released_assignment) - submission = create(:submission, grouping: grouping) - result = submission.get_latest_result - result.update!(released_to_students: true) - - get_as instructor, - :new, - params: { course_id: course.id, assignment_id: released_assignment.id }, - format: :js - end - - it 'displays an error message' do - expect(flash[:error]).to have_message(I18n.t('criteria.errors.released_marks')) - end - - it 'responds with :bad_request status' do - expect(response).to have_http_status(:bad_request) - end - end - end - - describe '#edit' do - context 'when assignment marks have not been released' do - before do - get_as instructor, - :edit, - params: { course_id: course.id, id: flexible_criterion.id }, - format: :js - end - - it 'should respond with appropriate content' do - expect(assigns(:criterion)).to be_truthy - end - - it 'should render edit template' do - expect(subject).to render_template(:edit) - end - - it 'should respond with success' do - expect(subject).to respond_with(:success) - end - end - -<<<<<<< HEAD - # there should not be a bad request expectation because it was not implemented. -======= ->>>>>>> upstream/master - context 'when assignment marks have been released' do - let!(:released_assignment) do - create(:assignment, course: course).tap do |assignment| - create(:flexible_criterion, assignment: assignment, name: 'Pre-release Criterion') - - grouping = create(:grouping, assignment: assignment) - submission = create(:submission, grouping: grouping) - submission.get_latest_result.update!(released_to_students: true) - end - end - - let(:flexible_criterion) do - released_assignment.criteria.find_by(type: 'FlexibleCriterion') - end - - before do - get_as instructor, - :edit, - params: { course_id: released_assignment.course_id, id: flexible_criterion.id }, - format: :js - end - - it 'flashes message with error' do - expect(flash[:notice]).to have_message(I18n.t('criteria.errors.released_marks')) - end - -<<<<<<< HEAD -======= - # there should not be a bad request expectation because the view renders successfully in read-only mode ->>>>>>> upstream/master - it 'responds with success' do - expect(subject).to respond_with(:success) - end - end - end - - describe '#update' do - context 'with errors' do - before do - allow_any_instance_of(FlexibleCriterion).to receive(:save).and_return(false) - allow_any_instance_of(FlexibleCriterion).to( - receive(:errors).and_return(ActiveModel::Errors.new(flexible_criterion)) - ) - - get_as instructor, - :update, - params: { course_id: course.id, id: flexible_criterion.id, - flexible_criterion: { name: 'one', max_mark: 10 } }, - format: :js - end - - it 'should respond with appropriate content' do - expect(assigns(:criterion)).to be_truthy - end - - it 'should respond with unprocessable entity' do - expect(subject).to respond_with(:unprocessable_entity) - end - end - - context 'without errors' do - before do - get_as instructor, - :update, - params: { course_id: course.id, id: flexible_criterion.id, - flexible_criterion: { name: 'one', max_mark: 10 } }, - format: :js - end - - it 'successfully assign criterion' do - expect(assigns(:criterion)).to be_truthy - end - - it 'should render the update template' do - expect(subject).to render_template(:update) - end - end - end - end - - describe 'An authenticated and authorized instructor doing a POST' do - describe '#index' do - before do - post_as instructor, :index, params: { course_id: course.id, assignment_id: assignment.id } - end - - it 'should respond with appropriate content' do - expect(assigns(:assignment)).to be_truthy - expect(assigns(:criteria)).to be_truthy - end - - it 'should render the index template' do - expect(subject).to render_template(:index) - end - - it 'should respond with success' do - expect(subject).to respond_with(:success) - end - end - - describe '#create' do - context 'with save error' do - before do - allow_any_instance_of(FlexibleCriterion).to receive(:save).and_return(false) - allow_any_instance_of(FlexibleCriterion).to receive(:errors).and_return(ActiveModel::Errors.new(self)) - post_as instructor, - :create, - params: { course_id: course.id, assignment_id: assignment.id, - flexible_criterion: { name: 'first', max_mark: 10 }, - new_criterion_prompt: 'first', criterion_type: 'FlexibleCriterion' }, - format: :js - end - - it 'should respond with appropriate content' do - expect(assigns(:criterion)).to be_truthy - expect(assigns(:assignment)).to be_truthy - end - - it 'should respond with unprocessable entity' do - expect(subject).to respond_with(:unprocessable_entity) - end - end - - context 'without error on an assignment as the first criterion' do - before do - post_as instructor, - :create, - params: { course_id: course.id, assignment_id: assignment.id, flexible_criterion: { name: 'first' }, - new_criterion_prompt: 'first', criterion_type: 'FlexibleCriterion', max_mark_prompt: 10 }, - format: :js - end - - it 'should respond with appropriate content' do - expect(assigns(:criterion)).to be_truthy - expect(assigns(:assignment)).to be_truthy - end - - it 'should render the create template' do - expect(subject).to render_template(:'criteria/create') - end - - it 'should respond with success' do - expect(subject).to respond_with(:success) - end - end - - context 'without error on an assignment that already has criteria' do - before do - create(:checkbox_criterion, assignment: assignment) - post_as instructor, - :create, - params: { course_id: course.id, assignment_id: assignment.id, - flexible_criterion: { name: 'second' }, new_criterion_prompt: 'second', - criterion_type: 'FlexibleCriterion', max_mark_prompt: 10 }, - format: :js - end - - it 'should respond with appropriate content' do - expect(assigns(:criterion)).to be_truthy - expect(assigns(:assignment)).to be_truthy - end - - it 'should render the create template' do - expect(subject).to render_template(:'criteria/create') - end - - it 'should respond with success' do - expect(subject).to respond_with(:success) - end - end - - context 'when assignment marks are released' do - let(:released_assignment) { create(:assignment) } - - before do - grouping = create(:grouping, assignment: released_assignment) - submission = create(:submission, grouping: grouping) - result = submission.get_latest_result - result.update!(released_to_students: true) - - post_as instructor, - :create, - params: { course_id: course.id, assignment_id: released_assignment.id, - flexible_criterion: { name: 'first', max_mark: 10 }, - new_criterion_prompt: 'first', criterion_type: 'RubricCriterion' }, - format: :js - end - - it 'displays an error message' do - expect(flash[:error]).to have_message(I18n.t('criteria.errors.released_marks')) - end - - it 'responds with :bad_request status' do - expect(response).to have_http_status(:bad_request) - end - end - end - - describe '#update' do - context 'when assignment marks have been released' do - let!(:released_assignment) do - create(:assignment, course: course).tap do |assignment| - create(:flexible_criterion, assignment: assignment, name: 'Pre-release Criterion') - - grouping = create(:grouping, assignment: assignment) - submission = create(:submission, grouping: grouping) - submission.get_latest_result.update!(released_to_students: true) - end - end - - let(:flexible_criterion) do - released_assignment.criteria.find_by(type: 'FlexibleCriterion') - end - - before do - post_as instructor, - :update, - params: { course_id: released_assignment.course_id, id: flexible_criterion.id }, - format: :js - end - - it 'flashes message with error' do - expect(flash[:error]).to have_message(I18n.t('criteria.errors.released_marks')) - end - - it 'responds with :bad_request status' do - expect(response).to have_http_status(:bad_request) - end - end - end - - describe '#edit' do - before do - post_as instructor, - :edit, - params: { course_id: course.id, id: flexible_criterion.id }, - format: :js - end - - it 'should respond with appropriate content' do - expect(assigns(:criterion)).to be_truthy - end - - it 'should render the edit template' do - expect(subject).to render_template(:edit) - end - - it 'should respond with success' do - expect(subject).to respond_with(:success) - end - end - - it 'should be able to update_positions' do - post_as instructor, - :update_positions, - params: { course_id: course.id, criterion: [flexible_criterion2.id, flexible_criterion.id], - assignment_id: assignment.id }, - format: :js - expect(subject).to render_template - expect(subject).to respond_with(:success) - - c1 = FlexibleCriterion.find(flexible_criterion.id) - expect(c1.position).to be(2) - c2 = FlexibleCriterion.find(flexible_criterion2.id) - expect(c2.position).to be(1) - end - end - - describe 'An authenticated and authorized instructor doing a DELETE' do - it 'should be able to delete the criterion' do - delete_as instructor, - :destroy, - params: { course_id: course.id, id: flexible_criterion.id }, - format: :js - expect(assigns(:criterion)).to be_truthy - expect(flash[:success]).to have_message(I18n.t('flash.criteria.destroy.success')) - expect(subject).to respond_with(:success) - - expect { FlexibleCriterion.find(flexible_criterion.id) }.to raise_error(ActiveRecord::RecordNotFound) - end - end - end - - describe 'Using Rubric Criteria' do - let(:criterion) { :rubric_criterion } - let(:rubric_criterion) do - create(:rubric_criterion, - assignment: assignment, - position: 1, - name: 'Rubric Criterion') - end - let(:rubric_criterion2) do - create(:rubric_criterion, - assignment: assignment, - position: 2, - name: 'Rubric Criterion 2') - end - - it_behaves_like 'callbacks' - - describe 'An unauthenticated and unauthorized user doing a GET' do - describe '#index' do - it 'should respond with redirect' do - get :index, params: { course_id: course.id, assignment_id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#new' do - it 'should respond with redirect' do - get :new, params: { course_id: course.id, assignment_id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#edit' do - it 'should respond with redirect' do - get :edit, params: { course_id: course.id, id: 1 } - expect(subject).to respond_with :redirect - end - - context 'with an assignment' do - context 'and a submission' do - describe '#edit' do - it 'should respond with redirect' do - get :edit, params: { course_id: course.id, assignment_id: assignment.id, id: 1 } - expect(subject).to respond_with :redirect - end - end - end - end - end - - describe '#destroy' do - it 'should respond with redirect' do - delete :destroy, params: { course_id: course.id, id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#update' do - it 'should respond with redirect' do - put :update, params: { course_id: course.id, id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#update_positions' do - it 'should respond with redirect' do - get :update_positions, params: { course_id: course.id, assignment_id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#download' do - it 'should respond with redirect' do - get :download, params: { course_id: course.id, assignment_id: 1 } - expect(subject).to respond_with :redirect - end - end - end - - describe 'An unauthenticated and unauthorized user doing a POST' do - describe '#index' do - it 'should respond with redirect' do - post :index, params: { course_id: course.id, assignment_id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#new' do - it 'should respond with redirect' do - post :new, params: { course_id: course.id, assignment_id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#edit' do - it 'should respond with redirect' do - post :edit, params: { course_id: course.id, id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#update' do - it 'should respond with redirect' do - put :update, params: { course_id: course.id, id: 1 } - expect(subject).to respond_with :redirect - end - end - - describe '#destroy' do - it 'should respond with redirect' do - delete :destroy, params: { course_id: course.id, id: 1 } - expect(subject).to respond_with :redirect - end - end - end - - describe 'An authenticated and authorized instructor doing a GET' do - describe '#index' do - before do - get_as instructor, :index, params: { course_id: course.id, assignment_id: assignment.id } - end - - it 'should respond assign assignment and criteria' do - expect(assigns(:assignment)).to be_truthy - expect(assigns(:criteria)).to be_truthy - end - - it 'should render the edit template' do - expect(subject).to render_template(:index) - end - - it 'should respond with success' do - expect(subject).to respond_with(:success) - end - end - - describe '#new' do - before do - get_as instructor, - :new, - params: { course_id: course.id, assignment_id: assignment.id }, - format: :js - end - - it 'should respond with appropriate content' do - expect(assigns(:assignment)).to be_truthy - end - - it 'should render the new template' do - expect(subject).to render_template(:new) - end - - it 'should respond with success' do - expect(subject).to respond_with(:success) - end - end - - describe '#edit' do - before do - get_as instructor, - :edit, - params: { course_id: course.id, id: rubric_criterion.id }, - format: :js - end - - it 'should respond with appropriate content' do - expect(assigns(:criterion)).to be_truthy - end - - it 'should render edit template' do - expect(subject).to render_template(:edit) - end - - it 'should respond with success' do - expect(subject).to respond_with(:success) - end - end - - describe '#update' do - context 'with errors' do - before do - allow_any_instance_of(RubricCriterion).to receive(:save).and_return(false) - allow_any_instance_of(RubricCriterion).to( - receive(:errors).and_return(ActiveModel::Errors.new(rubric_criterion)) - ) - get_as instructor, - :update, - params: { course_id: course.id, id: rubric_criterion.id, - rubric_criterion: { name: 'one', max_mark: 10 } }, - format: :js - end - - it 'should respond with appropriate content' do - expect(assigns(:criterion)).to be_truthy - end - - it 'should respond with unprocessable entity' do - expect(subject).to respond_with(:unprocessable_entity) - end - end - - context 'without errors' do - before do - get_as instructor, - :update, - params: { course_id: course.id, id: rubric_criterion.id, - rubric_criterion: { name: 'one', max_mark: 10 } }, - format: :js - end - - it 'successfully assign criterion' do - expect(assigns(:criterion)).to be_truthy - end - - it 'should render the update template' do - expect(subject).to render_template(:update) - end - end - end - end - - describe 'An authenticated and authorized instructor doing a POST' do - describe '#index' do - before do - post_as instructor, :index, params: { course_id: course.id, assignment_id: assignment.id } - end - - it 'should respond with appropriate content' do - expect(assigns(:assignment)).to be_truthy - expect(assigns(:criteria)).to be_truthy - end - - it 'should render the index template' do - expect(subject).to render_template(:index) - end - - it 'should respond with success' do - expect(subject).to respond_with(:success) - end - end - - describe '#create' do - context 'with save error' do - before do - allow_any_instance_of(RubricCriterion).to receive(:save).and_return(false) - allow_any_instance_of(RubricCriterion).to receive(:errors).and_return(ActiveModel::Errors.new(self)) - post_as instructor, - :create, - params: { course_id: course.id, assignment_id: assignment.id, max_mark_prompt: 10, - new_criterion_prompt: 'first', criterion_type: 'RubricCriterion' }, - format: :js - end - - it 'should respond with appropriate content' do - expect(assigns(:criterion)).to be_truthy - expect(assigns(:assignment)).to be_truthy - end - - it 'should respond with unprocessable entity' do - expect(subject).to respond_with(:unprocessable_entity) - end - end - - context 'without error on an assignment as the first criterion' do - before do - post_as instructor, - :create, - params: { course_id: course.id, assignment_id: assignment.id, - new_criterion_prompt: 'first', criterion_type: 'RubricCriterion', max_mark_prompt: 10 }, - format: :js - end - - it 'should respond with appropriate content' do - expect(assigns(:criterion)).to be_truthy - expect(assigns(:assignment)).to be_truthy - end - - it 'should render the create template' do - expect(subject).to render_template(:'criteria/create') - end - - it 'should respond with success' do - expect(subject).to respond_with(:success) - end - end - - context 'without error on an assignment that already has criteria' do - before do - post_as instructor, - :create, - params: { course_id: course.id, assignment_id: assignment.id, rubric_criterion: { name: 'first' }, - new_criterion_prompt: 'first', criterion_type: 'RubricCriterion', max_mark_prompt: 10 }, - format: :js - end - - it 'should respond with appropriate content' do - expect(assigns(:criterion)).to be_truthy - expect(assigns(:assignment)).to be_truthy - end - - it 'should render the create template' do - expect(subject).to render_template(:'criteria/create') - end - - it 'should respond with success' do - expect(subject).to respond_with(:success) - end - end - end - - describe '#edit' do - before do - post_as instructor, - :edit, - params: { course_id: course.id, id: rubric_criterion.id }, - format: :js - end - - it 'should respond with appropriate content' do - expect(assigns(:criterion)).to be_truthy - end - - it 'should render the edit template' do - expect(subject).to render_template(:edit) - end - - it 'should respond with success' do - expect(subject).to respond_with(:success) - end - end - - describe '#update_positions' do - context 'when all criteria id can be found under assignment' do - let(:rubric_criterion) do - create(:rubric_criterion, assignment: assignment, position: 1) - end - let(:rubric_criterion2) do - create(:rubric_criterion, assignment: assignment, position: 2) - end - - it 'should be able to update_positions' do - post_as instructor, - :update_positions, - params: { course_id: course.id, criterion: [rubric_criterion2.id, rubric_criterion.id], - assignment_id: assignment.id }, - format: :js - expect(subject).to render_template - expect(subject).to respond_with(:success) - - c1 = RubricCriterion.find(rubric_criterion.id) - expect(c1.position).to be(2) - c2 = RubricCriterion.find(rubric_criterion2.id) - expect(c2.position).to be(1) - end - end - - context 'when there exists criteria not under current assignment' do - let(:assignment2) { create(:assignment) } - let(:rubric_criterion) do - create(:rubric_criterion, assignment: assignment, position: 1) - end - let(:rubric_criterion2) do - create(:rubric_criterion, assignment: assignment, position: 2) - end - let(:rubric_criterion3) do - create(:rubric_criterion, assignment: assignment2, position: 3) - end - - before do - post_as instructor, - :update_positions, - params: { course_id: course.id, - criterion: [rubric_criterion3.id, - rubric_criterion2.id, - rubric_criterion.id], - assignment_id: assignment.id }, - format: :js - end - - it 'does not update position' do - c1 = RubricCriterion.find(rubric_criterion.id) - expect(c1.position).to be(1) - c2 = RubricCriterion.find(rubric_criterion2.id) - expect(c2.position).to be(2) - c3 = RubricCriterion.find(rubric_criterion3.id) - expect(c3.position).to be(3) - end - - it 'displays an error message' do - expect(flash[:error]).to have_message(I18n.t('criteria.errors.criteria_not_found')) - end - end - end - end - - describe 'An authenticated and authorized instructor doing a DELETE' do - it 'should be able to delete the criterion' do - delete_as instructor, - :destroy, - params: { course_id: course.id, id: rubric_criterion.id }, - format: :js - expect(assigns(:criterion)).to be_truthy - expect(flash[:success]).to have_message(I18n.t('flash.criteria.destroy.success')) - expect(subject).to respond_with(:success) - - expect { RubricCriterion.find(rubric_criterion.id) }.to raise_error(ActiveRecord::RecordNotFound) - end - end - end - - describe 'An authenticated and authorized instructor performing yml actions' do - let!(:rubric_criterion) do - create(:rubric_criterion, - assignment: assignment, - position: 1, - name: 'Rubric Criterion') - end - let!(:flexible_criterion) do - create(:flexible_criterion, - assignment: assignment, - position: 2, - name: 'Flexible Criterion') - end - let!(:checkbox_criterion) do - create(:checkbox_criterion, - assignment: assignment, - position: 3, - name: 'Checkbox Criterion') - end - let(:mixed_file) { fixture_file_upload('criteria/upload_yml_mixed.yaml', 'text/yaml') } - let(:mixed_file_no_ext) { fixture_file_upload('criteria/upload_yml_mixed', 'text/yaml') } - let(:mixed_file_wrong_ext) { fixture_file_upload('criteria/upload_yml_mixed.pdf', 'text/yaml') } - let(:invalid_mixed_file) { fixture_file_upload('criteria/upload_yml_mixed_invalid.yaml', 'text/yaml') } - let(:missing_levels_file) { fixture_file_upload('criteria/upload_yml_missing_levels.yaml', 'text/yaml') } - let(:empty_file) { fixture_file_upload('empty_file', 'text/yaml') } - let(:test_upload_download_file) { fixture_file_upload('criteria/criteria_upload_download.yaml', 'text/yaml') } - let(:expected_download) { fixture_file_upload('criteria/download_yml_output.yaml', 'text/yaml') } - let(:round_max_mark_file) { fixture_file_upload('criteria/round_max_mark.yaml', 'text/yaml') } - let(:partially_valid_file) { fixture_file_upload('criteria/partially_valid_file.yaml', 'text/yaml') } - let(:uploaded_file) { fixture_file_upload('criteria/upload_yml_mixed.yaml', 'text/yaml') } - let(:no_type_file) { fixture_file_upload('criteria/marking_criteria_no_type.yml', 'text/yaml') } - - context 'When a file containing a mixture of entries is uploaded' do - it 'raises an error if the file does not include any criteria' do - post_as instructor, :upload, - params: { course_id: course.id, assignment_id: assignment.id, upload_file: empty_file } - - expect(flash[:error]).to have_message(I18n.t('upload_errors.blank')) - end - - it 'deletes all criteria previously created' do - post_as instructor, :upload, - params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } - - expect(assignment.criteria.where(type: 'RubricCriterion').find_by(name: rubric_criterion.name)).to be_nil - expect(assignment.criteria.where(type: 'FlexibleCriterion').find_by(name: flexible_criterion.name)).to be_nil - expect(assignment.criteria.where(type: 'CheckboxCriterion').find_by(name: checkbox_criterion.name)).to be_nil - end - - it 'maintains the order between entries and positions for criteria' do - post_as instructor, :upload, - params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } - - expect(assignment.criteria.map { |cr| [cr.name, cr.position] }) - .to match_array([['cr30', 1], - ['cr20', 2], - ['cr100', 3], - ['cr40', 4], - ['cr80', 5], - ['cr50', 6], - ['cr60', 7], - ['cr90', 8]]) - end - - it 'creates all criteria with properly formatted entries' do - post_as instructor, :upload, - params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } - - expect(assignment.criteria.pluck(:name)).to contain_exactly('cr30', - 'cr20', - 'cr100', - 'cr80', - 'cr60', - 'cr90', - 'cr40', - 'cr50') - expect(flash[:success]).to have_message(I18n.t('upload_success', count: 8)) - end - - it 'creates rubric criteria with properly formatted entries' do - post_as instructor, :upload, - params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } - expect(assignment.criteria.where(type: 'RubricCriterion').pluck(:name)).to contain_exactly('cr30', 'cr90') - cr1 = assignment.criteria.where(type: 'RubricCriterion').find_by(name: 'cr30') - expect(cr1.levels.size).to eq(5) - expect(cr1.max_mark).to eq(5.0) - expect(cr1.bonus).to be true - expect(cr1.ta_visible).to be false - expect(cr1.peer_visible).to be true - # Since there are only 5 levels in this rubric criterion, if each of the following queries return an entity, - # then this rubric criterion is properly sat up. - expect(cr1.levels.find_by(name: 'Beginner', description: 'Fail', mark: 0)).not_to be_nil - expect(cr1.levels.find_by(name: 'Hmm', description: 'Almost fail', mark: 1)).not_to be_nil - expect(cr1.levels.find_by(name: 'Average', description: 'Not bad', mark: 2)).not_to be_nil - expect(cr1.levels.find_by(name: 'Good', description: 'Alright', mark: 3)).not_to be_nil - expect(cr1.levels.find_by(name: 'Excellent', description: 'Impressive', mark: 5)).not_to be_nil - - cr2 = assignment.criteria.where(type: 'RubricCriterion').find_by(name: 'cr90') - expect(cr2.max_mark).to eq(4.6) - expect(cr2.levels.size).to eq(5) - expect(cr2.ta_visible).to be true - expect(cr2.peer_visible).to be false - expect(cr2.bonus).to be false - end - - it 'creates flexible criteria with properly formatted entries' do - post_as instructor, :upload, - params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } - - expect(assignment.criteria.where(type: 'FlexibleCriterion').pluck(:name)) - .to contain_exactly('cr20', 'cr50', 'cr80', 'cr60') - - cr80 = assignment.criteria.where(type: 'FlexibleCriterion').find_by(name: 'cr80') - expect(cr80.max_mark).to eq(10.0) - expect(cr80.description).to eq('') - expect(cr80.ta_visible).to be true - expect(cr80.peer_visible).to be true - expect(cr80.bonus).to be false - - cr20 = assignment.criteria.where(type: 'FlexibleCriterion').find_by(name: 'cr20') - expect(cr20.max_mark).to eq(2.0) - expect(cr20.description).to eq('I am flexible') - expect(cr20.ta_visible).to be true - expect(cr20.peer_visible).to be true - expect(cr20.bonus).to be false - - cr50 = assignment.criteria.where(type: 'FlexibleCriterion').find_by(name: 'cr50') - expect(cr50.bonus).to be true - expect(cr50.max_mark).to eq(1.0) - expect(cr50.description).to eq('Another flexible.') - expect(cr50.ta_visible).to be true - expect(cr50.peer_visible).to be false - - cr60 = assignment.criteria.where(type: 'FlexibleCriterion').find_by(name: 'cr60') - expect(cr60.max_mark).to eq(10.0) - expect(cr60.description).to eq('') - expect(cr60.ta_visible).to be true - expect(cr60.peer_visible).to be false - expect(cr60.bonus).to be false - end - - it 'creates checkbox criteria with properly formatted entries' do - post_as instructor, :upload, - params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } - - expect(assignment.criteria.where(type: 'CheckboxCriterion').pluck(:name)).to contain_exactly('cr100', 'cr40') - cr1 = assignment.criteria.where(type: 'CheckboxCriterion').find_by(name: 'cr100') - expect(cr1.bonus).to be true - expect(cr1.max_mark).to eq(5.0) - expect(cr1.description).to eq('I am checkbox') - expect(cr1.ta_visible).to be true - expect(cr1.peer_visible).to be false - end - - it 'creates criteria being case insensitive with the type given' do - post_as instructor, :upload, - params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } - - expect(assignment.criteria.where(type: 'FlexibleCriterion').pluck(:name)) - .to contain_exactly('cr20', 'cr80', 'cr60', 'cr50') - end - - it 'creates criteria that lack a description' do - post_as instructor, :upload, - params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } - - expect(assignment.criteria.where(type: 'FlexibleCriterion').pluck(:name)).to include('cr80') - expect(assignment.criteria.where(type: 'FlexibleCriterion').find_by(name: 'cr80').description).to eq('') - end - - it 'creates criteria with the default visibility options if these are not given in the entries' do - post_as instructor, :upload, - params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file } - expect(assignment.criteria.pluck(:name)).to include('cr100', 'cr60') - expect(assignment.criteria.where(type: 'CheckboxCriterion').find_by(name: 'cr100').ta_visible).to be true - expect(assignment.criteria.where(type: 'CheckboxCriterion').find_by(name: 'cr100').peer_visible).to be false - expect(assignment.criteria.where(type: 'FlexibleCriterion').find_by(name: 'cr60').ta_visible).to be true - expect(assignment.criteria.where(type: 'FlexibleCriterion').find_by(name: 'cr60').peer_visible).to be false - end - - it 'creates criteria with rounded (up to first digit after decimal point) maximum mark' do - post_as instructor, :upload, params: { course_id: course.id, assignment_id: assignment.id, - upload_file: round_max_mark_file } - expect(assignment.criteria.where(type: 'RubricCriterion').first.name).to eq('cr90') - - expect(assignment.criteria.where(type: 'RubricCriterion').first.max_mark).to eq(4.6) - end - - it 'creates criteria correctly when a valid yml file with no extension is uploaded' do - post_as instructor, :upload, - params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file_no_ext } - - expect(assignment.criteria.pluck(:name)).to contain_exactly('cr30', - 'cr20', - 'cr100', - 'cr80', - 'cr60', - 'cr90', - 'cr40', - 'cr50') - expect(flash[:success]).to have_message(I18n.t('upload_success', count: 8)) - end - - it 'creates criteria correctly when a valid yml file with the wrong extension is uploaded' do - post_as instructor, :upload, - params: { course_id: course.id, assignment_id: assignment.id, upload_file: mixed_file_wrong_ext } - - expect(assignment.criteria.pluck(:name)).to contain_exactly('cr30', - 'cr20', - 'cr100', - 'cr80', - 'cr60', - 'cr90', - 'cr40', - 'cr50') - expect(flash[:success]).to have_message(I18n.t('upload_success', count: 8)) - end - - it 'does not create criteria with format errors in entries' do - post_as instructor, :upload, params: { course_id: course.id, assignment_id: assignment.id, - upload_file: invalid_mixed_file } - - expect(assignment.criteria.pluck(:name)).not_to include('cr40', 'cr50', 'cr70') - expect(flash[:error]).to contain_message(I18n.t('criteria.errors.invalid_format')) - expect(flash[:error]).to contain_message(' cr40, cr70, cr50') - end - - it 'does not create criteria with an invalid mark' do - post_as instructor, :upload, params: { course_id: course.id, assignment_id: assignment.id, - upload_file: invalid_mixed_file } - - expect(assignment.criteria.pluck(:name)).not_to include('cr40', 'cr50') - end - - it 'does not create rubric criteria when levels are missing' do - post_as instructor, :upload, params: { course_id: course.id, assignment_id: assignment.id, - upload_file: missing_levels_file } - - expect(assignment.criteria.where(name: %w[no_levels empty_levels])).to be_empty - expect(flash[:error]).to contain_message(I18n.t('criteria.errors.invalid_format')) - expect(flash[:error]).to contain_message(' no_levels, empty_levels') - end - - it 'does not create criteria that have both visibility options set to false' do - post_as instructor, :upload, params: { course_id: course.id, assignment_id: assignment.id, - upload_file: invalid_mixed_file } - - expect(assignment.criteria.pluck(:name)).not_to include('cr70') - end - - it 'does not create criteria that have unmatched keys / more keys than required' do - expect(assignment.criteria.where(type: 'RubricCriterion').length).to eq(1) - post_as instructor, :upload, params: { course_id: course.id, assignment_id: assignment.id, - upload_file: partially_valid_file } - expect(assignment.criteria.where(type: 'RubricCriterion').length).to eq(1) - expect(flash[:error]).not_to be_nil - end - - context 'when there is no type specified for one of the criteria' do - it 'flashes an error message' do - post_as instructor, :upload, params: { course_id: course.id, assignment_id: assignment.id, - upload_file: no_type_file } - expect(flash[:error]).not_to be_nil - end - end - - context 'When some criteria have been previously uploaded and and instructor performs a download' do - before do - Criterion.upload_criteria_from_yaml(assignment, parse_yaml_content(test_upload_download_file.read)) - end - - it 'responds with appropriate status' do - get_as instructor, :download, params: { course_id: course.id, assignment_id: assignment.id } - - expect(response).to have_http_status(:ok) - end - - it 'sends the correct information' do - get_as instructor, :download, params: { course_id: course.id, assignment_id: assignment.id } - - expect(YAML.safe_load(response.body, permitted_classes: [Symbol], symbolize_names: true)) - .to eq(YAML.safe_load(expected_download.read, symbolize_names: true)) - end - end - end - end - - describe '#upload' do - it_behaves_like 'a controller supporting upload', formats: [:yml] do - let(:params) { { course_id: course.id, assignment_id: assignment.id } } - end - end -end From eb6de310bc70be1cabe710747c6c49bfaefa65ac Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Thu, 29 May 2025 02:48:48 -0400 Subject: [PATCH 11/18] Added to changelog --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index 423fe0417d..84a55577b8 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,6 +5,7 @@ ### 🚨 Breaking changes ### ✨ New features and improvements +- Fix front-end Assignment view for students (#7533) ### 🐛 Bug fixes From c97aeb898ffedf287f244b1d8836eb81014aa931 Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Thu, 29 May 2025 03:51:50 -0400 Subject: [PATCH 12/18] Fixed rspec changes --- config/locales/views/assignments/en.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config/locales/views/assignments/en.yml b/config/locales/views/assignments/en.yml index d0a5d28edf..78d4db9b38 100644 --- a/config/locales/views/assignments/en.yml +++ b/config/locales/views/assignments/en.yml @@ -2,8 +2,8 @@ en: assignments: assignment_has_groupings: Assignment has groupings. - average_annotations: "%{average_annotations} annotations per marked submission" assignment_information: Assignment information + average_annotations: "%{average_annotations} annotations per marked submission" configuration_zip_file: Configuration Zip File deadline_with_extension: You have an extension until %{extension_deadline}. deletion_confirmation: Are you sure you want to delete this assignment? @@ -33,7 +33,6 @@ en: hidden: "%{assignment_text} (hidden)" manage_course_work: Manage Course Work marking_scheme: 'Marking Scheme: %{identifier}' - no_required_files: There are no required files for this assignment. none: There are currently no assignments. scanned_exam: under_review: This exam is still under review. From 609a964565965d88e7b518e35450c599b541fdd8 Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Wed, 4 Jun 2025 03:31:21 -0400 Subject: [PATCH 13/18] fixed from comments --- Changelog.md | 2 +- app/views/assignments/_read.html.erb | 4 ++-- app/views/assignments/show.html.erb | 6 +++++- config/locales/views/assignments/en.yml | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Changelog.md b/Changelog.md index 84a55577b8..b27314ceaf 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,7 +5,7 @@ ### 🚨 Breaking changes ### ✨ New features and improvements -- Fix front-end Assignment view for students (#7533) +- Improve Assignment view for students (#7533) ### 🐛 Bug fixes diff --git a/app/views/assignments/_read.html.erb b/app/views/assignments/_read.html.erb index 77a7b86051..513aa61820 100644 --- a/app/views/assignments/_read.html.erb +++ b/app/views/assignments/_read.html.erb @@ -132,7 +132,7 @@ <% end %> <% unless @assignment.starter_file_updated_at.nil? || @grouping.nil? %> <% if allowed_to?(:download_starter_file?, @grouping) %> -

      <%= I18n.t('assignments.starter_file.title') %>

      +

      <%= I18n.t('assignments.starter_file.title').downcase.capitalize %>

      <%= I18n.t('assignments.starter_file.provided') %>

      <%= I18n.t('assignments.starter_file.changed_at', changed_date: I18n.l(@assignment.starter_file_updated_at)) %>

      @@ -168,7 +168,7 @@

      <% end %>
        -
      • <%= link_to t('submissions.student.files_submitted', count: @num_submitted_files), +
      • <%= link_to t('submissions.student.files_submitted', count: @num_submitted_files), file_manager_course_assignment_submissions_path(course_id: @assignment.course_id, assignment_id: @assignment.id)%>
      • <% if @num_submitted_files > 0 %> diff --git a/app/views/assignments/show.html.erb b/app/views/assignments/show.html.erb index 5b8e8b9ed4..245abd3132 100644 --- a/app/views/assignments/show.html.erb +++ b/app/views/assignments/show.html.erb @@ -24,7 +24,11 @@ <% end %> <% end %> -<% content_for :title, "#{@assignment.short_identifier}: #{@assignment.description}" %> +<% short_identifier = @assignment.is_peer_review? ? + "#{@assignment.parent_assignment.short_identifier} #{PeerReview.model_name.human}" : + @assignment.short_identifier %> + +<% content_for :title, "#{short_identifier}: #{@assignment.description}" %>
        diff --git a/config/locales/views/assignments/en.yml b/config/locales/views/assignments/en.yml index 78d4db9b38..b5734a7129 100644 --- a/config/locales/views/assignments/en.yml +++ b/config/locales/views/assignments/en.yml @@ -66,7 +66,7 @@ en: sections: Assign starter file groups by section shuffle: Randomly select one top level file or directory from each starter file group simple: Assign the default starter file group to all students - title: Starter files + title: Starter Files upload_confirmation: The starter files for this assignment have changed since you last downloaded them. Are you sure you want to continue? use_original_filename: Use original filename successful_deletion: Assignment with id '%{invalid_id}' has been successfully deleted. From f489ab11d21ba9d31af134c0e50b43fc3df7c1e1 Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Wed, 4 Jun 2025 03:38:03 -0400 Subject: [PATCH 14/18] re-fixed a bug with styling --- app/views/assignments/_read.html.erb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/views/assignments/_read.html.erb b/app/views/assignments/_read.html.erb index 513aa61820..3ee011d55f 100644 --- a/app/views/assignments/_read.html.erb +++ b/app/views/assignments/_read.html.erb @@ -168,9 +168,10 @@

        <% end %>
          -
        • <%= link_to t('submissions.student.files_submitted', count: @num_submitted_files), +
        • <%= link_to t('submissions.student.files_submitted', count: @num_submitted_files), file_manager_course_assignment_submissions_path(course_id: @assignment.course_id, - assignment_id: @assignment.id)%>
        • + assignment_id: @assignment.id)%> + <% if @num_submitted_files > 0 %>
        • <%= t('submissions.student.last_revision_date') %> From c88a81d7748105d37b0d8810e672d6c7c2216cfa Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Wed, 4 Jun 2025 19:47:29 -0400 Subject: [PATCH 15/18] implemented new section in summary stats, before clean-up --- app/controllers/assignments_controller.rb | 7 +++++++ app/javascript/Components/assignment_chart.jsx | 9 +++++++++ config/routes.rb | 3 +++ 3 files changed, 19 insertions(+) diff --git a/app/controllers/assignments_controller.rb b/app/controllers/assignments_controller.rb index 6920e66106..75653ed45a 100644 --- a/app/controllers/assignments_controller.rb +++ b/app/controllers/assignments_controller.rb @@ -348,6 +348,7 @@ def grade_distribution assignment_remark_requests = assignment.groupings.joins(current_submission_used: :submitted_remark) summary = { name: "#{assignment.short_identifier}: #{assignment.description}", + average_annotations: assignment.average_annotations, average: assignment.results_average(points: true) || 0, median: assignment.results_median(points: true) || 0, max_mark: assignment.max_mark || 0, @@ -411,6 +412,12 @@ def grade_distribution render json: json_data end + # def average_annotations + # ta_id = params[:ta_id] + # average = @assignment.average_annotations(ta_id) + # render json: {average_annotations: average} + # + # end def view_summary @assignment = record end diff --git a/app/javascript/Components/assignment_chart.jsx b/app/javascript/Components/assignment_chart.jsx index f3d2eedfb2..1ef9d01687 100644 --- a/app/javascript/Components/assignment_chart.jsx +++ b/app/javascript/Components/assignment_chart.jsx @@ -11,6 +11,7 @@ export class AssignmentChart extends React.Component { this.state = { summary: { average: null, + average_annotations: null, median: null, num_submissions_collected: null, num_submissions_graded: null, @@ -187,6 +188,13 @@ export class AssignmentChart extends React.Component { ); } + let annotation_summary = ( +
          +

          {I18n.t("annotation_summary")}

          +

          {I18n.t("assignments.average_annotations", {average_annotations: 2.75})}

          +
          + ); + return (

          @@ -227,6 +235,7 @@ export class AssignmentChart extends React.Component { /> {criteria_graph} {ta_grade_distribution_chart} + {annotation_summary} ); } diff --git a/config/routes.rb b/config/routes.rb index d88ab5b198..e273d5ed24 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -32,6 +32,9 @@ end end resources :assignments, except: [:new, :edit] do + member do + get 'average_annotations' + end resources :groups, except: [:new, :edit, :destroy] do collection do get 'annotations' From fa3a513805c0e6412a9e6012014dee9881197edb Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Wed, 4 Jun 2025 19:49:38 -0400 Subject: [PATCH 16/18] removed commented code --- app/controllers/assignments_controller.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/controllers/assignments_controller.rb b/app/controllers/assignments_controller.rb index 75653ed45a..a073cd0e04 100644 --- a/app/controllers/assignments_controller.rb +++ b/app/controllers/assignments_controller.rb @@ -412,12 +412,6 @@ def grade_distribution render json: json_data end - # def average_annotations - # ta_id = params[:ta_id] - # average = @assignment.average_annotations(ta_id) - # render json: {average_annotations: average} - # - # end def view_summary @assignment = record end From 190b332631d7074ff962a893e315568d43aa0415 Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Wed, 4 Jun 2025 19:55:50 -0400 Subject: [PATCH 17/18] added to changelog --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index e89524c110..ea6b84c9dc 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ ### ✨ New features and improvements - Improved layout and labeling in the assignment settings form for both standard and timed assessments. (#7531) - Improve Assignment view for students (#7533) +- Add average annotations section in Assignment Summary (#7556) ### 🐛 Bug fixes From 8807ac7ef007aa31048f4ac4d5ca7f4ce292f168 Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Wed, 4 Jun 2025 21:41:04 -0400 Subject: [PATCH 18/18] fixed errors from rspec --- app/javascript/Components/assignment_chart.jsx | 2 +- config/locales/views/assignments/en.yml | 1 + spec/controllers/assignments_controller_spec.rb | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/javascript/Components/assignment_chart.jsx b/app/javascript/Components/assignment_chart.jsx index 1ef9d01687..2e142f728b 100644 --- a/app/javascript/Components/assignment_chart.jsx +++ b/app/javascript/Components/assignment_chart.jsx @@ -190,7 +190,7 @@ export class AssignmentChart extends React.Component { let annotation_summary = (
          -

          {I18n.t("annotation_summary")}

          +

          {I18n.t("assignments.annotation_summary")}

          {I18n.t("assignments.average_annotations", {average_annotations: 2.75})}

          ); diff --git a/config/locales/views/assignments/en.yml b/config/locales/views/assignments/en.yml index 8efdcd0134..b77ebf9c2d 100644 --- a/config/locales/views/assignments/en.yml +++ b/config/locales/views/assignments/en.yml @@ -1,6 +1,7 @@ --- en: assignments: + annotation_summary: Annotation Summary assignment_has_groupings: Assignment has groupings. assignment_information: Assignment information average_annotations: "%{average_annotations} annotations per marked submission" diff --git a/spec/controllers/assignments_controller_spec.rb b/spec/controllers/assignments_controller_spec.rb index 08028af555..0304204ee6 100644 --- a/spec/controllers/assignments_controller_spec.rb +++ b/spec/controllers/assignments_controller_spec.rb @@ -1305,6 +1305,7 @@ it 'should contain the right keys' do keys = response.parsed_body['summary'].keys expect(keys).to contain_exactly('name', + 'average_annotations', 'average', 'median', 'max_mark', @@ -1325,6 +1326,7 @@ summary = response.parsed_body['summary'] assignment_remark_requests = assignment.groupings.joins(current_submission_used: :submitted_remark) expected = { name: "#{assignment.short_identifier}: #{assignment.description}", + average_annotations: assignment.average_annotations, average: assignment.results_average(points: true) || 0, median: assignment.results_median(points: true) || 0, max_mark: assignment.max_mark || 0,