-
Notifications
You must be signed in to change notification settings - Fork 244
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
Prevent deletion of graded peer reviews #7263
Conversation
…r and reviewee pairs. Updated css stylesheet to centre the exclamation mark in error flashes when the error message is multiple lines. Added testcase to ensure that has_marks_or_annotations? works as expected, and prevents peer reviewers from being unassigned
Sorry, I requested a review prematurely. I'll re-request once I am fully prepared for a review. |
Pull Request Test Coverage Report for Build 11783156360Details
💛 - Coveralls |
…iews_controller.rb
…ections (Previously row selections bypassed the necessary checks)
app/models/peer_review.rb
Outdated
unless reviewee_group.nil? || reviewer_group.nil? | ||
peer_review = reviewer_group.review_for(reviewee_group) | ||
unless peer_review.nil? | ||
if peer_review.has_marks_or_annotations? |
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 check (peer_review.has_marks_or_annotations?
) is good, but you should reorganize as follows: instead of adding it here, add it as a before_destroy
callback. The delete_peer_review_between
method calls destroy
, and will trigger the callback. This is more robust because it will affect everywhere that a peer review is attempted to be destroyed, not just this particular method.
(It's possible to also skip callbacks, in case we ever want to enable that in the future.)
app/models/peer_review.rb
Outdated
unless peer_review.nil? | ||
if peer_review.has_marks_or_annotations? | ||
delete_all_reviews = false | ||
undeleted_reviews.append(reviewer_group.get_all_students_in_group + |
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.
- Use the group name rather than the students (the latter will make the message look weird when students are working in groups)
- Make this entire string internationalized
app/models/peer_review.rb
Outdated
def has_marks_or_annotations? | ||
result = self.result | ||
marks_not_nil = false | ||
result.marks.each do |mark| |
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 inefficient, and can be simplified into a single query with exists?
app/models/peer_review.rb
Outdated
deleted_count = 0 | ||
undeleted_reviews = [] | ||
|
||
# When an entire row is selected for unassignment |
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 interesting, it's seems you're actually fixing a separate bug here; please pull this out and make into into a new pull request with a description of just this bug.
PeerReview.unassign(selected_reviewee_group_ids, reviewers_to_remove_from_reviewees_map) | ||
reviews_deleted, deleted_count, undeleted_reviews = PeerReview.unassign(selected_reviewee_group_ids, | ||
reviewers_to_remove_from_reviewees_map) | ||
if !reviews_deleted && deleted_count == 0 |
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 case needs a separate message, you can merge it with the next one (length <= 5). See also my suggestion for rewording the message down below.
@@ -498,6 +498,8 @@ option.uncollected { | |||
.flash-content { | |||
display: inline-block; | |||
padding-left: 5pt; | |||
vertical-align: middle; | |||
max-width: calc(100% - 3em); |
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.
Keep all rules alphabetically ordered (I'm surprised the pre-commit hooks didn't pick up on this, but that's something I'll look into separately!)
@@ -9,6 +9,9 @@ en: | |||
assigned_reviewers_header: Reviewers | |||
errors: | |||
cannot_allow_reviewer_to_be_reviewee: A student cannot be a reviewer and reviewee | |||
cannot_unassign_all_reviewers: 'Cannot unassign all selected peer reviewers due to existing marks or annotations. %{deleted_count} peer reviewer(s) were unassigned, but the following could not be: %{undeleted_reviews}.' |
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.
Reword to "Successfully unassigned %{deleted_count} peer reviewer(s), but could not unassign the following due to existing marks or annotations: ..."
@reviewer = Grouping.find_by(id: @selected_reviewer_group_ids[0]) | ||
@reviewee = Grouping.find_by(id: @selected_reviewee_group_ids[1]) | ||
allow_any_instance_of(PeerReview).to receive(:has_marks_or_annotations?).and_return(true) | ||
selected_group = {} |
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.
It's not really necessary to create separate hash variables like this, you can define it inline as { @reviewee.id => { @reviewer.id => true } }
or something similar
end | ||
end | ||
|
||
it 'does not delete the peer review' 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.
It's good to be testing whether or not the database was actually changed here, and you should be doing it in the other tests as well
@@ -88,4 +88,23 @@ | |||
end | |||
end | |||
end | |||
|
|||
describe '#has_marks_or_annotations?' 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.
This set of test cases is incomplete, you should be adding more cases (don't just rely on code coverage to tell you whether the tests are complete or not)
…, added before_destroy callback to peer_review deletion, simplified some inefficient code
…check_marks_or_annotations
message = t('peer_reviews.errors.cannot_unassign_all_reviewers', | ||
deleted_count: deleted_count.to_s, undeleted_reviews: undeleted_reviews.first(5).join(', ')) | ||
if undeleted_reviews.length > 5 | ||
message += " #{t('additional_not_shown')}" |
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.
add a count
argument here as well (so the message becomes Additional {n} not shown
)
app/models/peer_review.rb
Outdated
def has_marks_or_annotations? | ||
result = self.result | ||
marks_not_nil = result | ||
.marks.where.not(mark: 0).exists? |
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 should be looking for nil
marks, not 0 marks
app/models/peer_review.rb
Outdated
@@ -69,16 +70,49 @@ def self.assign(reviewer_groups, reviewee_groups) | |||
end | |||
|
|||
def self.unassign(selected_reviewee_group_ids, reviewers_to_remove_from_reviewees_map) | |||
delete_all_reviews = true |
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 better name for this variable is all_reviews_deleted
(correctly implies it's a boolean).
However, this variable actually isn't needed at all, as its value is equivalent to undeleted_reviews.empty?
So you can simplify the code further by removing this variable entirely.
spec/models/peer_review_spec.rb
Outdated
create(:mark, criterion: criterion, result: peer_review.result, mark: 2.5) | ||
end | ||
|
||
it 'returns true when there are non-nil marks' 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.
in these descriptions, do not repeat phrasing from the context ("when there are..."). The full test label concatenates the context
and it
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.
This is a huge oversight on my part, wow. Thanks for pointing this out.
before do | ||
@reviewer = Grouping.find_by(id: @selected_reviewer_group_ids[0]) | ||
@reviewee = Grouping.find_by(id: @selected_reviewee_group_ids[1]) | ||
allow_any_instance_of(PeerReview).to receive(:has_marks_or_annotations?).and_return(true) |
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.
Overall, don't rely on mocks in this test suite. You can update the test objects directly to create marks/annotations for the relevant result(s).
…s_or_annotations logic, simplified unassign return, fixed repeated testcase descriptions
Not sure why these precommit tests are failing, they're failing in the exact same way on other member's PRs as well. None of my changes should have caused these failures. |
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.
@hemmatio great work!
Proposed Changes
(Describe your changes here. Also describe the motivation for your changes: what problem do they solve, or how do they improve the application or codebase? If this pull request fixes an open issue, use a keyword to link this pull request to the issue.)
This PR aims to fix #7119. Currently, instructors are able to unassign peer reviewers no matter the situation. This PR prevents peer reviewers from being unassigned in the case that grade data exists, annotations exist, or the peer review is set to complete.
Screenshots of your changes (if applicable)
Case 1: Successfully unassigned allCase 2: Could not unassign any
Case 3: Unassigned some, could not unassign rest (less than 5)
Case 4: Unassigned some, could not unassign rest (more than 5)
Associated documentation repository pull request (if applicable)
Type of Change
(Write an
X
or 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.)
09/10/24: This is still a WIP, I just wanted to save my work on GitHub.
15/10/24: Added more error/success flashes, moved flash messages to locale file, modified logic of mark checking to check for non-nil mark criteron
22/10/24: Updated error messages to include reviewer and reviewee pairs to prevent any confusion in the case that the same reviewer cannot be unassigned in multiple different cases. Updated error flashes to be truncated when more than 5 reviewers could not be unassigned. Updated the exclamation mark in error flashes to be centred when the message is more than one line long. Added testcase which mocks that has_marks_or_annotations? returns true, then ensures that no peer reviews are deleted in that case.
Also: Is it necessary to update the project documentation for this? I see that the peer review wiki does not have anything yet, which I believe would be the related documentation.
23/10/24: Added more comprehensive testcases to cover all written lines of code. Mocks behaviour for each flashed message, and fully covers logic of has_marks_or_annotations? checking each criterion for a non-nil mark.
24/10/24: When selecting an entire row, the necessary checks were being bypassed. To fix this, I processed each row selection to be treated as if individual reviewers were selected.
For reference, an image of "row selection":
28/10/24: Left to do: Make separate PR for row deletion, add more testcases, update testcases to check database for deletion.
30-31/10/24: Updated testcases in peer_reviews_controller_spec.rb
Created new (more comprehensive) testcases for peer_review_spec.rb, involving the testing of has_marks_or_annotations? and check_marks_or_annotations, as well as the before_destroy callback. I opted to not create separate testcases for unassign, as this is already handled by the controller test cases.
Created new PR for the row deletion error.
4/11/24: Made changes to clean up code. Still need to switch from mocking to direct object usage for peer_review_controller tests.
6/11/24: FINALLY! Made tests in peer_review_controller_spec.rb stub rather than mock. TODO: Work on the other PR.