cloudinary 1.18.0 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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