cloudinary 1.12.0 → 1.15.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.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +42 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
  4. data/CHANGELOG.md +62 -0
  5. data/cloudinary.gemspec +17 -4
  6. data/lib/active_storage/service/cloudinary_service.rb +58 -16
  7. data/lib/cloudinary.rb +22 -18
  8. data/lib/cloudinary/api.rb +3 -2
  9. data/lib/cloudinary/carrier_wave.rb +2 -1
  10. data/lib/cloudinary/carrier_wave/remote.rb +2 -2
  11. data/lib/cloudinary/cloudinary_controller.rb +2 -4
  12. data/lib/cloudinary/helper.rb +30 -3
  13. data/lib/cloudinary/railtie.rb +6 -2
  14. data/lib/cloudinary/uploader.rb +3 -2
  15. data/lib/cloudinary/utils.rb +12 -9
  16. data/lib/cloudinary/version.rb +1 -1
  17. data/vendor/assets/javascripts/cloudinary/jquery.cloudinary.js +2 -2
  18. metadata +12 -193
  19. data/spec/access_control_spec.rb +0 -102
  20. data/spec/active_storage/Gemfile +0 -12
  21. data/spec/active_storage/application_system_test_case.rb +0 -5
  22. data/spec/active_storage/database/create_users_migration.rb +0 -9
  23. data/spec/active_storage/database/setup.rb +0 -7
  24. data/spec/active_storage/dummy/Rakefile +0 -5
  25. data/spec/active_storage/dummy/app/assets/config/manifest.js +0 -3
  26. data/spec/active_storage/dummy/app/assets/javascripts/application.js +0 -13
  27. data/spec/active_storage/dummy/app/assets/stylesheets/application.css +0 -15
  28. data/spec/active_storage/dummy/app/controllers/application_controller.rb +0 -5
  29. data/spec/active_storage/dummy/app/helpers/application_helper.rb +0 -4
  30. data/spec/active_storage/dummy/app/jobs/application_job.rb +0 -4
  31. data/spec/active_storage/dummy/app/models/application_record.rb +0 -5
  32. data/spec/active_storage/dummy/app/views/layouts/application.html.erb +0 -14
  33. data/spec/active_storage/dummy/bin/bundle +0 -5
  34. data/spec/active_storage/dummy/bin/rails +0 -6
  35. data/spec/active_storage/dummy/bin/rake +0 -6
  36. data/spec/active_storage/dummy/bin/yarn +0 -11
  37. data/spec/active_storage/dummy/config.ru +0 -7
  38. data/spec/active_storage/dummy/config/application.rb +0 -22
  39. data/spec/active_storage/dummy/config/boot.rb +0 -7
  40. data/spec/active_storage/dummy/config/database.yml +0 -25
  41. data/spec/active_storage/dummy/config/environment.rb +0 -7
  42. data/spec/active_storage/dummy/config/environments/development.rb +0 -52
  43. data/spec/active_storage/dummy/config/environments/production.rb +0 -83
  44. data/spec/active_storage/dummy/config/environments/test.rb +0 -38
  45. data/spec/active_storage/dummy/config/initializers/application_controller_renderer.rb +0 -7
  46. data/spec/active_storage/dummy/config/initializers/assets.rb +0 -16
  47. data/spec/active_storage/dummy/config/initializers/backtrace_silencers.rb +0 -8
  48. data/spec/active_storage/dummy/config/initializers/cookies_serializer.rb +0 -7
  49. data/spec/active_storage/dummy/config/initializers/filter_parameter_logging.rb +0 -6
  50. data/spec/active_storage/dummy/config/initializers/inflections.rb +0 -17
  51. data/spec/active_storage/dummy/config/initializers/mime_types.rb +0 -5
  52. data/spec/active_storage/dummy/config/initializers/wrap_parameters.rb +0 -16
  53. data/spec/active_storage/dummy/config/routes.rb +0 -4
  54. data/spec/active_storage/dummy/config/secrets.yml +0 -32
  55. data/spec/active_storage/dummy/config/spring.rb +0 -8
  56. data/spec/active_storage/dummy/config/storage.yml +0 -3
  57. data/spec/active_storage/dummy/config/webpacker.yml +0 -72
  58. data/spec/active_storage/dummy/package.json +0 -5
  59. data/spec/active_storage/dummy/public/404.html +0 -67
  60. data/spec/active_storage/dummy/public/422.html +0 -67
  61. data/spec/active_storage/dummy/public/500.html +0 -66
  62. data/spec/active_storage/dummy/public/apple-touch-icon-precomposed.png +0 -0
  63. data/spec/active_storage/dummy/public/apple-touch-icon.png +0 -0
  64. data/spec/active_storage/dummy/public/favicon.ico +0 -0
  65. data/spec/active_storage/fixtures/files/colors.bmp +0 -0
  66. data/spec/active_storage/fixtures/files/empty_file.txt +0 -0
  67. data/spec/active_storage/fixtures/files/favicon.ico +0 -0
  68. data/spec/active_storage/fixtures/files/icon.psd +0 -0
  69. data/spec/active_storage/fixtures/files/icon.svg +0 -13
  70. data/spec/active_storage/fixtures/files/image.gif +0 -0
  71. data/spec/active_storage/fixtures/files/racecar.jpg +0 -0
  72. data/spec/active_storage/fixtures/files/racecar.tif +0 -0
  73. data/spec/active_storage/fixtures/files/racecar_rotated.jpg +0 -0
  74. data/spec/active_storage/fixtures/files/report.pdf +0 -0
  75. data/spec/active_storage/fixtures/files/rotated_video.mp4 +0 -0
  76. data/spec/active_storage/fixtures/files/video.mp4 +0 -0
  77. data/spec/active_storage/fixtures/files/video_with_rectangular_samples.mp4 +0 -0
  78. data/spec/active_storage/fixtures/files/video_with_undefined_display_aspect_ratio.mp4 +0 -0
  79. data/spec/active_storage/fixtures/files/video_without_video_stream.mp4 +0 -0
  80. data/spec/active_storage/service/cloudinary_service_spec.rb +0 -92
  81. data/spec/active_storage/service/configurations.yml +0 -4
  82. data/spec/active_storage/test_helper.rb +0 -43
  83. data/spec/api_spec.rb +0 -623
  84. data/spec/archive_spec.rb +0 -145
  85. data/spec/auth_token_spec.rb +0 -77
  86. data/spec/cache_spec.rb +0 -109
  87. data/spec/cloudinary_helper_spec.rb +0 -327
  88. data/spec/cloudinary_spec.rb +0 -56
  89. data/spec/data/sync_static/app/assets/javascripts/1.coffee +0 -1
  90. data/spec/data/sync_static/app/assets/javascripts/1.js +0 -1
  91. data/spec/data/sync_static/app/assets/stylesheets/1.css +0 -3
  92. data/spec/docx.docx +0 -0
  93. data/spec/favicon.ico +0 -0
  94. data/spec/image_spec.rb +0 -107
  95. data/spec/logo.png +0 -0
  96. data/spec/movie.mp4 +0 -0
  97. data/spec/rake_spec.rb +0 -160
  98. data/spec/sample_asset_file.tsv +0 -4
  99. data/spec/search_spec.rb +0 -109
  100. data/spec/spec_helper.rb +0 -273
  101. data/spec/storage_spec.rb +0 -44
  102. data/spec/streaminig_profiles_api_spec.rb +0 -74
  103. data/spec/support/helpers/temp_file_helpers.rb +0 -22
  104. data/spec/support/shared_contexts/rake.rb +0 -19
  105. data/spec/uploader_spec.rb +0 -409
  106. data/spec/utils_methods_spec.rb +0 -81
  107. data/spec/utils_spec.rb +0 -1052
  108. data/spec/video_tag_spec.rb +0 -253
  109. data/spec/video_url_spec.rb +0 -185
