-
Notifications
You must be signed in to change notification settings - Fork 253
Add scheduled visibility for assessments #7697
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add scheduled visibility for assessments #7697
Conversation
Add visible_on/visible_until columns to schedule assessment visibility automatically. Datetime columns override is_hidden when set. Section-specific datetime overrides global datetime. Updated models, policies, SQL function, API controllers, and added comprehensive tests.
Pull Request Test Coverage Report for Build 18783844054Warning: This coverage report may be inaccurate.This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.
Details
💛 - Coveralls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lxyhan nice work! I left a few inline comments. Note that my comments on the queries apply to both branches of the if statement.
In addition to the inline comments:
- Add tests for the SQL function in
spec/db/check_repo_permissions_spec.rb - You also need to update
Repository.visibility_hashandAssignment#visibility_changed?
Changelog.md
Outdated
| ### 🚨 Breaking changes | ||
|
|
||
| ### ✨ New features and improvements | ||
| - Added datetime-based visibility scheduling for assessments with `visible_on` and `visible_until` columns |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sure to include the PR number here
app/models/assessment.rb
Outdated
|
|
||
| def visible_dates_are_valid | ||
| return if visible_on.nil? || visible_until.nil? | ||
| return unless visible_on.respond_to?(:>=) && visible_until.respond_to?(:>=) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this line is necessary, if it's reach then shouldn't these attributes be dates?
|
|
||
| has_one :course, through: :assessment | ||
| validate :courses_should_match | ||
| validate :visible_dates_are_valid |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validations are typically run in top-down order, so it would be more typical to write this validation below the next two (so that the types are checked first)
app/models/student.rb
Outdated
| ) | ||
|
|
||
| # Use datetime if set, otherwise fall back to is_hidden | ||
| visible.where( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be simplified using built-in ActiveRecord methods. In this case you can use both .where.not(...) and .or
app/models/student.rb
Outdated
| visible = visible.where(is_hidden: false) | ||
| # No section assigned - just check global visibility | ||
| visible = visible.where( | ||
| '(assessments.visible_on IS NULL OR assessments.visible_on <= ?) AND ' \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to my comments below, I'd prefer using the ActiveRecord methods where possible. In this case the part with the <= is fine, but you can use .or instead of SQL OR and chained .wheres instead of AND
… SQL function tests
| section_visible = section_visible | ||
| .where.not(assessment_section_properties: { visible_on: nil }) | ||
| .or(section_visible.where.not(assessment_section_properties: { visible_until: nil })) | ||
| .or(section_visible.where(assessment_section_properties: { is_hidden: false })) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is something subtle here with the is_hidden section property.
In the case that for the section properties, visible_on: nil, visible_until: nil, is_hidden: true, then the assignment should not be visible to students in that section, regardless of what the global properties are. I don't think this is currently being implemented correctly by this logic.
You handled this differently in the visibility_hash method by first checking whether any of the three section properties were non-nil before overriding the global properties.
And in the SQL function, you're only checking assessment_section_properties.is_hidden IS NOT NULL but should probably be checking all three.
spec/models/student_spec.rb
Outdated
| expect(student.visible_assessments).not_to include(assignment) | ||
| end | ||
|
|
||
| it 'shows assessment when datetime range is valid (overrides is_hidden=true)' do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The word "valid" is not useful in this context. Better wording would be "when the datetime range includes the current time". This repeats a few times in the test descriptions.
…rove test descriptions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lxyhan nice work, I just left two small comments
app/models/student.rb
Outdated
|
|
||
| # Check section-specific visibility first (takes precedence when any section property is set) | ||
| section_visible = visible.where('assessment_section_properties.section_id': self.section_id) | ||
| .where('assessment_section_properties.is_hidden IS NOT NULL OR ' \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a place where you can use ActiveRecord methods like .or and .not
app/models/student.rb
Outdated
|
|
||
| # Check global visibility (when no section-specific settings exist) | ||
| global_visible = visible.where('assessment_section_properties.section_id': nil) | ||
| .or(visible.where('assessment_section_properties.is_hidden IS NULL AND ' \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a similar comment here, you can both use : nil and pass multiple conditions to .where instead of relying on raw SQL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh @lxyhan I just realized that in 322c3a8 you modified structure.sql directly, but did not modify the migration file. You should always modify migrations rather than structure.sql.
In this case, you can first rollback the existing migration, and then modify it, and then run it again. You won't see any changes in git to the structure.sql file, but you will see the changes to your migration file, which should be committed and pushed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work, @lxyhan!
Proposed Changes
Added datetime-based visibility scheduling for assessments. Instructors can now set
visible_onandvisible_untildates to automatically show/hide assessments instead of manually toggling them.Right now instructors can only mark assessments as visible or hidden with a boolean. They've been requesting the ability to schedule when assessments become visible (like "October 1 - December 31") so they can set it up at the start of the semester and not worry about manually publishing assignments later.
My changes in this PR
Database:
visible_onandvisible_untildatetime columns toassessmentsandassessment_section_propertiestablescheck_repo_permissionsSQL function to enforce datetime visibility for git accessModels:
Student#visible_assessmentsto check datetime rangesvisible_on < visible_untilis_hiddenwhen they're setAPI:
visible_onandvisible_untilfields in assignments and grade entry forms API endpointsTests:
Added validation tests for datetime columns
Added 18 test cases for visibility logic (global, section-specific, datetime ranges, edge cases)
Added 9 policy tests for datetime visibility authorization
If
visible_on/visible_untilare set, they override theis_hiddenbooleanSection-specific datetime settings override global settings (same pattern as section due dates)
Backwards compatible - if datetime columns are null, falls back to
is_hiddenCan set just
visible_on, justvisible_until, or bothType of Change
(Write an
Xor a brief description next to the type or types that best describe your changes.)Checklist
(Complete each of the following items for your pull request. Indicate that you have completed an item by changing the
[ ]into a[x]in the raw text, or by clicking on the checkbox in the rendered description on GitHub.)Before opening your pull request:
After opening your pull request:
Questions and Comments
(Include any questions or comments you have regarding your changes.)