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



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

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

.evaluate_manually!(teacher_evaluation) ⇒ Object



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

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



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

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)


219
220
221
# File 'app/models/assignment.rb', line 219

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



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

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

#current_contentObject



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

def current_content
  solution || default_content
end

#current_content_at(index) ⇒ Object



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

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

#current_notification_contextsObject



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

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

#default_contentObject



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

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

#errored!(message) ⇒ Object



159
160
161
# File 'app/models/assignment.rb', line 159

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



80
81
82
# File 'app/models/assignment.rb', line 80

def extension
  exercise.language.extension
end

#extraObject



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

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

#extra_previewObject



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

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

#filesObject



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

def files
  exercise.files_for(current_content)
end

#increment_attempts!Object



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

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

#manual_evaluation_pending!Object



139
140
141
# File 'app/models/assignment.rb', line 139

def manual_evaluation_pending!
  update! submission_status: :manual_evaluation_pending
end

#notify!Object



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

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



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

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



100
101
102
103
104
105
# File 'app/models/assignment.rb', line 100

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

#passed!Object



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

def passed!
  update! submission_status: :passed
end

#run_tests!(params) ⇒ Object



168
169
170
# File 'app/models/assignment.rb', line 168

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

#run_update!Object



129
130
131
132
133
134
135
136
137
# File 'app/models/assignment.rb', line 129

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

#running!Object



151
152
153
154
155
156
157
# File 'app/models/assignment.rb', line 151

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

#save_submission!(submission) ⇒ Object



71
72
73
74
75
76
77
78
# File 'app/models/assignment.rb', line 71

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



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

def skipped!
  update! submission_status: :skipped
end

#testObject



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

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

#tipsObject



203
204
205
# File 'app/models/assignment.rb', line 203

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

#to_resource_hObject



172
173
174
175
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
# File 'app/models/assignment.rb', line 172

def to_resource_h
  excluded_fields = i(created_at exercise_id id organization_id parent_id solution submission_id
                       submission_status  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])
      }})
end

#update_misplaced!(value) ⇒ Object



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

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

#update_top_submission!Object



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

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