-
Notifications
You must be signed in to change notification settings - Fork 194
/
attachment_data.rb
235 lines (176 loc) · 6.05 KB
/
attachment_data.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
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
require "pdf-reader"
require "timeout"
class AttachmentData < ApplicationRecord
mount_uploader :file, AttachmentUploader, mount_on: :carrierwave_file
has_many :attachments, -> { order(:attachable_id) }, inverse_of: :attachment_data
has_many :assets,
as: :assetable,
inverse_of: :assetable
delegate :url, :path, to: :file, allow_nil: true
before_save :update_file_attributes
validates :file, presence: true
validate :file_is_not_empty
attr_accessor :to_replace_id, :attachable
belongs_to :replaced_by, class_name: "AttachmentData"
validate :cant_be_replaced_by_self
after_save :handle_to_replace_id
OPENDOCUMENT_EXTENSIONS = %w[ODT ODP ODS].freeze
def filename
file.present? && file.file.filename
end
def filename_without_extension
filename && filename.sub(/.[^.]*$/, "")
end
def file_extension
File.extname(filename).delete(".") if filename.present?
end
def pdf?
content_type == AttachmentUploader::PDF_CONTENT_TYPE
end
def txt?
file_extension == "txt"
end
def csv?
return file_extension.casecmp("csv").zero? if file_extension
false
end
# Is in OpenDocument format? (see https://en.wikipedia.org/wiki/OpenDocument)
def opendocument?
OPENDOCUMENT_EXTENSIONS.include? file_extension.upcase
end
def indexable?
AttachmentUploader::INDEXABLE_TYPES.include?(file_extension)
end
def all_asset_variants_uploaded?
asset_variants = assets.map(&:variant).compact.map(&:to_sym)
(%i[original] - asset_variants).empty?
end
def update_file_attributes
if carrierwave_file.present? && carrierwave_file_changed?
self.content_type = file.file.content_type
self.file_size = file.file.size
if pdf?
self.number_of_pages = calculate_number_of_pages
end
end
end
def replace_with!(replacement)
# NOTE: we're doing this manually because carrierwave is setup such
# that production instances aren't valid because the storage location
# for files is not where carrierwave thinks they are (because of
# virus-checking).
self.replaced_by = replacement
cant_be_replaced_by_self
raise ActiveRecord::RecordInvalid, self if errors.any?
update_column(:replaced_by_id, replacement.id)
end
def deleted?
significant_attachment(include_deleted_attachables: true).deleted?
end
def draft?
!significant_attachable.publicly_visible?
end
delegate :accessible_to?, to: :significant_attachable
delegate :access_limited?, to: :last_attachable
delegate :access_limited_object, to: :last_attachable
delegate :unpublished?, to: :unpublished_attachable
def replaced?
replaced_by.present?
end
def replacement_asset_for(asset)
replaced_by.assets.where(variant: asset.variant).first || replaced_by.assets.where(variant: Asset.variants[:original]).first
end
def visible_to?(user)
!deleted? && (!draft? || (draft? && accessible_to?(user)))
end
def visible_attachment_for(user)
visible_to?(user) ? significant_attachment : nil
end
def visible_attachable_for(user)
visible_to?(user) ? significant_attachable : nil
end
def visible_edition_for(user)
visible_attachable = visible_attachable_for(user)
visible_attachable.is_a?(Edition) ? visible_attachable : nil
end
def draft_attachment_for(user)
visible_to?(user) ? attachments.find { |attachment| attachment.attachable_type == "Edition" && attachment.attachable&.draft? } : nil
end
def draft_edition_for(user)
draft_attachable = draft_attachment_for(user)&.attachable
draft_attachable.is_a?(Edition) ? draft_attachable : nil
end
def draft_attachment
attachments.find { |attachment| attachment.attachable_type == "Edition" && Edition::PRE_PUBLICATION_STATES.include?(attachment.attachable&.state) }
end
def draft_edition
draft_attachable = draft_attachment&.attachable
draft_attachable.is_a?(Edition) ? draft_attachable : nil
end
def significant_attachable
significant_attachment.attachable || Attachable::Null.new
end
def last_attachable
last_attachment.attachable || Attachable::Null.new
end
def unpublished_attachable
unpublished_attachment&.attachable || Attachable::Null.new
end
def significant_attachment(**args)
last_publicly_visible_attachment || last_attachment(**args)
end
def last_attachment(**args)
filtered_attachments(**args).last || Attachment::Null.new
end
def unpublished_attachment
attachments.reverse.detect { |a| a.attachable&.unpublished? }
end
def last_publicly_visible_attachment
attachments.reverse.detect { |a| (a.attachable || Attachable::Null.new).publicly_visible? }
end
def auth_bypass_ids
attachable && attachable.respond_to?(:auth_bypass_id) ? [attachable.auth_bypass_id] : []
end
def redirect_url
return nil unless unpublished?
unpublished_attachable.unpublishing.document_url
end
def attachable_url(user = nil)
visible_edition = visible_edition_for(user)
if visible_edition.blank? && draft_edition
draft_edition.public_url(draft: true)
elsif visible_edition.present?
visible_edition.public_url
end
end
def access_limitation
return [] unless access_limited?
AssetManagerAccessLimitation.for(access_limited_object)
end
private
def filtered_attachments(include_deleted_attachables: false)
if include_deleted_attachables
attachments
else
attachments.select { |attachment| attachment.attachable.present? }
end
end
def cant_be_replaced_by_self
return if replaced_by.nil?
errors.add(:base, "can't be replaced by itself") if replaced_by == self
end
def handle_to_replace_id
return if to_replace_id.blank?
AttachmentData.find(to_replace_id).replace_with!(self)
end
def calculate_number_of_pages
Timeout.timeout(10) do
PDF::Reader.new(path).page_count
end
rescue Timeout::Error, PDF::Reader::MalformedPDFError, PDF::Reader::UnsupportedFeatureError, OpenSSL::Cipher::CipherError
nil
end
def file_is_not_empty
errors.add(:file, "is an empty file") if file.present? && file.file.zero_size?
end
end