cloudinary 1.9.1 → 1.20.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +5 -5
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +42 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
  4. data/.github/pull_request_template.md +24 -0
  5. data/.gitignore +7 -1
  6. data/.travis.yml +15 -8
  7. data/CHANGELOG.md +261 -0
  8. data/README.md +3 -0
  9. data/Rakefile +3 -45
  10. data/cloudinary.gemspec +27 -20
  11. data/lib/active_storage/blob_key.rb +20 -0
  12. data/lib/active_storage/service/cloudinary_service.rb +249 -0
  13. data/lib/cloudinary.rb +53 -63
  14. data/lib/cloudinary/account_api.rb +231 -0
  15. data/lib/cloudinary/account_config.rb +30 -0
  16. data/lib/cloudinary/api.rb +228 -71
  17. data/lib/cloudinary/auth_token.rb +10 -4
  18. data/lib/cloudinary/base_api.rb +79 -0
  19. data/lib/cloudinary/base_config.rb +70 -0
  20. data/lib/cloudinary/cache.rb +38 -0
  21. data/lib/cloudinary/cache/breakpoints_cache.rb +31 -0
  22. data/lib/cloudinary/cache/key_value_cache_adapter.rb +25 -0
  23. data/lib/cloudinary/cache/rails_cache_adapter.rb +34 -0
  24. data/lib/cloudinary/cache/storage/rails_cache_storage.rb +5 -0
  25. data/lib/cloudinary/carrier_wave.rb +4 -2
  26. data/lib/cloudinary/carrier_wave/remote.rb +3 -2
  27. data/lib/cloudinary/carrier_wave/storage.rb +2 -1
  28. data/lib/cloudinary/{controller.rb → cloudinary_controller.rb} +3 -5
  29. data/lib/cloudinary/config.rb +43 -0
  30. data/lib/cloudinary/helper.rb +77 -7
  31. data/lib/cloudinary/migrator.rb +3 -1
  32. data/lib/cloudinary/railtie.rb +7 -3
  33. data/lib/cloudinary/responsive.rb +111 -0
  34. data/lib/cloudinary/uploader.rb +67 -15
  35. data/lib/cloudinary/utils.rb +324 -54
  36. data/lib/cloudinary/version.rb +1 -1
  37. data/lib/cloudinary/video_helper.rb +96 -22
  38. data/lib/tasks/cloudinary/fetch_assets.rake +48 -0
  39. data/lib/tasks/{cloudinary.rake → cloudinary/sync_static.rake} +0 -0
  40. data/tools/allocate_test_cloud.sh +9 -0
  41. data/tools/get_test_cloud.sh +9 -0
  42. data/tools/update_version +220 -0
  43. data/vendor/assets/javascripts/cloudinary/jquery.cloudinary.js +51 -13
  44. data/vendor/assets/javascripts/cloudinary/jquery.fileupload.js +24 -4
  45. data/vendor/assets/javascripts/cloudinary/jquery.ui.widget.js +741 -561
  46. data/vendor/assets/javascripts/cloudinary/load-image.all.min.js +1 -1
  47. metadata +92 -67
  48. data/spec/access_control_spec.rb +0 -99
  49. data/spec/api_spec.rb +0 -545
  50. data/spec/archive_spec.rb +0 -129
  51. data/spec/auth_token_spec.rb +0 -79
  52. data/spec/cloudinary_helper_spec.rb +0 -190
  53. data/spec/cloudinary_spec.rb +0 -32
  54. data/spec/data/sync_static/app/assets/javascripts/1.coffee +0 -1
  55. data/spec/data/sync_static/app/assets/javascripts/1.js +0 -1
  56. data/spec/data/sync_static/app/assets/stylesheets/1.css +0 -3
  57. data/spec/docx.docx +0 -0
  58. data/spec/favicon.ico +0 -0
  59. data/spec/logo.png +0 -0
  60. data/spec/rake_spec.rb +0 -160
  61. data/spec/sample_asset_file.tsv +0 -4
  62. data/spec/search_spec.rb +0 -109
  63. data/spec/spec_helper.rb +0 -245
  64. data/spec/storage_spec.rb +0 -44
  65. data/spec/streaminig_profiles_api_spec.rb +0 -74
  66. data/spec/support/helpers/temp_file_helpers.rb +0 -22
  67. data/spec/support/shared_contexts/rake.rb +0 -19
  68. data/spec/uploader_spec.rb +0 -363
  69. data/spec/utils_methods_spec.rb +0 -54
  70. data/spec/utils_spec.rb +0 -906
  71. data/spec/video_tag_spec.rb +0 -251
  72. data/spec/video_url_spec.rb +0 -164
