Scale existing scores when assignment total points change

Fixes CNVS-30027

Test plan:
* As a teacher, create an assignment worth 100 points
* As a student, submit something for the assignment
* As a teacher, grade the assignment (ie 70)
* Edit the assignment to change the possible points (ie 10 points)

The graded submission should scale its score, so 70 becomes 7 in this
example. This should work for all grade types.

Change-Id: I4e84075dbe406416df4378173a45fb5e3e9096fa
Reviewed-on: https://gerrit.instructure.com/82963
Tested-by: Jenkins
Reviewed-by: Keith T. Garner <kgarner@instructure.com>
QA-Review: KC Naegle <knaegle@instructure.com>
Product-Review: Christi Wruck
This commit is contained in:
Neil Gupta 2016-06-17 19:52:37 -05:00
parent e18ed1d8d1
commit b47516dc2f
6 changed files with 115 additions and 21 deletions

View File

@ -313,11 +313,24 @@ class Assignment < ActiveRecord::Base
true
end
def update_student_submissions
def update_student_submissions(old_points_possible = nil)
graded_at = Time.zone.now
submissions.graded.preload(:user).find_each do |s|
if grading_type == 'pass_fail' && ['complete', 'pass'].include?(s.grade)
s.score = points_possible
if points_possible.to_f > 0 &&
old_points_possible.to_f > 0 &&
s.score.to_f > 0
# Scale existing scores when total possible points changed
percentage = points_possible / old_points_possible.to_f
s.score = s.score * percentage
end
if grading_type == 'pass_fail'
# If a previously scored assignment just became pass/fail,
# update its score to be the max points possible or 0.
s.score = if ['complete', 'pass'].include?(s.grade) || score_to_grade(s.score, s.grade) == 'complete'
points_possible
else
0.0
end
end
s.grade = score_to_grade(s.score, s.grade)
s.graded_at = graded_at
@ -332,7 +345,7 @@ class Assignment < ActiveRecord::Base
# reflect the changes
def update_submissions_if_details_changed
if !new_record? && (points_possible_changed? || grading_type_changed? || grading_standard_id_changed?) && !submissions.graded.empty?
send_later_if_production(:update_student_submissions)
send_later_if_production(:update_student_submissions, points_possible_was)
end
true
end

View File

