532 lines
24 KiB
Ruby
532 lines
24 KiB
Ruby
#
|
|
# Copyright (C) 2012 - 2014 Instructure, Inc.
|
|
#
|
|
# This file is part of Canvas.
|
|
#
|
|
# Canvas is free software: you can redistribute it and/or modify it under
|
|
# the terms of the GNU Affero General Public License as published by the Free
|
|
# Software Foundation, version 3 of the License.
|
|
#
|
|
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License along
|
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
class GradebooksController < ApplicationController
|
|
include ActionView::Helpers::NumberHelper
|
|
include GradebooksHelper
|
|
include KalturaHelper
|
|
include Api::V1::AssignmentGroup
|
|
include Api::V1::Submission
|
|
include Api::V1::CustomGradebookColumn
|
|
|
|
before_filter :require_context
|
|
before_filter :require_user, only: %w(speed_grader speed_grader_settings)
|
|
|
|
batch_jobs_in_actions :only => :update_submission, :batch => { :priority => Delayed::LOW_PRIORITY }
|
|
|
|
add_crumb(proc { t '#crumbs.grades', "Grades" }) { |c| c.send :named_context_url, c.instance_variable_get("@context"), :context_grades_url }
|
|
before_filter { |c| c.active_tab = "grades" }
|
|
|
|
def grade_summary
|
|
@presenter = GradeSummaryPresenter.new(@context, @current_user, params[:id])
|
|
# do this as the very first thing, if the current user is a teacher in the course and they are not trying to view another user's grades, redirect them to the gradebook
|
|
if @presenter.user_needs_redirection?
|
|
return redirect_to polymorphic_url([@context, 'gradebook'])
|
|
end
|
|
|
|
if !@presenter.student || !@presenter.student_enrollment
|
|
return render_unauthorized_action
|
|
end
|
|
|
|
if authorized_action(@presenter.student_enrollment, @current_user, :read_grades)
|
|
log_asset_access([ "grades", @context ], "grades", "other")
|
|
if @presenter.student
|
|
add_crumb(@presenter.student_name, named_context_url(@context, :context_student_grades_url, @presenter.student_id))
|
|
|
|
gp_id = nil
|
|
if multiple_grading_periods?
|
|
set_current_grading_period
|
|
@grading_periods = get_active_grading_periods
|
|
gp_id = @current_grading_period_id unless view_all_grading_periods?
|
|
end
|
|
|
|
Shackles.activate(:slave) do
|
|
#run these queries on the slave database for speed
|
|
@presenter.assignments(gp_id)
|
|
@presenter.groups_assignments = groups_as_assignments(@presenter.groups, :out_of_final => true, :exclude_total => @context.hide_final_grades?)
|
|
@presenter.submissions
|
|
@presenter.submission_counts
|
|
@presenter.assignment_stats
|
|
end
|
|
|
|
submissions_json = @presenter.submissions.map { |s|
|
|
{
|
|
'assignment_id' => s.assignment_id,
|
|
'score' => s.grants_right?(@current_user, :read_grade)? s.score : nil
|
|
}
|
|
}
|
|
ags_json = light_weight_ags_json(@presenter.groups, {student: @presenter.student})
|
|
js_env submissions: submissions_json,
|
|
assignment_groups: ags_json,
|
|
group_weighting_scheme: @context.group_weighting_scheme,
|
|
show_total_grade_as_points: @context.settings[:show_total_grade_as_points],
|
|
grading_scheme: @context.grading_standard.try(:data) || GradingStandard.default_grading_standard,
|
|
grading_period: @grading_periods && @grading_periods.find {|grading_period| grading_period[:id].to_s == gp_id},
|
|
student_outcome_gradebook_enabled: @context.feature_enabled?(:student_outcome_gradebook),
|
|
student_id: @presenter.student_id
|
|
else
|
|
render :grade_summary_list
|
|
end
|
|
end
|
|
end
|
|
|
|
def light_weight_ags_json(assignment_groups, opts={})
|
|
assignment_groups.map do |ag|
|
|
assignments = ag.visible_assignments(opts[:student] || @current_user).map do |a|
|
|
{
|
|
:id => a.id,
|
|
:submission_types => a.submission_types_array,
|
|
:points_possible => a.points_possible,
|
|
:due_at => a.due_at
|
|
}
|
|
end
|
|
{
|
|
:id => ag.id,
|
|
:rules => ag.rules_hash({stringify_json_ids: true}),
|
|
:group_weight => ag.group_weight,
|
|
:assignments => assignments,
|
|
}
|
|
end
|
|
end
|
|
|
|
def grading_rubrics
|
|
@rubric_contexts = @context.rubric_contexts(@current_user)
|
|
if params[:context_code]
|
|
context = @rubric_contexts.detect{|r| r[:context_code] == params[:context_code] }
|
|
@rubric_context = @context
|
|
if context
|
|
@rubric_context = Context.find_by_asset_string(params[:context_code])
|
|
end
|
|
@rubric_associations = @context.sorted_rubrics(@current_user, @rubric_context)
|
|
render :json => @rubric_associations.map{ |r| r.as_json(methods: [:context_name], include: {:rubric => {:include_root => false}}) }
|
|
else
|
|
render :json => @rubric_contexts
|
|
end
|
|
end
|
|
|
|
def attendance
|
|
@enrollment = @context.all_student_enrollments.where(user_id: params[:user_id]).first if params[:user_id].present?
|
|
@enrollment ||= @context.all_student_enrollments.where(user_id: @current_user).first if !@context.grants_right?(@current_user, session, :manage_grades)
|
|
add_crumb t(:crumb, 'Attendance')
|
|
if !@enrollment && @context.grants_right?(@current_user, session, :manage_grades)
|
|
@assignments = @context.assignments.active.where(:submission_types => 'attendance').all
|
|
@students = @context.students_visible_to(@current_user).order_by_sortable_name
|
|
@at_least_one_due_at = @assignments.any?{|a| a.due_at }
|
|
# Find which assignment group most attendance items belong to,
|
|
# it'll be a better guess for default assignment group than the first
|
|
# in the list...
|
|
@default_group_id = @assignments.to_a.inject(Hash.new(0)){|h,a| h[a.assignment_group_id] += 1; h}.sort_by{|id, cnt| cnt }.reverse.first[0] rescue nil
|
|
elsif @enrollment && @enrollment.grants_right?(@current_user, session, :read_grades)
|
|
@assignments = @context.assignments.active.where(:submission_types => 'attendance').all
|
|
@students = @context.students_visible_to(@current_user).order_by_sortable_name
|
|
@submissions = @context.submissions.where(user_id: @enrollment.user_id).to_a
|
|
@user = @enrollment.user
|
|
render :student_attendance
|
|
# render student_attendance, optional params[:assignment_id] to highlight and scroll to that particular assignment
|
|
else
|
|
flash[:notice] = t('notices.unauthorized', "You are not authorized to view attendance for this course")
|
|
redirect_to named_context_url(@context, :context_url)
|
|
# redirect
|
|
end
|
|
end
|
|
|
|
def show
|
|
if authorized_action(@context, @current_user, [:manage_grades, :view_all_grades])
|
|
@last_exported_gradebook_csv = @context.gradebook_csvs.where(user_id: @current_user).first
|
|
set_current_grading_period if multiple_grading_periods?
|
|
set_js_env
|
|
case @current_user.preferred_gradebook_version
|
|
when "2"
|
|
render :gradebook2
|
|
return
|
|
when "srgb"
|
|
render :screenreader
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
def gradebook2
|
|
redirect_to action: :show
|
|
end
|
|
|
|
def set_current_grading_period
|
|
unless @current_grading_period_id = params[:grading_period_id].presence
|
|
return if view_all_grading_periods?
|
|
return unless current = GradingPeriod.for(@context).find(&:current?)
|
|
@current_grading_period_id = current.id.to_s
|
|
end
|
|
end
|
|
|
|
def view_all_grading_periods?
|
|
@current_grading_period_id == "0"
|
|
end
|
|
|
|
def get_active_grading_periods
|
|
GradingPeriod.for(@context).map do |gp|
|
|
json = gp.as_json(only: [:id, :title, :start_date, :end_date], permissions: {user: @current_user})
|
|
json[:grading_period][:is_last] = gp.last?
|
|
json[:grading_period]
|
|
end
|
|
end
|
|
|
|
def set_js_env
|
|
@gradebook_is_editable = @context.grants_right?(@current_user, session, :manage_grades)
|
|
per_page = Setting.get('api_max_per_page', '50').to_i
|
|
teacher_notes = @context.custom_gradebook_columns.not_deleted.where(:teacher_notes=> true).first
|
|
ag_includes = [:assignments]
|
|
ag_includes << :assignment_visibility if @context.feature_enabled?(:differentiated_assignments)
|
|
ag_includes << 'overrides' if @context.feature_enabled?(:differentiated_assignments)
|
|
js_env :GRADEBOOK_OPTIONS => {
|
|
:chunk_size => Setting.get('gradebook2.submissions_chunk_size', '35').to_i,
|
|
:assignment_groups_url => api_v1_course_assignment_groups_url(@context, :include => ag_includes, :override_assignment_dates => "false"),
|
|
:sections_url => api_v1_course_sections_url(@context, :include => 'passback_status'),
|
|
:course_url => api_v1_course_url(@context, :include => 'passback_status'),
|
|
:students_url => api_v1_course_enrollments_url(@context, :include => [:avatar_url], :type => ['StudentEnrollment', 'StudentViewEnrollment'], :per_page => per_page),
|
|
:students_url_with_concluded_enrollments => api_v1_course_enrollments_url(@context, :include => [:avatar_url], :type => ['StudentEnrollment', 'StudentViewEnrollment'], :state => ['active', 'invited', 'completed'], :per_page => per_page),
|
|
:submissions_url => api_v1_course_student_submissions_url(@context, :grouped => '1'),
|
|
:outcome_links_url => api_v1_course_outcome_group_links_url(@context, :outcome_style => :full),
|
|
:outcome_rollups_url => api_v1_course_outcome_rollups_url(@context, :per_page => 100),
|
|
:change_grade_url => api_v1_course_assignment_submission_url(@context, ":assignment", ":submission", :include =>[:visibility]),
|
|
:context_url => named_context_url(@context, :context_url),
|
|
:download_assignment_submissions_url => named_context_url(@context, :context_assignment_submissions_url, "{{ assignment_id }}", :zip => 1),
|
|
:re_upload_submissions_url => named_context_url(@context, :submissions_upload_context_gradebook_url, "{{ assignment_id }}"),
|
|
:context_id => @context.id,
|
|
:context_code => @context.asset_string,
|
|
:context_sis_id => @context.sis_source_id,
|
|
:group_weighting_scheme => @context.group_weighting_scheme,
|
|
:grading_standard => @context.grading_standard_enabled? && (@context.grading_standard.try(:data) || GradingStandard.default_grading_standard),
|
|
:course_is_concluded => @context.completed?,
|
|
:gradebook_is_editable => @gradebook_is_editable,
|
|
:setting_update_url => api_v1_course_settings_url(@context),
|
|
:show_total_grade_as_points => @context.settings[:show_total_grade_as_points],
|
|
:publish_to_sis_enabled => @context.allows_grade_publishing_by(@current_user) && @gradebook_is_editable,
|
|
:publish_to_sis_url => context_url(@context, :context_details_url, :anchor => 'tab-grade-publishing'),
|
|
:speed_grader_enabled => @context.allows_speed_grader?,
|
|
:differentiated_assignments_enabled => @context.feature_enabled?(:differentiated_assignments),
|
|
:multiple_grading_periods_enabled => multiple_grading_periods?,
|
|
:active_grading_periods => get_active_grading_periods,
|
|
:current_grading_period_id => @current_grading_period_id,
|
|
:outcome_gradebook_enabled => @context.feature_enabled?(:outcome_gradebook),
|
|
:custom_columns_url => api_v1_course_custom_gradebook_columns_url(@context),
|
|
:custom_column_url => api_v1_course_custom_gradebook_column_url(@context, ":id"),
|
|
:custom_column_data_url => api_v1_course_custom_gradebook_column_data_url(@context, ":id", per_page: per_page),
|
|
:custom_column_datum_url => api_v1_course_custom_gradebook_column_datum_url(@context, ":id", ":user_id"),
|
|
:reorder_custom_columns_url => api_v1_custom_gradebook_columns_reorder_url(@context),
|
|
:teacher_notes => teacher_notes && custom_gradebook_column_json(teacher_notes, @current_user, session),
|
|
:change_gradebook_version_url => context_url(@context, :change_gradebook_version_context_gradebook_url, :version => 2),
|
|
:export_gradebook_csv_url => course_gradebook_csv_url,
|
|
:gradebook_csv_progress => @last_exported_gradebook_csv.try(:progress),
|
|
:attachment_url => @last_exported_gradebook_csv.try(:attachment).try(:download_url),
|
|
:attachment => @last_exported_gradebook_csv.try(:attachment),
|
|
:sis_app_url => Setting.get('sis_app_url', nil),
|
|
:sis_app_token => Setting.get('sis_app_token', nil),
|
|
:post_grades_feature_enabled => Assignment.show_sis_grade_export_option?(@context),
|
|
:list_students_by_sortable_name_enabled => @context.feature_enabled?(:gradebook_list_students_by_sortable_name),
|
|
:gradebook_column_size_settings => @current_user.preferences[:gradebook_column_size],
|
|
:gradebook_column_size_settings_url => change_gradebook_column_size_course_gradebook_url,
|
|
:gradebook_column_order_settings => @current_user.preferences[:gradebook_column_order].try(:[], @context.id),
|
|
:gradebook_column_order_settings_url => save_gradebook_column_order_course_gradebook_url
|
|
}
|
|
end
|
|
|
|
def history
|
|
if authorized_action(@context, @current_user, :manage_grades)
|
|
#
|
|
# Temporary disabling of this page for large courses
|
|
# We need some reworking of the gradebook history to allow using it
|
|
# in large courses in a performant manner. Until that happens, we're
|
|
# disabling it over a certain threshold.
|
|
#
|
|
submissions_count = @context.submissions.count
|
|
submissions_limit = Setting.get('gradebook_history_submission_count_threshold', '0').to_i
|
|
if submissions_limit == 0 || submissions_count <= submissions_limit
|
|
# TODO this whole thing could go a LOT faster if you just got ALL the versions of ALL the submissions in this course then did a ruby sort_by day then grader
|
|
@days = SubmissionList.days(@context)
|
|
end
|
|
|
|
respond_to do |format|
|
|
format.html
|
|
end
|
|
end
|
|
end
|
|
|
|
def update_submission
|
|
if authorized_action(@context, @current_user, :manage_grades)
|
|
if params[:submissions].blank? && params[:submission].blank?
|
|
render nothing: true, status: 400
|
|
return
|
|
end
|
|
|
|
submissions = if params[:submissions]
|
|
params[:submissions].values
|
|
else
|
|
[params[:submission]]
|
|
end
|
|
|
|
valid_user_ids = Set.new(@context.students_visible_to(@current_user).pluck(:id))
|
|
submissions.select! { |s| valid_user_ids.include? s[:user_id].to_i }
|
|
users = @context.students.uniq.find(submissions.map { |s| s[:user_id] })
|
|
.index_by(&:id)
|
|
assignments = @context.assignments.active.find(submissions.map { |s|
|
|
s[:assignment_id]
|
|
}).index_by(&:id)
|
|
|
|
@submissions = []
|
|
submissions.compact.each do |submission|
|
|
@assignment = assignments[submission[:assignment_id].to_i]
|
|
@user = users[submission[:user_id].to_i]
|
|
submission[:grader] = @current_user
|
|
submission.delete :comment_attachments
|
|
if params[:attachments]
|
|
attachments = []
|
|
params[:attachments].each do |idx, attachment|
|
|
attachment[:user] = @current_user
|
|
attachments << @assignment.attachments.create(attachment)
|
|
end
|
|
submission[:comment_attachments] = attachments
|
|
end
|
|
begin
|
|
# if it's a percentage graded assignment, we need to ensure there's a
|
|
# percent sign on the end. eventually this will probably be done in
|
|
# the javascript.
|
|
if @assignment.grading_type == "percent" && submission[:grade] && submission[:grade] !~ /%\z/
|
|
submission[:grade] = "#{submission[:grade]}%"
|
|
end
|
|
|
|
submission[:dont_overwrite_grade] = value_to_boolean(params[:dont_overwrite_grades])
|
|
@submissions += @assignment.grade_student(@user, submission)
|
|
rescue Assignment::GradeError => e
|
|
logger.info "GRADES: grade_student failed because '#{e.message}'"
|
|
@error_message = e.to_s
|
|
end
|
|
end
|
|
@submissions = @submissions.reverse.uniq.reverse
|
|
@submissions = nil if submissions.empty? # no valid submissions
|
|
|
|
respond_to do |format|
|
|
if @submissions && !@error_message#&& !@submission.errors || @submission.errors.empty?
|
|
flash[:notice] = t('notices.updated', 'Assignment submission was successfully updated.')
|
|
format.html { redirect_to course_gradebook_url(@assignment.context) }
|
|
format.json {
|
|
render :json => @submissions.map{ |s| s.as_json(Submission.json_serialization_full_parameters) }, :status => :created, :location => course_gradebook_url(@assignment.context)
|
|
}
|
|
format.text {
|
|
render :json => @submissions.map{ |s| s.as_json(Submission.json_serialization_full_parameters) }, :status => :created, :location => course_gradebook_url(@assignment.context),
|
|
:as_text => true
|
|
}
|
|
else
|
|
flash[:error] = t('errors.submission_failed', "Submission was unsuccessful: %{error}", :error => @error_message || t('errors.submission_failed_default', 'Submission Failed'))
|
|
format.html { render :show, course_id: @assignment.context.id }
|
|
format.json { render :json => {:errors => {:base => @error_message}}, :status => :bad_request }
|
|
format.text { render :json => {:errors => {:base => @error_message}}, :status => :bad_request }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def submissions_zip_upload
|
|
unless @context.allows_gradebook_uploads?
|
|
flash[:error] = t('errors.not_allowed', "This course does not allow score uploads.")
|
|
redirect_to named_context_url(@context, :context_assignment_url, @assignment.id)
|
|
return
|
|
end
|
|
@assignment = @context.assignments.active.find(params[:assignment_id])
|
|
if !params[:submissions_zip] || params[:submissions_zip].is_a?(String)
|
|
flash[:error] = t('errors.missing_file', "Could not find file to upload")
|
|
redirect_to named_context_url(@context, :context_assignment_url, @assignment.id)
|
|
return
|
|
end
|
|
@comments, @failures = @assignment.generate_comments_from_files(params[:submissions_zip].path, @current_user)
|
|
flash[:notice] = t('notices.uploaded',
|
|
{ :one => "Files and comments created for 1 submission",
|
|
:other => "Files and comments created for %{count} submissions" },
|
|
:count => @comments.length)
|
|
end
|
|
|
|
def speed_grader
|
|
if !@context.allows_speed_grader?
|
|
flash[:notice] = t(:speed_grader_disabled, 'SpeedGrader is disabled for this course')
|
|
return redirect_to(course_gradebook_path(@context))
|
|
end
|
|
|
|
return unless authorized_action(@context, @current_user, [:manage_grades, :view_all_grades])
|
|
|
|
@assignment = @context.assignments.active.find(params[:assignment_id])
|
|
if @assignment.unpublished?
|
|
flash[:notice] = t(:speedgrader_enabled_only_for_published_content,
|
|
'SpeedGrader is enabled only for published content.')
|
|
return redirect_to polymorphic_url([@context, @assignment])
|
|
end
|
|
|
|
respond_to do |format|
|
|
format.html do
|
|
@headers = false
|
|
@outer_frame = true
|
|
log_asset_access([ "speed_grader", @context ], "grades", "other")
|
|
env = {
|
|
:CONTEXT_ACTION_SOURCE => :speed_grader,
|
|
:settings_url => speed_grader_settings_course_gradebook_path,
|
|
}
|
|
if @assignment.quiz
|
|
env[:quiz_history_url] = course_quiz_history_path @context.id,
|
|
@assignment.quiz.id,
|
|
:user_id => "{{user_id}}"
|
|
end
|
|
append_sis_data(env)
|
|
js_env(env)
|
|
render
|
|
end
|
|
|
|
format.json do
|
|
render :json => @assignment.speed_grader_json(@current_user, service_enabled?(:avatars))
|
|
end
|
|
end
|
|
end
|
|
|
|
def speed_grader_settings
|
|
grade_by_question = value_to_boolean(params[:enable_speedgrader_grade_by_question])
|
|
@current_user.preferences[:enable_speedgrader_grade_by_question] = grade_by_question
|
|
@current_user.save!
|
|
render nothing: true
|
|
end
|
|
|
|
def blank_submission
|
|
@headers = false
|
|
end
|
|
|
|
def change_gradebook_column_size
|
|
if authorized_action(@context, @current_user, :manage_grades)
|
|
unless @current_user.preferences.key?(:gradebook_column_size)
|
|
@current_user.preferences[:gradebook_column_size] = {}
|
|
end
|
|
|
|
@current_user.preferences[:gradebook_column_size][params[:column_id]] = params[:column_size]
|
|
@current_user.save!
|
|
render json: nil
|
|
end
|
|
end
|
|
|
|
def save_gradebook_column_order
|
|
if authorized_action(@context, @current_user, :manage_grades)
|
|
unless @current_user.preferences.key?(:gradebook_column_order)
|
|
@current_user.preferences[:gradebook_column_order] = {}
|
|
end
|
|
|
|
@current_user.preferences[:gradebook_column_order][@context.id] = params[:column_order]
|
|
@current_user.save!
|
|
render json: nil
|
|
end
|
|
end
|
|
|
|
def change_gradebook_version
|
|
@current_user.preferences[:gradebook_version] = params[:version]
|
|
@current_user.save!
|
|
redirect_to polymorphic_url([@context, 'gradebook'])
|
|
end
|
|
|
|
def groups_as_assignments(groups=nil, options = {})
|
|
groups ||= @context.assignment_groups.active
|
|
|
|
percentage = lambda do |weight|
|
|
# find the smallest precision necessary to capture up to two digits of
|
|
# significant decimals, but to avoid unnecessary zeros on the end. (so we
|
|
# can have 100%, but still have 33.33%, for example)
|
|
precision = sprintf('%.2f', weight % 1).sub(/^(?:0|1)\.(\d?[1-9])?0*$/, '\1').length
|
|
number_to_percentage(weight, :precision => precision)
|
|
end
|
|
|
|
points_possible =
|
|
(@context.group_weighting_scheme == "percent") ?
|
|
(options[:out_of_final] ?
|
|
lambda{ |group| t(:out_of_final, "%{weight} of Final", :weight => percentage[group.group_weight]) } :
|
|
lambda{ |group| percentage[group.group_weight] }) :
|
|
lambda{ |group| nil }
|
|
|
|
groups = groups.map { |group|
|
|
OpenObject.build('assignment',
|
|
:id => 'group-' + group.id.to_s,
|
|
:rules => group.rules,
|
|
:title => group.name,
|
|
:points_possible => points_possible[group],
|
|
:hard_coded => true,
|
|
:special_class => 'group_total',
|
|
:assignment_group_id => group.id,
|
|
:group_weight => group.group_weight,
|
|
:asset_string => "group_total_#{group.id}")
|
|
}
|
|
|
|
groups << OpenObject.build('assignment',
|
|
:id => 'final-grade',
|
|
:title => t('titles.total', 'Total'),
|
|
:points_possible => (options[:out_of_final] ? '' : percentage[100]),
|
|
:hard_coded => true,
|
|
:special_class => 'final_grade',
|
|
:asset_string => "final_grade_column") unless options[:exclude_total]
|
|
groups = [] if options[:exclude_total] && groups.length == 1
|
|
groups
|
|
end
|
|
|
|
def set_gradebook_warnings(groups, assignments)
|
|
@assignments_in_bad_groups = Set.new
|
|
|
|
if @context.group_weighting_scheme == "percent"
|
|
assignments_by_group = assignments.group_by(&:assignment_group_id)
|
|
bad_groups = groups.select do |group|
|
|
group_assignments = assignments_by_group[group.id] || []
|
|
points_in_group = group_assignments.map(&:points_possible).compact.sum
|
|
points_in_group.zero?
|
|
end
|
|
|
|
bad_group_ids = bad_groups.map(&:id)
|
|
bad_assignment_ids = assignments_by_group.
|
|
slice(*bad_group_ids).
|
|
values.
|
|
flatten
|
|
|
|
@assignments_in_bad_groups.replace bad_assignment_ids
|
|
|
|
warning = t('invalid_assignment_groups_warning',
|
|
{:one => "Score does not include %{groups} because " \
|
|
"it has no points possible",
|
|
:other => "Score does not include %{groups} because " \
|
|
"they have no points possible"},
|
|
:groups => bad_groups.map(&:name).to_sentence,
|
|
:count => bad_groups.size)
|
|
else
|
|
if assignments.all? { |a| (a.points_possible || 0).zero? }
|
|
warning = t(:no_assignments_have_points_warning,
|
|
"Can't compute score until an assignment " \
|
|
"has points possible")
|
|
end
|
|
end
|
|
|
|
js_env :total_grade_warning => warning if warning
|
|
end
|
|
private :set_gradebook_warnings
|
|
|
|
|
|
def assignment_groups_json(opts={})
|
|
@context.assignment_groups.active.includes(:published_assignments).map { |g|
|
|
assignment_group_json(g, @current_user, session, ['assignments'], {
|
|
stringify_json_ids: opts[:stringify_json_ids] || stringify_json_ids?
|
|
})
|
|
}
|
|
end
|
|
end
|