@@ -0,0 +1,231 @@
1
+ class Cloudinary::AccountApi
2
+ extend Cloudinary::BaseApi
3
+
4
+ # Creates a new sub-account. Any users that have access to all sub-accounts will also automatically have access to the
5
+ # new sub-account.
6
+ # @param [String] name The display name as shown in the management console
7
+ # @param [String] cloud_name A case-insensitive cloud name comprised of alphanumeric and underscore characters.
8
+ # Generates an error if the specified cloud name is not unique across all Cloudinary accounts.
9
+ # Note: Once created, the name can only be changed for accounts with fewer than 1000 assets.
10
+ # @param [Object] custom_attributes Any custom attributes you want to associate with the sub-account
11
+ # @param [Boolean] enabled Whether to create the account as enabled (default is enabled)
12
+ # @param [String] base_account ID of sub-account from which to copy settings
13
+ # @param [Object] options additional options
14
+ def self.create_sub_account(name, cloud_name = nil, custom_attributes = {}, enabled = nil, base_account = nil, options = {})
15
+ params = {
16
+ name: name,
17
+ cloud_name: cloud_name,
18
+ custom_attributes: custom_attributes,
19
+ enabled: enabled,
20
+ base_sub_account_id: base_account
21
+ }
22
+
23
+ call_account_api(:post, 'sub_accounts', params, options.merge(content_type: :json))
24
+ end
25
+
26
+ # Updates the specified details of the sub-account.
27
+ # @param [String] sub_account_id The ID of the sub-account.
28
+ # @param [String] name The display name as shown in the management console
29
+ # @param [String] cloud_name A case-insensitive cloud name comprised of alphanumeric and underscore characters.
30
+ # Generates an error if the specified cloud name is not unique across all Cloudinary accounts.
31
+ # Note: Once created, the name can only be changed for accounts with fewer than 1000 assets.
32
+ # @param [Object] custom_attributes Any custom attributes you want to associate with the sub-account, as a map/hash
33
+ # of key/value pairs.
34
+ # @param [Boolean] enabled Whether the sub-account is enabled.
35
+ # @param [Object] options additional options
36
+ def self.update_sub_account(sub_account_id, name = nil, cloud_name = nil, custom_attributes = nil, enabled = nil, options = {})
37
+ params = {
38
+ name: name,
39
+ cloud_name: cloud_name,
40
+ custom_attributes: custom_attributes,
41
+ enabled: enabled
42
+ }
43
+
44
+ call_account_api(:put, ['sub_accounts', sub_account_id], params, options.merge(content_type: :json))
45
+ end
46
+
47
+ # Lists sub-accounts.
48
+ # @param [Boolean] enabled Whether to only return enabled sub-accounts (true) or disabled accounts (false).
49
+ # Default: all accounts are returned (both enabled and disabled).
50
+ # @param [Array<String>] ids A list of up to 100 sub-account IDs. When provided, other parameters are ignored.
51
+ # @param [String] prefix Returns accounts where the name begins with the specified case-insensitive string.
52
+ # @param [Object] options additional options
53
+ def self.sub_accounts(enabled = nil, ids = [], prefix = nil, options = {})
54
+ params = {
55
+ enabled: enabled,
56
+ ids: ids,
57
+ prefix: prefix
58
+ }
59
+
60
+ call_account_api(:get, 'sub_accounts', params, options.merge(content_type: :json))
61
+ end
62
+
63
+ # Retrieves the details of the specified sub-account.
64
+ # @param [String] sub_account_id The ID of the sub-account.
65
+ # @param [Object] options additional options
66
+ def self.sub_account(sub_account_id, options = {})
67
+ call_account_api(:get, ['sub_accounts', sub_account_id], {}, options.merge(content_type: :json))
68
+ end
69
+
70
+ # Deletes the specified sub-account. Supported only for accounts with fewer than 1000 assets.
71
+ # @param [String] sub_account_id The ID of the sub-account.
72
+ # @param [Object] options additional options
73
+ def self.delete_sub_account(sub_account_id, options = {})
74
+ call_account_api(:delete, ['sub_accounts', sub_account_id], {}, options)
75
+ end
76
+
77
+ # Creates a new user in the account.
78
+ # @param [String] name The name of the user.
79
+ # @param [String] email A unique email address, which serves as the login name and notification address.
80
+ # @param [String] role The role to assign. Possible values: master_admin, admin, billing, technical_admin, reports,
81
+ # media_library_admin, media_library_user
82
+ # @param [Array<String>] sub_account_ids The list of sub-account IDs that this user can access.
83
+ # Note: This parameter is ignored if the role is specified as master_admin.
84
+ # @param [Object] options additional options
85
+ def self.create_user(name, email, role, sub_account_ids = [], options = {})
86
+ params = {
87
+ name: name,
88
+ email: email,
89
+ role: role,
90
+ sub_account_ids: sub_account_ids
91
+ }
92
+
93
+ call_account_api(:post, 'users', params, options.merge(content_type: :json))
94
+ end
95
+
96
+ # Deletes an existing user.
97
+ # @param [String] user_id The ID of the user to delete.
98
+ # @param [Object] options additional options
99
+ def self.delete_user(user_id, options = {})
100
+ call_account_api(:delete, ['users', user_id], {}, options)
101
+ end
102
+
103
+ # Updates the details of the specified user.
104
+ # @param [String] user_id The ID of the user to update.
105
+ # @param [String] name The name of the user.
106
+ # @param [String] email A unique email address, which serves as the login name and notification address.
107
+ # @param [String] role The role to assign. Possible values: master_admin, admin, billing, technical_admin, reports,
108
+ # media_library_admin, media_library_user
109
+ # @param [Array<String>] sub_account_ids The list of sub-account IDs that this user can access.
110
+ # Note: This parameter is ignored if the role is specified as master_admin.
111
+ # @param [Object] options additional options
112
+ def self.update_user(user_id, name = nil, email = nil, role = nil, sub_account_ids = nil, options = {})
113
+ params = {
114
+ name: name,
115
+ email: email,
116
+ role: role,
117
+ sub_account_ids: sub_account_ids
118
+ }
119
+
120
+ call_account_api(:put, ['users', user_id], params, options.merge(content_type: :json))
121
+ end
122
+
123
+ # Returns the user with the specified ID.
124
+ # @param [String] user_id The ID of the user.
125
+ # @param [Object] options additional options
126
+ def self.user(user_id, options = {})
127
+ call_account_api(:get, ['users', user_id], {}, options.merge(content_type: :json))
128
+ end
129
+
130
+ # Lists users in the account.
131
+ # @param [Boolean] pending Whether to only return pending users. Default: all users
132
+ # @param [Array<String>] user_ids A list of up to 100 user IDs. When provided, other parameters are ignored.
133
+ # @param [String] prefix Returns users where the name or email address begins with the specified case-insensitive string.
134
+ # @param [String] sub_account_id Only returns users who have access to the specified account.
135
+ # @param [Object] options additional options
136
+ def self.users(pending = nil, user_ids = [], prefix = nil, sub_account_id = nil, options = {})
137
+ params = if user_ids && user_ids.count > 0
138
+ {
139
+ ids: user_ids
140
+ }
141
+ else
142
+ {
143
+ prefix: prefix,
144
+ sub_account_id: sub_account_id,
145
+ pending: pending
146
+ }
147
+ end
148
+
149
+ call_account_api(:get, 'users', params, options.merge(content_type: :json))
150
+ end
151
+
152
+ # Creates a new user group.
153
+ # @param [String] name The name for the user group.
154
+ # @param [Object] options additional options
155
+ def self.create_user_group(name, options = {})
156
+ params = {
157
+ name: name
158
+ }
159
+
160
+ call_account_api(:post, 'user_groups', params, options.merge(content_type: :json))
161
+ end
162
+
163
+ # Updates the specified user group.
164
+ # @param [String] group_id The ID of the user group to update.
165
+ # @param [String] name The name for the user group.
166
+ # @param [Object] options additional options
167
+ def self.update_user_group(group_id, name, options = {})
168
+ params = {
169
+ name: name
170
+ }
171
+
172
+ call_account_api(:put, ['user_groups', group_id], params, options.merge(content_type: :json))
173
+ end
174
+
175
+ # Adds a user to a group with the specified ID.
176
+ # @param [String] group_id The ID of the user group.
177
+ # @param [String] user_id The ID of the user.
178
+ # @param [Object] options additional options
179
+ def self.add_user_to_group(group_id, user_id, options = {})
180
+ call_account_api(:post, ['user_groups', group_id, 'users', user_id], {}, options.merge(content_type: :json))
181
+ end
182
+
183
+ # Removes a user from a group with the specified ID.
184
+ # @param [String] group_id The ID of the user group.
185
+ # @param [String] user_id The ID of the user.
186
+ # @param [Object] options additional options
187
+ def self.remove_user_from_group(group_id, user_id, options = {})
188
+ call_account_api(:delete, ['user_groups', group_id, 'users', user_id], {}, options.merge(content_type: :json))
189
+ end
190
+
191
+ # Deletes the user group with the specified ID.
192
+ # @param [String] group_id The ID of the user group to delete.
193
+ # @param [Object] options additional options
194
+ def self.delete_user_group(group_id, options = {})
195
+ call_account_api(:delete, ['user_groups', group_id], {}, options)
196
+ end
197
+
198
+ # Lists user groups in the account.
199
+ # @param [Object] options additional options
200
+ def self.user_groups(options = {})
201
+ call_account_api(:get, 'user_groups', {}, options.merge(content_type: :json))
202
+ end
203
+
204
+ # Retrieves the details of the specified user group.
205
+ # @param [String] group_id The ID of the user group to retrieve.
206
+ # @param [Object] options additional options
207
+ def self.user_group(group_id, options = {})
208
+ call_account_api(:get, ['user_groups', group_id], {}, options.merge(content_type: :json))
209
+ end
210
+
211
+ # Lists users in the specified user group.
212
+ # @param [String] group_id The ID of the user group.
213
+ # @param [Object] options additional options
214
+ def self.user_group_users(group_id, options = {})
215
+ call_account_api(:get, ['user_groups', group_id, 'users'], {}, options.merge(content_type: :json))
216
+ end
217
+
218
+ def self.call_account_api(method, uri, params, options)
219
+ account_id = options[:account_id] || Cloudinary.account_config.account_id || raise('Must supply account_id')
220
+ api_key = options[:provisioning_api_key] || Cloudinary.account_config.provisioning_api_key || raise('Must supply provisioning api_key')
221
+ api_secret = options[:provisioning_api_secret] || Cloudinary.account_config.provisioning_api_secret || raise('Must supply provisioning api_secret')
222
+
223
+ params.reject! { |_, v| v.nil? }
224
+
225
+ call_cloudinary_api(method, uri, api_key, api_secret, params, options) do |cloudinary, inner_uri|
226
+ [cloudinary, 'v1_1', 'provisioning', 'accounts', account_id, inner_uri]
227
+ end
228
+ end
229
+
230
+ private_class_method :call_account_api
231
+ end
@@ -0,0 +1,30 @@
1
+ module Cloudinary
2
+ module AccountConfig
3
+ include BaseConfig
4
+
5
+ ENV_URL = "CLOUDINARY_ACCOUNT_URL"
6
+ SCHEME = "account"
7
+
8
+ def load_config_from_env
9
+ load_from_url(ENV[ENV_URL]) if ENV[ENV_URL]
10
+ end
11
+
12
+ private
13
+
14
+ def env_url
15
+ ENV_URL
16
+ end
17
+
18
+ def expected_scheme
19
+ SCHEME
20
+ end
21
+
22
+ def config_from_parsed_url(parsed_url)
23
+ {
24
+ "account_id" => parsed_url.host,
25
+ "provisioning_api_key" => parsed_url.user,
26
+ "provisioning_api_secret" => parsed_url.password
27
+ }
28
+ end
29
+ end
30
+ end
@@ -1,37 +1,28 @@
1
- require 'rest_client'
2
- require 'json'
3
-
4
1
  class Cloudinary::Api
