cloudinary 1.0.15 → 1.0.16
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.
- data/README.md +6 -2
- data/lib/cloudinary/carrier_wave.rb +84 -280
- data/lib/cloudinary/carrier_wave/error.rb +9 -0
- data/lib/cloudinary/carrier_wave/preloaded.rb +62 -0
- data/lib/cloudinary/carrier_wave/process.rb +117 -0
- data/lib/cloudinary/carrier_wave/remote.rb +23 -0
- data/lib/cloudinary/carrier_wave/storage.rb +51 -0
- data/lib/cloudinary/helper.rb +2 -1
- data/lib/cloudinary/utils.rb +8 -1
- data/lib/cloudinary/version.rb +1 -1
- metadata +7 -2
data/README.md
CHANGED
@@ -10,7 +10,7 @@ To install the Cloudinary Ruby GEM, run:
|
|
10
10
|
|
11
11
|
$ gem install cloudinary
|
12
12
|
|
13
|
-
|
13
|
+
If you use Rails 3.x or higher, edit your Gemfile, add the following line and run 'bundle'
|
14
14
|
|
15
15
|
$ gem 'cloudinary'
|
16
16
|
|
@@ -18,17 +18,21 @@ Or in Rails 2.x, edit your environment.rb and add:
|
|
18
18
|
|
19
19
|
$ config.gem 'cloudinary'
|
20
20
|
|
21
|
-
If you would like to use our optional integration module of image uploads with ActiveRecord using CarrierWave, install CarrierWave
|
21
|
+
If you would like to use our optional integration module of image uploads with ActiveRecord using CarrierWave, install CarrierWave GEM:
|
22
22
|
|
23
23
|
$ gem install carrierwave
|
24
24
|
|
25
25
|
Rails 3.x Gemfile:
|
26
26
|
|
27
27
|
$ gem 'carrierwave'
|
28
|
+
$ gem 'cloudinary'
|
28
29
|
|
29
30
|
Rails 2.x environment.rb
|
30
31
|
|
31
32
|
$ config.gem 'carrierwave', :version => '~> 0.4.1'
|
33
|
+
$ config.gem 'cloudinary'
|
34
|
+
|
35
|
+
Note: The CarrierWave GEM should be loaded before the Cloudinary GEM.
|
32
36
|
|
33
37
|
|
34
38
|
## Usage ######################################################################
|
@@ -1,319 +1,123 @@
|
|
1
1
|
# Copyright Cloudinary
|
2
|
-
require '
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
attr_reader :http_code
|
8
|
-
def initialize(message, http_code)
|
9
|
-
super(message)
|
10
|
-
@http_code = http_code
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
module ClassMethods
|
15
|
-
def eager
|
16
|
-
process :eager => true
|
17
|
-
end
|
18
|
-
|
19
|
-
def convert(format)
|
20
|
-
process :convert => format
|
21
|
-
end
|
22
|
-
|
23
|
-
def resize_to_limit(width, height)
|
24
|
-
process :resize_to_limit => [width, height]
|
25
|
-
end
|
26
|
-
|
27
|
-
def resize_to_fit(width, height)
|
28
|
-
process :resize_to_fit => [width, height]
|
29
|
-
end
|
30
|
-
|
31
|
-
def resize_to_fill(width, height, gravity="Center")
|
32
|
-
process :resize_to_fill => [width, height, gravity]
|
33
|
-
end
|
2
|
+
require 'cloudinary/carrier_wave/process'
|
3
|
+
require 'cloudinary/carrier_wave/error'
|
4
|
+
require 'cloudinary/carrier_wave/remote'
|
5
|
+
require 'cloudinary/carrier_wave/preloaded'
|
6
|
+
require 'cloudinary/carrier_wave/storage'
|
34
7
|
|
35
|
-
|
36
|
-
process :resize_and_pad => [width, height, background, gravity]
|
37
|
-
end
|
38
|
-
|
39
|
-
def scale(width, height)
|
40
|
-
process :scale => [width, height]
|
41
|
-
end
|
42
|
-
|
43
|
-
def crop(width, height, gravity="Center")
|
44
|
-
process :crop => [width, height, gravity]
|
45
|
-
end
|
46
|
-
|
47
|
-
def cloudinary_transformation(options)
|
48
|
-
process :cloudinary_transformation => options
|
49
|
-
end
|
50
|
-
|
51
|
-
def tags(*tags)
|
52
|
-
process :tags=>tags
|
53
|
-
end
|
54
|
-
end
|
8
|
+
module Cloudinary::CarrierWave
|
55
9
|
|
56
10
|
def self.included(base)
|
57
11
|
base.storage Cloudinary::CarrierWave::Storage
|
58
12
|
base.extend ClassMethods
|
59
13
|
base.send(:attr_accessor, :metadata)
|
60
|
-
base.send(:
|
61
|
-
|
62
|
-
base
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
module Override
|
67
|
-
def cache!(new_file)
|
68
|
-
if new_file.is_a?(String) && new_file.match(CLOUDINARY_PATH)
|
69
|
-
@file = CloudinaryFile.new(new_file)
|
70
|
-
self.original_filename = @cache_id = @my_filename = @filename = @file.original_filename
|
71
|
-
else
|
72
|
-
original_cache!(new_file)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def retrieve_from_cache!(new_file)
|
77
|
-
if new_file.is_a?(String) && new_file.match(CLOUDINARY_PATH)
|
78
|
-
@file = CloudinaryFile.new(new_file)
|
79
|
-
self.original_filename = @cache_id = @my_filename = @filename = @file.original_filename
|
80
|
-
else
|
81
|
-
original_retrieve_from_cache!(new_file)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def cache_name
|
86
|
-
if @file.is_a?(CloudinaryFile)
|
87
|
-
return @file.to_s
|
88
|
-
else
|
89
|
-
return original_cache_name
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def set_or_yell(hash, attr, value)
|
95
|
-
raise "conflicting transformation on #{attr} #{value}!=#{hash[attr]}" if hash[attr]
|
96
|
-
hash[attr] = value
|
97
|
-
end
|
98
|
-
|
99
|
-
def transformation
|
100
|
-
return @transformation if @transformation
|
101
|
-
transformation = {}
|
102
|
-
self.class.processors.each do
|
103
|
-
|name, args|
|
104
|
-
case name
|
105
|
-
when :convert # Do nothing. This is handled by format
|
106
|
-
when :resize_to_limit
|
107
|
-
set_or_yell(transformation, :width, args[0])
|
108
|
-
set_or_yell(transformation, :height, args[1])
|
109
|
-
set_or_yell(transformation, :crop, :limit)
|
110
|
-
when :resize_to_fit
|
111
|
-
set_or_yell(transformation, :width, args[0])
|
112
|
-
set_or_yell(transformation, :height, args[1])
|
113
|
-
set_or_yell(transformation, :crop, :fit)
|
114
|
-
when :resize_to_fill
|
115
|
-
set_or_yell(transformation, :width, args[0])
|
116
|
-
set_or_yell(transformation, :height, args[1])
|
117
|
-
set_or_yell(transformation, :gravity, args[2].to_s.downcase)
|
118
|
-
set_or_yell(transformation, :crop, :fill)
|
119
|
-
when :resize_and_pad
|
120
|
-
set_or_yell(transformation, :width, args[0])
|
121
|
-
set_or_yell(transformation, :height, args[1])
|
122
|
-
set_or_yell(transformation, :gravity, args[3].to_s.downcase)
|
123
|
-
set_or_yell(transformation, :crop, :pad)
|
124
|
-
when :scale
|
125
|
-
set_or_yell(transformation, :width, args[0])
|
126
|
-
set_or_yell(transformation, :height, args[1])
|
127
|
-
set_or_yell(transformation, :crop, :scale)
|
128
|
-
when :crop
|
129
|
-
set_or_yell(transformation, :width, args[0])
|
130
|
-
set_or_yell(transformation, :height, args[1])
|
131
|
-
set_or_yell(transformation, :gravity, args[2].to_s.downcase)
|
132
|
-
set_or_yell(transformation, :crop, :crop)
|
133
|
-
when :cloudinary_transformation
|
134
|
-
args.each do
|
135
|
-
|attr, value|
|
136
|
-
set_or_yell(transformation, attr, value)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
@transformation = transformation
|
141
|
-
@transformation
|
142
|
-
end
|
143
|
-
|
144
|
-
def eager
|
145
|
-
@eager ||= self.class.processors.any?{|processor| processor[0] == :eager}
|
146
|
-
end
|
147
|
-
|
148
|
-
def tags
|
149
|
-
@tags ||= self.class.processors.select{|processor| processor[0] == :tags}.map(&:last).first
|
150
|
-
end
|
14
|
+
base.send(:attr_reader, :stored_version)
|
15
|
+
|
16
|
+
override_in_versions(base, :blank?, :full_public_id)
|
17
|
+
end
|
151
18
|
|
152
|
-
def
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
19
|
+
def retrieve_from_store!(identifier)
|
20
|
+
if identifier.blank?
|
21
|
+
@file = @stored_version = @stored_public_id = nil
|
22
|
+
self.original_filename = nil
|
23
|
+
else
|
24
|
+
@file = CloudinaryFile.new(identifier, self)
|
25
|
+
@public_id = @stored_public_id = @file.public_id
|
26
|
+
@stored_version = @file.version
|
27
|
+
self.original_filename = @file.filename
|
159
28
|
end
|
160
|
-
|
161
|
-
|
162
|
-
"png" # TODO Default format?
|
163
|
-
end
|
164
|
-
|
29
|
+
end
|
30
|
+
|
165
31
|
def url(*args)
|
166
32
|
if args.first && !args.first.is_a?(Hash)
|
167
33
|
super
|
168
34
|
else
|
169
|
-
return
|
35
|
+
return super if self.blank?
|
170
36
|
options = args.extract_options!
|
171
|
-
options =
|
172
|
-
Cloudinary::Utils.cloudinary_url(self.
|
37
|
+
options = self.transformation.merge(options) if self.version_name.present?
|
38
|
+
Cloudinary::Utils.cloudinary_url(self.full_public_id, {:format=>self.format}.merge(options))
|
173
39
|
end
|
174
40
|
end
|
41
|
+
|
42
|
+
def full_public_id
|
43
|
+
return nil if self.blank?
|
44
|
+
return self.my_public_id if self.stored_version.blank?
|
45
|
+
return "v#{self.stored_version}/#{self.my_public_id}"
|
46
|
+
end
|
175
47
|
|
176
|
-
def
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
def process!(new_file=nil)
|
181
|
-
# Do nothing
|
182
|
-
end
|
183
|
-
|
184
|
-
def stored_filename
|
185
|
-
model.read_uploader(mounted_as)
|
186
|
-
end
|
187
|
-
|
188
|
-
def my_filename
|
189
|
-
return stored_filename if stored_filename.present?
|
190
|
-
@my_filename ||= "#{self.public_id}.#{self.format}"
|
48
|
+
def filename
|
49
|
+
return nil if self.blank?
|
50
|
+
return [self.full_public_id, self.format].join(".")
|
191
51
|
end
|
192
|
-
|
52
|
+
|
53
|
+
# public_id to use for uploaded file. Can be overridden by caller. Random public_id will be used otherwise.
|
193
54
|
def public_id
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
|
58
|
+
# If the user overrode public_id, that should be used, even if it's different from current public_id in the database.
|
59
|
+
# Otherwise, try to use public_id from the database.
|
60
|
+
# Otherwise, generate a new random public_id
|
61
|
+
def my_public_id
|
62
|
+
@public_id ||= self.public_id
|
63
|
+
@public_id ||= @stored_public_id
|
199
64
|
@public_id ||= Cloudinary::Utils.random_public_id
|
200
65
|
end
|
201
|
-
|
202
|
-
def
|
203
|
-
|
204
|
-
self.original_filename = @cache_id = @filename = File.basename(uri.path).gsub(/[^a-zA-Z0-9\.\-\+_]/, '')
|
205
|
-
@file = RemoteFile.new(uri, @filename)
|
66
|
+
|
67
|
+
def recreate_versions!
|
68
|
+
# Do nothing
|
206
69
|
end
|
207
70
|
|
208
|
-
def
|
209
|
-
|
71
|
+
def cache_versions!(new_file=nil)
|
72
|
+
# Do nothing
|
210
73
|
end
|
211
74
|
|
212
|
-
|
213
|
-
|
214
|
-
@public_id = identifier.split("/").last.split(".").first
|
215
|
-
end
|
216
|
-
|
217
|
-
def delete
|
218
|
-
Cloudinary::Uploader.destroy(@public_id)
|
219
|
-
end
|
75
|
+
def process!(new_file=nil)
|
76
|
+
# Do nothing
|
220
77
|
end
|
221
78
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
@uri = uri
|
226
|
-
@original_filename = filename
|
227
|
-
end
|
228
|
-
|
229
|
-
def delete
|
230
|
-
# Do nothing. This is a virtual file.
|
231
|
-
end
|
79
|
+
# Should removed files be removed from Cloudinary as well. Can be overridden.
|
80
|
+
def delete_remote?
|
81
|
+
true
|
232
82
|
end
|
233
83
|
|
234
84
|
class CloudinaryFile
|
235
|
-
attr_reader :
|
236
|
-
def initialize(
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
85
|
+
attr_reader :identifier, :public_id, :filename, :format, :version
|
86
|
+
def initialize(identifier, uploader)
|
87
|
+
@uploader = uploader
|
88
|
+
@identifier = identifier
|
89
|
+
if @identifier.include?("/")
|
90
|
+
version, @filename = @identifier.split("/")
|
91
|
+
@version = version[1..-1] # remove 'v' prefix
|
92
|
+
else
|
93
|
+
@filename = @identifier
|
94
|
+
@version = nil
|
243
95
|
end
|
96
|
+
@public_id, @format = Cloudinary::CarrierWave.split_format(@filename)
|
244
97
|
end
|
245
98
|
|
246
|
-
def to_s
|
247
|
-
"image/upload/v#{@version}/#{@original_filename}##{@signature}"
|
248
|
-
end
|
249
|
-
|
250
99
|
def delete
|
251
|
-
|
100
|
+
Cloudinary::Uploader.destroy(self.public_id) if @uploader.delete_remote?
|
252
101
|
end
|
253
102
|
end
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
if (file.is_a?(RemoteFile))
|
272
|
-
data = file.uri.to_s
|
273
|
-
else
|
274
|
-
data = file.file
|
275
|
-
data.rewind if !file.is_path? && data.respond_to?(:rewind)
|
276
|
-
end
|
277
|
-
uploader.metadata = Cloudinary::Uploader.upload(data, params)
|
278
|
-
if uploader.metadata["error"]
|
279
|
-
raise UploadError.new(uploader.metadata["error"]["message"], uploader.metadata["error"]["http_code"])
|
280
|
-
end
|
281
|
-
|
282
|
-
store_cloudinary_version(uploader.metadata["version"]) if uploader.metadata["version"]
|
283
|
-
# Will throw an exception on error
|
284
|
-
else
|
285
|
-
raise "nested versions are not allowed." if (uploader.class.version_names.length > 1)
|
286
|
-
# Do nothing
|
287
|
-
end
|
288
|
-
nil
|
289
|
-
end
|
290
|
-
|
291
|
-
def store_cloudinary_version(version)
|
292
|
-
name = "v#{version}/#{identifier.split("/").last}"
|
293
|
-
model_class = uploader.model.class
|
294
|
-
if defined?(ActiveRecord::Base) && uploader.model.is_a?(ActiveRecord::Base)
|
295
|
-
primary_key = model_class.primary_key.to_sym
|
296
|
-
model_class.update_all({uploader.mounted_as=>name}, {primary_key=>uploader.model.send(primary_key)})
|
297
|
-
uploader.model.send :write_attribute, uploader.mounted_as, name
|
298
|
-
elsif model_class.respond_to?(:update_all) && uploader.model.respond_to?(:_id)
|
299
|
-
# Mongoid support
|
300
|
-
model_class.where(:_id=>uploader.model._id).update_all(uploader.mounted_as=>name)
|
301
|
-
uploader.model.send :write_attribute, uploader.mounted_as, name
|
302
|
-
else
|
303
|
-
raise "Only ActiveRecord and Mongoid are supported at the moment!"
|
103
|
+
|
104
|
+
def self.split_format(identifier)
|
105
|
+
last_dot = identifier.rindex(".")
|
106
|
+
return [public_id, nil] if last_dot.nil?
|
107
|
+
public_id = identifier[0, last_dot]
|
108
|
+
format = identifier[last_dot+1..-1]
|
109
|
+
return [public_id, format]
|
110
|
+
end
|
111
|
+
|
112
|
+
# For the given methods - versions should call the main uploader method
|
113
|
+
def self.override_in_versions(base, *methods)
|
114
|
+
methods.each do
|
115
|
+
|method|
|
116
|
+
base.send :define_method, method do
|
117
|
+
return super() if self.version_name.blank?
|
118
|
+
uploader = self.model.send(self.mounted_as)
|
119
|
+
uploader.send(method)
|
304
120
|
end
|
305
|
-
end
|
306
|
-
|
307
|
-
def retrieve!(identifier)
|
308
|
-
if uploader.class.version_names.blank?
|
309
|
-
return RemoveableFile.new(identifier)
|
310
|
-
else
|
311
|
-
return nil # Version files should not be deleted.
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
def identifier
|
316
|
-
uploader.my_identifier
|
317
|
-
end
|
121
|
+
end
|
318
122
|
end
|
319
123
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Copyright Cloudinary
|
2
|
+
# Support for store in CarrierWave files that were preloaded to cloudinary (e.g., by javascript)
|
3
|
+
# Field value must be in the format: "image/upload/v<version>/#<public_id>.<format>#<signature>"
|
4
|
+
# Where signature is the cloduinary API signature on the public_id and version.
|
5
|
+
module Cloudinary::CarrierWave
|
6
|
+
PRELOADED_CLOUDINARY_PATH = /^([^\/]+)\/upload\/v(\d+)\/([^\/]+)#([^\/]+)$/
|
7
|
+
|
8
|
+
def cache!(new_file)
|
9
|
+
if new_file.is_a?(String) && new_file.match(PRELOADED_CLOUDINARY_PATH)
|
10
|
+
@file = PreloadedCloudinaryFile.new(new_file)
|
11
|
+
@stored_version = @file.version
|
12
|
+
@public_id = @stored_public_id = @file.public_id
|
13
|
+
self.original_filename = @file.original_filename
|
14
|
+
@cache_id = "unused" # must not be blank
|
15
|
+
else
|
16
|
+
super
|
17
|
+
@public_id = nil # allow overriding public_id
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def retrieve_from_cache!(new_file)
|
22
|
+
if new_file.is_a?(String) && new_file.match(PRELOADED_CLOUDINARY_PATH)
|
23
|
+
@file = PreloadedCloudinaryFile.new(new_file)
|
24
|
+
@stored_version = @file.version
|
25
|
+
@public_id = @stored_public_id = @file.public_id
|
26
|
+
self.original_filename = @file.original_filename
|
27
|
+
@cache_id = "unused" # must not be blank
|
28
|
+
else
|
29
|
+
super
|
30
|
+
@public_id = nil # allow overriding public_id
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def cache_name
|
35
|
+
return @file.is_a?(PreloadedCloudinaryFile) ? @file.to_s : super
|
36
|
+
end
|
37
|
+
|
38
|
+
class PreloadedCloudinaryFile
|
39
|
+
attr_reader :original_filename, :version, :public_id, :signature
|
40
|
+
def initialize(file_info)
|
41
|
+
resource_type, @version, @original_filename, @signature = file_info.scan(PRELOADED_CLOUDINARY_PATH).first
|
42
|
+
raise "Cloudinary CarrierWave integration supports images only" if resource_type != "image"
|
43
|
+
@public_id = @original_filename[0..(@original_filename.rindex(".")-1)]
|
44
|
+
expected_signature = Cloudinary::Utils.api_sign_request({:public_id=>public_id, :version=>version}, Cloudinary.config.api_secret)
|
45
|
+
if @signature != expected_signature
|
46
|
+
raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.cloudinary_signature_error", :public_id=>public_id, :default=>"Invalid signature for #{public_id}")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def identifier
|
51
|
+
"v#{version}/#{original_filename}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_s
|
55
|
+
"image/upload/v#{version}/#{original_filename}##{signature}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def delete
|
59
|
+
# Do nothing. This is a virtual file.
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Cloudinary::CarrierWave
|
2
|
+
module ClassMethods
|
3
|
+
def eager
|
4
|
+
process :eager => true
|
5
|
+
end
|
6
|
+
|
7
|
+
def convert(format)
|
8
|
+
process :convert => format
|
9
|
+
end
|
10
|
+
|
11
|
+
def resize_to_limit(width, height)
|
12
|
+
process :resize_to_limit => [width, height]
|
13
|
+
end
|
14
|
+
|
15
|
+
def resize_to_fit(width, height)
|
16
|
+
process :resize_to_fit => [width, height]
|
17
|
+
end
|
18
|
+
|
19
|
+
def resize_to_fill(width, height, gravity="Center")
|
20
|
+
process :resize_to_fill => [width, height, gravity]
|
21
|
+
end
|
22
|
+
|
23
|
+
def resize_and_pad(width, height, background=:transparent, gravity="Center")
|
24
|
+
process :resize_and_pad => [width, height, background, gravity]
|
25
|
+
end
|
26
|
+
|
27
|
+
def scale(width, height)
|
28
|
+
process :scale => [width, height]
|
29
|
+
end
|
30
|
+
|
31
|
+
def crop(width, height, gravity="Center")
|
32
|
+
process :crop => [width, height, gravity]
|
33
|
+
end
|
34
|
+
|
35
|
+
def cloudinary_transformation(options)
|
36
|
+
process :cloudinary_transformation => options
|
37
|
+
end
|
38
|
+
|
39
|
+
def tags(*tags)
|
40
|
+
process :tags=>tags
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_or_yell(hash, attr, value)
|
45
|
+
raise "conflicting transformation on #{attr} #{value}!=#{hash[attr]}" if hash[attr]
|
46
|
+
hash[attr] = value
|
47
|
+
end
|
48
|
+
|
49
|
+
def transformation
|
50
|
+
return @transformation if @transformation
|
51
|
+
@transformation = {}
|
52
|
+
self.class.processors.each do
|
53
|
+
|name, args|
|
54
|
+
case name
|
55
|
+
when :convert # Do nothing. This is handled by format
|
56
|
+
when :resize_to_limit
|
57
|
+
set_or_yell(@transformation, :width, args[0])
|
58
|
+
set_or_yell(@transformation, :height, args[1])
|
59
|
+
set_or_yell(@transformation, :crop, :limit)
|
60
|
+
when :resize_to_fit
|
61
|
+
set_or_yell(@transformation, :width, args[0])
|
62
|
+
set_or_yell(@transformation, :height, args[1])
|
63
|
+
set_or_yell(@transformation, :crop, :fit)
|
64
|
+
when :resize_to_fill
|
65
|
+
set_or_yell(@transformation, :width, args[0])
|
66
|
+
set_or_yell(@transformation, :height, args[1])
|
67
|
+
set_or_yell(@transformation, :gravity, args[2].to_s.downcase)
|
68
|
+
set_or_yell(@transformation, :crop, :fill)
|
69
|
+
when :resize_and_pad
|
70
|
+
set_or_yell(@transformation, :width, args[0])
|
71
|
+
set_or_yell(@transformation, :height, args[1])
|
72
|
+
set_or_yell(@transformation, :background, args[2].to_s.downcase)
|
73
|
+
set_or_yell(@transformation, :gravity, args[3].to_s.downcase)
|
74
|
+
set_or_yell(@transformation, :crop, :pad)
|
75
|
+
when :scale
|
76
|
+
set_or_yell(@transformation, :width, args[0])
|
77
|
+
set_or_yell(@transformation, :height, args[1])
|
78
|
+
set_or_yell(@transformation, :crop, :scale)
|
79
|
+
when :crop
|
80
|
+
set_or_yell(@transformation, :width, args[0])
|
81
|
+
set_or_yell(@transformation, :height, args[1])
|
82
|
+
set_or_yell(@transformation, :gravity, args[2].to_s.downcase)
|
83
|
+
set_or_yell(@transformation, :crop, :crop)
|
84
|
+
when :cloudinary_transformation
|
85
|
+
args.each do
|
86
|
+
|attr, value|
|
87
|
+
set_or_yell(@transformation, attr, value)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
@transformation
|
92
|
+
end
|
93
|
+
|
94
|
+
def eager
|
95
|
+
@eager ||= self.class.processors.any?{|processor| processor[0] == :eager}
|
96
|
+
end
|
97
|
+
|
98
|
+
def tags
|
99
|
+
@tags ||= self.class.processors.select{|processor| processor[0] == :tags}.map(&:last).first
|
100
|
+
end
|
101
|
+
|
102
|
+
def format
|
103
|
+
format_processor = self.class.processors.find{|processor| processor[0] == :convert}
|
104
|
+
if format_processor
|
105
|
+
# Explicit format is given
|
106
|
+
return Array(format_processor[1]).first
|
107
|
+
elsif self.version_name.present?
|
108
|
+
# No local format. The reset should be handled by main uploader
|
109
|
+
uploader = self.model.send(self.mounted_as)
|
110
|
+
return uploader.format
|
111
|
+
else
|
112
|
+
# Try to auto-detect format
|
113
|
+
format = Cloudinary::CarrierWave.split_format(original_filename || "").last
|
114
|
+
return format || "png" # TODO Default format?
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Cloudinary::CarrierWave
|
2
|
+
def download!(uri)
|
3
|
+
if respond_to?(:process_uri)
|
4
|
+
uri = process_uri(uri)
|
5
|
+
else # Backward compatibility with old CarrierWave
|
6
|
+
uri = URI.parse(URI.escape(URI.unescape(uri)))
|
7
|
+
end
|
8
|
+
self.original_filename = @cache_id = @filename = File.basename(uri.path).gsub(/[^a-zA-Z0-9\.\-\+_]/, '')
|
9
|
+
@file = RemoteFile.new(uri, @filename)
|
10
|
+
end
|
11
|
+
|
12
|
+
class RemoteFile
|
13
|
+
attr_reader :uri, :original_filename
|
14
|
+
def initialize(uri, filename)
|
15
|
+
@uri = uri
|
16
|
+
@original_filename = filename
|
17
|
+
end
|
18
|
+
|
19
|
+
def delete
|
20
|
+
# Do nothing. This is a virtual file.
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class Cloudinary::CarrierWave::Storage < ::CarrierWave::Storage::Abstract
|
2
|
+
def store!(file)
|
3
|
+
if uploader.class.version_names.blank?
|
4
|
+
return store_cloudinary_version(file.version) if file.is_a?(Cloudinary::CarrierWave::PreloadedCloudinaryFile)
|
5
|
+
|
6
|
+
# This is the toplevel, need to upload the actual file.
|
7
|
+
params = uploader.transformation.dup
|
8
|
+
params[:return_error] = true
|
9
|
+
params[:format] = uploader.format
|
10
|
+
params[:public_id] = uploader.my_public_id
|
11
|
+
params[:tags] = uploader.tags if uploader.tags
|
12
|
+
eager_versions = uploader.versions.values.select(&:eager)
|
13
|
+
params[:eager] = eager_versions.map{|version| [version.transformation, version.format]} if eager_versions.length > 0
|
14
|
+
|
15
|
+
data = nil
|
16
|
+
if (file.is_a?(Cloudinary::CarrierWave::RemoteFile))
|
17
|
+
data = file.uri.to_s
|
18
|
+
else
|
19
|
+
data = file.file
|
20
|
+
data.rewind if !file.is_path? && data.respond_to?(:rewind)
|
21
|
+
end
|
22
|
+
uploader.metadata = Cloudinary::Uploader.upload(data, params)
|
23
|
+
if uploader.metadata["error"]
|
24
|
+
raise Cloudinary::CarrierWave::UploadError.new(uploader.metadata["error"]["message"], uploader.metadata["error"]["http_code"])
|
25
|
+
end
|
26
|
+
|
27
|
+
store_cloudinary_version(uploader.metadata["version"]) if uploader.metadata["version"]
|
28
|
+
# Will throw an exception on error
|
29
|
+
else
|
30
|
+
raise "nested versions are not allowed." if (uploader.class.version_names.length > 1)
|
31
|
+
# Do nothing - versions are not handled locally.
|
32
|
+
end
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def store_cloudinary_version(version)
|
37
|
+
name = "v#{version}/#{identifier.split("/").last}"
|
38
|
+
model_class = uploader.model.class
|
39
|
+
if defined?(ActiveRecord::Base) && uploader.model.is_a?(ActiveRecord::Base)
|
40
|
+
primary_key = model_class.primary_key.to_sym
|
41
|
+
model_class.update_all({uploader.mounted_as=>name}, {primary_key=>uploader.model.send(primary_key)})
|
42
|
+
uploader.model.send :write_attribute, uploader.mounted_as, name
|
43
|
+
elsif model_class.respond_to?(:update_all) && uploader.model.respond_to?(:_id)
|
44
|
+
# Mongoid support
|
45
|
+
model_class.where(:_id=>uploader.model._id).update_all(uploader.mounted_as=>name)
|
46
|
+
uploader.model.send :write_attribute, uploader.mounted_as, name
|
47
|
+
else
|
48
|
+
raise "Only ActiveRecord and Mongoid are supported at the moment!"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/cloudinary/helper.rb
CHANGED
@@ -20,7 +20,7 @@ module CloudinaryHelper
|
|
20
20
|
def cl_image_path(source, options = {})
|
21
21
|
options = options.clone
|
22
22
|
url = cloudinary_url(source, options)
|
23
|
-
original_image_path(url
|
23
|
+
original_image_path(url)
|
24
24
|
end
|
25
25
|
|
26
26
|
def image_tag(*args)
|
@@ -188,6 +188,7 @@ rescue LoadError
|
|
188
188
|
end
|
189
189
|
|
190
190
|
begin
|
191
|
+
require 'sass'
|
191
192
|
require 'sass/script/functions'
|
192
193
|
module Sass::Script::Functions
|
193
194
|
def cloudinary_url(public_id, sass_options={})
|
data/lib/cloudinary/utils.rb
CHANGED
@@ -21,6 +21,8 @@ class Cloudinary::Utils
|
|
21
21
|
y = options.delete(:y)
|
22
22
|
radius = options.delete(:radius)
|
23
23
|
default_image = options.delete(:default_image)
|
24
|
+
background = options.delete(:background)
|
25
|
+
background = background.sub(/^#/, 'rgb:') if background
|
24
26
|
|
25
27
|
gravity = options.delete(:gravity)
|
26
28
|
quality = options.delete(:quality)
|
@@ -36,7 +38,7 @@ class Cloudinary::Utils
|
|
36
38
|
end
|
37
39
|
prefix = options.delete(:prefix)
|
38
40
|
|
39
|
-
params = {:w=>width, :h=>height, :t=>named_transformation, :c=>crop, :q=>quality, :g=>gravity, :p=>prefix, :x=>x, :y=>y, :r=>radius, :d=>default_image}
|
41
|
+
params = {:w=>width, :h=>height, :t=>named_transformation, :c=>crop, :q=>quality, :g=>gravity, :p=>prefix, :x=>x, :y=>y, :r=>radius, :d=>default_image, :b=>background}
|
40
42
|
transformation = params.reject{|k,v| v.blank?}.map{|k,v| [k.to_s, v]}.sort_by(&:first).map{|k,v| "#{k}_#{v}"}.join(",")
|
41
43
|
raw_transformation = options.delete(:raw_transformation)
|
42
44
|
transformation = [transformation, raw_transformation].reject(&:blank?).join(",")
|
@@ -64,6 +66,7 @@ class Cloudinary::Utils
|
|
64
66
|
secure_distribution = options.delete(:secure_distribution) || Cloudinary.config.secure_distribution
|
65
67
|
force_remote = options.delete(:force_remote)
|
66
68
|
|
69
|
+
return original_source if source.blank?
|
67
70
|
if !force_remote
|
68
71
|
return original_source if (type.nil? || type == :asset) && source.match(%r(^https?:/)i)
|
69
72
|
if source.start_with?("/")
|
@@ -138,6 +141,10 @@ class Cloudinary::Utils
|
|
138
141
|
def self.random_public_id
|
139
142
|
(defined?(ActiveSupport::SecureRandom) ? ActiveSupport::SecureRandom : SecureRandom).base64(16).downcase.gsub(/[^a-z0-9]/, "")
|
140
143
|
end
|
144
|
+
|
145
|
+
def self.signed_preloaded_image(result)
|
146
|
+
"#{result["resource_type"]}/upload/v#{result["version"]}/#{[result["public_id"], result["format"]].join(".")}##{result["signature"]}"
|
147
|
+
end
|
141
148
|
|
142
149
|
@@json_decode = false
|
143
150
|
def self.json_decode(str)
|
data/lib/cloudinary/version.rb
CHANGED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: cloudinary
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.0.
|
5
|
+
version: 1.0.16
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Nadav Soferman
|
@@ -12,7 +12,7 @@ autorequire:
|
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
14
|
|
15
|
-
date: 2012-04-
|
15
|
+
date: 2012-04-25 00:00:00 +03:00
|
16
16
|
default_executable:
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
@@ -58,6 +58,11 @@ files:
|
|
58
58
|
- lib/cloudinary.rb
|
59
59
|
- lib/cloudinary/blob.rb
|
60
60
|
- lib/cloudinary/carrier_wave.rb
|
61
|
+
- lib/cloudinary/carrier_wave/error.rb
|
62
|
+
- lib/cloudinary/carrier_wave/preloaded.rb
|
63
|
+
- lib/cloudinary/carrier_wave/process.rb
|
64
|
+
- lib/cloudinary/carrier_wave/remote.rb
|
65
|
+
- lib/cloudinary/carrier_wave/storage.rb
|
61
66
|
- lib/cloudinary/controller.rb
|
62
67
|
- lib/cloudinary/downloader.rb
|
63
68
|
- lib/cloudinary/helper.rb
|