cloudinary 1.15.0 → 1.18.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/.github/pull_request_template.md +24 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +57 -0
- data/Rakefile +3 -45
- data/cloudinary.gemspec +1 -0
- data/lib/active_storage/service/cloudinary_service.rb +10 -4
- data/lib/cloudinary/api.rb +154 -0
- data/lib/cloudinary/carrier_wave.rb +1 -0
- data/lib/cloudinary/carrier_wave/remote.rb +2 -1
- data/lib/cloudinary/carrier_wave/storage.rb +2 -1
- data/lib/cloudinary/helper.rb +1 -1
- data/lib/cloudinary/railtie.rb +1 -1
- data/lib/cloudinary/uploader.rb +29 -1
- data/lib/cloudinary/utils.rb +39 -3
- 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 +29 -11
- data/vendor/assets/javascripts/cloudinary/jquery.cloudinary.js +15 -11
- metadata +24 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c9179fe1c8105281b33780687c2bed49db41a35fca2d33ff15bd7fd4635d119f
|
4
|
+
data.tar.gz: 7b3bd01f71f1012bc7f315f707450ebb65537064e004fad615d713f489c4316c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 347fc122e9a31aa241afa194c09cdc3c0d19e63c5a206cc7751f4939de7c273769d648c7fd33af2cc4e7505fba0a5be9d555f1c3db1e2b41d45cfb58082e1cc3
|
7
|
+
data.tar.gz: 4f04b59256afe8f23c27625d94d761e9802e2ccd91d3c3dc992eb263e3430a7a053467c203d416d379815e317924f042c9310ac0f2b4ca185630307268aa66ca
|
@@ -0,0 +1,24 @@
|
|
1
|
+
### Brief Summary of Changes
|
2
|
+
<!--
|
3
|
+
Provide some context as to what was changed, from an implementation standpoint.
|
4
|
+
-->
|
5
|
+
|
6
|
+
#### What does this PR address?
|
7
|
+
[ ] Gitub issue (Add reference - #XX)
|
8
|
+
[ ] Refactoring
|
9
|
+
[ ] New feature
|
10
|
+
[ ] Bug fix
|
11
|
+
[ ] Adds more tests
|
12
|
+
|
13
|
+
#### Are tests included?
|
14
|
+
[ ] Yes
|
15
|
+
[ ] No
|
16
|
+
|
17
|
+
#### Reviewer, Please Note:
|
18
|
+
<!--
|
19
|
+
List anything here that the reviewer should pay special attention to. This might
|
20
|
+
include, for example:
|
21
|
+
• Dependence on other PRs
|
22
|
+
• Reference to other Cloudinary SDKs
|
23
|
+
• Changes that seem arbitrary without further explanations
|
24
|
+
-->
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,61 @@
|
|
1
1
|
|
2
|
+
1.18.0 / 2020-09-27
|
3
|
+
===================
|
4
|
+
|
5
|
+
New functionality and features
|
6
|
+
------------------------------
|
7
|
+
* Add `download_folder` helper
|
8
|
+
* Add support for `sources` in `video` tag
|
9
|
+
* Add structured metadata to Admin and Upload API
|
10
|
+
|
11
|
+
Other Changes
|
12
|
+
-------------
|
13
|
+
* Fix download of a raw file in ActiveStorage
|
14
|
+
* Update embedded `jquery.cloudinary.js` to fix ES5 compatibility issue
|
15
|
+
|
16
|
+
1.17.1 / 2020-08-25
|
17
|
+
===================
|
18
|
+
|
19
|
+
* Fix options handling issue in SassC
|
20
|
+
|
21
|
+
1.17.0 / 2020-08-21
|
22
|
+
===================
|
23
|
+
|
24
|
+
New functionality and features
|
25
|
+
------------------------------
|
26
|
+
|
27
|
+
* Add support for `eval` upload parameter
|
28
|
+
* Add support for 32-char signature length
|
29
|
+
|
30
|
+
Other Changes
|
31
|
+
-------------
|
32
|
+
|
33
|
+
* Fix escaping of query string characters in CarrierWave integration
|
34
|
+
* Fix detection integration test
|
35
|
+
* Integrate with sub-account test service
|
36
|
+
* Add pull request template
|
37
|
+
|
38
|
+
1.16.1 / 2020-07-06
|
39
|
+
===================
|
40
|
+
|
41
|
+
* Detect data URLs with suffix in mime type
|
42
|
+
* Fix `Invalid regular expression` error in Safari
|
43
|
+
|
44
|
+
1.16.0 / 2020-06-29
|
45
|
+
===================
|
46
|
+
|
47
|
+
New functionality and features
|
48
|
+
------------------------------
|
49
|
+
|
50
|
+
* Add support for uploading `StringIO`
|
51
|
+
|
52
|
+
Other Changes
|
53
|
+
-------------
|
54
|
+
|
55
|
+
* Set default cache storage to `file` in `CarrierWave`
|
56
|
+
* Fix `normalize_expression` to ignore predefined variables
|
57
|
+
* Fix sample projects
|
58
|
+
|
2
59
|
1.15.0 / 2020-06-11
|
3
60
|
===================
|
4
61
|
|
data/Rakefile
CHANGED
@@ -1,55 +1,13 @@
|
|
1
1
|
require 'bundler'
|
2
2
|
require 'fileutils'
|
3
|
-
require 'tmpdir'
|
4
|
-
require 'rest_client'
|
5
|
-
require 'json'
|
6
|
-
require 'rubygems/package'
|
7
|
-
|
8
3
|
require 'rspec/core/rake_task'
|
4
|
+
|
9
5
|
RSpec::Core::RakeTask.new(:spec)
|
10
6
|
task :default => :spec
|
11
7
|
|
12
8
|
Bundler::GemHelper.install_tasks
|
13
9
|
|
14
|
-
|
15
|
-
|
16
|
-
task :fetch_assets do
|
17
|
-
index_files = %w[jquery.ui.widget.js jquery.iframe-transport.js jquery.fileupload.js jquery.cloudinary.js]
|
18
|
-
processing_files = %w[canvas-to-blob.min.js load-image.all.min.js jquery.fileupload-process.js jquery.fileupload-image.js jquery.fileupload-validate.js]
|
19
|
-
files = index_files + processing_files
|
20
|
-
|
21
|
-
release = JSON(RestClient.get("https://api.github.com/repos/cloudinary/cloudinary_js/releases/latest"))
|
22
|
-
|
23
|
-
FileUtils.rm_rf 'vendor/assets'
|
24
|
-
html_folder = 'vendor/assets/html'
|
25
|
-
FileUtils.mkdir_p html_folder
|
26
|
-
js_folder = 'vendor/assets/javascripts/cloudinary'
|
27
|
-
FileUtils.mkdir_p js_folder
|
28
|
-
|
29
|
-
puts "Fetching cloudinary_js version #{release["tag_name"]}\n\n"
|
30
|
-
sio = StringIO.new(RestClient.get(release["tarball_url"]).body)
|
31
|
-
file =Zlib::GzipReader.new(sio)
|
32
|
-
tar = Gem::Package::TarReader.new(file)
|
33
|
-
tar.each_entry do |entry|
|
34
|
-
name = File.basename(entry.full_name)
|
35
|
-
if files.include? name
|
36
|
-
js_full_name = File.join(js_folder, name)
|
37
|
-
puts "Adding #{js_full_name}"
|
38
|
-
File.write js_full_name, entry.read
|
39
|
-
elsif name == 'cloudinary_cors.html'
|
40
|
-
html_full_name = File.join(html_folder, name)
|
41
|
-
puts "Adding #{html_full_name}"
|
42
|
-
File.write html_full_name, entry.read
|
43
|
-
end
|
44
|
-
end
|
45
|
-
puts "Creating 'index.js' and 'processing.js' files"
|
46
|
-
File.open("vendor/assets/javascripts/cloudinary/index.js", "w") do |f|
|
47
|
-
index_files.each { |name| f.puts "//= require ./#{name}" }
|
48
|
-
end
|
49
|
-
File.open("vendor/assets/javascripts/cloudinary/processing.js", "w") do |f|
|
50
|
-
processing_files.each { |name| f.puts "//= require ./#{name}" }
|
51
|
-
end
|
52
|
-
end
|
10
|
+
path = File.expand_path(__dir__)
|
11
|
+
Dir.glob("#{path}/lib/tasks/**/*.rake").each { |f| import f }
|
53
12
|
|
54
|
-
end
|
55
13
|
task :build => "cloudinary:fetch_assets"
|
data/cloudinary.gemspec
CHANGED
@@ -33,6 +33,7 @@ Gem::Specification.new do |s|
|
|
33
33
|
|
34
34
|
s.add_development_dependency "sqlite3"
|
35
35
|
s.add_development_dependency "rspec", '>=3.5'
|
36
|
+
s.add_development_dependency "rspec-retry"
|
36
37
|
s.add_development_dependency "rails", "~>5.2" if RUBY_VERSION >= "2.2.2"
|
37
38
|
|
38
39
|
s.add_development_dependency "railties", "<= 4.2.7" if RUBY_VERSION <= "1.9.3"
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'active_storage/blob_key'
|
2
2
|
require 'cloudinary/helper'
|
3
|
+
require 'net/http'
|
3
4
|
|
4
5
|
unless ActiveStorage::Blob.method_defined? :original_key
|
5
6
|
class ActiveStorage::Blob
|
@@ -57,7 +58,7 @@ module ActiveStorage
|
|
57
58
|
url = Cloudinary::Utils.cloudinary_url(
|
58
59
|
public_id(key),
|
59
60
|
resource_type: resource_type(nil, key),
|
60
|
-
format: ext_for_file(filename, content_type),
|
61
|
+
format: ext_for_file(key, filename, content_type),
|
61
62
|
**@options.merge(options.symbolize_keys)
|
62
63
|
)
|
63
64
|
|
@@ -107,8 +108,7 @@ module ActiveStorage
|
|
107
108
|
end
|
108
109
|
|
109
110
|
def download(key, &block)
|
110
|
-
|
111
|
-
uri = URI(url)
|
111
|
+
uri = URI(url(key))
|
112
112
|
if block_given?
|
113
113
|
instrument :streaming_download, key: key do
|
114
114
|
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
@@ -169,12 +169,18 @@ module ActiveStorage
|
|
169
169
|
#
|
170
170
|
# It does the best effort when original filename does not include extension, but we know the mime-type.
|
171
171
|
#
|
172
|
+
# @param [ActiveStorage::BlobKey] key The blob key with attributes.
|
172
173
|
# @param [ActiveStorage::Filename] filename The original filename.
|
173
174
|
# @param [string] content_type The content type of the file.
|
174
175
|
#
|
175
176
|
# @return [string] The extension of the filename.
|
176
|
-
def ext_for_file(filename, content_type)
|
177
|
+
def ext_for_file(key, filename, content_type)
|
178
|
+
if filename.blank?
|
179
|
+
options = key.respond_to?(:attributes) ? key.attributes : {}
|
180
|
+
filename = ActiveStorage::Filename.new(options[:filename]) if options.has_key?(:filename)
|
181
|
+
end
|
177
182
|
ext = filename.respond_to?(:extension_without_delimiter) ? filename.extension_without_delimiter : nil
|
183
|
+
|
178
184
|
return ext unless ext.blank?
|
179
185
|
|
180
186
|
# Raw files are not convertible, no extension guessing for them
|
data/lib/cloudinary/api.rb
CHANGED
@@ -348,6 +348,144 @@ class Cloudinary::Api
|
|
348
348
|
call_json_api('GET', json_url, {}, 60, {})
|
349
349
|
end
|
350
350
|
|
351
|
+
# Returns a list of all metadata field definitions.
|
352
|
+
#
|
353
|
+
# @see https://cloudinary.com/documentation/admin_api#get_metadata_fields Get metadata fields API reference
|
354
|
+
#
|
355
|
+
# @param [Hash] options Additional options
|
356
|
+
# @return [Cloudinary::Api::Response]
|
357
|
+
# @raise [Cloudinary::Api::Error]
|
358
|
+
def self.list_metadata_fields(options = {})
|
359
|
+
call_metadata_api(:get, [], {}, options)
|
360
|
+
end
|
361
|
+
|
362
|
+
# Gets a metadata field by external id.
|
363
|
+
#
|
364
|
+
# @see https://cloudinary.com/documentation/admin_api#get_a_metadata_field_by_external_id Get metadata field by external ID API reference
|
365
|
+
#
|
366
|
+
# @param [String] field_external_id The ID of the metadata field to retrieve
|
367
|
+
# @param [Hash] options Additional options
|
368
|
+
# @return [Cloudinary::Api::Response]
|
369
|
+
# @raise [Cloudinary::Api::Error]
|
370
|
+
def self.metadata_field_by_field_id(field_external_id, options = {})
|
371
|
+
uri = [field_external_id]
|
372
|
+
|
373
|
+
call_metadata_api(:get, uri, {}, options)
|
374
|
+
end
|
375
|
+
|
376
|
+
# Creates a new metadata field definition.
|
377
|
+
#
|
378
|
+
# @see https://cloudinary.com/documentation/admin_api#create_a_metadata_field Create metadata field API reference
|
379
|
+
#
|
380
|
+
# @param [Hash] field The field to add
|
381
|
+
# @param [Hash] options Additional options
|
382
|
+
# @return [Cloudinary::Api::Response]
|
383
|
+
# @raise [Cloudinary::Api::Error]
|
384
|
+
def self.add_metadata_field(field, options = {})
|
385
|
+
params = only(field, :type, :external_id, :label, :mandatory, :default_value, :validation, :datasource)
|
386
|
+
|
387
|
+
call_metadata_api(:post, [], params, options)
|
388
|
+
end
|
389
|
+
|
390
|
+
# Updates a metadata field by external id.
|
391
|
+
#
|
392
|
+
# Updates a metadata field definition (partially, no need to pass the entire object) passed as JSON data.
|
393
|
+
# See https://cloudinary.com/documentation/admin_api#generic_structure_of_a_metadata_field for the generic structure
|
394
|
+
# of a metadata field.
|
395
|
+
#
|
396
|
+
# @see https://cloudinary.com/documentation/admin_api#update_a_metadata_field_by_external_id Update metadata field API reference
|
397
|
+
#
|
398
|
+
# @param [String] field_external_id The id of the metadata field to update
|
399
|
+
# @param [Hash] field The field definition
|
400
|
+
# @param [Hash] options Additional options
|
401
|
+
# @return [Cloudinary::Api::Response]
|
402
|
+
# @raise [Cloudinary::Api::Error]
|
403
|
+
def self.update_metadata_field(field_external_id, field, options = {})
|
404
|
+
uri = [field_external_id]
|
405
|
+
params = only(field, :label, :mandatory, :default_value, :validation)
|
406
|
+
|
407
|
+
call_metadata_api(:put, uri, params, options)
|
408
|
+
end
|
409
|
+
|
410
|
+
# Deletes a metadata field definition.
|
411
|
+
#
|
412
|
+
# The field should no longer be considered a valid candidate for all other endpoints.
|
413
|
+
#
|
414
|
+
# @see https://cloudinary.com/documentation/admin_api#delete_a_metadata_field_by_external_id Delete metadata field API reference
|
415
|
+
#
|
416
|
+
# @param [String] field_external_id The external id of the field to delete
|
417
|
+
# @param [Hash] options Additional options
|
418
|
+
# @return [Cloudinary::Api::Response] A hash with a "message" key. "ok" value indicates a successful deletion
|
419
|
+
# @raise [Cloudinary::Api::Error]
|
420
|
+
def self.delete_metadata_field(field_external_id, options = {})
|
421
|
+
uri = [field_external_id]
|
422
|
+
|
423
|
+
call_metadata_api(:delete, uri, {}, options)
|
424
|
+
end
|
425
|
+
|
426
|
+
# Deletes entries in a metadata field datasource.
|
427
|
+
#
|
428
|
+
# Deletes (blocks) the datasource entries for a specified metadata field definition. Sets the state of the
|
429
|
+
# entries to inactive. This is a soft delete, the entries still exist under the hood and can be activated
|
430
|
+
# again with the restore datasource entries method.
|
431
|
+
#
|
432
|
+
# @see https://cloudinary.com/documentation/admin_api#delete_entries_in_a_metadata_field_datasource Delete entries in a metadata field datasource API reference
|
433
|
+
#
|
434
|
+
# @param [String] field_external_id The id of the field to update
|
435
|
+
# @param [Array] entries_external_id The ids of all the entries to delete from the datasource
|
436
|
+
# @param [Hash] options Additional options
|
437
|
+
# @return [Cloudinary::Api::Response] The remaining datasource entries
|
438
|
+
# @raise [Cloudinary::Api::Error]
|
439
|
+
def self.delete_datasource_entries(field_external_id, entries_external_id, options = {})
|
440
|
+
uri = [field_external_id, "datasource"]
|
441
|
+
params = {:external_ids => entries_external_id }
|
442
|
+
|
443
|
+
call_metadata_api(:delete, uri, params, options)
|
444
|
+
end
|
445
|
+
|
446
|
+
# Updates a metadata field datasource.
|
447
|
+
#
|
448
|
+
# Updates the datasource of a supported field type (currently only enum and set), passed as JSON data. The
|
449
|
+
# update is partial: datasource entries with an existing external_id will be updated and entries with new
|
450
|
+
# external_id’s (or without external_id’s) will be appended.
|
451
|
+
#
|
452
|
+
# @see https://cloudinary.com/documentation/admin_api#update_a_metadata_field_datasource Update a metadata field datasource API reference
|
453
|
+
#
|
454
|
+
# @param [String] field_external_id The external id of the field to update
|
455
|
+
# @param [Array] entries_external_id
|
456
|
+
# @param [Hash] options Additional options
|
457
|
+
# @return [Cloudinary::Api::Response]
|
458
|
+
# @raise [Cloudinary::Api::Error]
|
459
|
+
def self.update_metadata_field_datasource(field_external_id, entries_external_id, options = {})
|
460
|
+
uri = [field_external_id, "datasource"]
|
461
|
+
|
462
|
+
params = entries_external_id.each_with_object({:values => [] }) do |item, hash|
|
463
|
+
item = only(item, :external_id, :value)
|
464
|
+
hash[:values ] << item if item.present?
|
465
|
+
end
|
466
|
+
|
467
|
+
call_metadata_api(:put, uri, params, options)
|
468
|
+
end
|
469
|
+
|
470
|
+
# Restores entries in a metadata field datasource.
|
471
|
+
#
|
472
|
+
# Restores (unblocks) any previously deleted datasource entries for a specified metadata field definition.
|
473
|
+
# Sets the state of the entries to active.
|
474
|
+
#
|
475
|
+
# @see https://cloudinary.com/documentation/admin_api#restore_entries_in_a_metadata_field_datasource Restore entries in a metadata field datasource API reference
|
476
|
+
#
|
477
|
+
# @param [String] field_external_id The ID of the metadata field
|
478
|
+
# @param [Array] entries_external_ids An array of IDs of datasource entries to restore (unblock)
|
479
|
+
# @param [Hash] options Additional options
|
480
|
+
# @return [Cloudinary::Api::Response]
|
481
|
+
# @raise [Cloudinary::Api::Error]
|
482
|
+
def self.restore_metadata_field_datasource(field_external_id, entries_external_ids, options = {})
|
483
|
+
uri = [field_external_id, "datasource_restore"]
|
484
|
+
params = {:external_ids => entries_external_ids }
|
485
|
+
|
486
|
+
call_metadata_api(:post, uri, params, options)
|
487
|
+
end
|
488
|
+
|
351
489
|
protected
|
352
490
|
|
353
491
|
def self.call_api(method, uri, params, options)
|
@@ -396,6 +534,22 @@ class Cloudinary::Api
|
|
396
534
|
raise GeneralError.new("Error parsing server response (#{response.code}) - #{response.body}. Got - #{e}")
|
397
535
|
end
|
398
536
|
|
537
|
+
# Protected function that assists with performing an API call to the metadata_fields part of the Admin API.
|
538
|
+
#
|
539
|
+
# @protected
|
540
|
+
# @param [Symbol] method The HTTP method. Valid methods: get, post, put, delete
|
541
|
+
# @param [Array] uri REST endpoint of the API (without 'metadata_fields')
|
542
|
+
# @param [Hash] params Query/body parameters passed to the method
|
543
|
+
# @param [Hash] options Additional options. Can be an override of the configuration, headers, etc.
|
544
|
+
# @return [Cloudinary::Api::Response]
|
545
|
+
# @raise [Cloudinary::Api::Error]
|
546
|
+
def self.call_metadata_api(method, uri, params, options)
|
547
|
+
options[:content_type] = :json
|
548
|
+
uri = ["metadata_fields", uri].reject(&:empty?).join("/")
|
549
|
+
|
550
|
+
call_api(method, uri, params, options)
|
551
|
+
end
|
552
|
+
|
399
553
|
def self.only(hash, *keys)
|
400
554
|
result = {}
|
401
555
|
keys.each do |key|
|
@@ -9,6 +9,7 @@ module Cloudinary::CarrierWave
|
|
9
9
|
|
10
10
|
def self.included(base)
|
11
11
|
base.storage Cloudinary::CarrierWave::Storage
|
12
|
+
base.cache_storage = :file if base.cache_storage.blank?
|
12
13
|
base.extend ClassMethods
|
13
14
|
base.class_attribute :metadata
|
14
15
|
base.class_attribute :storage_type, instance_reader: false
|
@@ -4,7 +4,8 @@ module Cloudinary::CarrierWave
|
|
4
4
|
if respond_to?(:process_uri)
|
5
5
|
uri = process_uri(uri)
|
6
6
|
else # Backward compatibility with old CarrierWave
|
7
|
-
|
7
|
+
remote_url_unsafe_chars = /([^a-zA-Z0-9_.\-\/:?&=]+)/ # In addition allow query string characters: "?","&" and "="
|
8
|
+
uri = URI.parse(Cloudinary::Utils.smart_escape(Cloudinary::Utils.smart_unescape(uri), remote_url_unsafe_chars))
|
8
9
|
end
|
9
10
|
return if uri.to_s.blank?
|
10
11
|
self.original_filename = @cache_id = @filename = File.basename(uri.path).gsub(/[^a-zA-Z0-9\.\-\+_]/, '')
|
@@ -1,7 +1,8 @@
|
|
1
1
|
class Cloudinary::CarrierWave::Storage < ::CarrierWave::Storage::Abstract
|
2
2
|
|
3
3
|
def store!(file)
|
4
|
-
return
|
4
|
+
return unless uploader.enable_processing
|
5
|
+
|
5
6
|
if uploader.is_main_uploader?
|
6
7
|
case file
|
7
8
|
when Cloudinary::CarrierWave::PreloadedCloudinaryFile
|
data/lib/cloudinary/helper.rb
CHANGED
@@ -438,7 +438,7 @@ begin
|
|
438
438
|
# @return [::SassC::Script::Value::String]
|
439
439
|
def cloudinary_url(public_id, sass_options = {})
|
440
440
|
options = {}
|
441
|
-
sass_options.to_h.each { |k, v| options[k.value] = v.value }
|
441
|
+
sass_options.to_h.each { |k, v| options[k.value.to_sym] = v.value }
|
442
442
|
url = Cloudinary::Utils.cloudinary_url(public_id.value, {:type => :asset}.merge(options))
|
443
443
|
::SassC::Script::Value::String.new("url(#{url})")
|
444
444
|
end
|
data/lib/cloudinary/railtie.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class Cloudinary::Railtie < Rails::Railtie
|
2
2
|
rake_tasks do
|
3
|
-
Dir[File.join(File.dirname(__FILE__),'../tasks
|
3
|
+
Dir[File.join(File.dirname(__FILE__),'../tasks/**/*.rake')].each { |f| load f }
|
4
4
|
end
|
5
5
|
config.after_initialize do |app|
|
6
6
|
ActionView::Base.send :include, CloudinaryHelper
|
data/lib/cloudinary/uploader.rb
CHANGED
@@ -37,6 +37,7 @@ class Cloudinary::Uploader
|
|
37
37
|
:eager_async => Cloudinary::Utils.as_safe_bool(options[:eager_async]),
|
38
38
|
:eager_notification_url => options[:eager_notification_url],
|
39
39
|
:exif => Cloudinary::Utils.as_safe_bool(options[:exif]),
|
40
|
+
:eval => options[:eval],
|
40
41
|
:face_coordinates => Cloudinary::Utils.encode_double_array(options[:face_coordinates]),
|
41
42
|
:faces => Cloudinary::Utils.as_safe_bool(options[:faces]),
|
42
43
|
:folder => options[:folder],
|
@@ -64,7 +65,8 @@ class Cloudinary::Uploader
|
|
64
65
|
:unique_filename => Cloudinary::Utils.as_safe_bool(options[:unique_filename]),
|
65
66
|
:upload_preset => options[:upload_preset],
|
66
67
|
:use_filename => Cloudinary::Utils.as_safe_bool(options[:use_filename]),
|
67
|
-
:accessibility_analysis => Cloudinary::Utils.as_safe_bool(options[:accessibility_analysis])
|
68
|
+
:accessibility_analysis => Cloudinary::Utils.as_safe_bool(options[:accessibility_analysis]),
|
69
|
+
:metadata => Cloudinary::Utils.encode_context(options[:metadata])
|
68
70
|
}
|
69
71
|
params
|
70
72
|
end
|
@@ -78,6 +80,9 @@ class Cloudinary::Uploader
|
|
78
80
|
params = build_upload_params(options)
|
79
81
|
if file.is_a?(Pathname)
|
80
82
|
params[:file] = File.open(file, "rb")
|
83
|
+
elsif file.is_a?(StringIO)
|
84
|
+
file.rewind
|
85
|
+
params[:file] = Cloudinary::Blob.new(file.read, options)
|
81
86
|
elsif file.respond_to?(:read) || Cloudinary::Utils.is_remote?(file)
|
82
87
|
params[:file] = file
|
83
88
|
else
|
@@ -268,6 +273,29 @@ class Cloudinary::Uploader
|
|
268
273
|
return self.call_tags_api(nil, "remove_all", public_ids, options)
|
269
274
|
end
|
270
275
|
|
276
|
+
# Populates metadata fields with the given values. Existing values will be overwritten.
|
277
|
+
#
|
278
|
+
# Any metadata-value pairs given are merged with any existing metadata-value pairs
|
279
|
+
# (an empty value for an existing metadata field clears the value).
|
280
|
+
#
|
281
|
+
# @param [Hash] metadata A list of custom metadata fields (by external_id) and the values to assign to each of them.
|
282
|
+
# @param [Array] public_ids An array of Public IDs of assets uploaded to Cloudinary.
|
283
|
+
# @param [Hash] options
|
284
|
+
# @option options [String] :resource_type The type of file. Default: image. Valid values: image, raw, video.
|
285
|
+
# @option options [String] :type The storage type. Default: upload. Valid values: upload, private, authenticated
|
286
|
+
# @return mixed a list of public IDs that were updated
|
287
|
+
# @raise [Cloudinary::Api:Error]
|
288
|
+
def self.update_metadata(metadata, public_ids, options = {})
|
289
|
+
self.call_api("metadata", options) do
|
290
|
+
{
|
291
|
+
timestamp: (options[:timestamp] || Time.now.to_i),
|
292
|
+
type: options[:type],
|
293
|
+
public_ids: Cloudinary::Utils.build_array(public_ids),
|
294
|
+
metadata: Cloudinary::Utils.encode_context(metadata)
|
295
|
+
}
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
271
299
|
private
|
272
300
|
|
273
301
|
def self.call_tags_api(tag, command, public_ids = [], options = {})
|
data/lib/cloudinary/utils.rb
CHANGED
@@ -139,7 +139,10 @@ class Cloudinary::Utils
|
|
139
139
|
zoom
|
140
140
|
].map(&:to_sym)
|
141
141
|
|
142
|
-
REMOTE_URL_REGEX = %r(^ftp:|^https?:|^s3:|^gs:|^data:([\w-]+\/[\w-]+)?(;[\w-]+=[\w-]+)*;base64,([a-zA-Z0-9\/+\n=]+)$)
|
142
|
+
REMOTE_URL_REGEX = %r(^ftp:|^https?:|^s3:|^gs:|^data:([\w-]+\/[\w-]+(\+[\w-]+)?)?(;[\w-]+=[\w-]+)*;base64,([a-zA-Z0-9\/+\n=]+)$)
|
143
|
+
|
144
|
+
LONG_URL_SIGNATURE_LENGTH = 32
|
145
|
+
SHORT_URL_SIGNATURE_LENGTH = 8
|
143
146
|
|
144
147
|
def self.extract_config_params(options)
|
145
148
|
options.select{|k,v| URL_KEYS.include?(k)}
|
@@ -306,7 +309,7 @@ class Cloudinary::Utils
|
|
306
309
|
"if_" + normalize_expression(if_value) unless if_value.to_s.empty?
|
307
310
|
end
|
308
311
|
|
309
|
-
EXP_REGEXP = Regexp.new(PREDEFINED_VARS.keys.join("|")+'|('+CONDITIONAL_OPERATORS.keys.reverse.map { |k| Regexp.escape(k) }.join('|')+')(?=[ _])')
|
312
|
+
EXP_REGEXP = Regexp.new('(?<!\$)('+PREDEFINED_VARS.keys.join("|")+')'+'|('+CONDITIONAL_OPERATORS.keys.reverse.map { |k| Regexp.escape(k) }.join('|')+')(?=[ _])')
|
310
313
|
EXP_REPLACEMENT = PREDEFINED_VARS.merge(CONDITIONAL_OPERATORS)
|
311
314
|
|
312
315
|
def self.normalize_expression(expression)
|
@@ -497,6 +500,7 @@ class Cloudinary::Utils
|
|
497
500
|
url_suffix = options.delete(:url_suffix)
|
498
501
|
use_root_path = config_option_consume(options, :use_root_path)
|
499
502
|
auth_token = config_option_consume(options, :auth_token)
|
503
|
+
long_url_signature = config_option_consume(options, :long_url_signature)
|
500
504
|
unless auth_token == false
|
501
505
|
auth_token = Cloudinary::AuthToken.merge_auth_token(Cloudinary.config.auth_token, auth_token)
|
502
506
|
end
|
@@ -541,7 +545,7 @@ class Cloudinary::Utils
|
|
541
545
|
raise(CloudinaryException, "Must supply api_secret") if (secret.nil? || secret.empty?)
|
542
546
|
to_sign = [transformation, sign_version && version, source_to_sign].reject(&:blank?).join("/")
|
543
547
|
to_sign = fully_unescape(to_sign)
|
544
|
-
signature =
|
548
|
+
signature = compute_signature(to_sign, secret, long_url_signature)
|
545
549
|
end
|
546
550
|
|
547
551
|
prefix = unsigned_download_url_prefix(source, cloud_name, private_cdn, cdn_subdomain, secure_cdn_subdomain, cname, secure, secure_distribution)
|
@@ -732,6 +736,18 @@ class Cloudinary::Utils
|
|
732
736
|
download_archive_url(options.merge(:target_format => "zip"))
|
733
737
|
end
|
734
738
|
|
739
|
+
# Creates and returns a URL that when invoked creates an archive of a folder.
|
740
|
+
#
|
741
|
+
# @param [Object] folder_path Full path (from the root) of the folder to download.
|
742
|
+
# @param [Hash] options Additional options.
|
743
|
+
#
|
744
|
+
# @return [String]
|
745
|
+
def self.download_folder(folder_path, options = {})
|
746
|
+
resource_type = options[:resource_type] || "all"
|
747
|
+
|
748
|
+
download_archive_url(options.merge(:resource_type => resource_type, :prefixes => folder_path))
|
749
|
+
end
|
750
|
+
|
735
751
|
def self.signed_download_url(public_id, options = {})
|
736
752
|
aws_private_key_path = options[:aws_private_key_path] || Cloudinary.config.aws_private_key_path
|
737
753
|
if aws_private_key_path
|
@@ -1132,4 +1148,24 @@ class Cloudinary::Utils
|
|
1132
1148
|
def self.is_remote?(url)
|
1133
1149
|
REMOTE_URL_REGEX === url
|
1134
1150
|
end
|
1151
|
+
|
1152
|
+
# Computes a short or long signature based on a message and secret
|
1153
|
+
# @param [String] message The string to sign
|
1154
|
+
# @param [String] secret A secret that will be added to the message when signing
|
1155
|
+
# @param [Boolean] long_signature Whether to create a short or long signature
|
1156
|
+
# @return [String] Properly formatted signature
|
1157
|
+
def self.compute_signature(message, secret, long_url_signature)
|
1158
|
+
combined_message_secret = message + secret
|
1159
|
+
|
1160
|
+
algo, signature_length =
|
1161
|
+
if long_url_signature
|
1162
|
+
[Digest::SHA256, LONG_URL_SIGNATURE_LENGTH]
|
1163
|
+
else
|
1164
|
+
[Digest::SHA1, SHORT_URL_SIGNATURE_LENGTH]
|
1165
|
+
end
|
1166
|
+
|
1167
|
+
"s--#{Base64.urlsafe_encode64(algo.digest(combined_message_secret))[0, signature_length]}--"
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
private_class_method :compute_signature
|
1135
1171
|
end
|
data/lib/cloudinary/version.rb
CHANGED
@@ -3,12 +3,33 @@ module CloudinaryHelper
|
|
3
3
|
DEFAULT_POSTER_OPTIONS = { :format => 'jpg', :resource_type => 'video' }
|
4
4
|
DEFAULT_SOURCE_TYPES = %w(webm mp4 ogv)
|
5
5
|
DEFAULT_VIDEO_OPTIONS = { :resource_type => 'video' }
|
6
|
+
DEFAULT_SOURCES = [
|
7
|
+
{
|
8
|
+
:type => "mp4",
|
9
|
+
:codecs => "hev1",
|
10
|
+
:transformations => { :video_codec => "h265" }
|
11
|
+
},
|
12
|
+
{
|
13
|
+
:type => "webm",
|
14
|
+
:codecs => "vp9",
|
15
|
+
:transformations => { :video_codec => "vp9" }
|
16
|
+
},
|
17
|
+
{
|
18
|
+
:type => "mp4",
|
19
|
+
:transformations => { :video_codec => "auto" }
|
20
|
+
},
|
21
|
+
{
|
22
|
+
:type => "webm",
|
23
|
+
:transformations => { :video_codec => "auto" }
|
24
|
+
}
|
25
|
+
]
|
6
26
|
|
7
27
|
# Creates an HTML video tag for the provided +source+
|
8
28
|
#
|
9
29
|
# ==== Options
|
10
30
|
# * <tt>:source_types</tt> - Specify which source type the tag should include. defaults to webm, mp4 and ogv.
|
11
31
|
# * <tt>:source_transformation</tt> - specific transformations to use for a specific source type.
|
32
|
+
# * <tt>:sources</tt> - list of sources (overrides :source_types when present)
|
12
33
|
# * <tt>:poster</tt> - override default thumbnail:
|
13
34
|
# * url: provide an ad hoc url
|
14
35
|
# * options: with specific poster transformations and/or Cloudinary +:public_id+
|
@@ -20,6 +41,17 @@ module CloudinaryHelper
|
|
20
41
|
# cl_video_tag("mymovie.webm", :source_types => [:webm, :mp4], :poster => {:effect => 'sepia'}) do
|
21
42
|
# content_tag( :span, "Cannot present video!")
|
22
43
|
# end
|
44
|
+
# cl_video_tag("mymovie", :sources => [
|
45
|
+
# {
|
46
|
+
# :type => "mp4",
|
47
|
+
# :codecs => "hev1",
|
48
|
+
# :transformations => { :video_codec => "h265" }
|
49
|
+
# },
|
50
|
+
# {
|
51
|
+
# :type => "webm",
|
52
|
+
# :transformations => { :video_codec => "auto" }
|
53
|
+
# }
|
54
|
+
# ])
|
23
55
|
def cl_video_tag(source, options = {}, &block)
|
24
56
|
source = strip_known_ext(source)
|
25
57
|
video_attributes = [:autoplay,:controls,:loop,:muted,:poster, :preload]
|
@@ -48,30 +80,12 @@ module CloudinaryHelper
|
|
48
80
|
video_options[:poster] = cl_video_thumbnail_path(source, options)
|
49
81
|
end
|
50
82
|
|
51
|
-
|
52
|
-
source_types = Array(options.delete(:source_types))
|
53
|
-
fallback = (capture(&block) if block_given?) || options.delete(:fallback_content)
|
83
|
+
fallback = (capture(&block) if block_given?) || options.delete(:fallback_content)
|
54
84
|
|
55
|
-
if
|
56
|
-
|
57
|
-
content_tag('video', tag_options.merge(video_options)) do
|
58
|
-
source_tags = source_types.map do |type|
|
59
|
-
transformation = source_transformation[type.to_sym] || {}
|
60
|
-
cloudinary_tag("#{source}.#{type}", options.merge(transformation)) do |url, _tag_options|
|
61
|
-
mime_type = "video/#{(type == 'ogv' ? 'ogg' : type)}"
|
62
|
-
tag("source", :src => url, :type => mime_type)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
source_tags.push(fallback.html_safe) unless fallback.blank?
|
66
|
-
safe_join(source_tags)
|
67
|
-
end
|
68
|
-
end
|
85
|
+
if options[:sources]
|
86
|
+
video_tag_from_sources(source, options, video_options, fallback)
|
69
87
|
else
|
70
|
-
|
71
|
-
video_options[:src] = cl_video_path("#{source}.#{source_types.first.to_sym}", transformation.merge(options))
|
72
|
-
cloudinary_tag(source, options) do |_source, tag_options|
|
73
|
-
content_tag('video', fallback, tag_options.merge(video_options))
|
74
|
-
end
|
88
|
+
video_tag_from_source_types(source, options, video_options, fallback)
|
75
89
|
end
|
76
90
|
end
|
77
91
|
|
@@ -96,6 +110,66 @@ module CloudinaryHelper
|
|
96
110
|
name.sub(/\.(#{DEFAULT_SOURCE_TYPES.join("|")})$/, '')
|
97
111
|
end
|
98
112
|
|
113
|
+
private
|
114
|
+
|
115
|
+
def video_tag_from_source_types(source_name, options, video_options, fallback)
|
116
|
+
source_transformation = options.delete(:source_transformation) || {}
|
117
|
+
source_types = Array(options.delete(:source_types))
|
118
|
+
|
119
|
+
if source_types.size > 1
|
120
|
+
sources = source_types.map do |type|
|
121
|
+
{
|
122
|
+
:type => type,
|
123
|
+
:transformations => source_transformation[type.to_sym] || {}
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
generate_tag_from_sources(:source_name => source_name,
|
128
|
+
:sources => sources,
|
129
|
+
:options => options,
|
130
|
+
:video_options => video_options,
|
131
|
+
:fallback => fallback)
|
132
|
+
else
|
133
|
+
transformation = source_transformation[source_types.first.to_sym] || {}
|
134
|
+
video_options[:src] = cl_video_path("#{source_name}.#{source_types.first.to_sym}", transformation.merge(options))
|
135
|
+
cloudinary_tag(source_name, options) do |_source, tag_options|
|
136
|
+
content_tag('video', fallback, tag_options.merge(video_options))
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def video_tag_from_sources(source_name, options, video_options, fallback)
|
142
|
+
sources = options.delete(:sources)
|
143
|
+
|
144
|
+
generate_tag_from_sources(:source_name => source_name,
|
145
|
+
:sources => sources,
|
146
|
+
:options => options,
|
147
|
+
:video_options => video_options,
|
148
|
+
:fallback => fallback)
|
149
|
+
end
|
150
|
+
|
151
|
+
def generate_tag_from_sources(params)
|
152
|
+
source_name, sources, options, video_options, fallback = params.values_at(:source_name, :sources, :options, :video_options, :fallback)
|
153
|
+
|
154
|
+
cloudinary_tag(source_name, options) do |_source, tag_options|
|
155
|
+
content_tag('video', tag_options.merge(video_options)) do
|
156
|
+
source_tags = sources.map do |source|
|
157
|
+
type = source[:type]
|
158
|
+
transformation = source[:transformations] || {}
|
159
|
+
cloudinary_tag("#{source_name}.#{type}", options.merge(transformation)) do |url, _tag_options|
|
160
|
+
mime_type = "video/#{(type == 'ogv' ? 'ogg' : type)}"
|
161
|
+
if source[:codecs]
|
162
|
+
codecs = source[:codecs].is_a?(Array) ? source[:codecs].join(", ") : source[:codecs]
|
163
|
+
mime_type = "#{mime_type}; codecs=#{codecs}"
|
164
|
+
end
|
165
|
+
tag("source", :src => url, :type => mime_type)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
source_tags.push(fallback.html_safe) unless fallback.blank?
|
169
|
+
safe_join(source_tags)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
99
173
|
end
|
100
174
|
|
101
175
|
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
require 'rest_client'
|
3
|
+
require 'json'
|
4
|
+
require 'rubygems/package'
|
5
|
+
|
6
|
+
unless Rake::Task.task_defined?('cloudinary:fetch_assets') # prevent double-loading/execution
|
7
|
+
namespace :cloudinary do
|
8
|
+
desc "Fetch the latest JavaScript library files and create the JavaScript index files"
|
9
|
+
task :fetch_assets do
|
10
|
+
index_files = %w[jquery.ui.widget.js jquery.iframe-transport.js jquery.fileupload.js jquery.cloudinary.js]
|
11
|
+
processing_files = %w[canvas-to-blob.min.js load-image.all.min.js jquery.fileupload-process.js jquery.fileupload-image.js jquery.fileupload-validate.js]
|
12
|
+
files = index_files + processing_files
|
13
|
+
|
14
|
+
release = JSON(RestClient.get("https://api.github.com/repos/cloudinary/cloudinary_js/releases/latest"))
|
15
|
+
|
16
|
+
FileUtils.rm_rf 'vendor/assets'
|
17
|
+
html_folder = 'vendor/assets/html'
|
18
|
+
FileUtils.mkdir_p html_folder
|
19
|
+
js_folder = 'vendor/assets/javascripts/cloudinary'
|
20
|
+
FileUtils.mkdir_p js_folder
|
21
|
+
|
22
|
+
puts "Fetching cloudinary_js version #{release["tag_name"]}\n\n"
|
23
|
+
sio = StringIO.new(RestClient.get(release["tarball_url"]).body)
|
24
|
+
file = Zlib::GzipReader.new(sio)
|
25
|
+
tar = Gem::Package::TarReader.new(file)
|
26
|
+
tar.each_entry do |entry|
|
27
|
+
name = File.basename(entry.full_name)
|
28
|
+
if files.include? name
|
29
|
+
js_full_name = File.join(js_folder, name)
|
30
|
+
puts "Adding #{js_full_name}"
|
31
|
+
File.write js_full_name, entry.read
|
32
|
+
elsif name == 'cloudinary_cors.html'
|
33
|
+
html_full_name = File.join(html_folder, name)
|
34
|
+
puts "Adding #{html_full_name}"
|
35
|
+
File.write html_full_name, entry.read
|
36
|
+
end
|
37
|
+
end
|
38
|
+
puts "Creating 'index.js' and 'processing.js' files"
|
39
|
+
File.open("vendor/assets/javascripts/cloudinary/index.js", "w") do |f|
|
40
|
+
index_files.each { |name| f.puts "//= require ./#{name}" }
|
41
|
+
end
|
42
|
+
File.open("vendor/assets/javascripts/cloudinary/processing.js", "w") do |f|
|
43
|
+
processing_files.each { |name| f.puts "//= require ./#{name}" }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
File without changes
|
@@ -0,0 +1,9 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
API_ENDPOINT="https://sub-account-testing.cloudinary.com/create_sub_account"
|
4
|
+
|
5
|
+
SDK_NAME="${1}"
|
6
|
+
|
7
|
+
CLOUD_DETAILS=$(curl -sS -d "{\"prefix\" : \"${SDK_NAME}\"}" "${API_ENDPOINT}")
|
8
|
+
|
9
|
+
echo "${CLOUD_DETAILS}" | ruby -e "require 'json'; c=JSON.parse(ARGF.read)['payload']; puts 'cloudinary://' + c['cloudApiKey'] + ':'+ c['cloudApiSecret'] + '@' + c['cloudName']"
|
@@ -0,0 +1,9 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
4
|
+
|
5
|
+
RUBY_VER=$(ruby -v | head -n 1 | cut -d ' ' -f 2);
|
6
|
+
SDK_VER=$(grep -oiP '(?<=VERSION = ")([a-zA-Z0-9\-.]+)(?=")' lib/cloudinary/version.rb)
|
7
|
+
|
8
|
+
|
9
|
+
bash "${DIR}"/allocate_test_cloud.sh "Ruby ${RUBY_VER} SDK ${SDK_VER}"
|
data/tools/update_version
CHANGED
@@ -12,6 +12,8 @@ QUOTE=
|
|
12
12
|
|
13
13
|
NEW_VERSION=
|
14
14
|
|
15
|
+
UPDATE_ONLY=false
|
16
|
+
|
15
17
|
function echo_err
|
16
18
|
{
|
17
19
|
echo "$@" 1>&2;
|
@@ -23,6 +25,7 @@ function usage
|
|
23
25
|
echo " -v | --version <version> set a new version"
|
24
26
|
echo " -c | --current show current version"
|
25
27
|
echo " -d | --dry-run print the commands without executing them"
|
28
|
+
echo " -u | --update-only only update the version"
|
26
29
|
echo " -h | --help print this information and exit"
|
27
30
|
echo
|
28
31
|
echo "For example: $0 -v 1.2.3"
|
@@ -30,7 +33,7 @@ function usage
|
|
30
33
|
|
31
34
|
function process_arguments
|
32
35
|
{
|
33
|
-
while [ "$1" != "" ]; do
|
36
|
+
while [[ "$1" != "" ]]; do
|
34
37
|
case $1 in
|
35
38
|
-v | --version )
|
36
39
|
shift
|
@@ -53,6 +56,11 @@ function process_arguments
|
|
53
56
|
echo "Dry Run"
|
54
57
|
echo ""
|
55
58
|
;;
|
59
|
+
-u | --update-only )
|
60
|
+
UPDATE_ONLY=true
|
61
|
+
echo "Only update version"
|
62
|
+
echo ""
|
63
|
+
;;
|
56
64
|
-h | --help )
|
57
65
|
usage; return 0
|
58
66
|
;;
|
@@ -72,7 +80,7 @@ function pushd
|
|
72
80
|
# Intentionally make popd silent
|
73
81
|
function popd
|
74
82
|
{
|
75
|
-
command popd
|
83
|
+
command popd > /dev/null
|
76
84
|
}
|
77
85
|
|
78
86
|
# Check if one version is less than or equal than other
|
@@ -82,7 +90,7 @@ function popd
|
|
82
90
|
# ver_lte 1.2.4 1.2.3 && echo "yes" || echo "no" # no
|
83
91
|
function ver_lte
|
84
92
|
{
|
85
|
-
[ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]
|
93
|
+
[[ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]]
|
86
94
|
}
|
87
95
|
|
88
96
|
# Extract the last entry or entry for a given version
|
@@ -108,6 +116,10 @@ function verify_dependencies
|
|
108
116
|
return 1
|
109
117
|
fi
|
110
118
|
|
119
|
+
if [[ "${UPDATE_ONLY}" = true ]]; then
|
120
|
+
return 0;
|
121
|
+
fi
|
122
|
+
|
111
123
|
if [[ -z "$(type -t git-changelog)" ]]
|
112
124
|
then
|
113
125
|
echo_err "git-extras packages is not installed."
|
@@ -127,25 +139,26 @@ function safe_replace
|
|
127
139
|
|
128
140
|
grep -q "${old}" "${file}" || { echo_err "${old} was not found in ${file}"; return 1; }
|
129
141
|
|
130
|
-
${CMD_PREFIX} sed -
|
142
|
+
${CMD_PREFIX} sed -i.bak -e "${QUOTE}s/${old}/${new}/${QUOTE}" -- "${file}" && rm -- "${file}.bak"
|
131
143
|
}
|
132
144
|
|
133
145
|
function current_version
|
134
146
|
{
|
135
|
-
grep -oiP '(?<=VERSION = ")([
|
147
|
+
grep -oiP '(?<=VERSION = ")([a-zA-Z0-9\-.]+)(?=")' lib/cloudinary/version.rb
|
136
148
|
}
|
137
149
|
|
138
150
|
function update_version
|
139
151
|
{
|
140
|
-
if [ -z "${NEW_VERSION}" ]; then
|
152
|
+
if [[ -z "${NEW_VERSION}" ]]; then
|
141
153
|
usage; return 1
|
142
154
|
fi
|
143
155
|
|
144
156
|
# Enter git root
|
145
157
|
pushd $(git rev-parse --show-toplevel)
|
158
|
+
|
146
159
|
local current_version=$(current_version)
|
147
160
|
|
148
|
-
if [ -z "${current_version}" ]; then
|
161
|
+
if [[ -z "${current_version}" ]]; then
|
149
162
|
echo_err "Failed getting current version, please check directory structure and/or contact developer"
|
150
163
|
return 1
|
151
164
|
fi
|
@@ -166,12 +179,17 @@ function update_version
|
|
166
179
|
lib/cloudinary/version.rb\
|
167
180
|
|| return 1
|
168
181
|
|
169
|
-
|
182
|
+
if [[ "${UPDATE_ONLY}" = true ]]; then
|
183
|
+
popd;
|
184
|
+
return 0;
|
185
|
+
fi
|
186
|
+
|
187
|
+
${CMD_PREFIX} git changelog -t "${NEW_VERSION}" || true
|
170
188
|
|
171
189
|
echo ""
|
172
190
|
echo "# After editing CHANGELOG.md, optionally review changes and issue these commands:"
|
173
191
|
echo git add lib/cloudinary/version.rb CHANGELOG.md
|
174
|
-
echo git commit -m \"Version ${NEW_VERSION}\"
|
192
|
+
echo git commit -m "\"Version ${NEW_VERSION}\""
|
175
193
|
echo sed -e "'1,/^${NEW_VERSION//./\\.}/d'" \
|
176
194
|
-e "'/^=/d'" \
|
177
195
|
-e "'/^$/d'" \
|
@@ -180,7 +198,7 @@ function update_version
|
|
180
198
|
\| git tag -a "'${NEW_VERSION}'" --file=-
|
181
199
|
|
182
200
|
# Don't run those commands on dry run
|
183
|
-
[ -n "${CMD_PREFIX}" ] && { popd; return 0; }
|
201
|
+
[[ -n "${CMD_PREFIX}" ]] && { popd; return 0; }
|
184
202
|
|
185
203
|
echo ""
|
186
204
|
read -p "Run the above commands automatically? (y/N): " confirm && [[ ${confirm} == [yY] || ${confirm} == [yY][eE][sS] ]] || { popd; return 0; }
|
@@ -197,6 +215,6 @@ function update_version
|
|
197
215
|
popd
|
198
216
|
}
|
199
217
|
|
218
|
+
process_arguments "$@"
|
200
219
|
verify_dependencies
|
201
|
-
process_arguments $*
|
202
220
|
update_version
|
@@ -1403,7 +1403,8 @@ var slice = [].slice,
|
|
1403
1403
|
"*": "mul",
|
1404
1404
|
"/": "div",
|
1405
1405
|
"+": "add",
|
1406
|
-
"-": "sub"
|
1406
|
+
"-": "sub",
|
1407
|
+
"^": "pow",
|
1407
1408
|
};
|
1408
1409
|
|
1409
1410
|
|
@@ -1472,30 +1473,33 @@ var slice = [].slice,
|
|
1472
1473
|
return new this(expressionStr);
|
1473
1474
|
};
|
1474
1475
|
|
1475
|
-
|
1476
1476
|
/**
|
1477
1477
|
* Normalize a string expression
|
1478
1478
|
* @function Cloudinary#normalize
|
1479
1479
|
* @param {string} expression a expression, e.g. "w gt 100", "width_gt_100", "width > 100"
|
1480
1480
|
* @return {string} the normalized form of the value expression, e.g. "w_gt_100"
|
1481
1481
|
*/
|
1482
|
-
|
1483
1482
|
Expression.normalize = function(expression) {
|
1484
|
-
var operators,
|
1483
|
+
var operators, operatorsPattern, operatorsReplaceRE, predefinedVarsPattern, predefinedVarsReplaceRE;
|
1485
1484
|
if (expression == null) {
|
1486
1485
|
return expression;
|
1487
1486
|
}
|
1488
1487
|
expression = String(expression);
|
1489
|
-
operators = "
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
|
1494
|
-
|
1488
|
+
operators = "\\|\\||>=|<=|&&|!=|>|=|<|/|-|\\+|\\*|\\^";
|
1489
|
+
|
1490
|
+
// operators
|
1491
|
+
operatorsPattern = "((" + operators + ")(?=[ _]))";
|
1492
|
+
operatorsReplaceRE = new RegExp(operatorsPattern, "g");
|
1493
|
+
expression = expression.replace(operatorsReplaceRE, match => Expression.OPERATORS[match]);
|
1494
|
+
|
1495
|
+
// predefined variables
|
1496
|
+
predefinedVarsPattern = "(" + Object.keys(Expression.PREDEFINED_VARS).join("|") + ")";
|
1497
|
+
predefinedVarsReplaceRE = new RegExp(predefinedVarsPattern, "g");
|
1498
|
+
expression = expression.replace(predefinedVarsReplaceRE, (match, p1, offset) => (expression[offset - 1] === '$' ? match : Expression.PREDEFINED_VARS[match]));
|
1499
|
+
|
1495
1500
|
return expression.replace(/[ _]+/g, '_');
|
1496
1501
|
};
|
1497
1502
|
|
1498
|
-
|
1499
1503
|
/**
|
1500
1504
|
* Serialize the expression
|
1501
1505
|
* @return {string} the expression as a string
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudinary
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.18.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nadav Soferman
|
8
8
|
- Itai Lahan
|
9
9
|
- Tal Lev-Ami
|
10
|
-
autorequire:
|
10
|
+
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2020-
|
13
|
+
date: 2020-09-27 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: aws_cf_signer
|
@@ -110,6 +110,20 @@ dependencies:
|
|
110
110
|
- - ">="
|
111
111
|
- !ruby/object:Gem::Version
|
112
112
|
version: '3.5'
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: rspec-retry
|
115
|
+
requirement: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
type: :development
|
121
|
+
prerelease: false
|
122
|
+
version_requirements: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
113
127
|
- !ruby/object:Gem::Dependency
|
114
128
|
name: rails
|
115
129
|
requirement: !ruby/object:Gem::Requirement
|
@@ -177,6 +191,7 @@ extra_rdoc_files: []
|
|
177
191
|
files:
|
178
192
|
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
179
193
|
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
194
|
+
- ".github/pull_request_template.md"
|
180
195
|
- ".gitignore"
|
181
196
|
- ".rspec"
|
182
197
|
- ".travis.yml"
|
@@ -220,7 +235,10 @@ files:
|
|
220
235
|
- lib/cloudinary/utils.rb
|
221
236
|
- lib/cloudinary/version.rb
|
222
237
|
- lib/cloudinary/video_helper.rb
|
223
|
-
- lib/tasks/cloudinary.rake
|
238
|
+
- lib/tasks/cloudinary/fetch_assets.rake
|
239
|
+
- lib/tasks/cloudinary/sync_static.rake
|
240
|
+
- tools/allocate_test_cloud.sh
|
241
|
+
- tools/get_test_cloud.sh
|
224
242
|
- tools/update_version
|
225
243
|
- vendor/assets/html/cloudinary_cors.html
|
226
244
|
- vendor/assets/javascripts/cloudinary/canvas-to-blob.min.js
|
@@ -238,7 +256,7 @@ homepage: http://cloudinary.com
|
|
238
256
|
licenses:
|
239
257
|
- MIT
|
240
258
|
metadata: {}
|
241
|
-
post_install_message:
|
259
|
+
post_install_message:
|
242
260
|
rdoc_options: []
|
243
261
|
require_paths:
|
244
262
|
- lib
|
@@ -254,7 +272,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
254
272
|
version: '0'
|
255
273
|
requirements: []
|
256
274
|
rubygems_version: 3.1.4
|
257
|
-
signing_key:
|
275
|
+
signing_key:
|
258
276
|
specification_version: 4
|
259
277
|
summary: Client library for easily using the Cloudinary service
|
260
278
|
test_files: []
|