5
- class Error < CloudinaryException; end
6
- class NotFound < Error; end
7
- class NotAllowed < Error; end
8
- class AlreadyExists < Error; end
9
- class RateLimited < Error; end
10
- class BadRequest < Error; end
11
- class GeneralError < Error; end
12
- class AuthorizationRequired < Error; end
13
-
14
- class Response < Hash
15
- attr_reader :rate_limit_reset_at, :rate_limit_remaining, :rate_limit_allowed
16
-
17
- def initialize(response=nil)
18
- if response
19
- # This sets the instantiated self as the response Hash
20
- update Cloudinary::Api.parse_json_response response
21
-
22
- @rate_limit_allowed = response.headers[:x_featureratelimit_limit].to_i
23
- @rate_limit_reset_at = Time.parse(response.headers[:x_featureratelimit_reset])
24
- @rate_limit_remaining = response.headers[:x_featureratelimit_remaining].to_i
25
- end
26
- end
27
- end
2
+ extend Cloudinary::BaseApi
28
3
 
29
4
  def self.ping(options={})
30
5
  call_api(:get, "ping", {}, options)
31
6
  end
32
7
 
8
+ # Gets account usage details
9
+ #
10
+ # Get a report on the status of your Cloudinary account usage details, including
11
+ # storage, bandwidth, requests, number of resources, and add-on usage.
12
+ # Note that numbers are updated periodically.
13
+ #
14
+ # @see https://cloudinary.com/documentation/admin_api#get_account_usage_details Get account usage details
15
+ #
16
+ # @param [Hash] options Additional options
17
+ # @return [Cloudinary::Api::Response]
18
+ # @raise [Cloudinary::Api:Error]
33
19
  def self.usage(options={})
