salebot_uploader 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +0 -0
- data/lib/generators/templates/uploader.rb.erb +9 -0
- data/lib/generators/uploader_generator.rb +7 -0
- data/lib/salebot_uploader/compatibility/paperclip.rb +104 -0
- data/lib/salebot_uploader/downloader/base.rb +101 -0
- data/lib/salebot_uploader/downloader/remote_file.rb +68 -0
- data/lib/salebot_uploader/error.rb +8 -0
- data/lib/salebot_uploader/locale/en.yml +17 -0
- data/lib/salebot_uploader/mount.rb +446 -0
- data/lib/salebot_uploader/mounter.rb +255 -0
- data/lib/salebot_uploader/orm/activerecord.rb +68 -0
- data/lib/salebot_uploader/processing/mini_magick.rb +194 -0
- data/lib/salebot_uploader/processing/rmagick.rb +402 -0
- data/lib/salebot_uploader/processing/vips.rb +284 -0
- data/lib/salebot_uploader/processing.rb +3 -0
- data/lib/salebot_uploader/sanitized_file.rb +357 -0
- data/lib/salebot_uploader/storage/abstract.rb +41 -0
- data/lib/salebot_uploader/storage/file.rb +124 -0
- data/lib/salebot_uploader/storage/fog.rb +547 -0
- data/lib/salebot_uploader/storage.rb +3 -0
- data/lib/salebot_uploader/test/matchers.rb +398 -0
- data/lib/salebot_uploader/uploader/cache.rb +223 -0
- data/lib/salebot_uploader/uploader/callbacks.rb +33 -0
- data/lib/salebot_uploader/uploader/configuration.rb +184 -0
- data/lib/salebot_uploader/uploader/content_type_allowlist.rb +61 -0
- data/lib/salebot_uploader/uploader/content_type_denylist.rb +62 -0
- data/lib/salebot_uploader/uploader/default_url.rb +17 -0
- data/lib/salebot_uploader/uploader/dimension.rb +66 -0
- data/lib/salebot_uploader/uploader/download.rb +24 -0
- data/lib/salebot_uploader/uploader/extension_allowlist.rb +63 -0
- data/lib/salebot_uploader/uploader/extension_denylist.rb +64 -0
- data/lib/salebot_uploader/uploader/file_size.rb +43 -0
- data/lib/salebot_uploader/uploader/mountable.rb +44 -0
- data/lib/salebot_uploader/uploader/processing.rb +125 -0
- data/lib/salebot_uploader/uploader/proxy.rb +99 -0
- data/lib/salebot_uploader/uploader/remove.rb +21 -0
- data/lib/salebot_uploader/uploader/serialization.rb +28 -0
- data/lib/salebot_uploader/uploader/store.rb +142 -0
- data/lib/salebot_uploader/uploader/url.rb +44 -0
- data/lib/salebot_uploader/uploader/versions.rb +350 -0
- data/lib/salebot_uploader/uploader.rb +53 -0
- data/lib/salebot_uploader/utilities/file_name.rb +47 -0
- data/lib/salebot_uploader/utilities/uri.rb +26 -0
- data/lib/salebot_uploader/utilities.rb +7 -0
- data/lib/salebot_uploader/validations/active_model.rb +76 -0
- data/lib/salebot_uploader/version.rb +3 -0
- data/lib/salebot_uploader.rb +62 -0
- metadata +392 -0
@@ -0,0 +1,350 @@
|
|
1
|
+
require "active_support/core_ext/object/deep_dup"
|
2
|
+
|
3
|
+
module SalebotUploader
|
4
|
+
module Uploader
|
5
|
+
module Versions
|
6
|
+
class Builder
|
7
|
+
def initialize(name)
|
8
|
+
@name = name
|
9
|
+
@options = {}
|
10
|
+
@blocks = []
|
11
|
+
@klass = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def configure(options, &block)
|
15
|
+
@options.merge!(options)
|
16
|
+
@blocks << block if block
|
17
|
+
@klass = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def build(superclass)
|
21
|
+
return @klass if @klass
|
22
|
+
@klass = Class.new(superclass)
|
23
|
+
superclass.const_set("#{@name.to_s.camelize}VersionUploader", @klass)
|
24
|
+
|
25
|
+
@klass.version_names += [@name]
|
26
|
+
@klass.versions = {}
|
27
|
+
@klass.processors = []
|
28
|
+
@klass.version_options = @options
|
29
|
+
@klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
30
|
+
# Define the enable_processing method for versions so they get the
|
31
|
+
# value from the parent class unless explicitly overwritten
|
32
|
+
def self.enable_processing(value=nil)
|
33
|
+
self.enable_processing = value if value
|
34
|
+
if defined?(@enable_processing) && !@enable_processing.nil?
|
35
|
+
@enable_processing
|
36
|
+
else
|
37
|
+
superclass.enable_processing
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Regardless of what is set in the parent uploader, do not enforce the
|
42
|
+
# move_to_cache config option on versions because it moves the original
|
43
|
+
# file to the version's target file.
|
44
|
+
#
|
45
|
+
# If you want to enforce this setting on versions, override this method
|
46
|
+
# in each version:
|
47
|
+
#
|
48
|
+
# version :thumb do
|
49
|
+
# def move_to_cache
|
50
|
+
# true
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
def move_to_cache
|
55
|
+
false
|
56
|
+
end
|
57
|
+
|
58
|
+
# Need to rely on the parent version's identifier, as versions don't have its own one.
|
59
|
+
def identifier
|
60
|
+
parent_version.identifier
|
61
|
+
end
|
62
|
+
RUBY
|
63
|
+
@blocks.each { |block| @klass.class_eval(&block) }
|
64
|
+
@klass
|
65
|
+
end
|
66
|
+
|
67
|
+
def deep_dup
|
68
|
+
other = dup
|
69
|
+
other.instance_variable_set(:@blocks, @blocks.dup)
|
70
|
+
other
|
71
|
+
end
|
72
|
+
|
73
|
+
def method_missing(name, *args)
|
74
|
+
super
|
75
|
+
rescue NoMethodError => e
|
76
|
+
raise e.exception <<~ERROR
|
77
|
+
#{e.message}
|
78
|
+
If you're trying to configure a version, do it inside a block like `version(:thumb) { self.#{name} #{args.map(&:inspect).join(', ')} }`.
|
79
|
+
ERROR
|
80
|
+
end
|
81
|
+
|
82
|
+
def respond_to_missing?(*)
|
83
|
+
super
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
extend ActiveSupport::Concern
|
88
|
+
|
89
|
+
include SalebotUploader::Uploader::Callbacks
|
90
|
+
|
91
|
+
included do
|
92
|
+
class_attribute :versions, :version_names, :version_options, :instance_reader => false, :instance_writer => false
|
93
|
+
|
94
|
+
self.versions = {}
|
95
|
+
self.version_names = []
|
96
|
+
|
97
|
+
attr_accessor :parent_version
|
98
|
+
|
99
|
+
after :cache, :cache_versions!
|
100
|
+
after :store, :store_versions!
|
101
|
+
after :remove, :remove_versions!
|
102
|
+
after :retrieve_from_cache, :retrieve_versions_from_cache!
|
103
|
+
after :retrieve_from_store, :retrieve_versions_from_store!
|
104
|
+
|
105
|
+
prepend Module.new {
|
106
|
+
def initialize(*)
|
107
|
+
super
|
108
|
+
@versions = nil
|
109
|
+
end
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
module ClassMethods
|
114
|
+
|
115
|
+
##
|
116
|
+
# Adds a new version to this uploader
|
117
|
+
#
|
118
|
+
# === Parameters
|
119
|
+
#
|
120
|
+
# [name (#to_sym)] name of the version
|
121
|
+
# [options (Hash)] optional options hash
|
122
|
+
# [&block (Proc)] a block to eval on this version of the uploader
|
123
|
+
#
|
124
|
+
# === Examples
|
125
|
+
#
|
126
|
+
# class MyUploader < SalebotUploader::Uploader::Base
|
127
|
+
#
|
128
|
+
# version :thumb do
|
129
|
+
# process :scale => [200, 200]
|
130
|
+
# end
|
131
|
+
#
|
132
|
+
# version :preview, :if => :image? do
|
133
|
+
# process :scale => [200, 200]
|
134
|
+
# end
|
135
|
+
#
|
136
|
+
# version :square, :unless => :invalid_image_type? do
|
137
|
+
# process :scale => [100, 100]
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# end
|
141
|
+
#
|
142
|
+
def version(name, options = {}, &block)
|
143
|
+
name = name.to_sym
|
144
|
+
versions[name] ||= Builder.new(name)
|
145
|
+
versions[name].configure(options, &block)
|
146
|
+
|
147
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
148
|
+
def #{name}
|
149
|
+
versions[:#{name}]
|
150
|
+
end
|
151
|
+
RUBY
|
152
|
+
|
153
|
+
versions[name]
|
154
|
+
end
|
155
|
+
|
156
|
+
private
|
157
|
+
|
158
|
+
def inherited(subclass)
|
159
|
+
# To prevent subclass version changes affecting superclass versions
|
160
|
+
subclass.versions = versions.deep_dup
|
161
|
+
super
|
162
|
+
end
|
163
|
+
end # ClassMethods
|
164
|
+
|
165
|
+
##
|
166
|
+
# Returns a hash mapping the name of each version of the uploader to an instance of it
|
167
|
+
#
|
168
|
+
# === Returns
|
169
|
+
#
|
170
|
+
# [Hash{Symbol => SalebotUploader::Uploader}] a list of uploader instances
|
171
|
+
#
|
172
|
+
def versions
|
173
|
+
return @versions if @versions
|
174
|
+
@versions = {}
|
175
|
+
self.class.versions.each do |name, version|
|
176
|
+
@versions[name] = version.build(self.class).new(model, mounted_as)
|
177
|
+
@versions[name].parent_version = self
|
178
|
+
end
|
179
|
+
@versions
|
180
|
+
end
|
181
|
+
|
182
|
+
##
|
183
|
+
# === Returns
|
184
|
+
#
|
185
|
+
# [String] the name of this version of the uploader
|
186
|
+
#
|
187
|
+
def version_name
|
188
|
+
self.class.version_names.join('_').to_sym unless self.class.version_names.blank?
|
189
|
+
end
|
190
|
+
|
191
|
+
##
|
192
|
+
#
|
193
|
+
# === Parameters
|
194
|
+
#
|
195
|
+
# [name (#to_sym)] name of the version
|
196
|
+
#
|
197
|
+
# === Returns
|
198
|
+
#
|
199
|
+
# [Boolean] True when the version exists according to its :if or :unless condition
|
200
|
+
#
|
201
|
+
def version_exists?(name)
|
202
|
+
name = name.to_sym
|
203
|
+
|
204
|
+
return false unless versions.has_key?(name)
|
205
|
+
|
206
|
+
if_condition = versions[name].class.version_options[:if]
|
207
|
+
unless_condition = versions[name].class.version_options[:unless]
|
208
|
+
|
209
|
+
if if_condition
|
210
|
+
if if_condition.respond_to?(:call)
|
211
|
+
if_condition.call(self, :version => name, :file => file)
|
212
|
+
else
|
213
|
+
send(if_condition, file)
|
214
|
+
end
|
215
|
+
elsif unless_condition
|
216
|
+
if unless_condition.respond_to?(:call)
|
217
|
+
!unless_condition.call(self, :version => name, :file => file)
|
218
|
+
else
|
219
|
+
!send(unless_condition, file)
|
220
|
+
end
|
221
|
+
else
|
222
|
+
true
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
##
|
227
|
+
# Copies the parent's cache_id when caching a version file.
|
228
|
+
# This behavior is not essential but it makes easier to understand
|
229
|
+
# that the cached files are generated by the single upload attempt.
|
230
|
+
#
|
231
|
+
def cache!(*args)
|
232
|
+
self.cache_id = parent_version.cache_id if parent_version
|
233
|
+
|
234
|
+
super
|
235
|
+
end
|
236
|
+
|
237
|
+
##
|
238
|
+
# When given a version name as a parameter, will return the url for that version
|
239
|
+
# This also works with nested versions.
|
240
|
+
# When given a query hash as a parameter, will return the url with signature that contains query params
|
241
|
+
# Query hash only works with AWS (S3 storage).
|
242
|
+
#
|
243
|
+
# === Example
|
244
|
+
#
|
245
|
+
# my_uploader.url # => /path/to/my/uploader.gif
|
246
|
+
# my_uploader.url(:thumb) # => /path/to/my/thumb_uploader.gif
|
247
|
+
# my_uploader.url(:thumb, :small) # => /path/to/my/thumb_small_uploader.gif
|
248
|
+
# my_uploader.url(:query => {"response-content-disposition" => "attachment"})
|
249
|
+
# my_uploader.url(:version, :sub_version, :query => {"response-content-disposition" => "attachment"})
|
250
|
+
#
|
251
|
+
# === Parameters
|
252
|
+
#
|
253
|
+
# [*args (Symbol)] any number of versions
|
254
|
+
# OR/AND
|
255
|
+
# [Hash] query params
|
256
|
+
#
|
257
|
+
# === Returns
|
258
|
+
#
|
259
|
+
# [String] the location where this file is accessible via a url
|
260
|
+
#
|
261
|
+
def url(*args)
|
262
|
+
if (version = args.first) && version.respond_to?(:to_sym)
|
263
|
+
raise ArgumentError, "Version #{version} doesn't exist!" if versions[version.to_sym].nil?
|
264
|
+
# recursively proxy to version
|
265
|
+
versions[version.to_sym].url(*args[1..-1])
|
266
|
+
elsif args.first
|
267
|
+
super(args.first)
|
268
|
+
else
|
269
|
+
super
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
##
|
274
|
+
# Recreate versions and reprocess them. This can be used to recreate
|
275
|
+
# versions if their parameters somehow have changed.
|
276
|
+
#
|
277
|
+
def recreate_versions!(*names)
|
278
|
+
# As well as specified versions, we need to reprocess versions
|
279
|
+
# that are the source of another version.
|
280
|
+
|
281
|
+
self.cache_id = SalebotUploader.generate_cache_id
|
282
|
+
derived_versions.each_value do |v|
|
283
|
+
v.cache!(file) if names.empty? || !(v.descendant_version_names & names).empty?
|
284
|
+
end
|
285
|
+
active_versions.each do |name, v|
|
286
|
+
v.store! if names.empty? || names.include?(name)
|
287
|
+
end
|
288
|
+
ensure
|
289
|
+
@cache_id = nil
|
290
|
+
end
|
291
|
+
|
292
|
+
protected
|
293
|
+
|
294
|
+
def descendant_version_names
|
295
|
+
[version_name] + derived_versions.flat_map do |name, version|
|
296
|
+
version.descendant_version_names
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def active_versions
|
301
|
+
versions.select do |name, uploader|
|
302
|
+
version_exists?(name)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
private
|
307
|
+
|
308
|
+
def derived_versions
|
309
|
+
active_versions.reject do |name, v|
|
310
|
+
v.class.version_options[:from_version]
|
311
|
+
end.merge(active_sibling_versions.select do |name, v|
|
312
|
+
v.class.version_options[:from_version] == self.class.version_names.last
|
313
|
+
end)
|
314
|
+
end
|
315
|
+
|
316
|
+
def active_sibling_versions
|
317
|
+
parent_version&.active_versions || {}
|
318
|
+
end
|
319
|
+
|
320
|
+
def full_filename(for_file)
|
321
|
+
[version_name, super(for_file)].compact.join('_')
|
322
|
+
end
|
323
|
+
|
324
|
+
def full_original_filename
|
325
|
+
[version_name, super].compact.join('_')
|
326
|
+
end
|
327
|
+
|
328
|
+
def cache_versions!(new_file)
|
329
|
+
derived_versions.each_value { |v| v.cache!(new_file) }
|
330
|
+
end
|
331
|
+
|
332
|
+
def store_versions!(new_file)
|
333
|
+
active_versions.each_value { |v| v.store!(new_file) }
|
334
|
+
end
|
335
|
+
|
336
|
+
def remove_versions!
|
337
|
+
versions.each_value { |v| v.remove! }
|
338
|
+
end
|
339
|
+
|
340
|
+
def retrieve_versions_from_cache!(cache_name)
|
341
|
+
active_versions.each_value { |v| v.retrieve_from_cache!(cache_name) }
|
342
|
+
end
|
343
|
+
|
344
|
+
def retrieve_versions_from_store!(identifier)
|
345
|
+
active_versions.each_value { |v| v.retrieve_from_store!(identifier) }
|
346
|
+
end
|
347
|
+
|
348
|
+
end # Versions
|
349
|
+
end # Uploader
|
350
|
+
end # SalebotUploader
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'salebot_uploader/uploader/configuration'
|
2
|
+
require 'salebot_uploader/uploader/callbacks'
|
3
|
+
require 'salebot_uploader/uploader/proxy'
|
4
|
+
require 'salebot_uploader/uploader/url'
|
5
|
+
require 'salebot_uploader/uploader/mountable'
|
6
|
+
require 'salebot_uploader/uploader/cache'
|
7
|
+
require 'salebot_uploader/uploader/store'
|
8
|
+
require 'salebot_uploader/uploader/download'
|
9
|
+
require 'salebot_uploader/uploader/remove'
|
10
|
+
require 'salebot_uploader/uploader/extension_allowlist'
|
11
|
+
require 'salebot_uploader/uploader/extension_denylist'
|
12
|
+
require 'salebot_uploader/uploader/content_type_allowlist'
|
13
|
+
require 'salebot_uploader/uploader/content_type_denylist'
|
14
|
+
require 'salebot_uploader/uploader/file_size'
|
15
|
+
require 'salebot_uploader/uploader/dimension'
|
16
|
+
require 'salebot_uploader/uploader/processing'
|
17
|
+
require 'salebot_uploader/uploader/versions'
|
18
|
+
require 'salebot_uploader/uploader/default_url'
|
19
|
+
|
20
|
+
require 'salebot_uploader/uploader/serialization'
|
21
|
+
|
22
|
+
module SalebotUploader
|
23
|
+
|
24
|
+
##
|
25
|
+
# See SalebotUploader::Uploader::Base
|
26
|
+
#
|
27
|
+
module Uploader
|
28
|
+
class Base
|
29
|
+
attr_reader :file
|
30
|
+
|
31
|
+
include SalebotUploader::Uploader::Configuration
|
32
|
+
include SalebotUploader::Uploader::Callbacks
|
33
|
+
include SalebotUploader::Uploader::Proxy
|
34
|
+
include SalebotUploader::Uploader::Url
|
35
|
+
include SalebotUploader::Uploader::Mountable
|
36
|
+
include SalebotUploader::Uploader::Cache
|
37
|
+
include SalebotUploader::Uploader::Store
|
38
|
+
include SalebotUploader::Uploader::Download
|
39
|
+
include SalebotUploader::Uploader::Remove
|
40
|
+
include SalebotUploader::Uploader::ExtensionAllowlist
|
41
|
+
include SalebotUploader::Uploader::ExtensionDenylist
|
42
|
+
include SalebotUploader::Uploader::ContentTypeAllowlist
|
43
|
+
include SalebotUploader::Uploader::ContentTypeDenylist
|
44
|
+
include SalebotUploader::Uploader::FileSize
|
45
|
+
include SalebotUploader::Uploader::Dimension
|
46
|
+
include SalebotUploader::Uploader::Processing
|
47
|
+
include SalebotUploader::Uploader::Versions
|
48
|
+
include SalebotUploader::Uploader::DefaultUrl
|
49
|
+
include SalebotUploader::Uploader::Serialization
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module SalebotUploader
|
2
|
+
module Utilities
|
3
|
+
module FileName
|
4
|
+
|
5
|
+
##
|
6
|
+
# Returns the part of the filename before the extension. So if a file is called 'test.jpeg'
|
7
|
+
# this would return 'test'
|
8
|
+
#
|
9
|
+
# === Returns
|
10
|
+
#
|
11
|
+
# [String] the first part of the filename
|
12
|
+
#
|
13
|
+
def basename
|
14
|
+
split_extension(filename)[0] if filename
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Returns the file extension
|
19
|
+
#
|
20
|
+
# === Returns
|
21
|
+
#
|
22
|
+
# [String] extension of file or "" if the file has no extension
|
23
|
+
#
|
24
|
+
def extension
|
25
|
+
split_extension(filename)[1] if filename
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def split_extension(filename)
|
31
|
+
# regular expressions to try for identifying extensions
|
32
|
+
extension_matchers = [
|
33
|
+
/\A(.+)\.(tar\.([glx]?z|bz2))\z/, # matches "something.tar.gz"
|
34
|
+
/\A(.+)\.([^\.]+)\z/ # matches "something.jpg"
|
35
|
+
]
|
36
|
+
|
37
|
+
extension_matchers.each do |regexp|
|
38
|
+
if filename =~ regexp
|
39
|
+
return $1, $2
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
[filename, ""] # In case we weren't able to split the extension
|
44
|
+
end
|
45
|
+
end # FileName
|
46
|
+
end # Utilities
|
47
|
+
end # SalebotUploader
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module SalebotUploader
|
4
|
+
module Utilities
|
5
|
+
module Uri
|
6
|
+
# based on Ruby < 2.0's URI.encode
|
7
|
+
PATH_SAFE = URI::REGEXP::PATTERN::UNRESERVED + '\/'
|
8
|
+
PATH_UNSAFE = Regexp.new("[^#{PATH_SAFE}]", false)
|
9
|
+
NON_ASCII = /[^[:ascii:]]/
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def encode_path(path)
|
14
|
+
URI::DEFAULT_PARSER.escape(path, PATH_UNSAFE)
|
15
|
+
end
|
16
|
+
|
17
|
+
def encode_non_ascii(str)
|
18
|
+
URI::DEFAULT_PARSER.escape(str, NON_ASCII)
|
19
|
+
end
|
20
|
+
|
21
|
+
def decode_uri(str)
|
22
|
+
URI::DEFAULT_PARSER.unescape(str)
|
23
|
+
end
|
24
|
+
end # Uri
|
25
|
+
end # Utilities
|
26
|
+
end # SalebotUploader
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'active_model/validator'
|
2
|
+
require 'active_support/concern'
|
3
|
+
|
4
|
+
module SalebotUploader
|
5
|
+
|
6
|
+
# == Active Model Presence Validator
|
7
|
+
module Validations
|
8
|
+
module ActiveModel
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
class ProcessingValidator < ::ActiveModel::EachValidator
|
12
|
+
|
13
|
+
def validate_each(record, attribute, value)
|
14
|
+
record.__send__("#{attribute}_processing_errors").each do |e|
|
15
|
+
record.errors.add(attribute, :salebot_uploader_processing_error, message: (e.message != e.class.to_s) && e.message)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class IntegrityValidator < ::ActiveModel::EachValidator
|
21
|
+
|
22
|
+
def validate_each(record, attribute, value)
|
23
|
+
record.__send__("#{attribute}_integrity_errors").each do |e|
|
24
|
+
record.errors.add(attribute, :salebot_uploader_integrity_error, message: (e.message != e.class.to_s) && e.message)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class DownloadValidator < ::ActiveModel::EachValidator
|
30
|
+
|
31
|
+
def validate_each(record, attribute, value)
|
32
|
+
record.__send__("#{attribute}_download_errors").each do |e|
|
33
|
+
record.errors.add(attribute, :salebot_uploader_download_error, message: (e.message != e.class.to_s) && e.message)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module HelperMethods
|
39
|
+
|
40
|
+
##
|
41
|
+
# Makes the record invalid if the file couldn't be uploaded due to an integrity error
|
42
|
+
#
|
43
|
+
# Accepts the usual parameters for validations in Rails (:if, :unless, etc...)
|
44
|
+
#
|
45
|
+
def validates_integrity_of(*attr_names)
|
46
|
+
validates_with IntegrityValidator, _merge_attributes(attr_names)
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Makes the record invalid if the file couldn't be processed (assuming the process failed
|
51
|
+
# with a SalebotUploader::ProcessingError)
|
52
|
+
#
|
53
|
+
# Accepts the usual parameters for validations in Rails (:if, :unless, etc...)
|
54
|
+
#
|
55
|
+
def validates_processing_of(*attr_names)
|
56
|
+
validates_with ProcessingValidator, _merge_attributes(attr_names)
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
##
|
61
|
+
# Makes the record invalid if the remote file couldn't be downloaded
|
62
|
+
#
|
63
|
+
# Accepts the usual parameters for validations in Rails (:if, :unless, etc...)
|
64
|
+
#
|
65
|
+
def validates_download_of(*attr_names)
|
66
|
+
validates_with DownloadValidator, _merge_attributes(attr_names)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
included do
|
71
|
+
extend HelperMethods
|
72
|
+
include HelperMethods
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
require 'active_support/core_ext/object/try'
|
4
|
+
require 'active_support/core_ext/class/attribute'
|
5
|
+
require 'active_support/concern'
|
6
|
+
|
7
|
+
module SalebotUploader
|
8
|
+
class << self
|
9
|
+
attr_accessor :root, :base_path
|
10
|
+
attr_writer :tmp_path
|
11
|
+
|
12
|
+
def configure(&block)
|
13
|
+
SalebotUploader::Uploader::Base.configure(&block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def clean_cached_files!(seconds=60*60*24)
|
17
|
+
SalebotUploader::Uploader::Base.clean_cached_files!(seconds)
|
18
|
+
end
|
19
|
+
|
20
|
+
def tmp_path
|
21
|
+
@tmp_path ||= File.expand_path(File.join('..', 'tmp'), root)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
if defined?(Rails)
|
28
|
+
module SalebotUploader
|
29
|
+
class Railtie < Rails::Railtie
|
30
|
+
initializer 'salebot_uploader.setup_paths' do |app|
|
31
|
+
SalebotUploader.root = Rails.root.join(Rails.public_path).to_s
|
32
|
+
SalebotUploader.base_path = ENV['RAILS_RELATIVE_URL_ROOT']
|
33
|
+
available_locales = Array(app.config.i18n.available_locales || [])
|
34
|
+
if available_locales.blank? || available_locales.include?(:en)
|
35
|
+
I18n.load_path.prepend(File.join(File.dirname(__FILE__), 'salebot_uploader', 'locale', 'en.yml'))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
initializer 'salebot_uploader.active_record' do
|
40
|
+
ActiveSupport.on_load :active_record do
|
41
|
+
require 'salebot_uploader/orm/activerecord'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
config.before_eager_load do
|
46
|
+
SalebotUploader::Storage::Fog.eager_load
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
require 'salebot_uploader/utilities'
|
53
|
+
require 'salebot_uploader/error'
|
54
|
+
require 'salebot_uploader/sanitized_file'
|
55
|
+
require 'salebot_uploader/mounter'
|
56
|
+
require 'salebot_uploader/mount'
|
57
|
+
require 'salebot_uploader/processing'
|
58
|
+
require 'salebot_uploader/version'
|
59
|
+
require 'salebot_uploader/storage'
|
60
|
+
require 'salebot_uploader/uploader'
|
61
|
+
require 'salebot_uploader/compatibility/paperclip'
|
62
|
+
require 'salebot_uploader/test/matchers'
|