cloudinary 1.26.0 → 1.28.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/lib/cloudinary/api.rb +15 -0
- data/lib/cloudinary/carrier_wave/storage.rb +1 -8
- data/lib/cloudinary/search.rb +57 -2
- data/lib/cloudinary/search_folders.rb +5 -0
- data/lib/cloudinary/uploader.rb +5 -15
- data/lib/cloudinary/utils.rb +42 -13
- data/lib/cloudinary/version.rb +1 -1
- data/lib/cloudinary.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97b754051e806086f5dfb98479292bb84bed48968c242d8c55dfa073a8d90e52
|
4
|
+
data.tar.gz: 6a6484d454b0b074fa177b68e90bb62a100c90aa3f4b3ab33dad9acd64d7ec4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd822c6ec7144df3f7ab863d834802c486bc31ef5051cafbb9d331279a0f3092906990c211ccf1802515d53d51f64e71fd1bd73acc8a2f368c22bddd90ea3a38
|
7
|
+
data.tar.gz: cc2299facddd71188d08c0f934ad8483bc0c9414364699e3f84a20eee489f0883adca4ba838a9534d417e11580ff194761d0d26cc978079c9e3b2f42cceeaa48
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,28 @@
|
|
1
|
+
1.28.0 / 2023-11-06
|
2
|
+
==================
|
3
|
+
|
4
|
+
New functionality and features
|
5
|
+
------------------------------
|
6
|
+
|
7
|
+
* Add support for `image_file` parameter in `visual_search` Admin API
|
8
|
+
* Add support for `on_success` upload parameter
|
9
|
+
|
10
|
+
Other Changes
|
11
|
+
-------------
|
12
|
+
|
13
|
+
* Replace `update_all` to `update_column` in CarrierWave storage
|
14
|
+
|
15
|
+
1.27.0 / 2023-07-31
|
16
|
+
==================
|
17
|
+
|
18
|
+
New functionality and features
|
19
|
+
------------------------------
|
20
|
+
|
21
|
+
* Add support for `visual_search` Admin API
|
22
|
+
* Add support for Search URL
|
23
|
+
* Add support for `SearchFolders` API
|
24
|
+
* Add support for `media_metadata` API parameter
|
25
|
+
|
1
26
|
1.26.0 / 2023-06-01
|
2
27
|
==================
|
3
28
|
|
data/lib/cloudinary/api.rb
CHANGED
@@ -207,6 +207,20 @@ class Cloudinary::Api
|
|
207
207
|
call_api(:get, uri, params, options)
|
208
208
|
end
|
209
209
|
|
210
|
+
# Find images based on their visual content.
|
211
|
+
#
|
212
|
+
# @param [Hash] options The optional parameters.
|
213
|
+
#
|
214
|
+
# @return [Cloudinary::Api::Response]
|
215
|
+
#
|
216
|
+
# @raise [Cloudinary::Api::Error]
|
217
|
+
def self.visual_search(options = {})
|
218
|
+
uri = "resources/visual_search"
|
219
|
+
params = only(options, :image_url, :image_asset_id, :text, :image_file)
|
220
|
+
params[:image_file] = Cloudinary::Utils.handle_file_param(params[:image_file]) if params.has_key?(:image_file)
|
221
|
+
call_api(:post, uri, params, options)
|
222
|
+
end
|
223
|
+
|
210
224
|
# Returns the details of the specified asset and all its derived assets.
|
211
225
|
#
|
212
226
|
# Note that if you only need details about the original asset,
|
@@ -1293,6 +1307,7 @@ class Cloudinary::Api
|
|
1293
1307
|
:faces,
|
1294
1308
|
:quality_analysis,
|
1295
1309
|
:image_metadata,
|
1310
|
+
:media_metadata,
|
1296
1311
|
:phash,
|
1297
1312
|
:pages,
|
1298
1313
|
:cinemagraph_analysis,
|
@@ -82,14 +82,7 @@ class Cloudinary::CarrierWave::Storage < ::CarrierWave::Storage::Abstract
|
|
82
82
|
end
|
83
83
|
|
84
84
|
if defined?(ActiveRecord::Base) && uploader.model.is_a?(ActiveRecord::Base)
|
85
|
-
|
86
|
-
if defined?(::ActiveRecord::VERSION::MAJOR) && ::ActiveRecord::VERSION::MAJOR > 2
|
87
|
-
model_class.where(primary_key=>uploader.model.send(primary_key)).update_all(column=>name)
|
88
|
-
else
|
89
|
-
# Removed since active record version 3.0.0
|
90
|
-
model_class.update_all({column=>name}, {primary_key=>uploader.model.send(primary_key)})
|
91
|
-
end
|
92
|
-
uploader.model.send :write_attribute, column, name
|
85
|
+
uploader.model.update_column(column, name)
|
93
86
|
elsif defined?(Mongoid::Document) && uploader.model.is_a?(Mongoid::Document)
|
94
87
|
# Mongoid support
|
95
88
|
if Mongoid::VERSION.split(".").first.to_i >= 4
|
data/lib/cloudinary/search.rb
CHANGED
@@ -1,15 +1,23 @@
|
|
1
1
|
class Cloudinary::Search
|
2
|
+
ENDPOINT = 'resources'
|
3
|
+
|
2
4
|
SORT_BY = :sort_by
|
3
5
|
AGGREGATE = :aggregate
|
4
6
|
WITH_FIELD = :with_field
|
5
7
|
KEYS_WITH_UNIQUE_VALUES = [SORT_BY, AGGREGATE, WITH_FIELD].freeze
|
6
8
|
|
9
|
+
TTL = 300 # Used for search URLs
|
10
|
+
|
7
11
|
def initialize
|
8
12
|
@query_hash = {
|
9
13
|
SORT_BY => {},
|
10
14
|
AGGREGATE => {},
|
11
15
|
WITH_FIELD => {}
|
12
16
|
}
|
17
|
+
|
18
|
+
@endpoint = self.class::ENDPOINT
|
19
|
+
|
20
|
+
@ttl = self.class::TTL
|
13
21
|
end
|
14
22
|
|
15
23
|
## implicitly generate an instance delegate the method
|
@@ -69,11 +77,21 @@ class Cloudinary::Search
|
|
69
77
|
self
|
70
78
|
end
|
71
79
|
|
80
|
+
# Sets the time to live of the search URL.
|
81
|
+
#
|
82
|
+
# @param [Object] ttl The time to live in seconds.
|
83
|
+
#
|
84
|
+
# @return [Cloudinary::Search]
|
85
|
+
def ttl(ttl)
|
86
|
+
@ttl = ttl
|
87
|
+
self
|
88
|
+
end
|
89
|
+
|
72
90
|
# Returns the query as an hash.
|
73
91
|
#
|
74
92
|
# @return [Hash]
|
75
93
|
def to_h
|
76
|
-
@query_hash.each_with_object({}) do |(key, value), query|
|
94
|
+
@query_hash.sort.each_with_object({}) do |(key, value), query|
|
77
95
|
next if value.nil? || ((value.is_a?(Array) || value.is_a?(Hash)) && value.blank?)
|
78
96
|
|
79
97
|
query[key] = KEYS_WITH_UNIQUE_VALUES.include?(key) ? value.values : value
|
@@ -82,7 +100,44 @@ class Cloudinary::Search
|
|
82
100
|
|
83
101
|
def execute(options = {})
|
84
102
|
options[:content_type] = :json
|
85
|
-
uri =
|
103
|
+
uri = "#{@endpoint}/search"
|
86
104
|
Cloudinary::Api.call_api(:post, uri, to_h, options)
|
87
105
|
end
|
106
|
+
|
107
|
+
# Creates a signed Search URL that can be used on the client side.
|
108
|
+
#
|
109
|
+
# @param [Integer] ttl The time to live in seconds.
|
110
|
+
# @param [String] next_cursor Starting position.
|
111
|
+
# @param [Hash] options Additional url delivery options.
|
112
|
+
#
|
113
|
+
# @return [String] The resulting Search URL
|
114
|
+
def to_url(ttl = nil, next_cursor = nil, options = {})
|
115
|
+
api_secret = options[:api_secret] || Cloudinary.config.api_secret || raise(CloudinaryException, "Must supply api_secret")
|
116
|
+
|
117
|
+
ttl = ttl || @ttl
|
118
|
+
query = self.to_h
|
119
|
+
|
120
|
+
_next_cursor = query.delete(:next_cursor)
|
121
|
+
next_cursor = _next_cursor if next_cursor.nil?
|
122
|
+
|
123
|
+
b64query = Base64.urlsafe_encode64(JSON.generate(query))
|
124
|
+
|
125
|
+
prefix = Cloudinary::Utils.build_distribution_domain(options)
|
126
|
+
|
127
|
+
signature = Cloudinary::Utils.hash("#{ttl}#{b64query}#{api_secret}", :sha256, :hexdigest)
|
128
|
+
|
129
|
+
next_cursor = "/#{next_cursor}" if !next_cursor.nil? && !next_cursor.empty?
|
130
|
+
|
131
|
+
"#{prefix}/search/#{signature}/#{ttl}/#{b64query}#{next_cursor}"
|
132
|
+
end
|
133
|
+
|
134
|
+
# Sets the API endpoint.
|
135
|
+
#
|
136
|
+
# @param [String] endpoint the endpoint to set.
|
137
|
+
#
|
138
|
+
# @return [Cloudinary::Search]
|
139
|
+
def endpoint(endpoint)
|
140
|
+
@endpoint = endpoint
|
141
|
+
self
|
142
|
+
end
|
88
143
|
end
|
@@ -0,0 +1,5 @@
|
|
1
|
+
# The Cloudinary API folders search method allows you fine control on filtering and retrieving information on all the
|
2
|
+
# folders in your cloud with the help of query expressions in a Lucene-like query language.
|
3
|
+
class Cloudinary::SearchFolders < Cloudinary::Search
|
4
|
+
ENDPOINT = 'folders'
|
5
|
+
end
|
data/lib/cloudinary/uploader.rb
CHANGED
@@ -40,6 +40,7 @@ class Cloudinary::Uploader
|
|
40
40
|
:eager_notification_url => options[:eager_notification_url],
|
41
41
|
:exif => Cloudinary::Utils.as_safe_bool(options[:exif]),
|
42
42
|
:eval => options[:eval],
|
43
|
+
:on_success => options[:on_success],
|
43
44
|
:face_coordinates => Cloudinary::Utils.encode_double_array(options[:face_coordinates]),
|
44
45
|
:faces => Cloudinary::Utils.as_safe_bool(options[:faces]),
|
45
46
|
:folder => options[:folder],
|
@@ -47,6 +48,7 @@ class Cloudinary::Uploader
|
|
47
48
|
:filename_override => options[:filename_override],
|
48
49
|
:headers => build_custom_headers(options[:headers]),
|
49
50
|
:image_metadata => Cloudinary::Utils.as_safe_bool(options[:image_metadata]),
|
51
|
+
:media_metadata => Cloudinary::Utils.as_safe_bool(options[:media_metadata]),
|
50
52
|
:invalidate => Cloudinary::Utils.as_safe_bool(options[:invalidate]),
|
51
53
|
:moderation => options[:moderation],
|
52
54
|
:notification_url => options[:notification_url],
|
@@ -62,6 +64,7 @@ class Cloudinary::Uploader
|
|
62
64
|
:responsive_breakpoints => Cloudinary::Utils.generate_responsive_breakpoints_string(options[:responsive_breakpoints]),
|
63
65
|
:return_delete_token => Cloudinary::Utils.as_safe_bool(options[:return_delete_token]),
|
64
66
|
:similarity_search => options[:similarity_search],
|
67
|
+
:visual_search => Cloudinary::Utils.as_safe_bool(options[:visual_search]),
|
65
68
|
:tags => options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(","),
|
66
69
|
:timestamp => (options[:timestamp] || Time.now.to_i),
|
67
70
|
:transformation => Cloudinary::Utils.generate_transformation_string(options.clone),
|
@@ -85,16 +88,7 @@ class Cloudinary::Uploader
|
|
85
88
|
def self.upload(file, options={})
|
86
89
|
call_api("upload", options) do
|
87
90
|
params = build_upload_params(options)
|
88
|
-
|
89
|
-
params[:file] = File.open(file, "rb")
|
90
|
-
elsif file.is_a?(StringIO)
|
91
|
-
file.rewind
|
92
|
-
params[:file] = Cloudinary::Blob.new(file.read, options)
|
93
|
-
elsif file.respond_to?(:read) || Cloudinary::Utils.is_remote?(file)
|
94
|
-
params[:file] = file
|
95
|
-
else
|
96
|
-
params[:file] = File.open(file, "rb")
|
97
|
-
end
|
91
|
+
params[:file] = Cloudinary::Utils.handle_file_param(file, options)
|
98
92
|
[params, [:file]]
|
99
93
|
end
|
100
94
|
end
|
@@ -151,11 +145,7 @@ class Cloudinary::Uploader
|
|
151
145
|
options[:resource_type] ||= :raw
|
152
146
|
call_api("upload", options) do
|
153
147
|
params = build_upload_params(options)
|
154
|
-
|
155
|
-
params[:file] = File.open(file, "rb")
|
156
|
-
else
|
157
|
-
params[:file] = file
|
158
|
-
end
|
148
|
+
params[:file] = Cloudinary::Utils.handle_file_param(file, options)
|
159
149
|
[params, [:file]]
|
160
150
|
end
|
161
151
|
end
|
data/lib/cloudinary/utils.rb
CHANGED
@@ -524,18 +524,10 @@ class Cloudinary::Utils
|
|
524
524
|
version = options.delete(:version)
|
525
525
|
force_version = config_option_consume(options, :force_version, true)
|
526
526
|
format = options.delete(:format)
|
527
|
-
cloud_name = config_option_consume(options, :cloud_name) || raise(CloudinaryException, "Must supply cloud_name in tag or in configuration")
|
528
527
|
|
529
|
-
secure = options.delete(:secure)
|
530
|
-
ssl_detected = options.delete(:ssl_detected)
|
531
|
-
secure = ssl_detected || Cloudinary.config.secure if secure.nil?
|
532
|
-
private_cdn = config_option_consume(options, :private_cdn)
|
533
|
-
secure_distribution = config_option_consume(options, :secure_distribution)
|
534
|
-
cname = config_option_consume(options, :cname)
|
535
528
|
shorten = config_option_consume(options, :shorten)
|
536
529
|
force_remote = options.delete(:force_remote)
|
537
|
-
|
538
|
-
secure_cdn_subdomain = config_option_consume(options, :secure_cdn_subdomain)
|
530
|
+
|
539
531
|
sign_url = config_option_consume(options, :sign_url)
|
540
532
|
secret = config_option_consume(options, :api_secret)
|
541
533
|
sign_version = config_option_consume(options, :sign_version) # Deprecated behavior
|
@@ -558,7 +550,7 @@ class Cloudinary::Utils
|
|
558
550
|
type = type.to_s unless type.nil?
|
559
551
|
resource_type ||= "image"
|
560
552
|
source = source.to_s
|
561
|
-
|
553
|
+
unless force_remote
|
562
554
|
static_support = Cloudinary.config.static_file_support || Cloudinary.config.static_image_support
|
563
555
|
return original_source if !static_support && type == "asset"
|
564
556
|
return original_source if (type.nil? || type == "asset") && source.match(%r(^https?:/)i)
|
@@ -594,7 +586,9 @@ class Cloudinary::Utils
|
|
594
586
|
signature = "s--#{signature[0, long_url_signature ? LONG_URL_SIGNATURE_LENGTH : SHORT_URL_SIGNATURE_LENGTH ]}--"
|
595
587
|
end
|
596
588
|
|
597
|
-
|
589
|
+
options[:source] = source
|
590
|
+
prefix = build_distribution_domain(options)
|
591
|
+
|
598
592
|
source = [prefix, resource_type, type, signature, transformation, version, source].reject(&:blank?).join("/")
|
599
593
|
if sign_url && auth_token && !auth_token.empty?
|
600
594
|
auth_token[:url] = URI.parse(source).path
|
@@ -707,6 +701,22 @@ class Cloudinary::Utils
|
|
707
701
|
prefix
|
708
702
|
end
|
709
703
|
|
704
|
+
def self.build_distribution_domain(options = {})
|
705
|
+
cloud_name = config_option_consume(options, :cloud_name) || raise(CloudinaryException, "Must supply cloud_name in tag or in configuration")
|
706
|
+
|
707
|
+
source = options.delete(:source)
|
708
|
+
secure = options.delete(:secure)
|
709
|
+
ssl_detected = options.delete(:ssl_detected)
|
710
|
+
secure = ssl_detected || Cloudinary.config.secure if secure.nil?
|
711
|
+
private_cdn = config_option_consume(options, :private_cdn)
|
712
|
+
secure_distribution = config_option_consume(options, :secure_distribution)
|
713
|
+
cname = config_option_consume(options, :cname)
|
714
|
+
cdn_subdomain = config_option_consume(options, :cdn_subdomain)
|
715
|
+
secure_cdn_subdomain = config_option_consume(options, :secure_cdn_subdomain)
|
716
|
+
|
717
|
+
unsigned_download_url_prefix(source, cloud_name, private_cdn, cdn_subdomain, secure_cdn_subdomain, cname, secure, secure_distribution)
|
718
|
+
end
|
719
|
+
|
710
720
|
# Creates a base URL for the cloudinary api
|
711
721
|
#
|
712
722
|
# @param [Object] path Resource name
|
@@ -1285,6 +1295,27 @@ class Cloudinary::Utils
|
|
1285
1295
|
}
|
1286
1296
|
end
|
1287
1297
|
|
1298
|
+
# Handles file parameter.
|
1299
|
+
#
|
1300
|
+
# @param [Pathname, StringIO, File, String, int, _ToPath] file
|
1301
|
+
# @return [StringIO, File] A File object.
|
1302
|
+
#
|
1303
|
+
# @private
|
1304
|
+
def self.handle_file_param(file, options = {})
|
1305
|
+
if file.is_a?(Pathname)
|
1306
|
+
return File.open(file, "rb")
|
1307
|
+
elsif file.is_a?(Cloudinary::Blob)
|
1308
|
+
return file
|
1309
|
+
elsif file.is_a?(StringIO)
|
1310
|
+
file.rewind
|
1311
|
+
return Cloudinary::Blob.new(file.read, options)
|
1312
|
+
elsif file.respond_to?(:read) || Cloudinary::Utils.is_remote?(file)
|
1313
|
+
return file
|
1314
|
+
end
|
1315
|
+
|
1316
|
+
File.open(file, "rb")
|
1317
|
+
end
|
1318
|
+
|
1288
1319
|
# The returned url should allow downloading the backedup asset based on the version and asset id
|
1289
1320
|
#
|
1290
1321
|
# asset and version id are returned with resource(<PUBLIC_ID1>, { versions: true })
|
@@ -1373,6 +1404,4 @@ class Cloudinary::Utils
|
|
1373
1404
|
algorithm = ALGORITHM_SIGNATURE[signature_algorithm] || raise("Unsupported algorithm '#{signature_algorithm}'")
|
1374
1405
|
algorithm.public_send(hash_method, input)
|
1375
1406
|
end
|
1376
|
-
|
1377
|
-
private_class_method :hash
|
1378
1407
|
end
|
data/lib/cloudinary/version.rb
CHANGED
data/lib/cloudinary.rb
CHANGED
@@ -28,6 +28,7 @@ module Cloudinary
|
|
28
28
|
autoload :Static, "cloudinary/static"
|
29
29
|
autoload :CarrierWave, "cloudinary/carrier_wave"
|
30
30
|
autoload :Search, "cloudinary/search"
|
31
|
+
autoload :SearchFolders, "cloudinary/search_folders"
|
31
32
|
|
32
33
|
CF_SHARED_CDN = "d3jpl91pxevbkh.cloudfront.net"
|
33
34
|
AKAMAI_SHARED_CDN = "res.cloudinary.com"
|
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.28.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: 2023-06
|
13
|
+
date: 2023-11-06 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: aws_cf_signer
|
@@ -235,6 +235,7 @@ files:
|
|
235
235
|
- lib/cloudinary/railtie.rb
|
236
236
|
- lib/cloudinary/responsive.rb
|
237
237
|
- lib/cloudinary/search.rb
|
238
|
+
- lib/cloudinary/search_folders.rb
|
238
239
|
- lib/cloudinary/static.rb
|
239
240
|
- lib/cloudinary/uploader.rb
|
240
241
|
- lib/cloudinary/utils.rb
|