34
- call_api(:get, "usage", {}, options)
20
+ uri = 'usage'
21
+ date = options[:date]
22
+
23
+ uri += "/#{Cloudinary::Utils.to_usage_api_date_format(date)}" unless date.nil?
24
+
25
+ call_api(:get, uri, {}, options)
35
26
  end
36
27
 
37
28
  def self.resource_types(options={})
@@ -78,14 +69,29 @@ class Cloudinary::Api
78
69
  resource_type = options[:resource_type] || "image"
79
70
  type = options[:type] || "upload"
80
71
  uri = "resources/#{resource_type}/#{type}/#{public_id}"
81
- call_api(:get, uri, only(options, :colors, :exif, :faces, :image_metadata, :pages, :phash, :coordinates, :max_results), options)
72
+ call_api(:get, uri,
73
+ only(options,
74
+ :cinemagraph_analysis,
75
+ :colors,
76
+ :coordinates,
77
+ :exif,
78
+ :faces,
79
+ :image_metadata,
80
+ :max_results,
81
+ :pages,
82
+ :phash,
83
+ :quality_analysis,
84
+ :derived_next_cursor,
85
+ :accessibility_analysis,
86
+ :versions
87
+ ), options)
82
88
  end
83
89
 
84
90
  def self.restore(public_ids, options={})
