-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathtasks_controller.rb
More file actions
302 lines (250 loc) · 9.95 KB
/
tasks_controller.rb
File metadata and controls
302 lines (250 loc) · 9.95 KB
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# frozen_string_literal: true
require 'zip'
class TasksController < ApplicationController # rubocop:disable Metrics/ClassLength
include TaskParameters
before_action :load_and_authorize_task, except: %i[index new create import_start import_confirm import_uuid_check import_external]
before_action :load_and_authorize_account_link, only: %i[export_external_start export_external_check export_external_confirm]
before_action :only_authorize_action, only: %i[import_start import_confirm import_uuid_check import_external]
before_action :handle_search_params, only: :index
before_action :set_search, only: [:index]
before_action :redirect_task_contribution, only: %i[create update edit show]
prepend_before_action :set_user_for_api_request, only: %i[import_uuid_check import_external]
skip_before_action :verify_authenticity_token, only: %i[import_uuid_check import_external]
skip_before_action :require_user!, only: %i[show download]
def index
page = params[:page]
@search = Task.visibility(@visibility, current_user).ransack(params[:q])
@tasks = @search.result(distinct: true).paginate(page:, per_page: per_page_param).includes(:ratings, :programming_language,
:labels, :user, :groups).load
authorize @tasks
end
def duplicate
new_entry = @task.clean_duplicate(current_user)
if new_entry.save(context: :force_validations)
redirect_to new_entry, notice: t('common.notices.object_duplicated', model: Task.model_name.human), status: :see_other
else
redirect_to @task, alert: t('.error_alert'), status: :see_other
end
end
def show
@files = @task.files
@tests = @task.tests
@model_solutions = @task.model_solutions
@proforma_valid = ProformaService::Validation.call(task: @task)
@user_rating = @task.ratings&.find_by(user: current_user) || Rating.new(Rating::CATEGORIES.index_with {|_category| 0 })
end
def new
@task = Task.new
authorize @task
end
def edit; end
def create
@task = Task.new(task_params)
TaskService::HandleGroups.call(user: current_user, task: @task, group_tasks_params:)
@task.user = current_user
authorize @task
if @task.save(context: :force_validations)
redirect_to @task, notice: t('common.notices.object_created', model: Task.model_name.human), status: :see_other
else
render :new, status: :unprocessable_content
end
end
def update
@task.assign_attributes(task_params)
TaskService::HandleGroups.call(user: current_user, task: @task, group_tasks_params:)
if @task.save(context: :force_validations)
redirect_to @task, notice: t('common.notices.object_updated', model: Task.model_name.human), status: :see_other
else
render :edit, status: :unprocessable_content
end
end
def destroy
@task.destroy!
redirect_to Task, notice: t('common.notices.object_deleted', model: Task.model_name.human), status: :see_other
end
def add_to_collection
collection = Collection.find(params[:collection])
if collection.add_task(@task)
redirect_to @task, notice: t('.success_notice'), status: :see_other
else
redirect_to @task, alert: t('.error'), status: :see_other
end
end
def download
zip_file = ProformaService::ExportTask.call(task: @task, options: {version: params[:version]})
send_data(zip_file.string, type: 'application/zip', filename: "task_#{@task.id}.zip", disposition: 'attachment')
rescue ProformaXML::PostGenerateValidationError => e
redirect_to :root, danger: JSON.parse(e.message).map {|msg| t("proforma_errors.#{msg}", default: msg) }.join('<br>'), status: :see_other
end
def import_start # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
zip_file = params[:zip_file]
unless zip_file.is_a?(ActionDispatch::Http::UploadedFile)
return render json: {status: 'failure', message: t('.choose_file_error')}
end
@data = ProformaService::CacheImportFile.call(user: current_user, zip_file:)
respond_to do |format|
format.js { render layout: false }
end
rescue ProformaXML::ProformaError => e
messages = prettify_import_errors(e)
flash.now[:alert] = messages
render json: {
status: 'failure',
message: t('.error', error: messages),
actions: '',
}
rescue StandardError => e
Sentry.capture_exception(e)
render json: {
status: 'failure',
message: t('tasks.import.internal_error'),
actions: '',
}
end
def import_confirm # rubocop:disable Metrics/AbcSize
proforma_task = ProformaService::ProformaTaskFromCachedFile.call(**import_confirm_params.to_hash.symbolize_keys)
task = ProformaService::ImportTask.call(proforma_task:, user: current_user)
render json: {
status: 'success',
message: t('.success', title: proforma_task.title),
actions: render_to_string(partial: 'import_actions', locals: {task:, imported: true}),
}
rescue ProformaXML::ProformaError, ActiveRecord::RecordInvalid => e
render json: {
status: 'failure',
message: t('.error', title: proforma_task.title, error: e.message),
actions: '',
}
rescue StandardError => e
Sentry.capture_exception(e)
render json: {
status: 'failure',
message: t('tasks.import.internal_error'),
actions: '',
}
end
def import_uuid_check
task = Task.find_by(uuid: params[:uuid])
return render json: {uuid_found: false} if task.nil?
return render json: {uuid_found: true, update_right: false} unless Pundit.policy(current_user, task).manage?
render json: {uuid_found: true, update_right: true}
end
def import_external
tempfile = tempfile_from_string(request.body.read.force_encoding('UTF-8'))
ProformaService::Import.call(zip: tempfile, user: current_user)
render json: t('.success'), status: :created
rescue ProformaXML::ProformaError
render json: t('.invalid'), status: :bad_request
rescue StandardError => e
Sentry.capture_exception(e)
render json: t('tasks.import.internal_error'), status: :internal_server_error
end
def export_external_start
respond_to do |format|
format.js { render layout: false }
end
end
def export_external_check
external_check = TaskService::CheckExternal.call(uuid: @task.uuid, account_link: @account_link)
render json: {
message: external_check[:message],
actions: render_export_actions(task: @task,
task_found: external_check[:uuid_found],
update_right: external_check[:update_right],
error: external_check[:error],
exported: false),
}, status: :ok
end
def export_external_confirm
push_type = params[:push_type]
return render json: {}, status: :internal_server_error unless %w[create_new export].include? push_type
export_task, error = ProformaService::HandleExportConfirm.call(user: current_user, task: @task, push_type:, account_link: @account_link)
task_title = export_task.title
if error.nil?
render json: {
message: t('.success', title: task_title),
status: 'success', actions: render_export_actions(task: export_task, exported: true)
}
else
export_task.destroy if push_type == 'create_new'
render json: {
message: t('.error', title: task_title, error:),
status: 'fail', actions: render_export_actions(task: @task, exported: false, error:)
}
end
end
def generate_test
GptService::GenerateTests.call(task: @task, openai_api_key: current_user.openai_api_key)
flash.now[:notice] = I18n.t('tasks.task_service.gpt_generate_tests.successful_generation')
rescue Gpt::Error => e
flash.now[:alert] = e.localized_message
ensure
redirect_to @task, status: :see_other
end
private
def prettify_import_errors(error)
message = "#{t('proforma_errors.import')}<br>"
message + JSON.parse(error.message).map do |msg|
t("proforma_errors.#{msg}", default: msg)
end.join('<br>')
end
def load_and_authorize_task
@task = Task.find(params[:id])
authorize @task
end
def load_and_authorize_account_link
@account_link = AccountLink.find(params[:account_link])
authorize @account_link, :use?
end
def only_authorize_action
authorize Task
end
def redirect_task_contribution
return unless @task.present? && @task.contribution?
redirect_to action: action_name, controller: 'task_contributions', task_id: @task.parent, id: @task.task_contribution
end
def set_search # rubocop:disable Metrics/AbcSize
search = params[:q]
@req_labels = []
if search.is_a?(ActionController::Parameters)
@created_before_days = search[:created_before_days]
@min_stars = search[:min_stars]
@access_level = search[:access_level]
@req_labels = Label.where(name: search['has_all_labels'].compact_blank) if search['has_all_labels']
end
@visibility = params[:visibility]&.to_sym || :owner
@advanced_filter_active = params[:advancedFilterActive]
end
def restore_search_params
search_params = session.delete(:task_search_params)&.symbolize_keys || {}
%i[q advancedFilterActive page min_stars].each do |key|
params[key] ||= search_params[key]
end
end
def save_search_params
session[:task_search_params] = {q: params[:q], advancedFilterActive: params[:advancedFilterActive], page: params[:page]}
end
def handle_search_params
restore_search_params
save_search_params
end
def set_user_for_api_request
authorization_header = request.headers['Authorization']
api_key = authorization_header&.split&.second
@current_user = user_by_api_key(api_key)
end
def user_by_api_key(api_key)
AccountLink.find_by(api_key:)&.user
end
def tempfile_from_string(string)
Tempfile.new('codeharbor_import.zip').tap do |tempfile|
tempfile.write string
tempfile.rewind
end
end
def render_export_actions(task:, exported:, error: nil, task_found: nil, update_right: nil)
render_to_string(partial: 'export_actions',
formats: :html,
locals: {task:, exported:, error:, task_found:, update_right:})
end
end