Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Add computed_final_score_with_muted field to submissions API #254

Closed
wants to merge 1 commit into from

2 participants

@christopher-b

I had to make a change to the submissions API to allow it to show final computed grades, including grades for muted assignments. I'd love to see this merged into the trunk. Thanks.

@christopher-b

These changes don't work with the latest code, but I would still like to see this as a feature.

@cmatheson
Owner

I think the change that broke your commit might also solve your problem (or hopefully get you most of the way there). The gradebook CSV now includes muted assignments (see https://github.com/instructure/canvas-lms/blob/stable/app/models/course.rb#L1439). You could just grab the csv or pass the :ignore_muted option to GradeCalculator. We don't currently save the ignore_muted value to the database.

@cmatheson
Owner

Oh, one other note on the proposed API change: the grade including muted assignments should get filtered out for students (otherwise they would be able to infer the grade on the muted assignment the computed_final_score_with_muted grade change).

@christopher-b

Thanks Cameron. Can you give me a sense of how I can filter this out for students?

If anyone else is interested, here are the changes I needed to make to get it working.

lib/grade_calculator.rb, line 63, just after def save_scores:

def final_score_with_muted(user_id, submissions)
  @ignore_muted = false
  group_sums = create_group_sums(submissions, false)
  calculate_total_from_group_scores(group_sums)
end

app/model/enrollment.rb, line 779, after computed_final_grade:

def computed_final_score_with_muted
  user_ids = [user_id]
  submissions = course.submissions.for_user(user_id).to_a
  calc = GradeCalculator.new(user_ids, course_id)
  calc.final_score_with_muted(user_id, submissions)
end

app/controllers/submissions_api_controller.rb, line 132, in def for_students:

if includes.include?('total_scores') && params[:grouped].present?
hash.merge!(
  :computed_final_score => enrollment.computed_final_score,
  :computed_final_score_with_muted => enrollment.computed_final_score_with_muted,
  :computed_current_score => enrollment.computed_current_score)
end
@cmatheson
Owner

Hey Christopher, our api_json stuff calls filter_attributes_for_user on the model if it is defined. See https://github.com/instructure/canvas-lms/blob/stable/app/models/submission.rb#L1130 for an example of how it is used.

@christopher-b

In this case, the api change I made is in SubmissionsApiController#for_students, which seems to required permission to view / manage grades:

if authorized_action(@context, @current_user, [:manage_grades, :view_all_grades])

So student access to this shouldn't be a problem, right?

@cmatheson
Owner

Sorry you're right Christopher. You shouldn't have any issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 20, 2012
  1. Add computed_final_score_with_muted field to submissions API

    Christopher Bennell authored
This page is out of date. Refresh to see the latest.
View
1  app/controllers/courses_controller.rb
@@ -53,6 +53,7 @@
# role: StudentEnrollment,
# computed_final_score: 41.5,
# computed_current_score: 90,
+# computed_final_score_with_muted: 90
# computed_final_grade: 'A-'
# }
# ],
View
1  app/controllers/submissions_api_controller.rb
@@ -128,6 +128,7 @@ def for_students
if includes.include?('total_scores') && params[:grouped].present?
hash.merge!(
:computed_final_score => enrollment.computed_final_score,
+ :computed_final_score_with_muted => enrollment.computed_final_score_with_muted,
:computed_current_score => enrollment.computed_current_score)
end
hash
View
6 app/models/enrollment.rb
@@ -742,6 +742,10 @@ def computed_final_grade
self.course.score_to_grade(self.computed_final_score)
end
+ def computed_final_grade_with_muted
+ self.course.score_to_grade(self.computed_final_score_with_muted)
+ end
+
def self.students(opts={})
with_scope :find => opts do
find(:all, :conditions => {:type => 'Student'}).map(&:user).compact
@@ -907,7 +911,7 @@ def self.course_user_state(course, uuid)
end
end
- def self.serialization_excludes; [:uuid,:computed_final_score, :computed_current_score]; end
+ def self.serialization_excludes; [:uuid,:computed_final_score, :computed_current_score, :computed_final_score_with_muted]; end
# enrollment term per-section is deprecated; a section's term is inherited from the
# course it is currently tied to
View
11 db/migrate/20121210182911_add_computed_final_score_with_muted_to_enrollments.rb
@@ -0,0 +1,11 @@
+class AddComputedFinalScoreWithMutedToEnrollments < ActiveRecord::Migration
+ tag :predeploy
+
+ def self.up
+ add_column :enrollments, :computed_final_score_with_muted, :float
+ end
+
+ def self.down
+ remove_column :enrollments, :computed_final_score_with_muted
+ end
+end
View
17 lib/grade_calculator.rb
@@ -26,6 +26,7 @@ def initialize(user_ids, course_id)
@user_ids = Array(user_ids).map(&:to_i)
@current_updates = []
@final_updates = []
+ @final_updates_with_muted = []
end
def self.recompute_final_score(user_ids, course_id)
@@ -40,13 +41,15 @@ def recompute_and_save_scores
submissions = all_submissions.select { |submission| submission.user_id == user_id }
calculate_current_score(user_id, submissions)
calculate_final_score(user_id, submissions)
+ calculate_final_score_with_muted(user_id, submissions)
end
Course.update_all({:updated_at => Time.now.utc}, {:id => @course.id})
- if !@current_updates.empty? || !@final_updates.empty?
+ if !@current_updates.empty? || !@final_updates.empty? || !@final_updates_with_muted.empty?
query = "updated_at=#{Enrollment.sanitize(Time.now.utc)}"
query += ", computed_current_score=CASE #{@current_updates.join(" ")} ELSE computed_current_score END" unless @current_updates.empty?
query += ", computed_final_score=CASE #{@final_updates.join(" ")} ELSE computed_final_score END" unless @final_updates.empty?
+ query += ", computed_final_score_with_muted=CASE #{@final_updates_with_muted.join(" ")} ELSE computed_final_score_with_muted END" unless @final_updates_with_muted.empty?
Enrollment.update_all(query, {:user_id => @user_ids, :course_id => @course.id})
end
end
@@ -66,9 +69,15 @@ def calculate_final_score(user_id, submissions)
score = calculate_total_from_group_scores(group_sums, false)
@final_updates << "WHEN user_id=#{user_id} THEN #{score || "NULL"}"
end
+
+ def calculate_final_score_with_muted(user_id, submissions)
+ group_sums = create_group_sums(submissions, false, false)
+ score = calculate_total_from_group_scores(group_sums, false)
+ @final_updates_with_muted << "WHEN user_id=#{user_id} THEN #{score || "NULL"}"
+ end
# Creates a hash for each assignment group with stats and the end score for each group
- def create_group_sums(submissions, ignore_ungraded=true)
+ def create_group_sums(submissions, ignore_ungraded=true, ignore_muted=true)
group_sums = {}
@groups.each do |group|
group_assignments = @assignments.select { |a| a.assignment_group_id == group.id }
@@ -80,10 +89,10 @@ def create_group_sums(submissions, ignore_ungraded=true)
:submission_count => 0}
# collect submissions for this user for all the assignments
- # if an assignment is muted it will be treated as if there is no submission
+ # if an assignment is muted it will be treated as if there is no submission, unless ignore_muted is false
group_assignments.each do |assignment|
submission = submissions.detect { |s| s.assignment_id == assignment.id }
- submission = nil if assignment.muted
+ submission = nil if ignore_muted && assignment.muted
submission ||= OpenStruct.new(:assignment_id=>assignment.id, :score=>0) unless ignore_ungraded
assignment_submissions << {:assignment => assignment, :submission => submission}
end
Something went wrong with that request. Please try again.