85
91
  resource_type = options[:resource_type] || "image"
86
92
  type = options[:type] || "upload"
87
93
  uri = "resources/#{resource_type}/#{type}/restore"
88
- call_api(:post, uri, { :public_ids => public_ids }, options)
94
+ call_api(:post, uri, { :public_ids => public_ids, :versions => options[:versions] }, options)
89
95
  end
90
96
 
91
97
  def self.update(public_id, options={})
@@ -94,19 +100,20 @@ class Cloudinary::Api
94
100
  uri = "resources/#{resource_type}/#{type}/#{public_id}"
95
101
  update_options = {
96
102
  :access_control => Cloudinary::Utils.json_array_param(options[:access_control]),
97
- :tags => options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(","),
103
+ :auto_tagging => options[:auto_tagging] && options[:auto_tagging].to_f,
104
+ :background_removal => options[:background_removal],
105
+ :categorization => options[:categorization],
98
106
  :context => Cloudinary::Utils.encode_context(options[:context]),
99
- :face_coordinates => Cloudinary::Utils.encode_double_array(options[:face_coordinates]),
100
107
  :custom_coordinates => Cloudinary::Utils.encode_double_array(options[:custom_coordinates]),
108
+ :detection => options[:detection],
109
+ :face_coordinates => Cloudinary::Utils.encode_double_array(options[:face_coordinates]),
101
110
  :moderation_status => options[:moderation_status],
102
- :raw_convert => options[:raw_convert],
111
+ :notification_url => options[:notification_url],
112
+ :quality_override => options[:quality_override],
103
113
  :ocr => options[:ocr],
104
- :categorization => options[:categorization],
105
- :detection => options[:detection],
114
+ :raw_convert => options[:raw_convert],
106
115
  :similarity_search => options[:similarity_search],
107
- :background_removal => options[:background_removal],
108
- :auto_tagging => options[:auto_tagging] && options[:auto_tagging].to_f,
109
- :notification_url => options[:notification_url]
116
+ :tags => options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(",")
110
117
  }
