cloudinary 1.18.0 → 1.21.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c9179fe1c8105281b33780687c2bed49db41a35fca2d33ff15bd7fd4635d119f
4
- data.tar.gz: 7b3bd01f71f1012bc7f315f707450ebb65537064e004fad615d713f489c4316c
3
+ metadata.gz: fbc5f576707d33b684e97610585e92838695cbd373cace7c16b0078021b46871
4
+ data.tar.gz: a5fc7e5d8f0930223cb03b4ca07910ba3b8a6e8ac18b5d6028f9a8963311f8d8
5
5
  SHA512:
6
- metadata.gz: 347fc122e9a31aa241afa194c09cdc3c0d19e63c5a206cc7751f4939de7c273769d648c7fd33af2cc4e7505fba0a5be9d555f1c3db1e2b41d45cfb58082e1cc3
7
- data.tar.gz: 4f04b59256afe8f23c27625d94d761e9802e2ccd91d3c3dc992eb263e3430a7a053467c203d416d379815e317924f042c9310ac0f2b4ca185630307268aa66ca
6
+ metadata.gz: 888d693726c91cba5113ca6d4e13f89b859fc01fde5603ace994eb13a907881d4d5e84a7150501c970b1792c47286ae4a9d889f61b1e41408e25a4aea20cf11d
7
+ data.tar.gz: 6a76cfcc6187c87314f1676a769b8fbfcfda08a5a22d00403f689056a680e4acb15d7360b919a2132c254295c8439e2072be74a8a2891362920f217d387d14ef
@@ -3,7 +3,7 @@ name: Bug report
3
3
  about: Bug report for Cloudinary Ruby SDK
4
4
  title: ''
5
5
  labels: ''
6
- assignees: const-cloudinary
6
+ assignees: ''
7
7
 
8
8
  ---
9
9
 
@@ -14,11 +14,11 @@ Before proceeding, please update to latest version and test if the issue persist
14
14
 
15
15
 
16
16
  ## Issue Type (Can be multiple)
17
- [ ] Build - Can’t install or import the SDK
18
- [ ] Performance - Performance issues
19
- [ ] Behaviour - Functions aren’t working as expected (Such as generate URL)
20
- [ ] Documentation - Inconsistency between the docs and behaviour
21
- [ ] Other (Specify)
17
+ - [ ] Build - Cannot install or import the SDK
18
+ - [ ] Performance - Performance issues
19
+ - [ ] Behaviour - Functions are not working as expected (such as generate URL)
20
+ - [ ] Documentation - Inconsistency between the docs and behaviour
21
+ - [ ] Other (Specify)
22
22
 
23
23
  ## Steps to reproduce
24
24
  … if applicable
@@ -27,16 +27,17 @@ Before proceeding, please update to latest version and test if the issue persist
27
27
 
28
28
 
29
29
  ## Operating System
30
- [ ] Linux
31
- [ ] Windows
32
- [ ] OSX
33
- [ ] All
30
+ - [ ] Linux
31
+ - [ ] Windows
32
+ - [ ] macOS
33
+ - [ ] All
34
34
 
35
35
  ## Environment and Libraries (fill in the version numbers)
36
- Cloudinary Ruby SDK version - 0.0.0
37
- Ruby Version - 0.0.0
38
- Rails Version - 0.0.0
39
- Other Libraries (Carrierwave, ActiveStorage, etc) - 0.0.0
36
+ - Cloudinary Ruby SDK version - 0.0.0
37
+ - Ruby Version - 0.0.0
38
+ - Rails Version - 0.0.0
39
+ - Other Libraries (Carrierwave, ActiveStorage, etc) - 0.0.0
40
40
 
41
41
  ## Repository
42
+
42
43
  If possible, please provide a link to a reproducible repository that showcases the problem
@@ -3,7 +3,7 @@ name: Feature request
3
3
  about: Feature request for Cloudinary Ruby SDK
4
4
  title: ''
5
5
  labels: ''
