Consider "Enter Grades as" setting with grading schemes
Do not match grading scheme values if the Gradebook setting for "Enter Grades as" is set to "Points". See the community post in the ticket to get a better understanding of the issue. closes EVAL-2117 flag=none Test Plan: As a teacher: 1. Select/create a grading scheme that includes numbers e.g. Name Range 5 100% to 90.0% 4 < 90.0% to 70.0% 3 < 70.0% to 50.0% Revision required/Komplettering < 50.0% to 25.0% U < 25.0% to 0.0% 2. Create an assignment worth 100 points and set "Display grade as" to Letter grade 3. In gradebook, grade the assignment for students using names in grading scheme and other values and see that totals correspond to those values e.g. (5 -> 100%), (4 -> 89%) and (6 -> 6%) 4. Switch "Enter Grades as" option to "Points". Award 5 points to a student and see that it does not assign the value from grading scheme but the actual percentage. Try different values matching and not matching grading scheme names. Change-Id: I1312c6bfb5070c0b08e7590232e86d609e446025 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/283437 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Dustin Cowles <dustin.cowles@instructure.com> Reviewed-by: Spencer Olson <solson@instructure.com> QA-Review: Eduardo Escobar <eduardo.escobar@instructure.com> Product-Review: Jody Sailor
This commit is contained in:
parent
bfc1931b09
commit
bce89a6354
|
@ -725,6 +725,9 @@ class SubmissionsApiController < ApplicationController
|
|||
# @argument include[visibility] [String]
|
||||
# Whether this assignment is visible to the owner of the submission
|
||||
#
|
||||
# @argument prefer_points_over_scheme [Boolean]
|
||||
# Treat posted_grade as points if the value matches a grading scheme value
|
||||
#
|
||||
# @argument submission[posted_grade] [String]
|
||||
# Assign a score to the submission, updating both the "score" and "grade"
|
||||
# fields on the submission record. This parameter can be passed in a few
|
||||
|
@ -841,6 +844,7 @@ class SubmissionsApiController < ApplicationController
|
|||
submission[:submission_type] = params[:submission][:submission_type]
|
||||
submission[:url] = params[:submission][:url]
|
||||
end
|
||||
submission[:prefer_points_over_scheme] = value_to_boolean(params[:prefer_points_over_scheme])
|
||||
end
|
||||
|
||||
if submission[:grade] || submission[:excuse]
|
||||
|
|
|
@ -1455,14 +1455,14 @@ class Assignment < ActiveRecord::Base
|
|||
round_if_whole(result).to_s
|
||||
end
|
||||
|
||||
def interpret_grade(grade)
|
||||
def interpret_grade(grade, prefer_points_over_scheme: false)
|
||||
case grade.to_s
|
||||
when /^[+-]?\d*\.?\d+%$/
|
||||
# interpret as a percentage
|
||||
percentage = grade.to_f / 100.0.to_d
|
||||
points_possible.to_f * percentage
|
||||
when /^[+-]?\d*\.?\d+$/
|
||||
if uses_grading_standard && (standard_based_score = grading_standard_or_default.grade_to_score(grade))
|
||||
if !prefer_points_over_scheme && uses_grading_standard && (standard_based_score = grading_standard_or_default.grade_to_score(grade))
|
||||
(points_possible || 0.0) * standard_based_score / 100.0
|
||||
else
|
||||
grade.to_f
|
||||
|
@ -1481,10 +1481,10 @@ class Assignment < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def grade_to_score(grade = nil)
|
||||
def grade_to_score(grade = nil, prefer_points_over_scheme: false)
|
||||
return nil if grade.blank?
|
||||
|
||||
parsed_grade = interpret_grade(grade)
|
||||
parsed_grade = interpret_grade(grade, prefer_points_over_scheme: prefer_points_over_scheme)
|
||||
case self.grading_type
|
||||
when "points", "percent", "letter_grade", "gpa_scale"
|
||||
score = parsed_grade
|
||||
|
@ -1900,11 +1900,11 @@ class Assignment < ActiveRecord::Base
|
|||
all_submissions.where(user_id: user_id).first_or_initialize
|
||||
end
|
||||
|
||||
def compute_grade_and_score(grade, score)
|
||||
def compute_grade_and_score(grade, score, prefer_points_over_scheme: false)
|
||||
grade = nil if grade == ""
|
||||
|
||||
if grade
|
||||
score = grade_to_score(grade)
|
||||
score = grade_to_score(grade, prefer_points_over_scheme: prefer_points_over_scheme)
|
||||
end
|
||||
if score
|
||||
grade = score_to_grade(score, grade)
|
||||
|
@ -2021,7 +2021,7 @@ class Assignment < ActiveRecord::Base
|
|||
return if submission.user != original_student && submission.excused?
|
||||
|
||||
grader = opts[:grader]
|
||||
grade, score = compute_grade_and_score(opts[:grade], opts[:score])
|
||||
grade, score = compute_grade_and_score(opts[:grade], opts[:score], prefer_points_over_scheme: opts[:prefer_points_over_scheme])
|
||||
|
||||
did_grade = false
|
||||
submission.attributes = opts.slice(:submission_type, :url, :body)
|
||||
|
|
|
@ -3197,6 +3197,84 @@ describe "Submissions API", type: :request do
|
|||
}.by(1)
|
||||
end
|
||||
|
||||
context "grading scheme with numerics in names" do
|
||||
before do
|
||||
@standard = @course.grading_standards.create!(title: "course standard", standard_data: { a: { name: "5", value: "90" }, b: { name: "4", value: "70" }, c: { name: "3", value: "50" }, d: { name: "Revision required/Komplettering", value: "25" }, e: { name: "U", value: "0" } })
|
||||
@assignment.update_attribute :grading_standard, @standard
|
||||
api_call(:put, "/api/v1/courses/#{@course.id}",
|
||||
{ controller: "courses", action: "update", format: "json", id: @course.to_param }, course: { grading_standard_id: @standard.id })
|
||||
@course.reload
|
||||
end
|
||||
|
||||
it "can grade when it matches grading name and enter grades is set to points" do
|
||||
json = api_call(
|
||||
:put,
|
||||
"/api/v1/courses/#{@course.id}/assignments/#{@assignment.id}/submissions/#{@student.id}.json",
|
||||
{
|
||||
controller: "submissions_api",
|
||||
action: "update",
|
||||
format: "json",
|
||||
course_id: @course.id.to_s,
|
||||
assignment_id: @assignment.id.to_s,
|
||||
user_id: @student.id.to_s
|
||||
}, {
|
||||
submission: {
|
||||
posted_grade: 5
|
||||
},
|
||||
prefer_points_over_scheme: true
|
||||
}
|
||||
)
|
||||
|
||||
expect(json["grade"]).to eq "Revision required/Komplettering"
|
||||
expect(json["score"]).to eq 5.0
|
||||
end
|
||||
|
||||
it "can grade when it matches grading scheme name" do
|
||||
json = api_call(
|
||||
:put,
|
||||
"/api/v1/courses/#{@course.id}/assignments/#{@assignment.id}/submissions/#{@student.id}.json",
|
||||
{
|
||||
controller: "submissions_api",
|
||||
action: "update",
|
||||
format: "json",
|
||||
course_id: @course.id.to_s,
|
||||
assignment_id: @assignment.id.to_s,
|
||||
user_id: @student.id.to_s
|
||||
}, {
|
||||
submission: {
|
||||
posted_grade: 5
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
expect(json["grade"]).to eq "5"
|
||||
expect(json["score"]).to eq @assignment.points_possible
|
||||
end
|
||||
|
||||
it "can grade when it does not match grading scheme name" do
|
||||
# grading_type = "letter_grade"
|
||||
json = api_call(
|
||||
:put,
|
||||
"/api/v1/courses/#{@course.id}/assignments/#{@assignment.id}/submissions/#{@student.id}.json",
|
||||
{
|
||||
controller: "submissions_api",
|
||||
action: "update",
|
||||
format: "json",
|
||||
course_id: @course.id.to_s,
|
||||
assignment_id: @assignment.id.to_s,
|
||||
user_id: @student.id.to_s
|
||||
}, {
|
||||
submission: {
|
||||
posted_grade: 9
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
expect(json["grade"]).to eq "3"
|
||||
expect(json["score"]).to eq 9.0
|
||||
end
|
||||
end
|
||||
|
||||
context "group assignments" do
|
||||
before do
|
||||
@student2 = @course.enroll_student(User.create!, enrollment_state: :active).user
|
||||
|
|
|
@ -207,4 +207,32 @@ QUnit.module('GradebookApi.updateSubmission', hooks => {
|
|||
}).then(({data}) => {
|
||||
deepEqual(data, submissionData)
|
||||
}))
|
||||
|
||||
test('sends true for prefer_points_over_scheme param when passed "points"', () =>
|
||||
GradebookApi.updateSubmission(
|
||||
courseId,
|
||||
assignmentId,
|
||||
userId,
|
||||
{
|
||||
latePolicyStatus: 'none'
|
||||
},
|
||||
'points'
|
||||
).then(() => {
|
||||
const bodyData = JSON.parse(getRequest().requestBody)
|
||||
strictEqual(bodyData.prefer_points_over_scheme, true)
|
||||
}))
|
||||
|
||||
test('sends false for prefer_points_over_scheme param when not passed "points"', () =>
|
||||
GradebookApi.updateSubmission(
|
||||
courseId,
|
||||
assignmentId,
|
||||
userId,
|
||||
{
|
||||
latePolicyStatus: 'none'
|
||||
},
|
||||
'percent'
|
||||
).then(() => {
|
||||
const bodyData = JSON.parse(getRequest().requestBody)
|
||||
strictEqual(bodyData.prefer_points_over_scheme, false)
|
||||
}))
|
||||
})
|
||||
|
|
|
@ -3421,6 +3421,33 @@ describe Assignment do
|
|||
expect(decimal_part.length).to be <= 3
|
||||
end
|
||||
|
||||
context "with numeric grading standard" do
|
||||
before(:once) do
|
||||
@assignment.update!(grading_type: "letter_grade", points_possible: 10.0)
|
||||
grading_standard = @course.grading_standards.build(title: "Number Before Letter")
|
||||
grading_standard.data = {
|
||||
"1" => 0.9,
|
||||
"2" => 0.8,
|
||||
"3" => 0.7,
|
||||
"4" => 0.6,
|
||||
"5" => 0.5,
|
||||
"6" => 0
|
||||
}
|
||||
grading_standard.assignments << @assignment
|
||||
grading_standard.save!
|
||||
end
|
||||
|
||||
it "does not match a numeric grading standard if points are preferred over grading scheme value" do
|
||||
@assignment.points_possible = 100
|
||||
expect(@assignment.interpret_grade("1", prefer_points_over_scheme: true)).to eq 1.0
|
||||
end
|
||||
|
||||
it "matches a numeric grading standard if grading scheme value is preferred over points" do
|
||||
@assignment.points_possible = 100
|
||||
expect(@assignment.interpret_grade("1")).to eq 100.0
|
||||
end
|
||||
end
|
||||
|
||||
context "with alphanumeric grades" do
|
||||
before(:once) do
|
||||
@assignment.update!(grading_type: "letter_grade", points_possible: 10.0)
|
||||
|
|
|
@ -4447,14 +4447,20 @@ class Gradebook extends React.Component<GradebookProps, GradebookState> {
|
|||
})
|
||||
}
|
||||
|
||||
apiUpdateSubmission = (submission, gradeInfo) => {
|
||||
apiUpdateSubmission(submission, gradeInfo, enterGradesAs) {
|
||||
const {userId, assignmentId} = submission
|
||||
const student = this.student(userId)
|
||||
this.addPendingGradeInfo(submission, gradeInfo)
|
||||
if (this.getSubmissionTrayState().open) {
|
||||
this.renderSubmissionTray(student)
|
||||
}
|
||||
return GradebookApi.updateSubmission(this.options.context_id, assignmentId, userId, submission)
|
||||
return GradebookApi.updateSubmission(
|
||||
this.options.context_id,
|
||||
assignmentId,
|
||||
userId,
|
||||
submission,
|
||||
enterGradesAs
|
||||
)
|
||||
.then(response => {
|
||||
this.removePendingGradeInfo(submission)
|
||||
this.updateSubmissionsFromExternal(response.data.all_submissions)
|
||||
|
@ -4497,7 +4503,11 @@ class Gradebook extends React.Component<GradebookProps, GradebookState> {
|
|||
} else {
|
||||
submissionData.posted_grade = gradeInfo.score
|
||||
}
|
||||
return this.apiUpdateSubmission(submissionData, gradeInfo).then(response => {
|
||||
return this.apiUpdateSubmission(
|
||||
submissionData,
|
||||
gradeInfo,
|
||||
gradeChangeOptions.enterGradesAs
|
||||
).then(response => {
|
||||
const assignment = this.getAssignment(submission.assignmentId)
|
||||
const outlierScoreHelper = new OutlierScoreHelper(
|
||||
response.data.score,
|
||||
|
|
|
@ -42,9 +42,13 @@ function updateTeacherNotesColumn(courseId, columnId, attr) {
|
|||
return axios.put(url, {column: attr})
|
||||
}
|
||||
|
||||
function updateSubmission(courseId, assignmentId, userId, submission) {
|
||||
function updateSubmission(courseId, assignmentId, userId, submission, enterGradesAs) {
|
||||
const url = `/api/v1/courses/${courseId}/assignments/${assignmentId}/submissions/${userId}`
|
||||
return axios.put(url, {submission: underscore(submission), include: ['visibility']})
|
||||
return axios.put(url, {
|
||||
submission: underscore(submission),
|
||||
include: ['visibility'],
|
||||
prefer_points_over_scheme: enterGradesAs === 'points'
|
||||
})
|
||||
}
|
||||
|
||||
function saveUserSettings(courseId, gradebook_settings) {
|
||||
|
|
Loading…
Reference in New Issue