forked from opf/openproject
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexport_job.rb
123 lines (98 loc) · 3.24 KB
/
export_job.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
require "active_storage/filename"
module Exports
class ExportJob < ::ApplicationJob
queue_with_priority :above_normal
def perform(export:, user:, mime_type:, query:, **options)
self.export = export
self.current_user = user
self.mime_type = mime_type
self.query = query
self.options = options.with_indifferent_access
User.execute_as(user) do
prepare!
export!
schedule_cleanup
rescue StandardError => e
Rails.logger.error "Failed to run export job for #{user}: #{e.message}"
raise e
end
end
def status_reference
arguments.first[:export]
end
def updates_own_status?
true
end
protected
class_attribute :model
attr_accessor :export, :current_user, :mime_type, :query, :options
def prepare!
raise NotImplementedError
end
def export!
result = exporter_instance.export!
handle_export_result(export, result)
end
def exporter_instance
::Exports::Register
.list_exporter(model, mime_type)
.new(query, options)
end
def handle_export_result(export, result)
case result.content
when File
store_attachment(export, result.content, result)
when Tempfile
store_from_tempfile(export, result)
else
store_from_string(export, result)
end
end
def store_from_tempfile(export, export_result)
renamed_file_path = target_file_name(export_result)
File.rename(export_result.content.path, renamed_file_path)
file = File.open(renamed_file_path)
store_attachment(export, file, export_result)
file.close
end
##
# Create a target file name, replacing any invalid characters
def target_file_name(export_result)
File.join(File.dirname(export_result.content.path), clean_filename(export_result))
end
def schedule_cleanup
CleanupOutdatedJob.perform_after_grace
end
def clean_filename(export_result)
ActiveStorage::Filename.new(export_result.title).sanitized
end
def store_from_string(export, export_result)
with_tempfile(export_result.title, export_result.content) do |file|
store_attachment(export, file, export_result)
end
end
def with_tempfile(title, content)
name_parts = [title[0..title.rindex(".") - 1], title[title.rindex(".")..]]
Tempfile.create(name_parts, encoding: content.encoding) do |file|
file.write content
yield file
end
end
def store_attachment(container, file, export_result)
filename = clean_filename(export_result)
call = Attachments::CreateService
.bypass_whitelist(user: User.current)
.call(container:, file:, filename:, description: "")
call.on_success do
download_url = ::API::V3::Utilities::PathHelper::ApiV3Path.attachment_content(call.result.id)
upsert_status status: :success,
message: I18n.t("export.succeeded"),
payload: download_payload(download_url, export_result.mime_type)
end
call.on_failure do
upsert_status status: :failure,
message: I18n.t("export.failed", message: call.message)
end
end
end
end