cloudinary 1.26.0 → 1.28.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 +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
|