cloudinary 1.9.1 → 1.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/ISSUE_TEMPLATE/bug_report.md +42 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
- data/.github/pull_request_template.md +24 -0
- data/.gitignore +7 -1
- data/.travis.yml +15 -8
- data/CHANGELOG.md +261 -0
- data/README.md +3 -0
- data/Rakefile +3 -45
- data/cloudinary.gemspec +27 -20
- data/lib/active_storage/blob_key.rb +20 -0
- data/lib/active_storage/service/cloudinary_service.rb +249 -0
- data/lib/cloudinary.rb +53 -63
- data/lib/cloudinary/account_api.rb +231 -0
- data/lib/cloudinary/account_config.rb +30 -0
- data/lib/cloudinary/api.rb +228 -71
- data/lib/cloudinary/auth_token.rb +10 -4
- data/lib/cloudinary/base_api.rb +79 -0
- data/lib/cloudinary/base_config.rb +70 -0
- data/lib/cloudinary/cache.rb +38 -0
- data/lib/cloudinary/cache/breakpoints_cache.rb +31 -0
- data/lib/cloudinary/cache/key_value_cache_adapter.rb +25 -0
- data/lib/cloudinary/cache/rails_cache_adapter.rb +34 -0
- data/lib/cloudinary/cache/storage/rails_cache_storage.rb +5 -0
- data/lib/cloudinary/carrier_wave.rb +4 -2
- data/lib/cloudinary/carrier_wave/remote.rb +3 -2
- data/lib/cloudinary/carrier_wave/storage.rb +2 -1
- data/lib/cloudinary/{controller.rb → cloudinary_controller.rb} +3 -5
- data/lib/cloudinary/config.rb +43 -0
- data/lib/cloudinary/helper.rb +77 -7
- data/lib/cloudinary/migrator.rb +3 -1
- data/lib/cloudinary/railtie.rb +7 -3
- data/lib/cloudinary/responsive.rb +111 -0
- data/lib/cloudinary/uploader.rb +67 -15
- data/lib/cloudinary/utils.rb +324 -54
- data/lib/cloudinary/version.rb +1 -1
- data/lib/cloudinary/video_helper.rb +96 -22
- data/lib/tasks/cloudinary/fetch_assets.rake +48 -0
- data/lib/tasks/{cloudinary.rake → cloudinary/sync_static.rake} +0 -0
- data/tools/allocate_test_cloud.sh +9 -0
- data/tools/get_test_cloud.sh +9 -0
- data/tools/update_version +220 -0
- data/vendor/assets/javascripts/cloudinary/jquery.cloudinary.js +51 -13
- data/vendor/assets/javascripts/cloudinary/jquery.fileupload.js +24 -4
- data/vendor/assets/javascripts/cloudinary/jquery.ui.widget.js +741 -561
- data/vendor/assets/javascripts/cloudinary/load-image.all.min.js +1 -1
- metadata +92 -67
- data/spec/access_control_spec.rb +0 -99
- data/spec/api_spec.rb +0 -545
- data/spec/archive_spec.rb +0 -129
- data/spec/auth_token_spec.rb +0 -79
- data/spec/cloudinary_helper_spec.rb +0 -190
- data/spec/cloudinary_spec.rb +0 -32
- data/spec/data/sync_static/app/assets/javascripts/1.coffee +0 -1
- data/spec/data/sync_static/app/assets/javascripts/1.js +0 -1
- data/spec/data/sync_static/app/assets/stylesheets/1.css +0 -3
- data/spec/docx.docx +0 -0
- data/spec/favicon.ico +0 -0
- data/spec/logo.png +0 -0
- data/spec/rake_spec.rb +0 -160
- data/spec/sample_asset_file.tsv +0 -4
- data/spec/search_spec.rb +0 -109
- data/spec/spec_helper.rb +0 -245
- data/spec/storage_spec.rb +0 -44
- data/spec/streaminig_profiles_api_spec.rb +0 -74
- data/spec/support/helpers/temp_file_helpers.rb +0 -22
- data/spec/support/shared_contexts/rake.rb +0 -19
- data/spec/uploader_spec.rb +0 -363
- data/spec/utils_methods_spec.rb +0 -54
- data/spec/utils_spec.rb +0 -906
- data/spec/video_tag_spec.rb +0 -251
- data/spec/video_url_spec.rb +0 -164
data/lib/cloudinary/helper.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
require 'digest/md5'
|
2
2
|
require 'cloudinary/video_helper'
|
3
|
+
require 'cloudinary/responsive'
|
3
4
|
|
4
5
|
module CloudinaryHelper
|
6
|
+
include ActionView::Helpers::CaptureHelper
|
7
|
+
include Responsive
|
8
|
+
|
5
9
|
CL_BLANK = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
6
10
|
|
7
11
|
# Stand-in for Rails image_tag helper that accepts various options for transformations.
|
@@ -37,13 +41,45 @@ module CloudinaryHelper
|
|
37
41
|
|
38
42
|
end
|
39
43
|
|
44
|
+
|
45
|
+
def cl_picture_tag(source, options = {}, sources =[])
|
46
|
+
|
47
|
+
options = options.clone
|
48
|
+
content_tag 'picture' do
|
49
|
+
sources.map do |source_def|
|
50
|
+
source_options = options.clone
|
51
|
+
source_options = Cloudinary::Utils.chain_transformation(source_options, source_def[:transformation])
|
52
|
+
source_options[:media] = source_def
|
53
|
+
cl_source_tag(source, source_options)
|
54
|
+
end.push(cl_image_tag(source, options))
|
55
|
+
.join('')
|
56
|
+
.html_safe
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def cl_source_tag(source, options)
|
61
|
+
srcset_param = options.fetch(:srcset, {}).merge(Cloudinary.config.srcset || {})
|
62
|
+
attributes = options.fetch(:attributes, {}).clone
|
63
|
+
responsive_attributes = generate_image_responsive_attributes(source, attributes, srcset_param, options)
|
64
|
+
attributes = attributes.merge(responsive_attributes)
|
65
|
+
unless attributes.has_key? :srcset
|
66
|
+
attributes[:srcset] = Cloudinary::Utils.cloudinary_url(source, options)
|
67
|
+
end
|
68
|
+
media_attr = generate_media_attribute(options[:media])
|
69
|
+
attributes[:media] = media_attr unless media_attr.empty?
|
70
|
+
tag "source", attributes, true
|
71
|
+
end
|
72
|
+
|
73
|
+
|
40
74
|
def cloudinary_tag(source, options = {})
|
41
75
|
tag_options = options.clone
|
42
76
|
tag_options[:width] = tag_options.delete(:html_width) if tag_options.include?(:html_width)
|
43
77
|
tag_options[:height] = tag_options.delete(:html_height) if tag_options.include?(:html_height)
|
44
78
|
tag_options[:size] = tag_options.delete(:html_size) if tag_options.include?(:html_size)
|
45
79
|
tag_options[:border] = tag_options.delete(:html_border) if tag_options.include?(:html_border)
|
46
|
-
|
80
|
+
srcset_param = Cloudinary::Utils.config_option_consume(tag_options, :srcset, {})
|
81
|
+
src = cloudinary_url_internal(source, tag_options)
|
82
|
+
attributes = tag_options.delete(:attributes) || {}
|
47
83
|
|
48
84
|
responsive_placeholder = Cloudinary::Utils.config_option_consume(tag_options, :responsive_placeholder)
|
49
85
|
client_hints = Cloudinary::Utils.config_option_consume(tag_options, :client_hints)
|
@@ -51,15 +87,21 @@ module CloudinaryHelper
|
|
51
87
|
hidpi = tag_options.delete(:hidpi)
|
52
88
|
responsive = tag_options.delete(:responsive)
|
53
89
|
if !client_hints && (hidpi || responsive)
|
54
|
-
tag_options["data-src"] =
|
55
|
-
|
90
|
+
tag_options["data-src"] = src
|
91
|
+
src = nil
|
56
92
|
extra_class = responsive ? "cld-responsive" : "cld-hidpi"
|
57
93
|
tag_options[:class] = [tag_options[:class], extra_class].compact.join(" ")
|
58
94
|
responsive_placeholder = CL_BLANK if responsive_placeholder == "blank"
|
59
95
|
tag_options[:src] = responsive_placeholder
|
60
96
|
end
|
97
|
+
responsive_attrs = generate_image_responsive_attributes(source, attributes, srcset_param, options)
|
98
|
+
unless responsive_attrs.empty?
|
99
|
+
tag_options.delete(:width)
|
100
|
+
tag_options.delete(:height)
|
101
|
+
tag_options.merge! responsive_attrs
|
102
|
+
end
|
61
103
|
if block_given?
|
62
|
-
yield(
|
104
|
+
yield(src,tag_options)
|
63
105
|
else
|
64
106
|
tag('div', tag_options)
|
65
107
|
end
|
@@ -244,7 +286,7 @@ module CloudinaryHelper
|
|
244
286
|
Cloudinary::Utils.private_download_url(public_id, format, options)
|
245
287
|
end
|
246
288
|
|
247
|
-
# Helper method that uses the deprecated ZIP download API.
|
289
|
+
# Helper method that uses the deprecated ZIP download API.
|
248
290
|
# Replaced by cl_download_zip_url that uses the more advanced and robust archive generation and download API
|
249
291
|
# @deprecated
|
250
292
|
def cl_zip_download_url(tag, options = {})
|
@@ -254,7 +296,7 @@ module CloudinaryHelper
|
|
254
296
|
# @see {Cloudinary::Utils.download_archive_url}
|
255
297
|
def cl_download_archive_url(options = {})
|
256
298
|
Cloudinary::Utils.download_archive_url(options)
|
257
|
-
end
|
299
|
+
end
|
258
300
|
|
259
301
|
# @see {Cloudinary::Utils.download_zip_url}
|
260
302
|
def cl_download_zip_url(options = {})
|
@@ -276,11 +318,12 @@ module CloudinaryHelper
|
|
276
318
|
if Cloudinary.config.enhance_image_tag
|
277
319
|
alias_method :image_tag, :image_tag_with_cloudinary
|
278
320
|
alias_method :image_path, :image_path_with_cloudinary
|
279
|
-
end
|
321
|
+
end
|
280
322
|
end
|
281
323
|
end
|
282
324
|
|
283
325
|
private
|
326
|
+
|
284
327
|
def cloudinary_url_internal(source, options = {})
|
285
328
|
options[:ssl_detected] = request.ssl? if defined?(request) && request && request.respond_to?(:ssl?)
|
286
329
|
if defined?(CarrierWave::Uploader::Base) && source.is_a?(CarrierWave::Uploader::Base)
|
@@ -376,3 +419,30 @@ rescue LoadError
|
|
376
419
|
# no sass support. Ignore.
|
377
420
|
end
|
378
421
|
|
422
|
+
begin
|
423
|
+
require 'sassc'
|
424
|
+
require 'sassc/script/functions'
|
425
|
+
module SassC::Script::Functions
|
426
|
+
# Helper method for generating cloudinary_url in scss files.
|
427
|
+
#
|
428
|
+
# As opposed to sass(deprecated), optional named arguments are not supported, use hash map instead.
|
429
|
+
#
|
430
|
+
# Example:
|
431
|
+
# Sass: cloudinary-url("sample", $quality: "auto", $fetch_format: "auto");
|
432
|
+
# becomes
|
433
|
+
# SassC: cloudinary-url("sample", ("quality": "auto", "fetch_format": "auto"));
|
434
|
+
#
|
435
|
+
# @param [::SassC::Script::Value::String] public_id The public ID of the resource
|
436
|
+
# @param [::SassC::Script::Value::Map] sass_options Additional options
|
437
|
+
#
|
438
|
+
# @return [::SassC::Script::Value::String]
|
439
|
+
def cloudinary_url(public_id, sass_options = {})
|
440
|
+
options = {}
|
441
|
+
sass_options.to_h.each { |k, v| options[k.value.to_sym] = v.value }
|
442
|
+
url = Cloudinary::Utils.cloudinary_url(public_id.value, {:type => :asset}.merge(options))
|
443
|
+
::SassC::Script::Value::String.new("url(#{url})")
|
444
|
+
end
|
445
|
+
end
|
446
|
+
rescue LoadError
|
447
|
+
# no sassc support. Ignore.
|
448
|
+
end
|
data/lib/cloudinary/migrator.rb
CHANGED
@@ -299,7 +299,9 @@ class Cloudinary::Migrator
|
|
299
299
|
|
300
300
|
def debug(message)
|
301
301
|
if @debug
|
302
|
-
|
302
|
+
mutex.synchronize{
|
303
|
+
$stderr.print "#{Time.now} Cloudinary::Migrator #{message}\n"
|
304
|
+
}
|
303
305
|
end
|
304
306
|
end
|
305
307
|
|
data/lib/cloudinary/railtie.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
class Cloudinary::Railtie < Rails::Railtie
|
2
2
|
rake_tasks do
|
3
|
-
Dir[File.join(File.dirname(__FILE__),'../tasks
|
4
|
-
end
|
3
|
+
Dir[File.join(File.dirname(__FILE__),'../tasks/**/*.rake')].each { |f| load f }
|
4
|
+
end
|
5
5
|
config.after_initialize do |app|
|
6
6
|
ActionView::Base.send :include, CloudinaryHelper
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
|
+
ActiveSupport.on_load(:action_controller_base) do
|
10
|
+
ActionController::Base.send :include, Cloudinary::CloudinaryController
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Responsive
|
2
|
+
# Calculate breakpoints for the given configuration
|
3
|
+
# @private
|
4
|
+
def generate_breakpoints(srcset)
|
5
|
+
return srcset[:breakpoints] if srcset[:breakpoints].is_a? Array
|
6
|
+
min_width, max_width, max_images = [:min_width, :max_width, :max_images].map {|k| srcset[k]}
|
7
|
+
unless [min_width, max_width, max_images].all? {|a| a.is_a? Numeric}
|
8
|
+
throw 'Either (min_width, max_width, max_images) or breakpoints must be provided to the image srcset attribute'
|
9
|
+
end
|
10
|
+
if min_width > max_width
|
11
|
+
throw 'min_width must be less than max_width'
|
12
|
+
end
|
13
|
+
|
14
|
+
if max_images <= 0
|
15
|
+
throw 'max_images must be a positive integer'
|
16
|
+
elsif max_images === 1
|
17
|
+
min_width = max_width
|
18
|
+
end
|
19
|
+
step_size = ((max_width - min_width).to_f / [max_images - 1, 1].max).ceil
|
20
|
+
current = min_width
|
21
|
+
breakpoints = []
|
22
|
+
while current < max_width do
|
23
|
+
breakpoints.push(current)
|
24
|
+
current += step_size
|
25
|
+
end
|
26
|
+
breakpoints.push(max_width)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Generate the srcset and sizes attributes
|
30
|
+
# @private
|
31
|
+
def generate_image_responsive_attributes(public_id, attributes = {}, srcset_data = {}, options = {})
|
32
|
+
# Create both srcset and sizes here to avoid fetching breakpoints twice
|
33
|
+
|
34
|
+
responsive_attributes = {}
|
35
|
+
generate_srcset = !attributes[:srcset]
|
36
|
+
|
37
|
+
if srcset_data.empty?
|
38
|
+
return responsive_attributes
|
39
|
+
elsif srcset_data.is_a? String
|
40
|
+
responsive_attributes[:srcset] = srcset_data
|
41
|
+
return responsive_attributes
|
42
|
+
end
|
43
|
+
|
44
|
+
generate_sizes = !attributes[:sizes] && srcset_data[:sizes]
|
45
|
+
|
46
|
+
if generate_srcset || generate_sizes
|
47
|
+
breakpoints = get_or_generate_breakpoints(public_id, srcset_data, options)
|
48
|
+
|
49
|
+
if generate_srcset
|
50
|
+
transformation = srcset_data[:transformation]
|
51
|
+
srcset_attr = generate_srcset_attribute(public_id, breakpoints, transformation, options)
|
52
|
+
responsive_attributes[:srcset] = srcset_attr unless srcset_attr.empty?
|
53
|
+
end
|
54
|
+
|
55
|
+
if generate_sizes
|
56
|
+
sizes_attr = generate_sizes_attribute(breakpoints)
|
57
|
+
responsive_attributes[:sizes] = sizes_attr unless sizes_attr.empty?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
responsive_attributes
|
62
|
+
end
|
63
|
+
|
64
|
+
# If cache is enabled, get the breakpoints from the cache. If the values were not found in the cache,
|
65
|
+
# or cache is not enabled, generate the values.
|
66
|
+
# @private
|
67
|
+
def get_or_generate_breakpoints(public_id, srcset, options)
|
68
|
+
if srcset[:use_cache]
|
69
|
+
Cloudinary::Cache.get(public_id, options) || []
|
70
|
+
else
|
71
|
+
generate_breakpoints(srcset)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Generate a resource URL scaled to the given width
|
76
|
+
# @private
|
77
|
+
def generate_scaled_url(public_id, width, transformation={}, options={})
|
78
|
+
config_params = Cloudinary::Utils.extract_config_params(options)
|
79
|
+
transformation ||= options
|
80
|
+
config_params[:raw_transformation] = Cloudinary::Utils.generate_transformation_string(
|
81
|
+
[transformation.clone, {:crop => 'scale', :width => width}].reject(&:blank?))
|
82
|
+
config_params.delete :width
|
83
|
+
config_params.delete :height
|
84
|
+
Cloudinary::Utils.cloudinary_url public_id, config_params
|
85
|
+
end
|
86
|
+
|
87
|
+
# Generate srcset attribute value of the HTML img tag
|
88
|
+
# @private
|
89
|
+
def generate_srcset_attribute(public_id, breakpoints, transformation={}, options={})
|
90
|
+
options = options.clone
|
91
|
+
Cloudinary::Utils.patch_fetch_format(options)
|
92
|
+
breakpoints.map{|width| "#{generate_scaled_url(public_id, width, transformation, options)} #{width}w"}.join(', ').html_safe
|
93
|
+
end
|
94
|
+
|
95
|
+
# Generate media attribute value of the HTML img tag
|
96
|
+
# @private
|
97
|
+
def generate_media_attribute(options)
|
98
|
+
options ||= {}
|
99
|
+
[:min_width, :max_width]
|
100
|
+
.select {|name| options[name]}
|
101
|
+
.map {|name| "(#{name.to_s.tr('_', '-')}: #{options[name]}px)"}
|
102
|
+
.join(' and ').html_safe
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
# Generate the sizes attribute
|
107
|
+
# @private
|
108
|
+
def generate_sizes_attribute(breakpoints)
|
109
|
+
breakpoints.map{|width| "(max-width: #{width}px) #{width}px"}.join(', ')
|
110
|
+
end
|
111
|
+
end
|
data/lib/cloudinary/uploader.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# Copyright Cloudinary
|
2
2
|
require 'rest_client'
|
3
3
|
require 'json'
|
4
|
+
require 'cloudinary/cache'
|
4
5
|
|
5
6
|
class Cloudinary::Uploader
|
6
7
|
|
7
|
-
REMOTE_URL_REGEX =
|
8
|
-
|
8
|
+
REMOTE_URL_REGEX = Cloudinary::Utils::REMOTE_URL_REGEX
|
9
9
|
# @deprecated use {Cloudinary::Utils.build_eager} instead
|
10
10
|
def self.build_eager(eager)
|
11
11
|
Cloudinary::Utils.build_eager(eager)
|
@@ -27,6 +27,7 @@ class Cloudinary::Uploader
|
|
27
27
|
:backup => Cloudinary::Utils.as_safe_bool(options[:backup]),
|
28
28
|
:callback => options[:callback],
|
29
29
|
:categorization => options[:categorization],
|
30
|
+
:cinemagraph_analysis => Cloudinary::Utils.as_safe_bool(options[:cinemagraph_analysis]),
|
30
31
|
:colors => Cloudinary::Utils.as_safe_bool(options[:colors]),
|
31
32
|
:context => Cloudinary::Utils.encode_context(options[:context]),
|
32
33
|
:custom_coordinates => Cloudinary::Utils.encode_double_array(options[:custom_coordinates]),
|
@@ -36,10 +37,12 @@ class Cloudinary::Uploader
|
|
36
37
|
:eager_async => Cloudinary::Utils.as_safe_bool(options[:eager_async]),
|
37
38
|
:eager_notification_url => options[:eager_notification_url],
|
38
39
|
:exif => Cloudinary::Utils.as_safe_bool(options[:exif]),
|
40
|
+
:eval => options[:eval],
|
39
41
|
:face_coordinates => Cloudinary::Utils.encode_double_array(options[:face_coordinates]),
|
40
42
|
:faces => Cloudinary::Utils.as_safe_bool(options[:faces]),
|
41
43
|
:folder => options[:folder],
|
42
44
|
:format => options[:format],
|
45
|
+
:filename_override => options[:filename_override],
|
43
46
|
:headers => build_custom_headers(options[:headers]),
|
44
47
|
:image_metadata => Cloudinary::Utils.as_safe_bool(options[:image_metadata]),
|
45
48
|
:invalidate => Cloudinary::Utils.as_safe_bool(options[:invalidate]),
|
@@ -50,6 +53,8 @@ class Cloudinary::Uploader
|
|
50
53
|
:phash => Cloudinary::Utils.as_safe_bool(options[:phash]),
|
51
54
|
:proxy => options[:proxy],
|
52
55
|
:public_id => options[:public_id],
|
56
|
+
:quality_analysis => Cloudinary::Utils.as_safe_bool(options[:quality_analysis]),
|
57
|
+
:quality_override => options[:quality_override],
|
53
58
|
:raw_convert => options[:raw_convert],
|
54
59
|
:responsive_breakpoints => Cloudinary::Utils.generate_responsive_breakpoints_string(options[:responsive_breakpoints]),
|
55
60
|
:return_delete_token => Cloudinary::Utils.as_safe_bool(options[:return_delete_token]),
|
@@ -61,6 +66,8 @@ class Cloudinary::Uploader
|
|
61
66
|
:unique_filename => Cloudinary::Utils.as_safe_bool(options[:unique_filename]),
|
62
67
|
:upload_preset => options[:upload_preset],
|
63
68
|
:use_filename => Cloudinary::Utils.as_safe_bool(options[:use_filename]),
|
69
|
+
:accessibility_analysis => Cloudinary::Utils.as_safe_bool(options[:accessibility_analysis]),
|
70
|
+
:metadata => Cloudinary::Utils.encode_context(options[:metadata])
|
64
71
|
}
|
65
72
|
params
|
66
73
|
end
|
@@ -74,7 +81,10 @@ class Cloudinary::Uploader
|
|
74
81
|
params = build_upload_params(options)
|
75
82
|
if file.is_a?(Pathname)
|
76
83
|
params[:file] = File.open(file, "rb")
|
77
|
-
elsif file.
|
84
|
+
elsif file.is_a?(StringIO)
|
85
|
+
file.rewind
|
86
|
+
params[:file] = Cloudinary::Blob.new(file.read, options)
|
87
|
+
elsif file.respond_to?(:read) || Cloudinary::Utils.is_remote?(file)
|
78
88
|
params[:file] = file
|
79
89
|
else
|
80
90
|
params[:file] = File.open(file, "rb")
|
@@ -92,7 +102,7 @@ class Cloudinary::Uploader
|
|
92
102
|
public_id = public_id_or_options
|
93
103
|
options = old_options
|
94
104
|
end
|
95
|
-
if
|
105
|
+
if Cloudinary::Utils.is_remote?(file)
|
96
106
|
return upload(file, options.merge(:public_id => public_id))
|
97
107
|
elsif file.is_a?(Pathname) || !file.respond_to?(:read)
|
98
108
|
filename = file
|
@@ -100,6 +110,7 @@ class Cloudinary::Uploader
|
|
100
110
|
else
|
101
111
|
filename = "cloudinaryfile"
|
102
112
|
end
|
113
|
+
unique_upload_id = Cloudinary::Utils.random_public_id
|
103
114
|
upload = nil
|
104
115
|
index = 0
|
105
116
|
chunk_size = options[:chunk_size] || 20_000_000
|
@@ -107,8 +118,7 @@ class Cloudinary::Uploader
|
|
107
118
|
buffer = file.read(chunk_size)
|
108
119
|
current_loc = index*chunk_size
|
109
120
|
range = "bytes #{current_loc}-#{current_loc+buffer.size - 1}/#{file.size}"
|
110
|
-
upload = upload_large_part(Cloudinary::Blob.new(buffer, :original_filename => filename), options.merge(:public_id => public_id, :content_range => range))
|
111
|
-
public_id = upload["public_id"]
|
121
|
+
upload = upload_large_part(Cloudinary::Blob.new(buffer, :original_filename => filename), options.merge(:public_id => public_id, :unique_upload_id => unique_upload_id, :content_range => range))
|
112
122
|
index += 1
|
113
123
|
end
|
114
124
|
upload
|
@@ -245,7 +255,7 @@ class Cloudinary::Uploader
|
|
245
255
|
end
|
246
256
|
end
|
247
257
|
|
248
|
-
# options may include 'exclusive' (boolean) which causes clearing this tag from all other resources
|
258
|
+
# options may include 'exclusive' (boolean) which causes clearing this tag from all other resources
|
249
259
|
def self.add_tag(tag, public_ids = [], options = {})
|
250
260
|
exclusive = options.delete(:exclusive)
|
251
261
|
command = exclusive ? "set_exclusive" : "add"
|
@@ -264,6 +274,29 @@ class Cloudinary::Uploader
|
|
264
274
|
return self.call_tags_api(nil, "remove_all", public_ids, options)
|
265
275
|
end
|
266
276
|
|
277
|
+
# Populates metadata fields with the given values. Existing values will be overwritten.
|
278
|
+
#
|
279
|
+
# Any metadata-value pairs given are merged with any existing metadata-value pairs
|
280
|
+
# (an empty value for an existing metadata field clears the value).
|
281
|
+
#
|
282
|
+
# @param [Hash] metadata A list of custom metadata fields (by external_id) and the values to assign to each of them.
|
283
|
+
# @param [Array] public_ids An array of Public IDs of assets uploaded to Cloudinary.
|
284
|
+
# @param [Hash] options
|
285
|
+
# @option options [String] :resource_type The type of file. Default: image. Valid values: image, raw, video.
|
286
|
+
# @option options [String] :type The storage type. Default: upload. Valid values: upload, private, authenticated
|
287
|
+
# @return mixed a list of public IDs that were updated
|
288
|
+
# @raise [Cloudinary::Api:Error]
|
289
|
+
def self.update_metadata(metadata, public_ids, options = {})
|
290
|
+
self.call_api("metadata", options) do
|
291
|
+
{
|
292
|
+
timestamp: (options[:timestamp] || Time.now.to_i),
|
293
|
+
type: options[:type],
|
294
|
+
public_ids: Cloudinary::Utils.build_array(public_ids),
|
295
|
+
metadata: Cloudinary::Utils.encode_context(metadata)
|
296
|
+
}
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
267
300
|
private
|
268
301
|
|
269
302
|
def self.call_tags_api(tag, command, public_ids = [], options = {})
|
@@ -292,7 +325,7 @@ class Cloudinary::Uploader
|
|
292
325
|
return call_api("context", options) do
|
293
326
|
{
|
294
327
|
:timestamp => (options[:timestamp] || Time.now.to_i),
|
295
|
-
:context => Cloudinary::Utils.
|
328
|
+
:context => Cloudinary::Utils.encode_context(context),
|
296
329
|
:public_ids => Cloudinary::Utils.build_array(public_ids),
|
297
330
|
:command => command,
|
298
331
|
:type => options[:type]
|
@@ -303,25 +336,29 @@ class Cloudinary::Uploader
|
|
303
336
|
def self.call_api(action, options)
|
304
337
|
options = options.clone
|
305
338
|
return_error = options.delete(:return_error)
|
339
|
+
use_cache = options[:use_cache] || Cloudinary.config.use_cache
|
306
340
|
|
307
341
|
params, non_signable = yield
|
308
342
|
non_signable ||= []
|
309
343
|
|
310
344
|
unless options[:unsigned]
|
311
|
-
api_key
|
312
|
-
api_secret
|
313
|
-
|
314
|
-
params[:
|
345
|
+
api_key = options[:api_key] || Cloudinary.config.api_key || raise(CloudinaryException, "Must supply api_key")
|
346
|
+
api_secret = options[:api_secret] || Cloudinary.config.api_secret || raise(CloudinaryException, "Must supply api_secret")
|
347
|
+
signature_algorithm = options[:signature_algorithm]
|
348
|
+
params[:signature] = Cloudinary::Utils.api_sign_request(params.reject { |k, v| non_signable.include?(k) }, api_secret, signature_algorithm)
|
349
|
+
params[:api_key] = api_key
|
315
350
|
end
|
316
|
-
|
351
|
+
proxy = options[:api_proxy] || Cloudinary.config.api_proxy
|
352
|
+
timeout = options.fetch(:timeout) { Cloudinary.config.to_h.fetch(:timeout, 60) }
|
317
353
|
|
318
354
|
result = nil
|
319
355
|
|
320
356
|
api_url = Cloudinary::Utils.cloudinary_api_url(action, options)
|
321
357
|
headers = { "User-Agent" => Cloudinary::USER_AGENT }
|
322
358
|
headers['Content-Range'] = options[:content_range] if options[:content_range]
|
359
|
+
headers['X-Unique-Upload-Id'] = options[:unique_upload_id] if options[:unique_upload_id]
|
323
360
|
headers.merge!(options[:extra_headers]) if options[:extra_headers]
|
324
|
-
RestClient::Request.execute(:method => :post, :url => api_url, :payload => params.reject { |k, v| v.nil? || v=="" }, :timeout => timeout, :headers => headers) do
|
361
|
+
RestClient::Request.execute(:method => :post, :url => api_url, :payload => params.reject { |k, v| v.nil? || v=="" }, :timeout => timeout, :headers => headers, :proxy => proxy) do
|
325
362
|
|response, request, tmpresult|
|
326
363
|
raise CloudinaryException, "Server returned unexpected status code - #{response.code} - #{response.body}" unless [200, 400, 401, 403, 404, 500].include?(response.code)
|
327
364
|
begin
|
@@ -338,11 +375,26 @@ class Cloudinary::Uploader
|
|
338
375
|
end
|
339
376
|
end
|
340
377
|
end
|
341
|
-
|
378
|
+
if use_cache && !result.nil?
|
379
|
+
cache_results(result)
|
380
|
+
end
|
342
381
|
result
|
343
382
|
end
|
344
383
|
|
345
384
|
def self.build_custom_headers(headers)
|
346
385
|
Array(headers).map { |*a| a.join(": ") }.join("\n")
|
347
386
|
end
|
387
|
+
|
388
|
+
def self.cache_results(result)
|
389
|
+
if result["responsive_breakpoints"]
|
390
|
+
result["responsive_breakpoints"].each do |bp|
|
391
|
+
Cloudinary::Cache.set(
|
392
|
+
result["public_id"],
|
393
|
+
{type: result["type"], resource_type: result["resource_type"], raw_transformation: bp["transformation"]},
|
394
|
+
bp["breakpoints"].map{|o| o['width']}
|
395
|
+
)
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
end
|
348
400
|
end
|