Class: Assignment

Inherits:
Progress show all
Includes:
Contextualization, Gamified, WithMessages
Defined in:
app/models/assignment.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Gamified

#award_experience_points!, #net_experience

Methods included from WithMessages

#build_message, #has_messages?, #pending_messages?, #receive_answer!, #send_question!

Methods included from Contextualization

#affable_expectation_results, #affable_test_results, #affable_tips, #expectation_results_visible?, #failed_expectation_results, #feedback_html, #first_test_result, #first_test_result_html, #humanized_expectation_results, #iconize, #queries_with_results, #result_html, #results_body_hidden?, #sanitized_affable_test_results, #single_visible_test_result?, #single_visual_result?, #single_visual_result_html, #test_result_html, #visible_expectation_results

Methods inherited from Progress

#_copy_to!, #delete_duplicates_in!, #dirty_parent_by_submission!, #guide_indicator?, #has_duplicates_in?, #parent, #transfer_to!

Methods inherited from ApplicationRecord

active_between, aggregate_of, all_except, defaults, #delete, #destroy!, enum_prefixed_translations_for, numbered, organic_on, resource_fields, #save, #save_and_notify!, #save_and_notify_changes!, serialize_symbolized_hash_array, teaser_on, #update_and_notify!, update_or_create!, whitelist_attributes, with_pg_retry, with_temporary_token

Methods included from WithPgLock

#with_pg_lock

Class Method Details

.build_for(user, exercise, organization) ⇒ Object



252
253
254
# File 'app/models/assignment.rb', line 252

def self.build_for(user, exercise, organization)
  Assignment.new submitter: user, exercise: exercise, organization: organization
end

.evaluate_manually!(teacher_evaluation) ⇒ Object



111
112
113
# File 'app/models/assignment.rb', line 111

def self.evaluate_manually!(teacher_evaluation)
  Assignment.find_by(submission_id: teacher_evaluation[:submission_id])&.evaluate_manually! teacher_evaluation
end

Instance Method Details

#attempts_leftObject



216
217
218
# File 'app/models/assignment.rb', line 216

def attempts_left
  navigable_parent.attempts_left_for(self)
end

#attempts_left?Boolean

Tells whether the submitter of this assignment can keep on sending submissions which is true for non limited or for assignments that have not reached their submissions limit

Returns:

  • (Boolean)


224
225
226
# File 'app/models/assignment.rb', line 224

def attempts_left?
  !limited? || attempts_left > 0
end

#completed_before_last_save?Boolean

Returns:

  • (Boolean)


55
56
57
# File 'app/models/assignment.rb', line 55

def completed_before_last_save?
  status_before_last_save.completed?
end

#completion_changed?Boolean

Returns:

  • (Boolean)


51
52
53
# File 'app/models/assignment.rb', line 51

def completion_changed?
  completed_before_last_save? != completed?
end

#content=(content) ⇒ Object



115
116
117
118
119
# File 'app/models/assignment.rb', line 115

def content=(content)
  if exercise.solvable?
    self.solution = exercise.single_choice? ? exercise.choice_index_for(content) : content
  end
end

#current_contentObject



228
229
230
# File 'app/models/assignment.rb', line 228

def current_content
  solution || default_content
end

#current_content_at(index) ⇒ Object



232
233
234
# File 'app/models/assignment.rb', line 232

def current_content_at(index)
  exercise.sibling_at(index).assignment_for(submitter).current_content
end

#current_notification_contextsObject



95
96
97
# File 'app/models/assignment.rb', line 95

def current_notification_contexts
  [Organization.current, submitter.current_immersive_context_at(exercise)].uniq
end

#default_contentObject



236
237
238
# File 'app/models/assignment.rb', line 236

def default_content
  @default_content ||= language.interpolate_references_for(self, exercise.default_content)
end

#errored!(message) ⇒ Object



163
164
165
# File 'app/models/assignment.rb', line 163

def errored!(message)
  update! result: message, submission_status: :errored
end

#evaluate_manually!(teacher_evaluation) ⇒ Object



59
60
61
# File 'app/models/assignment.rb', line 59

def evaluate_manually!(teacher_evaluation)
  update! status: teacher_evaluation[:status], manual_evaluation_comment: teacher_evaluation[:manual_evaluation]
end

#extensionObject



84
85
86
# File 'app/models/assignment.rb', line 84

def extension
  exercise.language.extension
end

#extraObject



125
126
127
# File 'app/models/assignment.rb', line 125

def extra
  exercise.extra && language.interpolate_references_for(self, exercise.extra)
end

#extra_previewObject



129
130
131
# File 'app/models/assignment.rb', line 129

def extra_preview
  Mumukit::ContentType::Markdown.highlighted_code(language.name, extra)
end

#filesObject



240
241
242
# File 'app/models/assignment.rb', line 240

def files
  exercise.files_for(current_content)
end

#increment_attempts!Object



