1111# lis_outcome_service_url :string(255)
1212# lis_result_sourcedid :string(255)
1313# score :float(24)
14+ # started_at :datetime
1415# created_at :datetime
1516# updated_at :datetime
1617# lti_workout_id :integer
@@ -110,14 +111,29 @@ def closed?
110111 end
111112
112113 now = Time . zone . now
113- minutes_open = ( now - self . created_at ) /60.0
114+ minutes_open = ( now - self . started_at ) /60.0
114115 time_limit = workout_offering . time_limit_for ( user )
115116 hard_deadline = workout_offering . hard_deadline_for ( user )
116117
117- ( time_limit && self . created_at && minutes_open >= time_limit ) ||
118+ ( time_limit && self . started_at && minutes_open >= time_limit ) ||
118119 ( hard_deadline && now > hard_deadline )
119120 end
120121
122+
123+ # -------------------------------------------------------------
124+ def started_at
125+ val = self . read_attribute ( :started_at )
126+ if !val
127+ # If started_at is null, set it to current time on first access
128+ # and save to database
129+ val = Time . zone . now
130+ write_attribute ( :started_at , val )
131+ save
132+ end
133+ val
134+ end
135+
136+
121137 # -------------------------------------------------------------
122138 # Increase the score of a workout by a specified amount
123139 # FIXME: misnamed method. Used in ExerciseVersion code, though.
@@ -127,6 +143,7 @@ def rescore(delta)
127143 self . save!
128144 end
129145
146+
130147 # -------------------------------------------------------------
131148 def time_remaining
132149 if !workout_offering
@@ -136,7 +153,7 @@ def time_remaining
136153
137154 if time_limit
138155 now = Time . zone . now
139- remaining = time_limit - ( now - self . created_at ) /60.0
156+ remaining = time_limit - ( now - self . started_at ) /60.0
140157 hard_deadline = workout_offering . hard_deadline_for ( user )
141158
142159 if hard_deadline
@@ -165,15 +182,19 @@ def show_feedback?
165182 if workout_offering . shutdown?
166183 # FIXME: ???
167184 # true
168- !workout_offering . andand . workout_policy . andand . hide_feedback_in_review_before_close
185+ !workout_offering . andand . workout_policy . andand .
186+ hide_feedback_in_review_before_close
169187 else
170- !workout_offering . andand . workout_policy . andand . hide_feedback_in_review_before_close
188+ !workout_offering . andand . workout_policy . andand .
189+ hide_feedback_in_review_before_close
171190 end
172191 else
173- !workout_offering . andand . workout_policy . andand . hide_feedback_before_finish
192+ !workout_offering . andand . workout_policy . andand .
193+ hide_feedback_before_finish
174194 end
175195 end
176196
197+
177198 # -------------------------------------------------------------
178199 def attempts_left_for_exercise_version ( exercise_version )
179200 if self . workout_offering . andand . attempt_limit
@@ -187,6 +208,7 @@ def attempts_left_for_exercise_version(exercise_version)
187208 return nil
188209 end
189210
211+
190212 # -------------------------------------------------------------
191213 def scoring_attempt_for ( exercise )
192214 workout_score = self
@@ -218,6 +240,7 @@ def update_attempt(attempt, old_score)
218240 end
219241 end
220242
243+
221244 # -------------------------------------------------------------
222245 def record_attempt ( attempt )
223246 self . with_lock do
@@ -266,6 +289,8 @@ def record_attempt(attempt)
266289 end
267290 end
268291
292+
293+ # ------------------------------------------------------------
269294 def recalculate_score! ( options = { } )
270295 self . with_lock do
271296 attempt = options [ :attempt ]
@@ -319,7 +344,7 @@ def self.late(options={})
319344 WorkoutScore . joins { workout_offering }
320345 . joins ( 'inner join student_extensions on student_extensions.workout_offering_id = workout_offerings.id
321346 and student_extensions.user_id = workout_scores.user_id' )
322- . where ( 'workout_scores.last_attempted_at >
347+ . where ( 'workout_scores.last_attempted_at >
323348 coalesce(student_extensions.hard_deadline, workout_offerings.hard_deadline, "2030-12-31")' )
324349 end
325350
@@ -402,6 +427,7 @@ def self.grade_unprocessed_attempts(exercise_version_id)
402427 end
403428 end
404429
430+
405431 # Sends scores to the appropriate LTI consumer
406432 # -------------------------------------------------------------
407433 def update_lti
@@ -424,4 +450,13 @@ def update_lti
424450 tp . post_replace_result! ( result )
425451 end
426452 end
453+
454+
455+ # -------------------------------------------------------------
456+ # Initialize the started_at field for new objects only
457+ after_initialize do |ws |
458+ if ws . new_record? && ws . has_attribute? ( :started_at ) && !ws . started_at
459+ ws . started_at = Time . zone . now
460+ end
461+ end
427462end
0 commit comments