111
118
  call_api(:post, uri, update_options, options)
112
119
  end
@@ -214,11 +221,21 @@ class Cloudinary::Api
214
221
  end
215
222
 
216
223
  def self.root_folders(options={})
217
- call_api(:get, "folders", {}, options)
224
+ params = only(options, :max_results, :next_cursor)
225
+ call_api(:get, "folders", params, options)
218
226
  end
219
227
 
220
228
  def self.subfolders(of_folder_path, options={})
221
- call_api(:get, "folders/#{of_folder_path}", {}, options)
229
+ params = only(options, :max_results, :next_cursor)
230
+ call_api(:get, "folders/#{of_folder_path}", params, options)
231
+ end
232
+
233
+ def self.delete_folder(path, options={})
234
+ call_api(:delete, "folders/#{path}", {}, options)
235
+ end
236
+
237
+ def self.create_folder(folder_name, options={})
238
+ call_api(:post, "folders/#{folder_name}", {}, options)
222
239
  end
223
240
 
224
241
  def self.upload_mappings(options={})
@@ -311,40 +328,165 @@ class Cloudinary::Api
311
328
  update_resources_access_mode(access_mode, :public_ids, public_ids, options)
312
329
  end
313
330
 
331
+ def self.get_breakpoints(public_id, options)
332
+ local_options = options.clone
333
+ base_transformation = Cloudinary::Utils.generate_transformation_string(local_options)
334
+ srcset = local_options[:srcset]
335
+ breakpoints = [:min_width, :max_width, :bytes_step, :max_images].map {|k| srcset[k]}.join('_')
336
+
337
+
338
+ local_options[:transformation] = [base_transformation, width: "auto:breakpoints_#{breakpoints}:json"]
339
+ json_url = Cloudinary::Utils.cloudinary_url public_id, local_options
340
+ call_json_api('GET', json_url, {}, 60, {})
341
+ end
342
+
343
+ # Returns a list of all metadata field definitions.
344
+ #
345
+ # @see https://cloudinary.com/documentation/admin_api#get_metadata_fields Get metadata fields API reference
346
+ #
347
+ # @param [Hash] options Additional options
348
+ # @return [Cloudinary::Api::Response]
349
+ # @raise [Cloudinary::Api::Error]
350
+ def self.list_metadata_fields(options = {})
351
+ call_metadata_api(:get, [], {}, options)
352
+ end
353
+
354
+ # Gets a metadata field by external id.
355
+ #
356
+ # @see https://cloudinary.com/documentation/admin_api#get_a_metadata_field_by_external_id Get metadata field by external ID API reference
357
+ #
358
+ # @param [String] field_external_id The ID of the metadata field to retrieve
359
+ # @param [Hash] options Additional options
360
+ # @return [Cloudinary::Api::Response]
361
+ # @raise [Cloudinary::Api::Error]
362
+ def self.metadata_field_by_field_id(field_external_id, options = {})
363
+ uri = [field_external_id]
364
+
365
+ call_metadata_api(:get, uri, {}, options)
366
+ end
367
+
368
+ # Creates a new metadata field definition.
369
+ #
370
+ # @see https://cloudinary.com/documentation/admin_api#create_a_metadata_field Create metadata field API reference
371
+ #
372
+ # @param [Hash] field The field to add
373
+ # @param [Hash] options Additional options
374
+ # @return [Cloudinary::Api::Response]
375
+ # @raise [Cloudinary::Api::Error]
376
+ def self.add_metadata_field(field, options = {})
377
+ params = only(field, :type, :external_id, :label, :mandatory, :default_value, :validation, :datasource)
378
+
379
+ call_metadata_api(:post, [], params, options)
380
+ end
381
+
382
+ # Updates a metadata field by external id.
383
+ #
384
+ # Updates a metadata field definition (partially, no need to pass the entire object) passed as JSON data.
385
+ # See https://cloudinary.com/documentation/admin_api#generic_structure_of_a_metadata_field for the generic structure
386
+ # of a metadata field.
387
+ #
388
+ # @see https://cloudinary.com/documentation/admin_api#update_a_metadata_field_by_external_id Update metadata field API reference
389
+ #
390
+ # @param [String] field_external_id The id of the metadata field to update
391
+ # @param [Hash] field The field definition
392
+ # @param [Hash] options Additional options
393
+ # @return [Cloudinary::Api::Response]
394
+ # @raise [Cloudinary::Api::Error]
395
+ def self.update_metadata_field(field_external_id, field, options = {})
396
+ uri = [field_external_id]
397
+ params = only(field, :label, :mandatory, :default_value, :validation)
398
+
399
+ call_metadata_api(:put, uri, params, options)
400
+ end
401
+
402
+ # Deletes a metadata field definition.
403
+ #
404
+ # The field should no longer be considered a valid candidate for all other endpoints.
405
+ #
406
+ # @see https://cloudinary.com/documentation/admin_api#delete_a_metadata_field_by_external_id Delete metadata field API reference
407
+ #
408
+ # @param [String] field_external_id The external id of the field to delete
409
+ # @param [Hash] options Additional options
410
+ # @return [Cloudinary::Api::Response] A hash with a "message" key. "ok" value indicates a successful deletion
411
+ # @raise [Cloudinary::Api::Error]
412
+ def self.delete_metadata_field(field_external_id, options = {})
413
+ uri = [field_external_id]
414
+
415
+ call_metadata_api(:delete, uri, {}, options)
416
+ end
417
+
418
+ # Deletes entries in a metadata field datasource.
419
+ #
420
+ # Deletes (blocks) the datasource entries for a specified metadata field definition. Sets the state of the
421
+ # entries to inactive. This is a soft delete, the entries still exist under the hood and can be activated
422
+ # again with the restore datasource entries method.
423
+ #
424
+ # @see https://cloudinary.com/documentation/admin_api#delete_entries_in_a_metadata_field_datasource Delete entries in a metadata field datasource API reference
425
+ #
426
+ # @param [String] field_external_id The id of the field to update
427
+ # @param [Array] entries_external_id The ids of all the entries to delete from the datasource
428
+ # @param [Hash] options Additional options
429
+ # @return [Cloudinary::Api::Response] The remaining datasource entries
430
+ # @raise [Cloudinary::Api::Error]
431
+ def self.delete_datasource_entries(field_external_id, entries_external_id, options = {})
432
+ uri = [field_external_id, "datasource"]
433
+ params = {:external_ids => entries_external_id }
434
+
435
+ call_metadata_api(:delete, uri, params, options)
436
+ end
437
+
438
+ # Updates a metadata field datasource.
439
+ #
440
+ # Updates the datasource of a supported field type (currently only enum and set), passed as JSON data. The
441
+ # update is partial: datasource entries with an existing external_id will be updated and entries with new
442
+ # external_id’s (or without external_id’s) will be appended.
443
+ #
444
+ # @see https://cloudinary.com/documentation/admin_api#update_a_metadata_field_datasource Update a metadata field datasource API reference
445
+ #
446
+ # @param [String] field_external_id The external id of the field to update
447
+ # @param [Array] entries_external_id
448
+ # @param [Hash] options Additional options
449
+ # @return [Cloudinary::Api::Response]
450
+ # @raise [Cloudinary::Api::Error]
451
+ def self.update_metadata_field_datasource(field_external_id, entries_external_id, options = {})
452
+ uri = [field_external_id, "datasource"]
453
+
454
+ params = entries_external_id.each_with_object({:values => [] }) do |item, hash|
455
+ item = only(item, :external_id, :value)
456
+ hash[:values ] << item if item.present?
457
+ end
458
+
459
+ call_metadata_api(:put, uri, params, options)
460
+ end
461
+
462
+ # Restores entries in a metadata field datasource.
463
+ #
464
+ # Restores (unblocks) any previously deleted datasource entries for a specified metadata field definition.
465
+ # Sets the state of the entries to active.
466
+ #
467
+ # @see https://cloudinary.com/documentation/admin_api#restore_entries_in_a_metadata_field_datasource Restore entries in a metadata field datasource API reference
468
+ #
469
+ # @param [String] field_external_id The ID of the metadata field
470
+ # @param [Array] entries_external_ids An array of IDs of datasource entries to restore (unblock)
471
+ # @param [Hash] options Additional options
472
+ # @return [Cloudinary::Api::Response]
473
+ # @raise [Cloudinary::Api::Error]
474
+ def self.restore_metadata_field_datasource(field_external_id, entries_external_ids, options = {})
475
+ uri = [field_external_id, "datasource_restore"]
476
+ params = {:external_ids => entries_external_ids }
477
+
478
+ call_metadata_api(:post, uri, params, options)
479
+ end
480
+
314
481
  protected