212
213
214
# File 'app/models/assignment.rb', line 212

def increment_attempts!
  self.attempts_count += 1 if should_retry?
end

#manual_evaluation_pending!Object



143
144
145
# File 'app/models/assignment.rb', line 143

def manual_evaluation_pending!
  update! submission_status: :manual_evaluation_pending
end

#notify!Object



88
89
90
91
92
93
# File 'app/models/assignment.rb', line 88

def notify!
  unless Organization.silenced?
    update_misplaced!(current_notification_contexts.size > 1)
    Mumukit::Nuntius.notify! 'submissions', to_resource_h
  end
end

#notify_to_accessible_organizations!Object



99
100
101
102
# File 'app/models/assignment.rb', line 99

def notify_to_accessible_organizations!
  warn "Don't use notify_to_accessible_organizations!. Use notify_to_student_granted_organizations! instead"
  notify_to_student_granted_organizations!
end

#notify_to_student_granted_organizations!Object



104
105
106
107
108
109
# File 'app/models/assignment.rb', line 104

def notify_to_student_granted_organizations!
  submitter.student_granted_organizations.each do |organization|
    organization.switch!
    notify!
  end
end

#passed!Object



147
148
149
# File 'app/models/assignment.rb', line 147

def passed!
  update! submission_status: :passed
end

#randomized_valuesObject



71
72
73
# File 'app/models/assignment.rb', line 71

def randomized_values
  exercise.randomizer.randomized_values(submitter.id)
end

#run_tests!(params) ⇒ Object



172
173
174
# File 'app/models/assignment.rb', line 172

def run_tests!(params)
  exercise.run_tests! params.merge(extra: extra, test: test, settings: settings)
end

#run_update!Object



133
134
135
136
137
138
139
140
141
# File 'app/models/assignment.rb', line 133

def run_update!
  running!
  begin
    update! yield
  rescue => e
    errored! e.message
    raise e
  end
end

#running!Object



155
156
157
158
159
160
161
# File 'app/models/assignment.rb', line 155

def running!
  update! submission_status: :running,
          result: nil,
          test_results: nil,
          expectation_results: [],
          manual_evaluation_comment: nil
end

#save_submission!(submission) ⇒ Object



75
76
77
78
79
80
81
82
# File 'app/models/assignment.rb', line 75

def save_submission!(submission)
  transaction do
    update! submission_id: submission.id
    update! submitted_at: Time.current
    update_submissions_count!
    update_last_submission!
  end
end

#set_default_top_submission_statusObject



47
48
49
# File 'app/models/assignment.rb', line 47

def set_default_top_submission_status
  self.top_submission_status ||= 0
end

#skipped!Object



151
152
153
# File 'app/models/assignment.rb', line 151

def skipped!
  update! submission_status: :skipped
end

#testObject



121
122
123
# File 'app/models/assignment.rb', line 121

def test
  exercise.test && language.interpolate_references_for(self, exercise.test)
end

#tipsObject



208
209
210
# File 'app/models/assignment.rb', line 208

def tips
  @tips ||= exercise.assist_with(self)
end

#to_resource_hObject



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'app/models/assignment.rb', line 176

def to_resource_h
  excluded_fields = %i(created_at exercise_id id organization_id parent_id solution submission_id
                       submission_status submitted_at submitter_id top_submission_status updated_at misplaced)

  as_json(except: excluded_fields,
            include: {
              guide: {
                only: [:slug, :name],
                include: {
                  lesson: {only: [:number]},
                  language: {only: [:name]}},
              },
              exercise: {only: [:name, :number]},
              submitter: {only: [:email, :social_id, :uid], methods: [:name, :profile_picture]}})
    .deep_merge(
      'organization' => Organization.current.name,
      'sid' => submission_id,
      'created_at' =>  || updated_at,
      'content' => solution,
      'status' => submission_status,
      'exercise' => {
        'eid' => exercise.bibliotheca_id
      },
      'guide' => {'parent' => {
        'type' => navigable_parent.class.to_s,
        'name' => navigable_parent.name,
        'position' => navigable_parent.try(:number),
        'chapter' => guide.chapter.as_json(only: [:id], methods: [:name])
      }})
    .merge({'randomized_values' => randomized_values.presence}.compact)
end

#update_misplaced!(value) ⇒ Object



248
249
250
# File 'app/models/assignment.rb', line 248

def update_misplaced!(value)
  update! misplaced: value if value != misplaced?
end

#update_top_submission!Object



244
245
246
# File 'app/models/assignment.rb', line 244

def update_top_submission!
  self.top_submission_status = submission_status unless submission_status.improved_by?(top_submission_status)
end

#visible_statusObject



63
64
65
66
67
68
69
# File 'app/models/assignment.rb', line 63

def visible_status
  if results_hidden? && !pending?
    :manual_evaluation_pending.to_submission_status
  else
    super
  end
end