-
Notifications
You must be signed in to change notification settings - Fork 2.4k
/
outcome_response_processor.rb
130 lines (115 loc) · 4.53 KB
/
outcome_response_processor.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
require 'turnitin_api'
module Turnitin
class OutcomeResponseProcessor
MAX_ATTEMPTS=11.freeze # this one goes to 11
INTERVAL=5.minutes.freeze
def initialize(tool, assignment, user, outcomes_response_json)
@tool = tool
@assignment = assignment
@user = user
@outcomes_response_json = outcomes_response_json
end
def process
attachment = create_attachment
submission = @assignment.submit_homework(@user, attachments:[attachment], submission_type: 'online_upload')
asset_string = attachment.asset_string
update_turnitin_data!(submission, asset_string, status: 'pending', outcome_response: @outcomes_response_json)
self.send_later(:update_originality_data, submission, asset_string)
end
handle_asynchronously :process, max_attempts: 1, run_at: 5.minutes.from_now, priority: Delayed::LOW_PRIORITY
def resubmit(submission, asset_string)
self.send_later(:update_originality_data, submission, asset_string)
end
def turnitin_client
@turnitin_client ||= (
lti_params = {
'user_id' => Lti::Asset.opaque_identifier_for(@user),
'context_id' => Lti::Asset.opaque_identifier_for(@assignment.context),
'context_title' => @assignment.context.name,
'lis_person_contact_email_primary' => @user.email
}
TurnitinApi::OutcomesResponseTransformer.new(
@tool.consumer_key,
@tool.shared_secret,
lti_params,
@outcomes_response_json
)
)
end
def update_originality_data(submission, asset_string, attempt=1)
if turnitin_client.scored?
update_turnitin_data!(submission, asset_string, turnitin_data)
elsif attempt <= MAX_ATTEMPTS
send_at(INTERVAL.from_now, :update_originality_data, submission, asset_string, attempt + 1)
else
new_data = {
status: 'error',
public_error_message: I18n.t('turnitin.no_score_after_retries', 'Turnitin has not returned a score after %{max_tries} attempts to retrieve one.', max_tries: MAX_ATTEMPTS)
}
update_turnitin_data!(submission, asset_string, new_data)
end
end
# dont try and recreate the turnitin client in a delayed job. bad things happen
def send_later(*args)
stash { super(*args) }
end
# dont try and recreate the turnitin client in a delayed job. bad things happen
def send_at(*args)
stash { super(*args) }
end
private
def stash
old_turnit_client = @turnitin_client
@turnitin_client = nil
yield
@turnitin_client = old_turnit_client
end
def create_attachment
attachment = nil
Dir.mktmpdir do |dirname|
begin
turnitin_client.original_submission do |response|
filename = response.headers['content-disposition'].match(/filename=(\"?)(.+)\1/)[2]
path = File.join(dirname, filename)
File.open(path, 'wb') do |f|
f.write(response.body)
end
attachment = @assignment.attachments.new(
uploaded_data: Rack::Test::UploadedFile.new(path, response.headers['content-type'], true),
display_name: filename,
user: @user
)
attachment.save!
end
rescue StandardError
@assignment.attachments.create!(
uploaded_data: StringIO.new(I18n.t('An error occurred while attempting to contact Turnitin.')),
display_name: 'Failed turnitin submission',
filename: 'failed_turnitin.txt',
user: @user
)
raise
end
end
attachment
end
def turnitin_data
{
similarity_score: turnitin_client.originality_data["numeric"]["score"].to_f,
web_overlap: turnitin_client.originality_data["breakdown"]["internet_score"].to_f,
publication_overlap: turnitin_client.originality_data["breakdown"]["publications_score"].to_f,
student_overlap: turnitin_client.originality_data["breakdown"]["submitted_works_score"].to_f,
state: Turnitin.state_from_similarity_score(turnitin_client.originality_data["numeric"]["score"].to_f),
report_url: turnitin_client.originality_report_url,
status: "scored"
}
end
def update_turnitin_data!(submission, asset_string, new_data)
turnitin_data = submission.turnitin_data || {}
turnitin_data[asset_string] ||= {}
turnitin_data[asset_string].merge!(new_data)
submission.turnitin_data_changed!
submission.save
end
end
end