@@ -1,13 +0,0 @@
1
- <!-- The XML declaration is intentionally omitted. -->
2
- <svg width="792px" height="584px" viewBox="0 0 792 584" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
- <path d="M9.51802657,28.724593 C9.51802657,18.2155955 18.1343454,9.60822622 28.6542694,9.60822622 L763.245541,9.60822622 C773.765465,9.60822622 782.381784,18.2155955 782.381784,28.724593 L782.381784,584 L792,584 L792,28.724593 C792,12.911054 779.075522,0 763.245541,0 L28.7544592,0 C12.9244782,0 0,12.911054 0,28.724593 L0,584 L9.61821632,584 C9.51802657,584 9.51802657,28.724593 9.51802657,28.724593 L9.51802657,28.724593 Z" id="Shape" opacity="0.3" fill="#CCCCCC"></path>
4
- <circle id="Oval" fill="#FFCC33" cx="119.1" cy="147.2" r="33"></circle>
5
- <circle id="Oval" fill="#3399FF" cx="119.1" cy="281.1" r="33"></circle>
6
- <circle id="Oval" fill="#FF3333" cx="676.1" cy="376.8" r="33"></circle>
7
- <circle id="Oval" fill="#FFCC33" cx="119.1" cy="477.2" r="33"></circle>
8
- <rect id="Rectangle-path" opacity="0.75" fill="#CCCCCC" x="176.5" y="130.5" width="442.1" height="33.5"></rect>
9
- <rect id="Rectangle-path" opacity="0.75" fill="#CCCCCC" x="176.5" y="183.1" width="442.1" height="33.5"></rect>
10
- <rect id="Rectangle-path" opacity="0.75" fill="#CCCCCC" x="176.5" y="265.8" width="442.1" height="33.5"></rect>
11
- <rect id="Rectangle-path" opacity="0.75" fill="#CCCCCC" x="176.5" y="363.4" width="442.1" height="33.5"></rect>
12
- <rect id="Rectangle-path" opacity="0.75" fill="#CCCCCC" x="176.5" y="465.3" width="442.1" height="33.5"></rect>
13
- </svg>
@@ -1,92 +0,0 @@
1
- if RUBY_VERSION > '2.2.2'
2
- require 'spec_helper'
3
-
4
- AS_TAG = "active_storage_" + SUFFIX
5
- BASENAME = File.basename(TEST_IMG, '.*')
6
-
7
- CONFIGURATION_PATH = Pathname.new(File.expand_path("service/configurations.yml", __dir__))
8
- SERVICE = ActiveStorage::Service.configure(:cloudinary, SERVICE_CONFIGURATIONS)
9
-
10
- describe 'active_storage' do
11
- let(:key) {ActiveStorage::BlobKey.new({key: SecureRandom.base58(24), filename: BASENAME})}
12
-
13
- before :all do
14
- @key = ActiveStorage::BlobKey.new key: SecureRandom.base58(24), filename: BASENAME
15
- @service = self.class.const_get(:SERVICE)
16
- @service.upload @key, TEST_IMG, tags: [TEST_TAG, TIMESTAMP_TAG, AS_TAG]
17
- end
18
-
19
- after :all do
20
- Cloudinary::Api.delete_resources_by_tag AS_TAG
21
- end
22
-
23
- describe :url_for_direct_upload do
24
- it "should use the key" do
25
- key = SecureRandom.base58(24)
26
- url = @service.url_for_direct_upload(key)
27
- expect(url).not_to include(BASENAME)
28
- expect(url).to include("public_id=#{key}")
29
- end
30
- it "should include the key in a context field" do
31
- key = SecureRandom.base58(24)
32
- url = @service.url_for_direct_upload(key)
33
- expect(url).to include("context=active_storage_key%3D#{key}")
34
- end
35
- end
36
-
37
- it "should support uploading to Cloudinary" do
38
- url = @service.url_for_direct_upload(key, tags: [TEST_TAG, TIMESTAMP_TAG, AS_TAG])
39
- uri = URI.parse url
40
- request = Net::HTTP::Put.new uri.request_uri
41
- file = File.open(TEST_IMG)
42
- request.body_stream = file
43
- request['content-length'] = file.size
44
- request['content-type'] = 'image/png'
45
- response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
46
- http.request request
47
- end
48
- result = Cloudinary::Utils.json_decode(response.body)
49
- expect(result['error']).not_to be_truthy
50
- #Same test as uploader_spec "should successfully upload file"
51
- expect(result["width"]).to eq(TEST_IMG_W)
52
- expect(result["height"]).to eq(TEST_IMG_H)
53
- expected_signature = Cloudinary::Utils.api_sign_request({:public_id => result["public_id"], :version => result["version"]}, Cloudinary.config.api_secret)
54
- expect(result["signature"]).to eq(expected_signature)
55
- end
56
-
57
- it "should check if resource exists" do
58
- expect(@service.exist?(@key)).to be_truthy
59
- expect(@service.exist?(@key + "nonsense")).to be_falsey
60
- end
61
-
62
- it "should delete a resource" do
63
- @service.delete @key
64
- expect(@service.exist?(@key)).to be_falsey
65
- end
66
-
67
- it "should fail to delete nonexistent key" do
68
- expect {@service.delete SecureRandom.base58(24)}.not_to raise_error
69
- end
70
-
71
- it "should support transformations" do
72
- url = @service.url(@key, crop: 'scale', width: 100)
73
- expect(url).to match(/c_scale,w_100/)
74
- end
75
-
76
- it "should use global configuration options" do
77
- tags = SERVICE_CONFIGURATIONS[:cloudinary][:tags]
78
- expect(tags).not_to be_empty, "Please set a tags value under cloudinary in #{CONFIGURATION_PATH}"
79
- expect(Cloudinary::Uploader).to receive(:upload).with(TEST_IMG, hash_including(tags: tags))
80
- @service.upload(key, TEST_IMG, tags: tags)
81
- end
82
-
83
- it "should accept options that override global configuration" do
84
- tags = SERVICE_CONFIGURATIONS[:cloudinary][:tags]
85
- expect(tags).not_to be_empty, "Please set a tags value under cloudinary in #{CONFIGURATION_PATH}"
86
- override_tags = [TEST_TAG, TIMESTAMP_TAG, AS_TAG]
87
- expect(override_tags).not_to eql(tags), "Overriding tags should be different from configuration"
88
- expect(Cloudinary::Uploader).to receive(:upload).with(TEST_IMG, hash_including(tags: override_tags))
89
- @service.upload(key, TEST_IMG, tags: override_tags)
90
- end
91
- end
92
- end
@@ -1,4 +0,0 @@
1
- cloudinary:
2
- service: Cloudinary
3
- tags:
4
- - ActiveStorageTestTag
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
- ENV['RAILS_ENV'] ||= 'test'
3
- require_relative './dummy/config/environment'
4
-
5
- require "bundler/setup"
6
- require "active_support"
7
- require "rails"
8
- require "active_model/railtie"
9
- require "active_job/railtie"
10
- require "active_record/railtie"
11
- require "action_controller/railtie"
12
- require "action_view/railtie"
13
- require "active_storage/engine"
14
- require "net/http"
15
- require "active_support/core_ext/securerandom"
16
- require "active_storage/database/setup"
17
-
18
- begin
19
- require "byebug"
20
- rescue LoadError
21
- end
22
-
23
- require "active_job"
24
- ActiveJob::Base.queue_adapter = :test
25
- ActiveJob::Base.logger = ActiveSupport::Logger.new(nil)
26
-
27
-
28
- require "yaml"
29
- SERVICE_CONFIGURATIONS = begin
30
- erb = ERB.new(Pathname.new(File.expand_path("service/configurations.yml", __dir__)).read)
31
- configuration = YAML.load(erb.result) || {}
32
- configuration.deep_symbolize_keys
33
- rescue Errno::ENOENT
34
- puts "Missing service configuration file in test/service/configurations.yml"
35
- {}
36
- end
37
-
38
- ActiveStorage.logger = ActiveSupport::Logger.new(nil)
39
- ActiveStorage.verifier = ActiveSupport::MessageVerifier.new("Testing")
40
-
41
- require "global_id"
42
- GlobalID.app = "ActiveStorageExampleApp"
43
- ActiveRecord::Base.send :include, GlobalID::Identification
@@ -1,623 +0,0 @@
1
- require 'spec_helper'
2
- require 'cloudinary'
3
-
4
- describe Cloudinary::Api do
5
- break puts("Please setup environment for api test to run") if Cloudinary.config.api_secret.blank?
6
- include_context "cleanup", TIMESTAMP_TAG
7
- TEST_WIDTH = rand(1000)
8
- TEST_TRANSFOMATION = "c_scale,w_#{TEST_WIDTH}"
9
- prefix = "api_test_#{SUFFIX}"
10
- test_id_1 = "#{prefix}_1"
11
- test_id_2 = "#{prefix}_2"
12
- test_id_3 = "#{prefix}_3"
13
- test_key = "test_key_#{SUFFIX}"
14
- before(:all) do
15
-
16
- @api = Cloudinary::Api
17
- Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_1, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "key=value", :eager =>[:width =>TEST_WIDTH, :crop =>:scale])
18
- Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_2, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "key=value", :eager =>[:width =>TEST_WIDTH, :crop =>:scale])
19
- Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_3, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "key=value", :eager =>[:width =>TEST_WIDTH, :crop =>:scale])
20
- Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_1, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "#{test_key}=test", :eager =>[:width =>TEST_WIDTH, :crop =>:scale])
21
- Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_3, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "#{test_key}=tasty", :eager =>[:width =>TEST_WIDTH, :crop =>:scale])
22
- end
23
-
24
- after(:all) do
25
- # in addition to "cleanup" context
26
- unless Cloudinary.config.keep_test_products
27
- up = Cloudinary::Api.upload_presets max_results: 500
28
- up["presets"].each do |u|
29
- tags = u["settings"]["tags"]
30
- name = u["name"]
31
- if tags =~ /.*#{TIMESTAMP_TAG}.*/
32
- Cloudinary::Api.delete_upload_preset(name)
33
- end
34
- end
35
- end
36
- end
37
-
38
- it "should allow using derived_next_cursor when listing details of a single resource" do
39
- expected = {
40
- [:payload, :derived_next_cursor] => "b16b8bd80426df43a107f26b0348"
41
- }
42
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
43
- @api.resource("test", {"derived_next_cursor" => "b16b8bd80426df43a107f26b0348"})
44
- end
45
-
46
- it "should allow listing resource_types" do
47
- expect(@api.resource_types()["resource_types"]).to include("image")
48
- end
49
-
50
- it "should allow listing resources" do
51
- resource = @api.resources()["resources"].find{|resource| resource["public_id"] == test_id_1
52
- }
53
- expect(resource).not_to be_blank
54
- expect(resource["type"]).to eq("upload")
55
- end
56
-
57
- it "should allow listing resources with cursor" do
58
- result = @api.resources(:max_results=>1)
59
- expect(result["resources"]).not_to be_blank
60
- expect(result["resources"].length).to eq(1)
61
- expect(result["next_cursor"]).not_to be_blank
62
- result2 = @api.resources(:max_results=>1, :next_cursor=>result["next_cursor"])
63
- expect(result2["resources"]).not_to be_blank
64
- expect(result2["resources"].length).to eq(1)
65
- expect(result2["resources"][0]["public_id"]).not_to eq(result["resources"][0]["public_id"] )
66
- end
67
-
68
- it "should allow listing resources by type" do
69
- resource = @api.resources(:type=>"upload", :tags=>true)["resources"].find{|resource| resource["public_id"] == test_id_1
70
- }
71
- expect(resource).not_to be_blank
72
- expect(resource["tags"]).to match_array([TEST_TAG, TIMESTAMP_TAG])
73
- end
74
-
75
- it "should allow listing resources by prefix" do
76
- resources = @api.resources(:type =>"upload", :prefix => prefix, :tags => true, :context => true)["resources"]
77
- expect(resources.map{|resource| resource["public_id"]}).to include(test_id_1, test_id_2)
78
- expect(resources.map{|resource| resource["tags"]}.flatten).to include(TEST_TAG, TIMESTAMP_TAG)
79
- expect(resources.map{|resource| resource["context"]}).to include({"custom" => {"key" => "value"}})
80
- end
81
-
82
- it "should allow listing resources by tag" do
83
- resources = @api.resources_by_tag(TEST_TAG, :tags => true, :context => true)["resources"]
84
- expect(resources.find{|resource| resource["public_id"] == test_id_1
85
- }).not_to be_blank
86
- expect(resources.map{|resource| resource["tags"]}.flatten).to include(TEST_TAG, TIMESTAMP_TAG)
87
- expect(resources.map{|resource| resource["context"]}).to include({"custom" => {"key" => "value"}})
88
- end
89
-
90
- it "should allow listing resources by context" do
91
- resources = @api.resources_by_context(test_key)["resources"]
92
- expect(resources.count).to eq(2)
93
- resources = @api.resources_by_context(test_key,'test')["resources"]
94
- expect(resources.count).to eq(1)
95
- end
96
-
97
- it "should allow listing resources by public ids" do
98
- resources = @api.resources_by_ids([test_id_1, test_id_2], :tags => true, :context => true)["resources"]
99
- expect(resources.length).to eq(2)
100
- expect(resources.find{|resource| resource["public_id"] == test_id_1
101
- }).not_to be_blank
102
- expect(resources.map{|resource| resource["tags"]}.flatten).to include(TEST_TAG, TIMESTAMP_TAG)
103
- expect(resources.map{|resource| resource["context"]}).to include({"custom" => {"key" => "value"}})
104
- end
105
-
106
- it "should allow listing resources by start date", :start_at => true do
107
- start_at = Time.now
108
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( {[:payload, :start_at] => start_at, [:payload, :direction] => "asc"}))
109
- @api.resources(:type=>"upload", :start_at=>start_at, :direction => "asc")
110
- end
111
-
112
- describe ":direction" do
113
-
114
- it "should accept a string 'desc' and 'asc'" do
115
- expected = {
116
- :url => /.*\/resources\/image\/tags\/#{TIMESTAMP_TAG}/,
117
- [:payload, :direction] => "asc"
118
- }
119
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
120
-
121
- @api.resources_by_tag(TIMESTAMP_TAG, :type=>"upload", :direction => "asc")
122
- end
123
- it "should accept an integer of '1' or '-1'" do
124
- expected = {
125
- :url => /.*\/resources\/image\/tags\/#{TIMESTAMP_TAG}/,
126
- [:payload, :direction] => "-1"
127
- }
128
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
129
- @api.resources_by_tag(TIMESTAMP_TAG, :type=>"upload", :direction => "-1")
130
- end
131
- end
132
-
133
- it "should allow get resource metadata" do
134
- resource = @api.resource(test_id_1)
135
- expect(resource).not_to be_blank
136
- expect(resource["public_id"]).to eq(test_id_1)
137
- expect(resource["bytes"]).to eq(3381)
138
- expect(resource["derived"].length).to eq(1)
139
- end
140
-
141
- it "should support the quality_analysis parameter" do
142
- resource = @api.resource(test_id_1, :quality_analysis => true)
143
- expect(resource).not_to be_blank
144
- expect(resource).to have_key("quality_analysis")
145
- expect(resource["quality_analysis"]).to have_key("focus")
146
- end
147
-
148
- it "should support the cinemagraph_analysis parameter" do
149
- expected = {
150
- [:payload, :cinemagraph_analysis] => true,
151
- [:method] => :get
152
- }
153
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
154
- @api.resource(test_id_1, :cinemagraph_analysis => true)
155
- end
156
-
157
- it "should allow deleting derived resource" do
158
- derived_resource_id = "derived_id"
159
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( {[:payload, :derived_resource_ids] => derived_resource_id}))
160
- @api.delete_derived_resources(derived_resource_id)
161
- end
162
-
163
- it "should allow deleting derived resources by transformations" do
164
- public_id = "public_id"
165
- transformations = "c_crop,w_100"
166
- expect(RestClient::Request).to receive(:execute).with(
167
- deep_hash_value( {[:payload, :public_ids] => public_id,
168
- [:payload, :transformations] => "c_crop,w_100"}))
169
- @api.delete_derived_by_transformation(public_id, "c_crop,w_100")
170
-
171
- transformations = {:crop => "crop", :width => 100}
172
- expect(RestClient::Request).to receive(:execute).with(
173
- deep_hash_value( {[:payload, :public_ids] => public_id,
174
- [:payload, :transformations] => "c_crop,w_100"}))
175
- @api.delete_derived_by_transformation(public_id, transformations)
176
-
177
- transformations = [{:crop => "crop", :width => 100}, {:crop => "scale", :width => 300}]
178
- expect(RestClient::Request).to receive(:execute).with(
179
- deep_hash_value( {[:payload, :public_ids] => public_id,
180
- [:payload, :transformations] => "c_crop,w_100|c_scale,w_300"}))
181
- @api.delete_derived_by_transformation(public_id, transformations)
182
-
183
- end
184
-
185
- it "should allow deleting multiple resources and comma inclusive public IDs", :focus => true do
186
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( {[:payload, :public_ids] => ["apit_test", "test_id_2", "api_test3"]}))
187
- @api.delete_resources(["apit_test", "test_id_2", "api_test3"])
188
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( {[:payload, :public_ids] => "apit_test,test_id_2,api_test3"}))
189
- @api.delete_resources("apit_test,test_id_2,api_test3")
190
- end
191
-
192
- it "should allow deleting resource transformations" do
193
- resource = Cloudinary::Uploader.upload(TEST_IMG, :eager => [{:width=>101,:crop=>:scale}, {:width=>200,:crop=>:crop}])
194
- public_id = resource["public_id"]
195
- expect(resource).not_to be_blank
196
- derived = resource["eager"].map{|d| d["transformation"]}
197
- expect(derived).to include("c_scale,w_101", "c_crop,w_200")
198
- @api.delete_resources([public_id], :transformations => "c_crop,w_200")
199
- resource = @api.resource(public_id)
200
- derived = resource["derived"].map{|d| d["transformation"]}
201
- expect(derived).not_to include("c_crop,w_200")
202
- expect(derived).to include("c_scale,w_101")
203
- end
204
-
205
- it "should allow deleting resources by prefix" do
206
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( {[:payload, :prefix] => "api_test_by"}))
207
- @api.delete_resources_by_prefix("api_test_by")
208
- end
209
-
210
- it "should allow deleting resources by tags" do
211
- expect(RestClient::Request).to receive(:execute).with(hash_including( :url => /.*\/tags\/api_test_tag_for_delete$/))
212
- @api.delete_resources_by_tag("api_test_tag_for_delete")
213
- end
214
-
215
- it "should allow listing tags" do
216
- tags = @api.tags(:max_results => 500)["tags"]
217
- expect(tags).to include(TEST_TAG)
218
- end
219
-
220
- it "should allow listing tag by prefix" do
221
- tags = @api.tags(:prefix=> TEST_TAG)["tags"]
222
- expect(tags).to include(TIMESTAMP_TAG)
223
- tags = @api.tags(:prefix=>"api_test_no_such_tag")["tags"]
224
- expect(tags).to be_blank
225
- end
226
-
227
- describe 'transformations' do
228
- it "should allow listing transformations" do
229
- transformations = @api.transformations()["transformations"]
230
- t0 = transformations[0]
231
- expect(t0).not_to be_empty
232
- expect(t0).to have_key("used")
233
- end
234
-
235
- it "should allow getting transformation metadata" do
236
- transformation = @api.transformation(TEST_TRANSFOMATION)
237
- expect(transformation).not_to be_blank
238
- expect(transformation["info"]).to eq(["crop" => "scale", "width" => TEST_WIDTH])
239
- transformation = @api.transformation("crop" => "scale", "width" => TEST_WIDTH)
240
- expect(transformation).not_to be_blank
241
- expect(transformation["info"]).to eq(["crop" => "scale", "width" => TEST_WIDTH])
242
- end
243
-
244
- it "should allow updating transformation allowed_for_strict" do
245
- @api.update_transformation(TEST_TRANSFOMATION, :allowed_for_strict => true)
246
- transformation = @api.transformation(TEST_TRANSFOMATION)
247
- expect(transformation).not_to be_blank
248
- expect(transformation["allowed_for_strict"]).to eq(true)
249
- @api.update_transformation(TEST_TRANSFOMATION, :allowed_for_strict => false)
250
- transformation = @api.transformation(TEST_TRANSFOMATION)
251
- expect(transformation).not_to be_blank
252
- expect(transformation["allowed_for_strict"]).to eq(false)
253
- end
254
-
255
- it "should fetch two different derived images using next_cursor" do
256
- result = @api.transformation(TEST_TRANSFOMATION, :max_results=>1)
257
- expect(result["derived"]).not_to be_blank
258
- expect(result["derived"].length).to eq(1)
259
- expect(result["next_cursor"]).not_to be_blank
260
- result2 = @api.transformation(TEST_TRANSFOMATION, :max_results=>1, :next_cursor=>result["next_cursor"])
261
- expect(result2["derived"]).not_to be_blank
262
- expect(result2["derived"].length).to eq(1)
263
- expect(result2["derived"][0]["id"]).not_to eq(result["derived"][0]["id"] )
264
- end
265
-
266
- describe "named transformations" do
267
- it "should allow creating named transformation" do
268
- public_id = "api_test_transformation_#{Time.now.to_i}"
269
- @api.create_transformation(public_id, "crop" => "scale", "width" => 102)
270
- transformation = @api.transformation(public_id)
271
- expect(transformation).not_to be_blank
272
- expect(transformation["allowed_for_strict"]).to eq(true)
273
- expect(transformation["info"]).to eq(["crop" => "scale", "width" => 102])
274
- expect(transformation["used"]).to eq(false)
275
- end
276
-
277
- it "should allow deleting named transformation" do
278
- public_id = "api_test_transformation_#{Time.now.to_i}"
279
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( :url => /.*\/transformations\/#{public_id}/, :method => :delete))
280
- @api.delete_transformation(public_id)
281
- end
282
-
283
- it "should allow unsafe update of named transformation" do
284
- public_id = "api_test_transformation_#{Time.now.to_i}"
285
- expected = {
286
- :url => /.*\/transformations\/#{public_id}$/,
287
- :method => :put,
288
- [:payload, :unsafe_update] => "c_scale,w_103"}
289
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
290
- @api.update_transformation(public_id, :unsafe_update => { "crop" => "scale", "width" => 103 })
291
- end
292
-
293
- it "should allow listing of named transformations" do
294
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:payload, :named ]=> true))
295
- @api.transformations :named => true
296
- end
297
-
298
- end
299
- it "should allow deleting implicit transformation" do
300
- @api.transformation(TEST_TRANSFOMATION)
301
- @api.delete_transformation(TEST_TRANSFOMATION)
302
- expect { @api.transformation(TEST_TRANSFOMATION) }.to raise_error(Cloudinary::Api::NotFound)
303
- end
304
- end
305
-
306
- it "should allow creating upload_presets" do
307
- expected = {:url => /.*\/upload_presets$/,
308
- [:payload, :name] => "new_preset",
309
- [:payload, :folder] => "some_folder"}
310
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
311
-
312
- @api.create_upload_preset(:name => "new_preset", :folder => "some_folder", :tags => [TEST_TAG, TIMESTAMP_TAG])
313
- end
314
-
315
- describe "upload_presets" do
316
- it 'should not accept parameters' do
317
- expected = {
318
- :url => /.*\/upload_presets/,
319
- [:payload, :next_cursor] => 1234567,
320
- [:payload, :max_results] => 10
321
- }
322
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
323
- @api.upload_presets :next_cursor => 1234567, :max_results => 10
324
-
325
- end
326
- end
327
- it "should allow getting a single upload_preset", :upload_preset => true do
328
- result = @api.create_upload_preset(:unsigned => true, :folder => "folder", :width => 100, :crop => :scale, :tags => ["a","b","c", TEST_TAG, TIMESTAMP_TAG], :context => {:a => "b", :c => "d"})
329
- name = result["name"]
330
- preset = @api.upload_preset(name)
331
- expect(preset["name"]).to eq(name)
332
- expect(preset["unsigned"]).to eq(true)
333
- expect(preset["settings"]["folder"]).to eq("folder")
334
- expect(preset["settings"]["transformation"]).to eq([{"width" => 100, "crop" => "scale"}])
335
- expect(preset["settings"]["context"]).to eq({"a" => "b", "c" => "d"})
336
- expect(preset["settings"]["tags"]).to eq(["a","b","c", TEST_TAG, TIMESTAMP_TAG])
337
- end
338
-
339
- it "should allow deleting upload_presets", :upload_preset => true do
340
- id = "#{prefix}_upload_preset"
341
- @api.create_upload_preset(:name => id, :folder => "folder", :tags => [TEST_TAG, TIMESTAMP_TAG])
342
- preset = @api.upload_preset(id)
343
- @api.delete_upload_preset(id)
344
- expect{preset = @api.upload_preset(id)}.to raise_error(Cloudinary::Api::NotFound)
345
- end
346
-
347
- it "should allow updating upload_presets", :upload_preset => true do
348
- name = @api.create_upload_preset(:folder => "folder", :tags => [TEST_TAG, TIMESTAMP_TAG])["name"]
349
- preset = @api.upload_preset(name)
350
- @api.update_upload_preset(name, preset["settings"].merge(:colors => true, :unsigned => true, :disallow_public_id => true))
351
- preset = @api.upload_preset(name)
352
- expect(preset["name"]).to eq(name)
353
- expect(preset["unsigned"]).to eq(true)
354
- expect(preset["settings"]).to eq({"folder" => "folder", "colors" => true, "disallow_public_id" => true, "tags" => [TEST_TAG, TIMESTAMP_TAG]})
355
- end
356
-
357
- # this test must be last because it deletes (potentially) all dependent transformations which some tests rely on. Excluded by default.
358
- skip "should allow deleting all resources", :delete_all=>true do
359
- Cloudinary::Uploader.upload(TEST_IMG, :public_id=>"api_test5", :eager=>[:width=>101,:crop=>:scale], :tags => [TEST_TAG, TIMESTAMP_TAG])
360
- resource = @api.resource("api_test5")
361
- expect(resource).not_to be_blank
362
- expect(resource["derived"].length).to eq(1)
363
- @api.delete_all_resources(:keep_original => true)
364
- resource = @api.resource("api_test5")
365
- expect(resource).not_to be_blank
366
- expect(resource["derived"].length).to eq(0)
367
- end
368
-
369
- it "should support setting manual moderation status" do
370
- result = Cloudinary::Uploader.upload(TEST_IMG, {:moderation => :manual, :tags => [TEST_TAG, TIMESTAMP_TAG]})
371
- expect(result["moderation"][0]["status"]).to eq("pending")
372
- expect(result["moderation"][0]["kind"]).to eq("manual")
373
- api_result = Cloudinary::Api.update(result["public_id"], {:moderation_status => :approved})
374
- expect(api_result["moderation"][0]["status"]).to eq("approved")
375
- expect(api_result["moderation"][0]["kind"]).to eq("manual")
376
- end
377
-
378
- it "should support requesting raw conversion" do
379
- result = Cloudinary::Uploader.upload(TEST_RAW, :resource_type => :raw, :tags => [TEST_TAG, TIMESTAMP_TAG])
380
- expect{Cloudinary::Api.update(result["public_id"], {:resource_type => :raw, :raw_convert => :illegal})}.to raise_error(Cloudinary::Api::BadRequest, /^Illegal value|not a valid/)
381
- end
382
-
383
- it "should support requesting categorization" do
384
- result = Cloudinary::Uploader.upload(TEST_IMG, :tags => [TEST_TAG, TIMESTAMP_TAG])
385
- expect{Cloudinary::Api.update(result["public_id"], {:categorization => :illegal})}.to raise_error(Cloudinary::Api::BadRequest, /^Illegal value/)
386
- end
387
-
388
- it "should support requesting detection with server notification", :focus => true do
389
- expected = {
390
- [:payload, :detection] => "adv_face",
391
- [:payload, :notification_url] => "http://example.com"
392
- }
393
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
394
- Cloudinary::Api.update("public_id", {:detection => "adv_face", :notification_url => "http://example.com"})
395
- end
396
-
397
- it "should support requesting auto_tagging" do
398
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:payload, :auto_tagging] => 0.5))
399
- Cloudinary::Api.update("public_id", {:auto_tagging => 0.5})
400
- end
401
-
402
- it "should support quality_override" do
403
- ['auto:advanced', 'auto:best', '80:420', 'none'].each do |q|
404
- expected = {[:payload, :quality_override] => q}
405
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
406
- Cloudinary::Api.update Pathname.new(TEST_IMG), :quality_override => q
407
- end
408
- end
409
-
410
- it "should support listing by moderation kind and value" do
411
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value([:url] => /.*manual\/approved$/, [:payload, :max_results] => 1000))
412
- Cloudinary::Api.resources_by_moderation(:manual, :approved, :max_results => 1000)
413
- end
414
-
415
- describe 'folders' do
416
- it 'should create folder' do
417
- expected = {
418
- [:url] => /.*\/folders\/#{UNIQUE_TEST_FOLDER}$/,
419
- [:method] => :post
420
- }
421
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
422
- @api.create_folder(UNIQUE_TEST_FOLDER)
423
- end
424
- it "should support listing folders" do
425
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:url] => /.*\/folders$/, [:method] => :get))
426
- Cloudinary::Api.root_folders
427
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:url] => /.*\/folders\/test_folder1$/, [:method] => :get))
428
- Cloudinary::Api.subfolders("test_folder1")
429
- end
430
- it "should URL escape the folder name" do
431
- expected = {
432
- [:url] => %r".*\/folders\/sub%5Efolder%20test$"
433
- }
434
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
435
- Cloudinary::Api.subfolders("sub^folder test")
436
- end
437
- it "should throw if folder is missing" do
438
- expect{Cloudinary::Api.subfolders("I_do_not_exist")}.to raise_error(Cloudinary::Api::NotFound)
439
- end
440
- it 'should include max_results and next_cursor for root_folders call' do
441
- expected = {
442
- [:payload, :max_results] => 3,
443
- [:payload, :next_cursor] => NEXT_CURSOR,
444
- }
445
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
446
- @api.root_folders :max_results => 3, :next_cursor => NEXT_CURSOR
447
- end
448
- it 'should include max_results and next_cursor for subfolders call' do
449
- expected = {
450
- [:payload, :max_results] => 3,
451
- [:payload, :next_cursor] => NEXT_CURSOR,
452
- }
453
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
454
- @api.subfolders GENERIC_FOLDER_NAME, :max_results => 3, :next_cursor => NEXT_CURSOR
455
- end
456
- it "should support deleting a folder" do
457
- expected = {
458
- :url => %r"/folders/#{GENERIC_FOLDER_NAME}$",
459
- :method => :delete
460
- }
461
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
462
- @api.delete_folder(GENERIC_FOLDER_NAME)
463
- end
464
- end
465
-
466
- describe '.restore' do
467
- it 'should restore a deleted resource' do
468
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:payload, :public_ids] => "api_test_restore", [:url] => /.*\/restore$/))
469
- Cloudinary::Api.restore("api_test_restore")
470
- end
471
- end
472
-
473
- describe 'create_upload_mapping' do
474
- mapping = "api_test_upload_mapping#{rand(100000)}"
475
- it 'should create mapping' do
476
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:payload, :template] => "http://cloudinary.com"))
477
- Cloudinary::Api.create_upload_mapping(mapping, :template =>"http://cloudinary.com")
478
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:payload, :template] => "http://res.cloudinary.com"))
479
- Cloudinary::Api.update_upload_mapping(mapping, "template" =>"http://res.cloudinary.com")
480
- end
481
- end
482
-
483
- describe "access_mode" do
484
- i = 0
485
-
486
- publicId = ""
487
- access_mode_tag = ''
488
- before(:each) do
489
- i += 1
490
- access_mode_tag = TEST_TAG + "access_mode" + i.to_s
491
- result = Cloudinary::Uploader.upload TEST_IMG, access_mode: "authenticated", tags: [TEST_TAG, TIMESTAMP_TAG, access_mode_tag]
492
- publicId = result["public_id"]
493
- expect(result["access_mode"]).to eq("authenticated")
494
- end
495
-
496
- it "should update access mode by ids" do
497
- result = Cloudinary::Api.update_resources_access_mode_by_ids "public", [publicId]
498
-
499
- expect(result["updated"]).to be_an_instance_of(Array)
500
- expect(result["updated"].length).to eq(1)
501
- resource = result["updated"][0]
502
- expect(resource["public_id"]).to eq(publicId)
503
- expect(resource["access_mode"]).to eq('public')
504
- end
505
- it "should update access mode by prefix" do
506
- result = Cloudinary::Api.update_resources_access_mode_by_prefix "public", publicId[0..-3]
507
-
508
- expect(result["updated"]).to be_an_instance_of(Array)
509
- expect(result["updated"].length).to eq(1)
510
- resource = result["updated"][0]
511
- expect(resource["public_id"]).to eq(publicId)
512
- expect(resource["access_mode"]).to eq('public')
513
- end
514
- it "should update access mode by tag" do
515
- result = Cloudinary::Api.update_resources_access_mode_by_tag "public", access_mode_tag
516
-
517
- expect(result["updated"]).to be_an_instance_of(Array)
518
- expect(result["updated"].length).to eq(1)
519
- resource = result["updated"][0]
520
- expect(resource["public_id"]).to eq(publicId)
521
- expect(resource["access_mode"]).to eq('public')
522
- end
523
- end
524
-
525
- context "resource of type authenticated" do
526
- i = 0
527
- bytes = nil
528
- publicId = ""
529
- publish_resource_tag = "publish_resource_tag"
530
- before(:each) do
531
- i += 1
532
- result = Cloudinary::Uploader.upload TEST_IMG, type: "authenticated", tags: [TEST_TAG, TIMESTAMP_TAG, publish_resource_tag], transformation: {width: 100*i, crop: "scale"}
533
- publicId = result["public_id"]
534
- expect(result["type"]).to eq("authenticated")
535
- end
536
-
537
- it "should publish resources by ids" do
538
- result = Cloudinary::Api.publish_by_ids( [publicId])
539
-
540
- expect(result["published"]).to be_an_instance_of(Array)
541
- expect(result["published"].length).to eq(1)
542
-
543
- resource = result["published"][0]
544
-
545
- expect(resource["public_id"]).to eq(publicId)
546
- expect(resource["type"]).to eq('upload')
547
-
548
- bytes = resource["bytes"]
549
- end
550
- it "should publish resources by prefix and overwrite" do
551
- result = Cloudinary::Api.publish_by_prefix(publicId[0..-3], overwrite: true)
552
-
553
- expect(result["published"]).to be_an_instance_of(Array)
554
- expect(result["published"].length).to eq(1)
555
-
556
- resource = result["published"][0]
557
-
558
- expect(resource["public_id"]).to eq(publicId)
559
- expect(resource["bytes"]).not_to eq(bytes)
560
- expect(resource["type"]).to eq('upload')
561
-
562
- bytes = resource["bytes"]
563
- end
564
- it "should publish resources by tag and overwrite" do
565
- result = Cloudinary::Api.publish_by_tag(publish_resource_tag, overwrite: true)
566
-
567
- expect(result["published"]).to be_an_instance_of(Array)
568
- expect(result["published"].length).to eq(1)
569
-
570
- resource = result["published"][0]
571
-
572
- expect(resource["public_id"]).to eq(publicId)
573
- expect(resource["bytes"]).not_to eq(bytes)
574
- expect(resource["type"]).to eq('upload')
575
-
576
- bytes = resource["bytes"]
577
- end
578
- end
579
- describe "json breakpoints" do
580
- it "should retrieve breakpoints as json array" do
581
- bp = Cloudinary::Api.get_breakpoints(test_id_1, srcset: {min_width:10, max_width:2000, bytes_step: 10, max_images: 20})
582
- expect(bp).to be_truthy
583
- end
584
- end
585
- end
586
-
587
- describe Cloudinary::Api::Response do
588
- let(:api_response) { described_class.new }
589
-
590
- shared_examples 'a Hash' do
591
- it 'inherits from Hash' do
592
- expect(api_response).to be_a Hash
593
- end
594
- end
595
-
596
- context 'when there is no argument given on instantiation' do
597
- it 'does not raise an error' do
598
- expect { api_response }.to_not raise_error
599
- end
600
-
601
- it_behaves_like 'a Hash'
602
- end
603
-
604
- context 'when the response is nil' do
605
- it 'does not raise an error' do
606
- expect { described_class.new nil }.to_not raise_error
607
- end
608
-
609
- it_behaves_like 'a Hash'
610
- end
611
-
612
- context 'when the response is present' do
613
- let(:body) { { 'foo' => 'bar' } }
614
- let(:http_response) { double code: 200, body: body.to_json, headers: { x_featureratelimit_reset: Time.new.to_s } }
615
- let(:api_response) { described_class.new http_response }
616
-
617
- it 'sets the instantiated self as the parsed response which is a Hash' do
618
- expect(api_response).to eq body
619
- end
620
-
621
- it_behaves_like 'a Hash'
622
- end
623
- end