2018-06-20 01:36:47 +08:00
|
|
|
#
|
|
|
|
# Copyright (C) 2016 - present 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/>.
|
|
|
|
#
|
|
|
|
|
|
|
|
module Services
|
|
|
|
class SubmitHomeworkService
|
2018-06-26 03:42:09 +08:00
|
|
|
EmailWorker = Struct.new(:message) do
|
2018-06-20 01:36:47 +08:00
|
|
|
def perform
|
|
|
|
Mailer.deliver(Mailer.create_message(message))
|
|
|
|
end
|
2018-06-26 03:42:09 +08:00
|
|
|
|
|
|
|
def on_permanent_failure(error)
|
|
|
|
Canvas::Errors.capture_exception(self.class.name, error)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
CloneUrlExecutor = Struct.new(:url, :duplicate_handling, :check_quota, :opts) do
|
|
|
|
def execute(attachment)
|
|
|
|
attachment.clone_url(url, duplicate_handling, check_quota, opts)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
SubmitWorker = Struct.new(:progress_id, :attachment_id, :eula_agreement_timestamp, :clone_url_executor) do
|
|
|
|
def progress
|
|
|
|
@progress ||= Progress.find(progress_id)
|
|
|
|
end
|
|
|
|
|
|
|
|
def attachment
|
|
|
|
@attachment ||= Attachment.find(attachment_id)
|
|
|
|
end
|
|
|
|
|
2018-07-20 03:23:37 +08:00
|
|
|
def assignment
|
2018-08-24 04:31:02 +08:00
|
|
|
@assignment ||= begin
|
|
|
|
progress.context if progress.context.is_a? Assignment
|
|
|
|
end
|
2018-07-20 03:23:37 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def homework_service
|
|
|
|
@homework_service ||= SubmitHomeworkService.new(attachment, assignment)
|
|
|
|
end
|
|
|
|
|
2018-06-26 03:42:09 +08:00
|
|
|
def perform
|
|
|
|
progress.start
|
|
|
|
clone_url_executor.execute(attachment)
|
2018-07-20 03:23:37 +08:00
|
|
|
progress.reload
|
|
|
|
|
2018-08-24 04:31:02 +08:00
|
|
|
# If the assignment exists, submit it
|
|
|
|
if assignment
|
|
|
|
homework_service.submit(progress.created_at, eula_agreement_timestamp)
|
|
|
|
homework_service.deliver_email
|
|
|
|
end
|
2018-07-20 03:23:37 +08:00
|
|
|
|
|
|
|
progress.complete unless progress.failed?
|
2018-06-26 03:42:09 +08:00
|
|
|
rescue => error
|
|
|
|
mark_as_failure(error)
|
|
|
|
end
|
|
|
|
|
|
|
|
def on_permanent_failure(error)
|
|
|
|
mark_as_failure(error)
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def mark_as_failure(error)
|
2018-07-20 03:23:37 +08:00
|
|
|
progress.reload
|
|
|
|
unless progress.failed?
|
|
|
|
error_id = Canvas::Errors.capture_exception(self.class.name, error)[:error_report]
|
|
|
|
message = "Unexpected error, ID: #{error_id || 'unknown'}"
|
|
|
|
|
|
|
|
attachment.file_state = 'errored'
|
|
|
|
attachment.workflow_state = 'errored'
|
|
|
|
attachment.upload_error_message = message
|
|
|
|
attachment.save
|
|
|
|
|
|
|
|
progress.message = message
|
|
|
|
progress.save
|
|
|
|
progress.fail
|
|
|
|
end
|
|
|
|
|
|
|
|
homework_service.failure_email
|
2018-06-26 03:42:09 +08:00
|
|
|
end
|
2018-06-20 01:36:47 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
class << self
|
2018-06-26 03:42:09 +08:00
|
|
|
def create_clone_url_executor(url, duplicate_handling, check_quota, opts)
|
|
|
|
CloneUrlExecutor.new(url, duplicate_handling, check_quota, opts)
|
|
|
|
end
|
|
|
|
|
|
|
|
def submit_job(progress, attachment, eula_agreement_timestamp, clone_url_executor)
|
|
|
|
SubmitWorker.new(progress.id, attachment.id, eula_agreement_timestamp, clone_url_executor).
|
|
|
|
tap do |worker|
|
2018-09-12 21:37:17 +08:00
|
|
|
Delayed::Job.enqueue(worker,
|
|
|
|
priority: Delayed::HIGH_PRIORITY,
|
|
|
|
n_strand: Attachment.clone_url_strand(clone_url_executor.url))
|
2018-06-26 03:42:09 +08:00
|
|
|
end
|
|
|
|
end
|
2018-07-20 03:23:37 +08:00
|
|
|
end
|
2018-06-26 03:42:09 +08:00
|
|
|
|
2018-07-20 03:23:37 +08:00
|
|
|
def initialize(attachment, assignment)
|
|
|
|
@attachment = attachment
|
|
|
|
@assignment = assignment
|
|
|
|
end
|
2018-06-20 01:36:47 +08:00
|
|
|
|
2018-07-20 03:23:37 +08:00
|
|
|
def submit(submitted_at, eula_agreement_timestamp)
|
|
|
|
opts = {
|
|
|
|
submission_type: 'online_upload',
|
|
|
|
submitted_at: submitted_at,
|
|
|
|
attachments: [@attachment],
|
|
|
|
eula_agreement_timestamp: eula_agreement_timestamp
|
|
|
|
}
|
2018-06-20 01:36:47 +08:00
|
|
|
|
2018-07-20 03:23:37 +08:00
|
|
|
@assignment.submit_homework(@attachment.user, opts)
|
|
|
|
end
|
2018-06-20 01:36:47 +08:00
|
|
|
|
2018-07-20 03:23:37 +08:00
|
|
|
def deliver_email
|
2018-09-08 05:21:21 +08:00
|
|
|
failure_email if @attachment.errored?
|
2018-07-20 03:23:37 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def failure_email
|
|
|
|
body = "Your file, #{@attachment.display_name}, failed to upload to your "\
|
|
|
|
"Canvas assignment, #{@assignment.name}. Please re-submit to "\
|
|
|
|
"the assignment or contact your instructor if you are no "\
|
|
|
|
"longer able to do so."
|
|
|
|
user_email = User.where(id: @attachment.user_id).first.email
|
|
|
|
|
|
|
|
message = OpenStruct.new(
|
|
|
|
from_name: 'notifications@instructure.com',
|
|
|
|
subject: "Submission upload failed: #{@assignment.name}",
|
|
|
|
to: user_email,
|
|
|
|
body: body
|
|
|
|
)
|
|
|
|
queue_email(message)
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def queue_email(message)
|
|
|
|
Delayed::Job.enqueue(EmailWorker.new(message))
|
2018-06-20 01:36:47 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|