cloudinary 1.20.0 → 1.21.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +15 -14
- data/.github/ISSUE_TEMPLATE/feature_request.md +1 -1
- data/.github/pull_request_template.md +18 -11
- data/CHANGELOG.md +27 -0
- data/lib/cloudinary.rb +10 -1
- data/lib/cloudinary/account_api.rb +7 -12
- data/lib/cloudinary/api.rb +37 -12
- data/lib/cloudinary/search.rb +40 -7
- data/lib/cloudinary/uploader.rb +44 -18
- data/lib/cloudinary/utils.rb +122 -5
- data/lib/cloudinary/version.rb +1 -1
- data/vendor/assets/javascripts/cloudinary/jquery.cloudinary.js +10 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fbc5f576707d33b684e97610585e92838695cbd373cace7c16b0078021b46871
|
4
|
+
data.tar.gz: a5fc7e5d8f0930223cb03b4ca07910ba3b8a6e8ac18b5d6028f9a8963311f8d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 888d693726c91cba5113ca6d4e13f89b859fc01fde5603ace994eb13a907881d4d5e84a7150501c970b1792c47286ae4a9d889f61b1e41408e25a4aea20cf11d
|
7
|
+
data.tar.gz: 6a76cfcc6187c87314f1676a769b8fbfcfda08a5a22d00403f689056a680e4acb15d7360b919a2132c254295c8439e2072be74a8a2891362920f217d387d14ef
|
@@ -3,7 +3,7 @@ name: Bug report
|
|
3
3
|
about: Bug report for Cloudinary Ruby SDK
|
4
4
|
title: ''
|
5
5
|
labels: ''
|
6
|
-
assignees:
|
6
|
+
assignees: ''
|
7
7
|
|
8
8
|
---
|
9
9
|
|
@@ -14,11 +14,11 @@ Before proceeding, please update to latest version and test if the issue persist
|
|
14
14
|
…
|
15
15
|
|
16
16
|
## Issue Type (Can be multiple)
|
17
|
-
[ ] Build -
|
18
|
-
[ ] Performance - Performance issues
|
19
|
-
[ ] Behaviour - Functions
|
20
|
-
[ ] Documentation - Inconsistency between the docs and behaviour
|
21
|
-
[ ] Other (Specify)
|
17
|
+
- [ ] Build - Cannot install or import the SDK
|
18
|
+
- [ ] Performance - Performance issues
|
19
|
+
- [ ] Behaviour - Functions are not working as expected (such as generate URL)
|
20
|
+
- [ ] Documentation - Inconsistency between the docs and behaviour
|
21
|
+
- [ ] Other (Specify)
|
22
22
|
|
23
23
|
## Steps to reproduce
|
24
24
|
… if applicable
|
@@ -27,16 +27,17 @@ Before proceeding, please update to latest version and test if the issue persist
|
|
27
27
|
…
|
28
28
|
|
29
29
|
## Operating System
|
30
|
-
[ ] Linux
|
31
|
-
[ ] Windows
|
32
|
-
[ ]
|
33
|
-
[ ] All
|
30
|
+
- [ ] Linux
|
31
|
+
- [ ] Windows
|
32
|
+
- [ ] macOS
|
33
|
+
- [ ] All
|
34
34
|
|
35
35
|
## Environment and Libraries (fill in the version numbers)
|
36
|
-
Cloudinary Ruby SDK version - 0.0.0
|
37
|
-
Ruby Version - 0.0.0
|
38
|
-
Rails Version - 0.0.0
|
39
|
-
Other Libraries (Carrierwave, ActiveStorage, etc) - 0.0.0
|
36
|
+
- Cloudinary Ruby SDK version - 0.0.0
|
37
|
+
- Ruby Version - 0.0.0
|
38
|
+
- Rails Version - 0.0.0
|
39
|
+
- Other Libraries (Carrierwave, ActiveStorage, etc) - 0.0.0
|
40
40
|
|
41
41
|
## Repository
|
42
|
+
|
42
43
|
If possible, please provide a link to a reproducible repository that showcases the problem
|
@@ -4,21 +4,28 @@ Provide some context as to what was changed, from an implementation standpoint.
|
|
4
4
|
-->
|
5
5
|
|
6
6
|
#### What does this PR address?
|
7
|
-
[ ]
|
8
|
-
[ ] Refactoring
|
9
|
-
[ ] New feature
|
10
|
-
[ ] Bug fix
|
11
|
-
[ ] Adds more tests
|
7
|
+
- [ ] GitHub issue (Add reference - #XX)
|
8
|
+
- [ ] Refactoring
|
9
|
+
- [ ] New feature
|
10
|
+
- [ ] Bug fix
|
11
|
+
- [ ] Adds more tests
|
12
12
|
|
13
13
|
#### Are tests included?
|
14
|
-
[ ] Yes
|
15
|
-
[ ] No
|
14
|
+
- [ ] Yes
|
15
|
+
- [ ] No
|
16
16
|
|
17
|
-
#### Reviewer,
|
17
|
+
#### Reviewer, please note:
|
18
18
|
<!--
|
19
19
|
List anything here that the reviewer should pay special attention to. This might
|
20
20
|
include, for example:
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
* Dependence on other PRs
|
22
|
+
* Reference to other Cloudinary SDKs
|
23
|
+
* Changes that seem arbitrary without further explanations
|
24
24
|
-->
|
25
|
+
|
26
|
+
#### Checklist:
|
27
|
+
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
|
28
|
+
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
|
29
|
+
- [ ] My code follows the code style of this project.
|
30
|
+
- [ ] My change requires a change to the documentation.
|
31
|
+
- [ ] I ran the full test suite before pushing the changes and all the tests pass.
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,30 @@
|
|
1
|
+
1.21.0 / 2021-08-23
|
2
|
+
==================
|
3
|
+
|
4
|
+
New functionality and features
|
5
|
+
------------------------------
|
6
|
+
|
7
|
+
* Add support for `create_slideshow` Upload API
|
8
|
+
* Add support for variables in text style
|
9
|
+
* Add support for `context` and `metadata` in `rename` Upload API
|
10
|
+
* Add support for `reorder_metadata_field_datasource` Admin API
|
11
|
+
* Add `verify_api_response_signature` and `verify_notification_signature` helpers
|
12
|
+
* Add `download_generated_sprite` and `download_multi` methods
|
13
|
+
* Add support for `urls` in multi and sprite APIs
|
14
|
+
* Add support for `live` parameter in upload presets
|
15
|
+
* Add support for `metadata` parameter in `resources` Admin APIs
|
16
|
+
|
17
|
+
Other Changes
|
18
|
+
-------------
|
19
|
+
|
20
|
+
* Fix `transformations` API call
|
21
|
+
* Fix named parameters normalization issue
|
22
|
+
* Remove duplicates in Search Api fields
|
23
|
+
* Improve configuration tests
|
24
|
+
* Add tests for Provisioning API
|
25
|
+
* Refactor metadata usage in tests
|
26
|
+
* Update GitHub templates
|
27
|
+
|
1
28
|
1.20.0 / 2021-03-26
|
2
29
|
==================
|
3
30
|
|
data/lib/cloudinary.rb
CHANGED
@@ -133,13 +133,22 @@ module Cloudinary
|
|
133
133
|
#
|
134
134
|
# @return [OpenStruct]
|
135
135
|
def self.make_new_config(config_module)
|
136
|
-
|
136
|
+
import_settings_from_file.tap do |config|
|
137
137
|
config.extend(config_module)
|
138
138
|
config.load_config_from_env
|
139
139
|
end
|
140
140
|
end
|
141
141
|
|
142
142
|
private_class_method :make_new_config
|
143
|
+
|
144
|
+
# Import settings from yaml file
|
145
|
+
#
|
146
|
+
# @return [OpenStruct]
|
147
|
+
def self.import_settings_from_file
|
148
|
+
OpenStruct.new((YAML.load(ERB.new(IO.read(config_dir.join("cloudinary.yml"))).result)[config_env] rescue {}))
|
149
|
+
end
|
150
|
+
|
151
|
+
private_class_method :import_settings_from_file
|
143
152
|
end
|
144
153
|
# Prevent require loop if included after Rails is already initialized.
|
145
154
|
require "cloudinary/helper" if defined?(::ActionView::Base)
|
@@ -128,23 +128,18 @@ class Cloudinary::AccountApi
|
|
128
128
|
end
|
129
129
|
|
130
130
|
# Lists users in the account.
|
131
|
-
# @param [Boolean] pending
|
131
|
+
# @param [Boolean] pending Limit results to pending users (true), users that are not pending (false), or all users (nil, the default)
|
132
132
|
# @param [Array<String>] user_ids A list of up to 100 user IDs. When provided, other parameters are ignored.
|
133
133
|
# @param [String] prefix Returns users where the name or email address begins with the specified case-insensitive string.
|
134
134
|
# @param [String] sub_account_id Only returns users who have access to the specified account.
|
135
135
|
# @param [Object] options additional options
|
136
136
|
def self.users(pending = nil, user_ids = [], prefix = nil, sub_account_id = nil, options = {})
|
137
|
-
params =
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
prefix: prefix,
|
144
|
-
sub_account_id: sub_account_id,
|
145
|
-
pending: pending
|
146
|
-
}
|
147
|
-
end
|
137
|
+
params = {
|
138
|
+
ids: user_ids,
|
139
|
+
prefix: prefix,
|
140
|
+
sub_account_id: sub_account_id,
|
141
|
+
pending: pending
|
142
|
+
}
|
148
143
|
|
149
144
|
call_account_api(:get, 'users', params, options.merge(content_type: :json))
|
150
145
|
end
|
data/lib/cloudinary/api.rb
CHANGED
@@ -34,25 +34,25 @@ class Cloudinary::Api
|
|
34
34
|
type = options[:type]
|
35
35
|
uri = "resources/#{resource_type}"
|
36
36
|
uri += "/#{type}" unless type.blank?
|
37
|
-
call_api(:get, uri, only(options, :next_cursor, :max_results, :prefix, :tags, :context, :moderations, :direction, :start_at), options)
|
37
|
+
call_api(:get, uri, only(options, :next_cursor, :max_results, :prefix, :tags, :context, :moderations, :direction, :start_at, :metadata), options)
|
38
38
|
end
|
39
39
|
|
40
40
|
def self.resources_by_tag(tag, options={})
|
41
41
|
resource_type = options[:resource_type] || "image"
|
42
42
|
uri = "resources/#{resource_type}/tags/#{tag}"
|
43
|
-
call_api(:get, uri, only(options, :next_cursor, :max_results, :tags, :context, :moderations, :direction), options)
|
43
|
+
call_api(:get, uri, only(options, :next_cursor, :max_results, :tags, :context, :moderations, :direction, :metadata), options)
|
44
44
|
end
|
45
45
|
|
46
46
|
def self.resources_by_moderation(kind, status, options={})
|
47
47
|
resource_type = options[:resource_type] || "image"
|
48
48
|
uri = "resources/#{resource_type}/moderations/#{kind}/#{status}"
|
49
|
-
call_api(:get, uri, only(options, :next_cursor, :max_results, :tags, :context, :moderations, :direction), options)
|
49
|
+
call_api(:get, uri, only(options, :next_cursor, :max_results, :tags, :context, :moderations, :direction, :metadata), options)
|
50
50
|
end
|
51
51
|
|
52
52
|
def self.resources_by_context(key, value=nil, options={})
|
53
53
|
resource_type = options[:resource_type] || "image"
|
54
54
|
uri = "resources/#{resource_type}/context"
|
55
|
-
params = only(options, :next_cursor, :max_results, :tags, :context, :moderations, :direction
|
55
|
+
params = only(options, :next_cursor, :max_results, :tags, :context, :moderations, :direction, :key, :value, :metadata)
|
56
56
|
params[:key] = key
|
57
57
|
params[:value] = value
|
58
58
|
call_api(:get, uri, params, options)
|
@@ -177,24 +177,32 @@ class Cloudinary::Api
|
|
177
177
|
end
|
178
178
|
|
179
179
|
def self.transformation(transformation, options={})
|
180
|
-
|
180
|
+
params = only(options, :next_cursor, :max_results)
|
181
|
+
params[:transformation] = Cloudinary::Utils.build_eager(transformation)
|
182
|
+
call_api(:get, "transformations", params, options)
|
181
183
|
end
|
182
184
|
|
183
185
|
def self.delete_transformation(transformation, options={})
|
184
|
-
call_api(:delete, "transformations
|
186
|
+
call_api(:delete, "transformations", {:transformation => Cloudinary::Utils.build_eager(transformation)}, options)
|
185
187
|
end
|
186
188
|
|
187
189
|
# updates - supports:
|
188
190
|
# "allowed_for_strict" boolean
|
189
191
|
# "unsafe_update" transformation params - updates a named transformation parameters without regenerating existing images
|
190
192
|
def self.update_transformation(transformation, updates, options={})
|
191
|
-
params
|
192
|
-
params[:unsafe_update]
|
193
|
-
|
193
|
+
params = only(updates, :allowed_for_strict)
|
194
|
+
params[:unsafe_update] = Cloudinary::Utils.build_eager(updates[:unsafe_update]) if updates[:unsafe_update]
|
195
|
+
params[:transformation] = Cloudinary::Utils.build_eager(transformation)
|
196
|
+
call_api(:put, "transformations", params, options)
|
194
197
|
end
|
195
198
|
|
196
199
|
def self.create_transformation(name, definition, options={})
|
197
|
-
|
200
|
+
params = {
|
201
|
+
:name => name,
|
202
|
+
:transformation => Cloudinary::Utils.build_eager(definition)
|
203
|
+
}
|
204
|
+
|
205
|
+
call_api(:post, "transformations", params, options)
|
198
206
|
end
|
199
207
|
|
200
208
|
# upload presets
|
@@ -212,12 +220,12 @@ class Cloudinary::Api
|
|
212
220
|
|
213
221
|
def self.update_upload_preset(name, options={})
|
214
222
|
params = Cloudinary::Uploader.build_upload_params(options)
|
215
|
-
call_api(:put, "upload_presets/#{name}", params.merge(only(options, :unsigned, :disallow_public_id)), options)
|
223
|
+
call_api(:put, "upload_presets/#{name}", params.merge(only(options, :unsigned, :disallow_public_id, :live)), options)
|
216
224
|
end
|
217
225
|
|
218
226
|
def self.create_upload_preset(options={})
|
219
227
|
params = Cloudinary::Uploader.build_upload_params(options)
|
220
|
-
call_api(:post, "upload_presets", params.merge(only(options, :name, :unsigned, :disallow_public_id)), options)
|
228
|
+
call_api(:post, "upload_presets", params.merge(only(options, :name, :unsigned, :disallow_public_id, :live)), options)
|
221
229
|
end
|
222
230
|
|
223
231
|
def self.root_folders(options={})
|
@@ -478,6 +486,23 @@ class Cloudinary::Api
|
|
478
486
|
call_metadata_api(:post, uri, params, options)
|
479
487
|
end
|
480
488
|
|
489
|
+
# Reorders metadata field datasource. Currently supports only value.
|
490
|
+
#
|
491
|
+
# @param [String] field_external_id The ID of the metadata field
|
492
|
+
# @param [String] order_by Criteria for the order. Currently supports only value
|
493
|
+
# @param [String] direction Optional (gets either asc or desc)
|
494
|
+
# @param [Hash] options Configuration options
|
495
|
+
#
|
496
|
+
# @return [Cloudinary::Api::Response]
|
497
|
+
#
|
498
|
+
# @raise [Cloudinary::Api::Error]
|
499
|
+
def self.reorder_metadata_field_datasource(field_external_id, order_by, direction = nil, options = {})
|
500
|
+
uri = [field_external_id, "datasource", "order"]
|
501
|
+
params = { :order_by => order_by, :direction => direction }
|
502
|
+
|
503
|
+
call_metadata_api(:post, uri, params, options)
|
504
|
+
end
|
505
|
+
|
481
506
|
protected
|
482
507
|
|
483
508
|
def self.call_api(method, uri, params, options)
|
data/lib/cloudinary/search.rb
CHANGED
@@ -1,9 +1,14 @@
|
|
1
1
|
class Cloudinary::Search
|
2
|
+
SORT_BY = :sort_by
|
3
|
+
AGGREGATE = :aggregate
|
4
|
+
WITH_FIELD = :with_field
|
5
|
+
KEYS_WITH_UNIQUE_VALUES = [SORT_BY, AGGREGATE, WITH_FIELD].freeze
|
6
|
+
|
2
7
|
def initialize
|
3
8
|
@query_hash = {
|
4
|
-
|
5
|
-
|
6
|
-
|
9
|
+
SORT_BY => {},
|
10
|
+
AGGREGATE => {},
|
11
|
+
WITH_FIELD => {}
|
7
12
|
}
|
8
13
|
end
|
9
14
|
|
@@ -28,23 +33,51 @@ class Cloudinary::Search
|
|
28
33
|
self
|
29
34
|
end
|
30
35
|
|
36
|
+
# Sets the `sort_by` field.
|
37
|
+
#
|
38
|
+
# @param [String] field_name The field to sort by. You can specify more than one sort_by parameter;
|
39
|
+
# results will be sorted according to the order of the fields provided.
|
40
|
+
# @param [String] dir Sort direction. Valid sort directions are 'asc' or 'desc'. Default: 'desc'.
|
41
|
+
#
|
42
|
+
# @return [Cloudinary::Search]
|
31
43
|
def sort_by(field_name, dir = 'desc')
|
32
|
-
@query_hash[
|
44
|
+
@query_hash[SORT_BY][field_name] = { field_name => dir }
|
33
45
|
self
|
34
46
|
end
|
35
47
|
|
48
|
+
# The name of a field (attribute) for which an aggregation count should be calculated and returned in the response.
|
49
|
+
#
|
50
|
+
# You can specify more than one aggregate parameter.
|
51
|
+
#
|
52
|
+
# @param [String] value Supported values: resource_type, type, pixels (only the image assets in the response are
|
53
|
+
# aggregated), duration (only the video assets in the response are aggregated), format, and
|
54
|
+
# bytes. For aggregation fields without discrete values, the results are divided into
|
55
|
+
# categories.
|
56
|
+
# @return [Cloudinary::Search]
|
36
57
|
def aggregate(value)
|
37
|
-
@query_hash[
|
58
|
+
@query_hash[AGGREGATE][value] = value
|
38
59
|
self
|
39
60
|
end
|
40
61
|
|
62
|
+
# The name of an additional asset attribute to include for each asset in the response.
|
63
|
+
#
|
64
|
+
# @param [String] value Possible value: context, tags, and for Tier 2 also image_metadata, and image_analysis.
|
65
|
+
#
|
66
|
+
# @return [Cloudinary::Search]
|
41
67
|
def with_field(value)
|
42
|
-
@query_hash[
|
68
|
+
@query_hash[WITH_FIELD][value] = value
|
43
69
|
self
|
44
70
|
end
|
45
71
|
|
72
|
+
# Returns the query as an hash.
|
73
|
+
#
|
74
|
+
# @return [Hash]
|
46
75
|
def to_h
|
47
|
-
@query_hash.
|
76
|
+
@query_hash.each_with_object({}) do |(key, value), query|
|
77
|
+
next if value.nil? || ((value.is_a?(Array) || value.is_a?(Hash)) && value.blank?)
|
78
|
+
|
79
|
+
query[key] = KEYS_WITH_UNIQUE_VALUES.include?(key) ? value.values : value
|
80
|
+
end
|
48
81
|
end
|
49
82
|
|
50
83
|
def execute(options = {})
|
data/lib/cloudinary/uploader.rb
CHANGED
@@ -159,7 +159,9 @@ class Cloudinary::Uploader
|
|
159
159
|
:from_public_id => from_public_id,
|
160
160
|
:to_public_id => to_public_id,
|
161
161
|
:to_type => options[:to_type],
|
162
|
-
:invalidate => Cloudinary::Utils.as_safe_bool(options[:invalidate])
|
162
|
+
:invalidate => Cloudinary::Utils.as_safe_bool(options[:invalidate]),
|
163
|
+
:context => options[:context],
|
164
|
+
:metadata => options[:metadata]
|
163
165
|
}
|
164
166
|
end
|
165
167
|
end
|
@@ -207,17 +209,42 @@ class Cloudinary::Uploader
|
|
207
209
|
end
|
208
210
|
end
|
209
211
|
|
210
|
-
|
212
|
+
SLIDESHOW_PARAMS = [:notification_url, :public_id, :upload_preset]
|
213
|
+
|
214
|
+
# Creates auto-generated video slideshow.
|
215
|
+
#
|
216
|
+
# @param [Hash] options Additional options.
|
217
|
+
#
|
218
|
+
# @return [Hash] Hash with meta information URLs of generated slideshow resources.
|
219
|
+
def self.create_slideshow(options = {})
|
220
|
+
options[:resource_type] ||= :video
|
221
|
+
|
222
|
+
call_api("create_slideshow", options) do
|
223
|
+
params = {
|
224
|
+
:timestamp => Time.now.to_i,
|
225
|
+
:transformation => Cloudinary::Utils.build_eager(options[:transformation]),
|
226
|
+
:manifest_transformation => Cloudinary::Utils.build_eager(options[:manifest_transformation]),
|
227
|
+
:manifest_json => options[:manifest_json] && options[:manifest_json].to_json,
|
228
|
+
:tags => options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(","),
|
229
|
+
:overwrite => Cloudinary::Utils.as_safe_bool(options[:overwrite])
|
230
|
+
}
|
231
|
+
SLIDESHOW_PARAMS.each { |k| params[k] = options[k] unless options[k].nil? }
|
232
|
+
|
233
|
+
params
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# Generates sprites by merging multiple images into a single large image.
|
238
|
+
#
|
239
|
+
# @param [String|Hash] tag Treated as additional options when hash is passed, otherwise as a tag
|
240
|
+
# @param [Hash] options Additional options. Should be omitted when +tag_or_options+ is a Hash
|
241
|
+
#
|
242
|
+
# @return [Hash] Hash with meta information URLs of generated sprite resources
|
243
|
+
def self.generate_sprite(tag, options = {})
|
211
244
|
version_store = options.delete(:version_store)
|
212
245
|
|
213
246
|
result = call_api("sprite", options) do
|
214
|
-
|
215
|
-
:timestamp => (options[:timestamp] || Time.now.to_i),
|
216
|
-
:tag => tag,
|
217
|
-
:async => options[:async],
|
218
|
-
:notification_url => options[:notification_url],
|
219
|
-
:transformation => Cloudinary::Utils.generate_transformation_string(options.merge(:fetch_format => options[:format]))
|
220
|
-
}
|
247
|
+
Cloudinary::Utils.build_multi_and_sprite_params(tag, options)
|
221
248
|
end
|
222
249
|
|
223
250
|
if version_store == :file && result && result["version"]
|
@@ -229,16 +256,15 @@ class Cloudinary::Uploader
|
|
229
256
|
return result
|
230
257
|
end
|
231
258
|
|
232
|
-
|
259
|
+
# Creates either a single animated image, video or a PDF.
|
260
|
+
#
|
261
|
+
# @param [String|Hash] tag Treated as additional options when hash is passed, otherwise as a tag
|
262
|
+
# @param [Hash] options Additional options. Should be omitted when +tag_or_options+ is a Hash
|
263
|
+
#
|
264
|
+
# @return [Hash] Hash with meta information URLs of the generated file
|
265
|
+
def self.multi(tag, options = {})
|
233
266
|
call_api("multi", options) do
|
234
|
-
|
235
|
-
:timestamp => (options[:timestamp] || Time.now.to_i),
|
236
|
-
:tag => tag,
|
237
|
-
:format => options[:format],
|
238
|
-
:async => options[:async],
|
239
|
-
:notification_url => options[:notification_url],
|
240
|
-
:transformation => Cloudinary::Utils.generate_transformation_string(options.clone)
|
241
|
-
}
|
267
|
+
Cloudinary::Utils.build_multi_and_sprite_params(tag, options)
|
242
268
|
end
|
243
269
|
end
|
244
270
|
|
data/lib/cloudinary/utils.rb
CHANGED
@@ -13,6 +13,7 @@ require 'cloudinary/responsive'
|
|
13
13
|
class Cloudinary::Utils
|
14
14
|
# @deprecated Use Cloudinary::SHARED_CDN
|
15
15
|
SHARED_CDN = Cloudinary::SHARED_CDN
|
16
|
+
MODE_DOWNLOAD = "download"
|
16
17
|
DEFAULT_RESPONSIVE_WIDTH_TRANSFORMATION = {:width => :auto, :crop => :limit}
|
17
18
|
CONDITIONAL_OPERATORS = {
|
18
19
|
"=" => 'eq',
|
@@ -334,7 +335,7 @@ class Cloudinary::Utils
|
|
334
335
|
"if_" + normalize_expression(if_value) unless if_value.to_s.empty?
|
335
336
|
end
|
336
337
|
|
337
|
-
EXP_REGEXP = Regexp.new('(\$_*[^_ ]+)|(
|
338
|
+
EXP_REGEXP = Regexp.new('(\$_*[^_ ]+)|(?<![\$:])('+PREDEFINED_VARS.keys.join("|")+')'+'|('+CONDITIONAL_OPERATORS.keys.reverse.map { |k| Regexp.escape(k) }.join('|')+')(?=[ _])')
|
338
339
|
EXP_REPLACEMENT = PREDEFINED_VARS.merge(CONDITIONAL_OPERATORS)
|
339
340
|
|
340
341
|
def self.normalize_expression(expression)
|
@@ -430,6 +431,8 @@ class Cloudinary::Utils
|
|
430
431
|
]
|
431
432
|
|
432
433
|
def self.text_style(layer)
|
434
|
+
return layer[:text_style] if layer[:text_style].present?
|
435
|
+
|
433
436
|
font_family = layer[:font_family]
|
434
437
|
font_size = layer[:font_size]
|
435
438
|
keywords = []
|
@@ -719,6 +722,43 @@ class Cloudinary::Utils
|
|
719
722
|
params
|
720
723
|
end
|
721
724
|
|
725
|
+
# Helper method for generating download URLs
|
726
|
+
#
|
727
|
+
# @param [String] action @see Cloudinary::Utils.cloudinary_api_url
|
728
|
+
# @param [Hash] params Query parameters in generated URL
|
729
|
+
# @param [Hash] options Additional options
|
730
|
+
# @yield [query_parameters] Invokes the block with query parameters to override how to encode them
|
731
|
+
#
|
732
|
+
# @return [String]
|
733
|
+
def self.cloudinary_api_download_url(action, params, options = {})
|
734
|
+
cloudinary_params = sign_request(params.merge(mode: MODE_DOWNLOAD), options)
|
735
|
+
|
736
|
+
"#{Cloudinary::Utils.cloudinary_api_url(action, options)}?#{hash_query_params(cloudinary_params)}"
|
737
|
+
end
|
738
|
+
private_class_method :cloudinary_api_download_url
|
739
|
+
|
740
|
+
# Return a signed URL to the 'generate_sprite' endpoint with 'mode=download'.
|
741
|
+
#
|
742
|
+
# @param [String|Hash] tag Treated as additional options when hash is passed, otherwise as a tag
|
743
|
+
# @param [Hash] options Additional options. Should be omitted when +tag_or_options+ is a Hash
|
744
|
+
#
|
745
|
+
# @return [String] The signed URL to download sprite
|
746
|
+
def self.download_generated_sprite(tag, options = {})
|
747
|
+
params = build_multi_and_sprite_params(tag, options)
|
748
|
+
cloudinary_api_download_url("sprite", params, options)
|
749
|
+
end
|
750
|
+
|
751
|
+
# Return a signed URL to the 'multi' endpoint with 'mode=download'.
|
752
|
+
#
|
753
|
+
# @param [String|Hash] tag Treated as additional options when hash is passed, otherwise as a tag
|
754
|
+
# @param [Hash] options Additional options. Should be omitted when +tag_or_options+ is a Hash
|
755
|
+
#
|
756
|
+
# @return [String] The signed URL to download multi
|
757
|
+
def self.download_multi(tag, options = {})
|
758
|
+
params = build_multi_and_sprite_params(tag, options)
|
759
|
+
cloudinary_api_download_url("multi", params, options)
|
760
|
+
end
|
761
|
+
|
722
762
|
def self.private_download_url(public_id, format, options = {})
|
723
763
|
cloudinary_params = sign_request({
|
724
764
|
:timestamp=>Time.now.to_i,
|
@@ -767,11 +807,10 @@ class Cloudinary::Utils
|
|
767
807
|
# @option options [String] :keep_derived (false) keep the derived images used for generating the archive
|
768
808
|
# @return [String] archive url
|
769
809
|
def self.download_archive_url(options = {})
|
770
|
-
|
771
|
-
|
810
|
+
params = Cloudinary::Utils.archive_params(options)
|
811
|
+
cloudinary_api_download_url("generate_archive", params, options)
|
772
812
|
end
|
773
813
|
|
774
|
-
|
775
814
|
# Returns a URL that when invokes creates an zip archive and returns it.
|
776
815
|
# @see download_archive_url
|
777
816
|
def self.download_zip_url(options = {})
|
@@ -1191,6 +1230,41 @@ class Cloudinary::Utils
|
|
1191
1230
|
REMOTE_URL_REGEX === url
|
1192
1231
|
end
|
1193
1232
|
|
1233
|
+
# Build params for multi, download_multi, generate_sprite, and download_generated_sprite methods
|
1234
|
+
#
|
1235
|
+
# @param [String|Hash] tag_or_options Treated as additional options when hash is passed, otherwise as a tag
|
1236
|
+
# @param [Hash] options Additional options. Should be omitted when +tag_or_options+ is a Hash
|
1237
|
+
#
|
1238
|
+
# @return [Hash]
|
1239
|
+
#
|
1240
|
+
# @private
|
1241
|
+
def self.build_multi_and_sprite_params(tag_or_options, options)
|
1242
|
+
if tag_or_options.is_a?(Hash)
|
1243
|
+
if options.blank?
|
1244
|
+
options = tag_or_options
|
1245
|
+
tag_or_options = nil
|
1246
|
+
else
|
1247
|
+
raise "First argument must be a tag when additional options are passed"
|
1248
|
+
end
|
1249
|
+
end
|
1250
|
+
urls = options.delete(:urls)
|
1251
|
+
|
1252
|
+
if tag_or_options.blank? && urls.blank?
|
1253
|
+
raise "Either tag or urls are required"
|
1254
|
+
end
|
1255
|
+
|
1256
|
+
{
|
1257
|
+
:tag => tag_or_options,
|
1258
|
+
:urls => urls,
|
1259
|
+
:transformation => Cloudinary::Utils.generate_transformation_string(options.merge(:fetch_format => options[:format])),
|
1260
|
+
:notification_url => options[:notification_url],
|
1261
|
+
:format => options[:format],
|
1262
|
+
:async => options[:async],
|
1263
|
+
:mode => options[:mode],
|
1264
|
+
:timestamp => (options[:timestamp] || Time.now.to_i)
|
1265
|
+
}
|
1266
|
+
end
|
1267
|
+
|
1194
1268
|
# The returned url should allow downloading the backedup asset based on the version and asset id
|
1195
1269
|
#
|
1196
1270
|
# asset and version id are returned with resource(<PUBLIC_ID1>, { versions: true })
|
@@ -1224,10 +1298,53 @@ class Cloudinary::Utils
|
|
1224
1298
|
end
|
1225
1299
|
end
|
1226
1300
|
|
1301
|
+
# Verifies the authenticity of an API response signature.
|
1302
|
+
#
|
1303
|
+
# @param [String] public_id he public id of the asset as returned in the API response
|
1304
|
+
# @param [Fixnum] version The version of the asset as returned in the API response
|
1305
|
+
# @param [String] signature Actual signature. Can be retrieved from the X-Cld-Signature header
|
1306
|
+
# @param [Symbol|nil] signature_algorithm Algorithm to use for computing hash
|
1307
|
+
# @param [Hash] options
|
1308
|
+
# @option options [String] :api_secret API secret, if not passed taken from global config
|
1309
|
+
#
|
1310
|
+
# @return [Boolean]
|
1311
|
+
def self.verify_api_response_signature(public_id, version, signature, signature_algorithm = nil, options = {})
|
1312
|
+
api_secret = options[:api_secret] || Cloudinary.config.api_secret || raise("Must supply api_secret")
|
1313
|
+
|
1314
|
+
parameters_to_sign = {
|
1315
|
+
:public_id => public_id,
|
1316
|
+
:version => version
|
1317
|
+
}
|
1318
|
+
|
1319
|
+
signature == api_sign_request(parameters_to_sign, api_secret, signature_algorithm)
|
1320
|
+
end
|
1321
|
+
|
1322
|
+
# Verifies the authenticity of a notification signature.
|
1323
|
+
#
|
1324
|
+
# @param [String] body JSON of the request's body
|
1325
|
+
# @param [Fixnum] timestamp Unix timestamp. Can be retrieved from the X-Cld-Timestamp header
|
1326
|
+
# @param [String] signature Actual signature. Can be retrieved from the X-Cld-Signature header
|
1327
|
+
# @param [Fixnum] valid_for The desired time in seconds for considering the request valid
|
1328
|
+
# @param [Symbol|nil] signature_algorithm Algorithm to use for computing hash
|
1329
|
+
# @param [Hash] options
|
1330
|
+
# @option options [String] :api_secret API secret, if not passed taken from global config
|
1331
|
+
#
|
1332
|
+
# @return [Boolean]
|
1333
|
+
def self.verify_notification_signature(body, timestamp, signature, valid_for = 7200, signature_algorithm = nil, options = {})
|
1334
|
+
api_secret = options[:api_secret] || Cloudinary.config.api_secret || raise("Must supply api_secret")
|
1335
|
+
raise("Body should be of String type") unless body.is_a?(String)
|
1336
|
+
# verify that signature is valid for the given timestamp
|
1337
|
+
return false if timestamp < (Time.now - valid_for).to_i
|
1338
|
+
|
1339
|
+
payload_hash = hash("#{body}#{timestamp}#{api_secret}", signature_algorithm, :hexdigest)
|
1340
|
+
|
1341
|
+
signature == payload_hash
|
1342
|
+
end
|
1343
|
+
|
1227
1344
|
# Computes hash from input string using specified algorithm.
|
1228
1345
|
#
|
1229
1346
|
# @param [String] input String which to compute hash from
|
1230
|
-
# @param [
|
1347
|
+
# @param [Symbol|nil] signature_algorithm Algorithm to use for computing hash
|
1231
1348
|
# @param [Symbol] hash_method Hash method applied to a signature algorithm (:digest or :hexdigest)
|
1232
1349
|
#
|
1233
1350
|
# @return [String] Computed hash value
|
data/lib/cloudinary/version.rb
CHANGED
@@ -4302,12 +4302,20 @@ var slice = [].slice,
|
|
4302
4302
|
switch (false) {
|
4303
4303
|
case !/w_auto:breakpoints/.test(dataSrc):
|
4304
4304
|
requiredWidth = maxWidth(containerWidth, tag);
|
4305
|
-
|
4305
|
+
if (requiredWidth) {
|
4306
|
+
dataSrc = dataSrc.replace(/w_auto:breakpoints([_0-9]*)(:[0-9]+)?/, "w_auto:breakpoints$1:" + requiredWidth);
|
4307
|
+
} else {
|
4308
|
+
setUrl = false;
|
4309
|
+
}
|
4306
4310
|
break;
|
4307
4311
|
case !(match = /w_auto(:(\d+))?/.exec(dataSrc)):
|
4308
4312
|
requiredWidth = applyBreakpoints.call(this, tag, containerWidth, match[2], options);
|
4309
4313
|
requiredWidth = maxWidth(requiredWidth, tag);
|
4310
|
-
|
4314
|
+
if (requiredWidth) {
|
4315
|
+
dataSrc = dataSrc.replace(/w_auto[^,\/]*/g, "w_" + requiredWidth);
|
4316
|
+
} else {
|
4317
|
+
setUrl = false;
|
4318
|
+
}
|
4311
4319
|
}
|
4312
4320
|
Util.removeAttribute(tag, 'width');
|
4313
4321
|
if (!options.responsive_preserve_height) {
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudinary
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.21.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nadav Soferman
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2021-
|
13
|
+
date: 2021-08-23 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: aws_cf_signer
|