cloudinary 1.9.1 → 1.20.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 +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
|