@@ -8,13 +8,16 @@ class Course::Gradebook::Contribution < ApplicationRecord
88 belongs_to :course , inverse_of : :gradebook_contributions
99 belongs_to :tab , class_name : 'Course::Assessment::Tab' ,
1010 inverse_of : :gradebook_contribution , optional : true
11+ belongs_to :external_assessment , class_name : 'Course::ExternalAssessment' ,
12+ inverse_of : :gradebook_contribution , optional : true
1113
1214 validates :creator , presence : true
1315 validates :updater , presence : true
1416 validates :weight , numericality : { greater_than_or_equal_to : 0 , less_than_or_equal_to : 100 }
1517 validates :weight_mode , presence : true
1618 validates :keep_highest , numericality : { only_integer : true , greater_than_or_equal_to : 0 }
17- validates :tab_id , uniqueness : true
19+ validates :tab_id , uniqueness : { allow_nil : true }
20+ validates :external_assessment_id , uniqueness : { allow_nil : true }
1821 validate :exactly_one_contributor
1922 validate :course_matches_contributor
2023 # Bulk-upserts tab contributions and their per-assessment contributions for a course.
@@ -27,13 +30,22 @@ class Course::Gradebook::Contribution < ApplicationRecord
2730 # @param updates [Array<Hash>] each { tab_id:, weight:, weight_mode:, keep_highest:,
2831 # excluded_assessment_ids: [Integer], assessment_weights: [{ assessment_id:, weight: }] }
2932 def self . bulk_update ( course :, updates :)
33+ external_updates , tab_updates = updates . partition { |e | e [ :tab_id ] . to_i < 0 }
34+
3035 course_tab_ids = course . assessment_tabs . pluck ( :id ) . to_set
31- updates . each { |e | raise ActiveRecord ::RecordNotFound unless course_tab_ids . include? ( e [ :tab_id ] ) }
36+ tab_updates . each { |e | raise ActiveRecord ::RecordNotFound unless course_tab_ids . include? ( e [ :tab_id ] ) }
37+
38+ external_ids = external_updates . map { |e | -e [ :tab_id ] }
39+ externals_by_id = course . external_assessments . where ( id : external_ids ) . index_by ( &:id )
40+ external_updates . each { |e | raise ActiveRecord ::RecordNotFound unless externals_by_id . key? ( -e [ :tab_id ] ) }
3241
33- tabs_by_id = Course ::Assessment ::Tab . where ( id : updates . map { |e | e [ :tab_id ] } ) .
42+ tabs_by_id = Course ::Assessment ::Tab . where ( id : tab_updates . map { |e | e [ :tab_id ] } ) .
3443 includes ( :assessments ) . index_by ( &:id )
3544
36- transaction { updates . each { |entry | apply_entry ( course , tabs_by_id , entry ) } }
45+ transaction do
46+ tab_updates . each { |entry | apply_entry ( course , tabs_by_id , entry ) }
47+ external_updates . each { |entry | apply_external_entry ( course , externals_by_id [ -entry [ :tab_id ] ] , entry ) }
48+ end
3749 end
3850
3951 # @api private
@@ -58,6 +70,16 @@ def self.apply_entry(course, tabs_by_id, entry)
5870 end
5971 private_class_method :apply_entry
6072
73+ # @api private
74+ def self . apply_external_entry ( course , external , entry )
75+ contribution = find_or_initialize_by ( external_assessment_id : external . id )
76+ contribution . tab = nil
77+ contribution . course = course
78+ contribution . assign_attributes ( weight : entry [ :weight ] , weight_mode : 'equal' , keep_highest : 0 )
79+ contribution . save!
80+ end
81+ private_class_method :apply_external_entry
82+
6183 # @api private
6284 def self . assessment_contribution_for ( assessment )
6385 Course ::Gradebook ::AssessmentContribution . find_or_initialize_by ( assessment_id : assessment . id )
@@ -117,15 +139,19 @@ def self.validate_custom_assessment_weights_sum!(tab, entry, included_sum, inclu
117139
118140 private
119141
120- # Until the external-alignment design adds `external_assessment_id`, the only
121- # contributor is the tab, so "exactly one" reduces to "tab present".
122142 def exactly_one_contributor
123- errors . add ( :tab , :blank ) if tab_id . blank?
143+ return if [ tab_id , external_assessment_id ] . compact . size == 1
144+
145+ errors . add ( :base , :exactly_one_contributor )
124146 end
125147
126148 def course_matches_contributor
127- return if tab . nil? || course . nil?
149+ return if course . nil?
128150
129- errors . add ( :course , :invalid ) if tab . category . course_id != course_id
151+ contributor_course_id =
152+ if tab then tab . category . course_id
153+ elsif external_assessment then external_assessment . course_id
154+ end
155+ errors . add ( :course , :invalid ) if contributor_course_id && contributor_course_id != course_id
130156 end
131157end
0 commit comments