@ -262,7 +262,7 @@
value="{{assignment.pointsPossible}}" />
</div>
<div id=discussion_point_change_warning class="alert form-column-right">
{{#t}}If you change an assignment's points possible you must regrade the assignment.{{/t}}
{{#t}}If you change an assignment's points possible, existing grades will be automatically scaled.{{/t}}
</div>
</div>

View File

@ -59,7 +59,7 @@
{{disabledIfIncludes frozenAttributes "points_possible"}}/>
<div aria-live="polite" role="alert">
<div id=point_change_warning class="alert">
{{#t}}If you change an assignment's points possible you must regrade the assignment.{{/t}}
{{#t}}If you change an assignment's points possible, existing grades will be automatically scaled.{{/t}}
</div>
</div>
</div>

View File

@ -41,8 +41,8 @@ describe GradeCalculator do
@assignment.points_possible = 5
@assignment.save!
expect(@user.enrollments.first.computed_current_score).to eql(100.0)
expect(@user.enrollments.first.computed_final_score).to eql(100.0)
expect(@user.enrollments.first.computed_current_score).to eql(50.0)
expect(@user.enrollments.first.computed_final_score).to eql(50.0)
end
it "should recompute when an assignment group's weight changes'" do

View File

@ -280,9 +280,7 @@ describe Assignment::SpeedGrader do
submission_type: 'online_text_entry',
body: 'hi'
})
others.each { |u|
@assignment.grade_student(u, excuse: true)
}
others.each { |u| @assignment.grade_student(u, excuse: true) }
expect(@assignment.representatives(@teacher)).to include g1rep
end

View File

@ -17,7 +17,8 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
require_relative '../spec_helper.rb'
require_relative '../sharding_spec_helper'
describe Assignment do
before :once do
@ -1359,9 +1360,9 @@ describe Assignment do
@assignment.points_possible = 30
@assignment.save!
@sub.reload
expect(@sub.score).to eql(15.2)
expect(@sub.grade).to eql('F')
expect(@enrollment.reload.computed_current_score).to eq 50.67
expect(@sub.score).to eql(22.8)
expect(@sub.grade).to eql('C')
expect(@enrollment.reload.computed_current_score).to eq 76.0
end
it "should accept lowercase letter grades" do
@ -1404,9 +1405,9 @@ describe Assignment do
@assignment.points_possible = 30
@assignment.save!
@sub.reload
expect(@sub.score).to eql(15.2)
expect(@sub.grade).to eql('0')
expect(@enrollment.reload.computed_current_score).to eq 50.67
expect(@sub.score).to eql(22.8)
expect(@sub.grade).to eql('2.0')
expect(@enrollment.reload.computed_current_score).to eq 76.0
end
it "should accept lowercase gpa grades" do
@ -2932,7 +2933,7 @@ describe Assignment do
it "preserves pass/fail grade when changing from 0 to positive points possible" do
@assignment.grade_student(@user, :grade => 'pass')
@assignment.points_possible = 1.0
@assignment.update_student_submissions
@assignment.update_student_submissions(@assignment.points_possible_was)
submission.reload
expect(submission.grade).to eql('complete')
@ -2941,7 +2942,7 @@ describe Assignment do
it "changes the score of 'complete' pass/fail submissions to match the assignment's possible points" do
@assignment.grade_student(@user, :grade => 'pass')
@assignment.points_possible = 3.0
@assignment.update_student_submissions
@assignment.update_student_submissions(@assignment.points_possible_was)
submission.reload
expect(submission.score).to eql(3.0)
@ -2950,12 +2951,94 @@ describe Assignment do
it "does not change the score of 'incomplete' pass/fail submissions if assignment points possible has changed" do
@assignment.grade_student(@user, :grade => 'fail')
@assignment.points_possible = 2.0
@assignment.update_student_submissions
@assignment.update_student_submissions(@assignment.points_possible_was)
submission.reload
expect(submission.score).to eql(0.0)
end
end
context "percent assignments with initial 100 points possible" do
before :once do
setup_assignment_without_submission
@assignment.grading_type = "percent"
@assignment.points_possible = 100.0
@assignment.save
end
let(:submission) { @assignment.submissions.first }
it "preserves percent grade when changing to 10 points possible" do
@assignment.grade_student(@user, :grade => '70')
@assignment.points_possible = 10.0
@assignment.update_student_submissions(@assignment.points_possible_was)
submission.reload
expect(submission.grade).to eql('70%')
end
it "scales score when changing to 10 points possible" do
@assignment.grade_student(@user, :grade => '70')
@assignment.points_possible = 10.0
@assignment.update_student_submissions(@assignment.points_possible_was)
submission.reload
expect(submission.score).to eql(7.0)
end
it "preserves percent grade when changing to 200 points possible" do
@assignment.grade_student(@user, :grade => '70')
@assignment.points_possible = 200.0
@assignment.update_student_submissions(@assignment.points_possible_was)
submission.reload
expect(submission.grade).to eql('70%')
end
it "scales score when changing to 200 points possible" do
@assignment.grade_student(@user, :grade => '70')
@assignment.points_possible = 200.0
@assignment.update_student_submissions(@assignment.points_possible_was)
submission.reload
expect(submission.score).to eql(140.0)
end
it "changes the grade to 'complete' if positive score when changing type to pass/fail" do
@assignment.grade_student(@user, :grade => '70')
@assignment.grading_type = 'pass_fail'
@assignment.update_student_submissions(@assignment.points_possible_was)
submission.reload
expect(submission.grade).to eql('complete')
end
it "sets the max score if positive score when changing type to pass/fail" do
@assignment.grade_student(@user, :grade => '70')
@assignment.grading_type = 'pass_fail'
@assignment.update_student_submissions(@assignment.points_possible_was)
submission.reload
expect(submission.score).to eql(100.0)
end
it "changes the grade to 'fail' if 0 score when changing type to pass/fail" do
@assignment.grade_student(@user, :grade => '0')
@assignment.grading_type = 'pass_fail'
@assignment.update_student_submissions(@assignment.points_possible_was)
submission.reload
expect(submission.grade).to eql('incomplete')
end
it "preserves 0 score when changing type to pass/fail" do
@assignment.grade_student(@user, :grade => '0')
@assignment.grading_type = 'pass_fail'
@assignment.update_student_submissions(@assignment.points_possible_was)
submission.reload
expect(submission.score).to eql(0.0)
end
end
end