6
- assignees: const-cloudinary
6
+ assignees: ''
7
7
 
8
8
  ---
9
9
 
@@ -4,21 +4,28 @@ Provide some context as to what was changed, from an implementation standpoint.
4
4
  -->
5
5
 
6
6
  #### What does this PR address?
7
- [ ] Gitub issue (Add reference - #XX)
8
- [ ] Refactoring
9
- [ ] New feature
10
- [ ] Bug fix
11
- [ ] Adds more tests
7
+ - [ ] GitHub issue (Add reference - #XX)
8
+ - [ ] Refactoring
9
+ - [ ] New feature
10
+ - [ ] Bug fix
11
+ - [ ] Adds more tests
12
12
 
13
13
  #### Are tests included?
14
- [ ] Yes
15
- [ ] No
14
+ - [ ] Yes
15
+ - [ ] No
16
16
 
17
- #### Reviewer, Please Note:
17
+ #### Reviewer, please note:
18
18
  <!--
19
19
  List anything here that the reviewer should pay special attention to. This might
20
20
  include, for example:
21
- Dependence on other PRs
22
- Reference to other Cloudinary SDKs
23
- Changes that seem arbitrary without further explanations
21
+ * Dependence on other PRs
22
+ * Reference to other Cloudinary SDKs
23
+ * Changes that seem arbitrary without further explanations
24
24
  -->
25
+
26
+ #### Checklist:
27
+ <!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
28
+ <!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
29
+ - [ ] My code follows the code style of this project.
30
+ - [ ] My change requires a change to the documentation.
31
+ - [ ] I ran the full test suite before pushing the changes and all the tests pass.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,72 @@
1
+ 1.21.0 / 2021-08-23
2
+ ==================
3
+
4
+ New functionality and features
5
+ ------------------------------
6
+
7
+ * Add support for `create_slideshow` Upload API
8
+ * Add support for variables in text style
9
+ * Add support for `context` and `metadata` in `rename` Upload API
10
+ * Add support for `reorder_metadata_field_datasource` Admin API
11
+ * Add `verify_api_response_signature` and `verify_notification_signature` helpers
12
+ * Add `download_generated_sprite` and `download_multi` methods
13
+ * Add support for `urls` in multi and sprite APIs
14
+ * Add support for `live` parameter in upload presets
15
+ * Add support for `metadata` parameter in `resources` Admin APIs
16
+
17
+ Other Changes
18
+ -------------
19
+
20
+ * Fix `transformations` API call
21
+ * Fix named parameters normalization issue
22
+ * Remove duplicates in Search Api fields
23
+ * Improve configuration tests
24
+ * Add tests for Provisioning API
25
+ * Refactor metadata usage in tests
26
+ * Update GitHub templates
27
+
28
+ 1.20.0 / 2021-03-26
29
+ ==================
30
+
31
+ New functionality and features
32
+ ------------------------------
33
+
34
+ * Add support for `download_backedup_asset` helper method
35
+ * Add support for `filename_override` upload parameter
36
+ * Add support for `SHA-256` algorithm in auth signatures
37
+
38
+ Other Changes
39
+ -------------
40
+
41
+ * Fix `type` parameter support in ActiveStorage service
42
+ * Fix expression normalization in advanced cases
43
+ * Add test for context metadata as user variables
44
+ * Improve validation of auth token generation
45
+
46
+
47
+ 1.19.0 / 2021-03-05
48
+ ==================
49
+
50
+ New functionality and features
51
+ ------------------------------
52
+
53
+ * Add Account Provisioning API
54
+ * Add support for `api_proxy` parameter
55
+ * Add support for `date` parameter in `usage` Admin API
56
+
57
+ Other Changes
58
+ -------------
59
+
60
+ * Fix direct upload of raw files
61
+ * Improve unit testing of add-ons
62
+ * Change test for `eval` upload parameter
63
+ * Bump vulnerable version of rubyzip
64
+ * Fix `cloudinary.gemspec` glob issue
65
+
66
+ 1.18.1 / 2020-09-30
67
+ ===================
68
+
69
+ * Update embedded `jquery.cloudinary.js` to fix ES5 compatibility issue
1
70
 
2
71
  1.18.0 / 2020-09-27
3
72
  ===================
data/cloudinary.gemspec CHANGED
@@ -15,12 +15,17 @@ Gem::Specification.new do |s|
15
15
 
16
16
  s.rubyforge_project = "cloudinary"
17
17
 
18
- s.files = (`git ls-files`.split("\n") - `git ls-files {test,spec,features,samples}/*`.split("\n")) + Dir.glob("vendor/assets/javascripts/*/*") + Dir.glob("vendor/assets/html/*")
18
+ s.files = `git ls-files`.split("\n").select { |f| !f.start_with?("test", "spec", "features", "samples") } + Dir.glob("vendor/assets/javascripts/*/*") + Dir.glob("vendor/assets/html/*")
19
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
20
  s.require_paths = ["lib"]
21
21
 
22
22
  s.add_dependency "aws_cf_signer"
23
- s.add_dependency "rest-client"
23
+
24
+ if RUBY_VERSION >= "2.0.0"
25
+ s.add_dependency "rest-client", ">= 2.0.0"
26
+ else
27
+ s.add_dependency "rest-client"
28
+ end
24
29
 
25
30
  s.add_development_dependency "actionpack"
26
31
  s.add_development_dependency "nokogiri"
@@ -39,7 +44,7 @@ Gem::Specification.new do |s|
39
44
  s.add_development_dependency "railties", "<= 4.2.7" if RUBY_VERSION <= "1.9.3"
40
45
  s.add_development_dependency "rspec-rails"
41
46
 
42
- s.add_development_dependency "rubyzip", "<=1.2.0" # support testing Ruby 1.9
47
+ s.add_development_dependency "rubyzip"
43
48
 
44
49
  if RUBY_VERSION <= "2.4.0"
45
50
  s.add_development_dependency "simplecov", "<= 0.17.1" # support testing Ruby 1.9
@@ -72,6 +72,14 @@ module ActiveStorage
72
72
  instrument :url, key: key do |payload|
73
73
  options = {:resource_type => resource_type(nil, key)}.merge(@options.merge(options.symbolize_keys))
74
74
  options[:public_id] = public_id_internal(key)
75
+ # Provide file format for raw files, since js client does not include original file name.
76
+ #
77
+ # When the file is uploaded from the server, the request includes original filename. That allows Cloudinary
78
+ # to identify file extension and append it to the public id of the file (raw files include file extension
79
+ # in their public id, opposed to transformable assets (images/video) that use only basename). When uploading
80
+ # through direct upload (client side js), filename is missing, and that leads to inconsistent/broken URLs.
81
+ # To avoid that, we explicitly pass file format in options.
82
+ options[:format] = ext_for_file(key) if options[:resource_type] == "raw"
75
83
  options[:context] = {active_storage_key: key}
76
84
  options.delete(:file)
77
85
  payload[:url] = api_uri("upload", options)
@@ -87,7 +95,12 @@ module ActiveStorage
87
95
 
88
96
  def delete(key)
89
97
  instrument :delete, key: key do
90
- Cloudinary::Uploader.destroy public_id(key), resource_type: resource_type(nil, key)
98
+ options = {
99
+ resource_type: resource_type(nil, key),
100
+ type: @options[:type]
101
+ }.compact
102
+
103
+ Cloudinary::Uploader.destroy public_id(key), **options
91
104
  end
92
105
  end
93
106
 
@@ -99,7 +112,12 @@ module ActiveStorage
99
112
  def exist?(key)
100
113
  instrument :exist, key: key do |payload|
101
114
  begin
102
- Cloudinary::Api.resource public_id(key), resource_type: resource_type(nil, key)
115
+ options = {
116
+ resource_type: resource_type(nil, key),
117
+ type: @options[:type]
118
+ }.compact
119
+
120
+ Cloudinary::Api.resource public_id(key), **options
103
121
  true
104
122
  rescue Cloudinary::Api::NotFound => e
105
123
  false
@@ -174,7 +192,7 @@ module ActiveStorage
174
192
  # @param [string] content_type The content type of the file.
175
193
  #
176
194
  # @return [string] The extension of the filename.
177
- def ext_for_file(key, filename, content_type)
195
+ def ext_for_file(key, filename = nil, content_type = nil)
178
196
  if filename.blank?
179
197
  options = key.respond_to?(:attributes) ? key.attributes : {}
180
198
  filename = ActiveStorage::Filename.new(options[:filename]) if options.has_key?(:filename)
@@ -200,6 +218,8 @@ module ActiveStorage
200
218
  end
201
219
 
202
220
  def content_type_to_resource_type(content_type)
221
+ return 'image' if content_type.nil?
222
+
203
223
  type, subtype = content_type.split('/')
204
224
  case type
205
225
  when 'video', 'audio'
data/lib/cloudinary.rb CHANGED
@@ -16,7 +16,12 @@ require "cloudinary/missing"
16
16
  module Cloudinary
17
17
  autoload :Utils, 'cloudinary/utils'
18
18
  autoload :Uploader, 'cloudinary/uploader'
19
+ autoload :BaseConfig, "cloudinary/base_config"
20
+ autoload :Config, "cloudinary/config"
21
+ autoload :AccountConfig, "cloudinary/account_config"
22
+ autoload :BaseApi, "cloudinary/base_api"
19
23
  autoload :Api, "cloudinary/api"
24
+ autoload :AccountApi, "cloudinary/account_api"
20
25
  autoload :Downloader, "cloudinary/downloader"
21
26
  autoload :Blob, "cloudinary/blob"
22
27
  autoload :PreloadedFile, "cloudinary/preloaded_file"
@@ -58,64 +63,42 @@ module Cloudinary
58
63
  "ept" => "eps"
59
64
  }
60
65
 
61
- @@config = nil
62
-
66
+ # Cloudinary config
67
+ #
68
+ # @param [Hash] new_config If +new_config+ is passed, Config will be updated with it
69
+ # @yieldparam [OpenStruct] Config can be updated in the block
70
+ #
71
+ # @return [OpenStruct]
63
72
  def self.config(new_config=nil)
64
- first_time = @@config.nil?
65
- @@config ||= OpenStruct.new((YAML.load(ERB.new(IO.read(config_dir.join("cloudinary.yml"))).result)[config_env] rescue {}))
66
-
67
- config_from_env if first_time
73
+ @@config ||= make_new_config(Config)
68
74
 
69
- set_config(new_config) if new_config
70
- yield(@@config) if block_given?
75
+ @@config.update(new_config) if new_config
76
+ yield @@config if block_given?
71
77
 
72
78
  @@config
73
79
  end
74
80
 
75
- def self.config_from_url(url)
76
- @@config ||= OpenStruct.new
77
- return unless url && !url.empty?
78
- uri = URI.parse(url)
79
- if !uri.scheme || "cloudinary" != uri.scheme.downcase
80
- raise(CloudinaryException,
81
- "Invalid CLOUDINARY_URL scheme. Expecting to start with 'cloudinary://'")
82
- end
83
- set_config(
84
- "cloud_name" => uri.host,
85
- "api_key" => uri.user,
86
- "api_secret" => uri.password,
87
- "private_cdn" => !uri.path.blank?,
88
- "secure_distribution" => uri.path[1..-1]
89
- )
90
- uri.query.to_s.split("&").each do
91
- |param|
92
- key, value = param.split("=")
93
- if isNestedKey? key
94
- putNestedKey key, value
95
- else
96
- set_config(key => Utils.smart_unescape(value))
97
- end
98
- end
99
- end
81
+ # Cloudinary account config
82
+ #
83
+ # @param [Hash] new_config If +new_config+ is passed, Account Config will be updated with it
84
+ # @yieldparam [OpenStruct] Account config can be updated in the block
85
+ #
86
+ # @return [OpenStruct]
87
+ def self.account_config(new_config=nil)
88
+ @@account_config ||= make_new_config(AccountConfig)
100
89
 
101
- def self.putNestedKey(key, value)
102
- chain = key.split(/[\[\]]+/).reject { |i| i.empty? }
103
- outer = @@config
104
- lastKey = chain.pop()
105
- chain.each do |innerKey|
106
- inner = outer[innerKey]
107
- if inner.nil?
108
- inner = OpenStruct.new
109
- outer[innerKey] = inner
110
- end
111
- outer = inner
112
- end
113
- outer[lastKey] = value
90
+ @@account_config.update(new_config) if new_config
91
+ yield @@account_config if block_given?
92
+
93
+ @@account_config
114
94
  end
115
95
 
96
+ def self.config_from_url(url)
97
+ config.load_from_url(url)
98
+ end
116
99
 
117
- def self.isNestedKey?(key)
118
- /\w+\[\w+\]/ =~ key
100
+ def self.config_from_account_url(url)
101
+ account_config.load_from_url(url)
119
102
  end
120
103
 
121
104
  def self.app_root
@@ -129,22 +112,6 @@ module Cloudinary
129
112
 
130
113
  private
131
114
 
132
- def self.config_from_env
133
- # Heroku support
134
- if ENV["CLOUDINARY_CLOUD_NAME"]
135
- config_keys = ENV.keys.select! { |key| key.start_with? "CLOUDINARY_" }
136
- config_keys -= ["CLOUDINARY_URL"] # ignore it when explicit options are passed
137
- config_keys.each do |full_key|
138
- conf_key = full_key["CLOUDINARY_".length..-1].downcase # convert "CLOUDINARY_CONFIG_NAME" to "config_name"
139
- conf_val = ENV[full_key]
140
- conf_val = conf_val == 'true' if %w[true false].include?(conf_val) # cast relevant boolean values
141
- set_config(conf_key => conf_val)
142
- end
143
- elsif ENV["CLOUDINARY_URL"]
144
- config_from_url(ENV["CLOUDINARY_URL"])
145
- end
146
- end
147
-
148
115
  def self.config_env
149
116
  return ENV["CLOUDINARY_ENV"] if ENV["CLOUDINARY_ENV"]
150
117
  return Rails.env if defined? Rails::env
@@ -159,6 +126,29 @@ module Cloudinary
159
126
  def self.set_config(new_config)
160
127
  new_config.each{|k,v| @@config.send(:"#{k}=", v) if !v.nil?}
161
128
  end
129
+
130
+ # Builds config from yaml file, extends it with specific module and loads configuration from environment variable
131
+ #
132
+ # @param [Module] config_module Config is extended with this module after being built
133
+ #
134
+ # @return [OpenStruct]
135
+ def self.make_new_config(config_module)
136
+ import_settings_from_file.tap do |config|
137
+ config.extend(config_module)
138
+ config.load_config_from_env
139
+ end
140
+ end
141
+
142
+ private_class_method :make_new_config
143
+
144
+ # Import settings from yaml file
145
+ #
146
+ # @return [OpenStruct]
147
+ def self.import_settings_from_file
148
+ OpenStruct.new((YAML.load(ERB.new(IO.read(config_dir.join("cloudinary.yml"))).result)[config_env] rescue {}))
149
+ end
150
+
151
+ private_class_method :import_settings_from_file
162
152
  end
163
153
  # Prevent require loop if included after Rails is already initialized.
164
154
  require "cloudinary/helper" if defined?(::ActionView::Base)
@@ -0,0 +1,226 @@
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 Limit results to pending users (true), users that are not pending (false), or all users (nil, the default)
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 = {
138
+ ids: user_ids,
139
+ prefix: prefix,
140
+ sub_account_id: sub_account_id,
141
+ pending: pending
142
+ }
143
+
144
+ call_account_api(:get, 'users', params, options.merge(content_type: :json))
145
+ end
146
+
147
+ # Creates a new user group.
148
+ # @param [String] name The name for the user group.
149
+ # @param [Object] options additional options
150
+ def self.create_user_group(name, options = {})
151
+ params = {
152
+ name: name
153
+ }
154
+
155
+ call_account_api(:post, 'user_groups', params, options.merge(content_type: :json))
156
+ end
157
+
158
+ # Updates the specified user group.
159
+ # @param [String] group_id The ID of the user group to update.
160
+ # @param [String] name The name for the user group.
161
+ # @param [Object] options additional options
162
+ def self.update_user_group(group_id, name, options = {})
163
+ params = {
164
+ name: name
165
+ }
166
+
167
+ call_account_api(:put, ['user_groups', group_id], params, options.merge(content_type: :json))
168
+ end
169
+
170
+ # Adds a user to a group with the specified ID.
171
+ # @param [String] group_id The ID of the user group.
172
+ # @param [String] user_id The ID of the user.
173
+ # @param [Object] options additional options
174
+ def self.add_user_to_group(group_id, user_id, options = {})
175
+ call_account_api(:post, ['user_groups', group_id, 'users', user_id], {}, options.merge(content_type: :json))
176
+ end
177
+
178
+ # Removes a user from a group with the specified ID.
179
+ # @param [String] group_id The ID of the user group.
180
+ # @param [String] user_id The ID of the user.
181
+ # @param [Object] options additional options
182
+ def self.remove_user_from_group(group_id, user_id, options = {})
183
+ call_account_api(:delete, ['user_groups', group_id, 'users', user_id], {}, options.merge(content_type: :json))
184
+ end
185
+
186
+ # Deletes the user group with the specified ID.
187
+ # @param [String] group_id The ID of the user group to delete.
188
+ # @param [Object] options additional options
189
+ def self.delete_user_group(group_id, options = {})
190
+ call_account_api(:delete, ['user_groups', group_id], {}, options)
191
+ end
192
+
193
+ # Lists user groups in the account.
194
+ # @param [Object] options additional options
195
+ def self.user_groups(options = {})
196
+ call_account_api(:get, 'user_groups', {}, options.merge(content_type: :json))
197
+ end
198
+
199
+ # Retrieves the details of the specified user group.
200
+ # @param [String] group_id The ID of the user group to retrieve.
201
+ # @param [Object] options additional options
202
+ def self.user_group(group_id, options = {})
203
+ call_account_api(:get, ['user_groups', group_id], {}, options.merge(content_type: :json))
204
+ end
205
+
206
+ # Lists users in the specified user group.
207
+ # @param [String] group_id The ID of the user group.
208
+ # @param [Object] options additional options
209
+ def self.user_group_users(group_id, options = {})
210
+ call_account_api(:get, ['user_groups', group_id, 'users'], {}, options.merge(content_type: :json))
211
+ end
212
+
213
+ def self.call_account_api(method, uri, params, options)
214
+ account_id = options[:account_id] || Cloudinary.account_config.account_id || raise('Must supply account_id')
215
+ api_key = options[:provisioning_api_key] || Cloudinary.account_config.provisioning_api_key || raise('Must supply provisioning api_key')
216
+ api_secret = options[:provisioning_api_secret] || Cloudinary.account_config.provisioning_api_secret || raise('Must supply provisioning api_secret')
217
+
218
+ params.reject! { |_, v| v.nil? }
219
+
220
+ call_cloudinary_api(method, uri, api_key, api_secret, params, options) do |cloudinary, inner_uri|
221
+ [cloudinary, 'v1_1', 'provisioning', 'accounts', account_id, inner_uri]
222
+ end
223
+ end
224
+
225
+ private_class_method :call_account_api
226
+ end