315
482
 
316
483
  def self.call_api(method, uri, params, options)
317
- cloudinary = options[:upload_prefix] || Cloudinary.config.upload_prefix || "https://api.cloudinary.com"
318
- cloud_name = options[:cloud_name] || Cloudinary.config.cloud_name || raise("Must supply cloud_name")
319
- api_key = options[:api_key] || Cloudinary.config.api_key || raise("Must supply api_key")
320
- api_secret = options[:api_secret] || Cloudinary.config.api_secret || raise("Must supply api_secret")
321
- timeout = options[:timeout] || Cloudinary.config.timeout || 60
322
- api_url = [cloudinary, "v1_1", cloud_name, uri].join("/")
323
- # Add authentication
324
- api_url.sub!(%r(^(https?://)), "\\1#{api_key}:#{api_secret}@")
325
-
326
- headers = { "User-Agent" => Cloudinary::USER_AGENT }
327
- if options[:content_type]== :json
328
- payload = params.to_json
329
- headers.merge!("Content-Type"=> 'application/json', "Accept"=> 'application/json')
330
- else
331
- payload = params.reject { |k, v| v.nil? || v=="" }
332
- end
333
- RestClient::Request.execute(:method => method, :url => api_url, :payload => payload, :timeout => timeout, :headers => headers) do
334
- |response, request, tmpresult|
335
- return Response.new(response) if response.code == 200
336
- exception_class = case response.code
337
- when 400 then BadRequest
338
- when 401 then AuthorizationRequired
339
- when 403 then NotAllowed
340
- when 404 then NotFound
341
- when 409 then AlreadyExists
342
- when 420 then RateLimited
343
- when 500 then GeneralError
344
- else raise GeneralError.new("Server returned unexpected status code - #{response.code} - #{response.body}")
345
- end
346
- json = parse_json_response(response)
347
- raise exception_class.new(json["error"]["message"])
484
+ cloud_name = options[:cloud_name] || Cloudinary.config.cloud_name || raise('Must supply cloud_name')
485
+ api_key = options[:api_key] || Cloudinary.config.api_key || raise('Must supply api_key')
486
+ api_secret = options[:api_secret] || Cloudinary.config.api_secret || raise('Must supply api_secret')
487
+
488
+ call_cloudinary_api(method, uri, api_key, api_secret, params, options) do |cloudinary, inner_uri|
489
+ [cloudinary, 'v1_1', cloud_name, inner_uri]
348
490
  end
349
491
  end
350
492
 
@@ -355,6 +497,22 @@ class Cloudinary::Api
355
497
  raise GeneralError.new("Error parsing server response (#{response.code}) - #{response.body}. Got - #{e}")
356
498
  end
357
499
 
500
+ # Protected function that assists with performing an API call to the metadata_fields part of the Admin API.
501
+ #
502
+ # @protected
503
+ # @param [Symbol] method The HTTP method. Valid methods: get, post, put, delete
504
+ # @param [Array] uri REST endpoint of the API (without 'metadata_fields')
505
+ # @param [Hash] params Query/body parameters passed to the method
506
+ # @param [Hash] options Additional options. Can be an override of the configuration, headers, etc.
507
+ # @return [Cloudinary::Api::Response]
508
+ # @raise [Cloudinary::Api::Error]
509
+ def self.call_metadata_api(method, uri, params, options)
510
+ options[:content_type] = :json
511
+ uri = ["metadata_fields", uri].reject(&:empty?).join("/")
512
+
513
+ call_api(method, uri, params, options)
514
+ end
515
+
358
516
  def self.only(hash, *keys)
359
517
  result = {}
360
518
  keys.each do |key|
@@ -398,5 +556,4 @@ class Cloudinary::Api
398
556
  params[by_key] = value
399
557
  call_api("post", "resources/#{resource_type}/#{type}/update_access_mode", params, options)
400
558
  end
401
-
402
559
  end