gooddata 0.6.24 → 0.6.25

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 (114) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +54 -0
  3. data/CHANGELOG.md +3 -0
  4. data/DEPENDENCIES.md +155 -154
  5. data/README.md +15 -6
  6. data/Rakefile +5 -3
  7. data/dependency_decisions.yml +2 -0
  8. data/gooddata.gemspec +2 -3
  9. data/lib/gooddata/cli/cli.rb +1 -3
  10. data/lib/gooddata/cli/commands/auth_cmd.rb +16 -7
  11. data/lib/gooddata/cli/commands/project_cmd.rb +16 -178
  12. data/lib/gooddata/cli/shared.rb +46 -44
  13. data/lib/gooddata/commands/auth.rb +4 -0
  14. data/lib/gooddata/commands/project.rb +7 -24
  15. data/lib/gooddata/exceptions/object_migration.rb +4 -0
  16. data/lib/gooddata/exceptions/segment_not_empty.rb +18 -0
  17. data/lib/gooddata/extensions/object.rb +12 -0
  18. data/lib/gooddata/goodzilla/goodzilla.rb +56 -9
  19. data/lib/gooddata/helpers/global_helpers.rb +92 -0
  20. data/lib/gooddata/mixins/md_finders.rb +2 -8
  21. data/lib/gooddata/mixins/md_grantees.rb +42 -0
  22. data/lib/gooddata/mixins/md_id_to_uri.rb +1 -8
  23. data/lib/gooddata/mixins/md_object_id.rb +1 -1
  24. data/lib/gooddata/mixins/md_object_indexer.rb +5 -8
  25. data/lib/gooddata/mixins/md_object_query.rb +2 -2
  26. data/lib/gooddata/mixins/not_group.rb +17 -0
  27. data/lib/gooddata/mixins/rest_getters.rb +2 -2
  28. data/lib/gooddata/mixins/rest_resource.rb +1 -0
  29. data/lib/gooddata/mixins/to_json.rb +11 -0
  30. data/lib/gooddata/mixins/uri_getter.rb +9 -0
  31. data/lib/gooddata/models/blueprint/anchor_field.rb +14 -0
  32. data/lib/gooddata/models/blueprint/project_blueprint.rb +15 -1
  33. data/lib/gooddata/models/blueprint/to_wire.rb +10 -0
  34. data/lib/gooddata/models/client.rb +178 -0
  35. data/lib/gooddata/models/client_synchronization_result.rb +31 -0
  36. data/lib/gooddata/models/client_synchronization_result_details.rb +41 -0
  37. data/lib/gooddata/models/datawarehouse.rb +1 -5
  38. data/lib/gooddata/models/domain.rb +85 -1
  39. data/lib/gooddata/models/execution.rb +0 -2
  40. data/lib/gooddata/models/execution_detail.rb +0 -2
  41. data/lib/gooddata/models/from_wire.rb +10 -0
  42. data/lib/gooddata/models/invitation.rb +1 -1
  43. data/lib/gooddata/models/links.rb +1 -1
  44. data/lib/gooddata/models/membership.rb +10 -6
  45. data/lib/gooddata/models/metadata.rb +98 -11
  46. data/lib/gooddata/models/metadata/attribute.rb +6 -7
  47. data/lib/gooddata/models/metadata/dashboard.rb +41 -75
  48. data/lib/gooddata/models/metadata/dashboard/dashboard_item.rb +20 -4
  49. data/lib/gooddata/models/metadata/dashboard/filter_apply_item.rb +37 -0
  50. data/lib/gooddata/models/metadata/dashboard/filter_item.rb +49 -0
  51. data/lib/gooddata/models/metadata/dashboard/geo_chart_item.rb +56 -0
  52. data/lib/gooddata/models/metadata/dashboard/headline_item.rb +56 -0
  53. data/lib/gooddata/models/metadata/dashboard/iframe_item.rb +46 -0
  54. data/lib/gooddata/models/metadata/dashboard/report_item.rb +49 -8
  55. data/lib/gooddata/models/metadata/dashboard/text_item.rb +55 -0
  56. data/lib/gooddata/models/metadata/dashboard_tab.rb +83 -30
  57. data/lib/gooddata/models/metadata/dataset.rb +0 -2
  58. data/lib/gooddata/models/metadata/dimension.rb +1 -3
  59. data/lib/gooddata/models/metadata/fact.rb +1 -3
  60. data/lib/gooddata/models/metadata/label.rb +1 -3
  61. data/lib/gooddata/models/metadata/metric.rb +11 -42
  62. data/lib/gooddata/models/metadata/report.rb +7 -18
  63. data/lib/gooddata/models/metadata/report_definition.rb +21 -113
  64. data/lib/gooddata/models/metadata/scheduled_mail.rb +274 -0
  65. data/lib/gooddata/models/metadata/scheduled_mail/dashboard_attachment.rb +62 -0
  66. data/lib/gooddata/models/metadata/scheduled_mail/report_attachment.rb +64 -0
  67. data/lib/gooddata/models/metadata/variable.rb +8 -2
  68. data/lib/gooddata/models/model.rb +2 -9
  69. data/lib/gooddata/models/process.rb +7 -29
  70. data/lib/gooddata/models/profile.rb +1 -1
  71. data/lib/gooddata/models/project.rb +131 -167
  72. data/lib/gooddata/models/project_creator.rb +2 -7
  73. data/lib/gooddata/models/project_metadata.rb +2 -10
  74. data/lib/gooddata/models/project_role.rb +4 -10
  75. data/lib/gooddata/models/report_data_result.rb +3 -5
  76. data/lib/gooddata/models/schedule.rb +4 -31
  77. data/lib/gooddata/models/segment.rb +192 -0
  78. data/lib/gooddata/models/user_filters/mandatory_user_filter.rb +2 -2
  79. data/lib/gooddata/models/user_filters/user_filter_builder.rb +1 -1
  80. data/lib/gooddata/models/user_filters/variable_user_filter.rb +11 -0
  81. data/lib/gooddata/models/user_group.rb +241 -0
  82. data/lib/gooddata/rest/connection.rb +81 -16
  83. data/lib/gooddata/rest/object.rb +29 -0
  84. data/lib/gooddata/rest/object_factory.rb +6 -1
  85. data/lib/gooddata/rest/resource.rb +7 -1
  86. data/lib/gooddata/version.rb +1 -1
  87. data/spec/environment/default.rb +19 -16
  88. data/spec/environment/develop.rb +10 -10
  89. data/spec/environment/hotfix.rb +6 -6
  90. data/spec/environment/production.rb +14 -14
  91. data/spec/environment/release.rb +6 -6
  92. data/spec/environment/staging.rb +9 -9
  93. data/spec/environment/staging_3.rb +14 -15
  94. data/spec/integration/blueprint_with_grain_spec.rb +72 -0
  95. data/spec/integration/clients_spec.rb +135 -0
  96. data/spec/integration/date_dim_switch_spec.rb +142 -0
  97. data/spec/integration/full_project_spec.rb +3 -3
  98. data/spec/integration/project_spec.rb +20 -0
  99. data/spec/integration/segments_spec.rb +141 -0
  100. data/spec/integration/user_group_spec.rb +127 -0
  101. data/spec/spec_helper.rb +4 -0
  102. data/spec/unit/models/domain_spec.rb +7 -1
  103. data/spec/unit/models/metric_spec.rb +0 -8
  104. data/spec/unit/models/profile_spec.rb +1 -1
  105. data/spec/unit/models/report_result_data_spec.rb +6 -0
  106. metadata +38 -38
  107. data/lib/gooddata/cli/commands/api_cmd.rb +0 -34
  108. data/lib/gooddata/cli/commands/console_cmd.rb +0 -40
  109. data/lib/gooddata/cli/commands/domain_cmd.rb +0 -46
  110. data/lib/gooddata/cli/commands/process_cmd.rb +0 -145
  111. data/lib/gooddata/cli/commands/projects_cmd.rb +0 -23
  112. data/lib/gooddata/cli/commands/run_ruby_cmd.rb +0 -77
  113. data/lib/gooddata/cli/commands/scaffold_cmd.rb +0 -35
  114. data/lib/gooddata/cli/commands/user_cmd.rb +0 -24
@@ -30,6 +30,7 @@ module GoodData
30
30
  base.send :include, GoodData::Mixin::NotAttribute
31
31
  base.send :include, GoodData::Mixin::NotExportable
32
32
  base.send :include, GoodData::Mixin::NotFact
33
+ base.send :include, GoodData::Mixin::NotUserGroup
33
34
  base.send :include, GoodData::Mixin::NotMetric
34
35
  base.send :include, GoodData::Mixin::NotLabel
35
36
  base.send :include, GoodData::Mixin::MdRelations
@@ -0,0 +1,11 @@
1
+ require 'multi_json'
2
+
3
+ module GoodData
4
+ module Mixin
5
+ module ToJson
6
+ def to_json(pretty = false)
7
+ MultiJson.dump(json, pretty)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module GoodData
2
+ module Mixin
3
+ module UriGetter
4
+ def uri
5
+ data && data['links'] && data['links']['self']
6
+ end
7
+ end
8
+ end
9
+ end
@@ -16,6 +16,20 @@ module GoodData
16
16
  true
17
17
  end
18
18
 
19
+ # Returns true if grain is defined
20
+ #
21
+ # @return [Boolean] Returns true if grain is defined on the anchor
22
+ def grain?
23
+ !data[:grain].nil?
24
+ end
25
+
26
+ # Returns grain definition if the anchor has it. Nil otherwise
27
+ #
28
+ # @return [Array<Hash>] Returns grain definitions
29
+ def grain
30
+ data[:grain]
31
+ end
32
+
19
33
  # Removes all the labels from the anchor. This is a typical operation that people want to perform
20
34
  #
21
35
  # @return [GoodData::Model::ProjectBlueprint] Returns changed blueprint
@@ -92,6 +92,20 @@ module GoodData
92
92
  end
93
93
  end
94
94
 
95
+ # Returns blueprint with all references to one date dimensions changed to reference to the other. Changes the Blueprint in place.
96
+ #
97
+ # @param what [GoodData::Model::ReferenceBlueprintField | String] Date dimension reference field to be replaced.
98
+ # @param for_what [GoodData::Model::ReferenceBlueprintField | String] Date dimension reference field to be used as a replacement.
99
+ # @return [GoodData::Model::ProjectBlueprint]
100
+ def swap_date_dimension!(what, for_what)
101
+ what_id = what.respond_to?(:id) ? what.id : what
102
+ for_what_id = what.respond_to?(:id) ? for_what.id : for_what
103
+
104
+ fields = to_hash[:datasets].flat_map { |x| x[:columns] }.select { |x| x[:type] == :date }.select { |i| i[:dataset] == what_id }
105
+ fields.each { |f| f[:dataset] = for_what_id }
106
+ self
107
+ end
108
+
95
109
  # Returns true if a dataset contains a particular dataset false otherwise
96
110
  #
97
111
  # @param project [GoodData::Model::ProjectBlueprint | Hash] Project blueprint
@@ -536,7 +550,7 @@ module GoodData
536
550
  star, metrics = e
537
551
  metrics.each(&:save)
538
552
  reports_stubs = metrics.map do |m|
539
- breaks = broken_by(star).map { |ds, aM| ds.identifier_for(aM) }
553
+ breaks = broken_by(star).map { |ds, a_m| ds.identifier_for(a_m) }
540
554
  [breaks, m]
541
555
  end
542
556
  a.concat(reports_stubs)
@@ -54,6 +54,16 @@ module GoodData
54
54
  a[:attribute][:folder] = attribute[:folder] || dataset[:folder] || GoodData::Model.title(dataset)
55
55
  a[:attribute][:labels] = labels unless labels.empty?
56
56
  a[:attribute][:description] = GoodData::Model.description(attribute) if GoodData::Model.description(attribute)
57
+ if attribute[:grain]
58
+ a[:attribute][:grain] = attribute[:grain].map do |g|
59
+ case g.keys.first
60
+ when :date
61
+ { dateDimension: g.values.first }
62
+ else
63
+ g
64
+ end
65
+ end
66
+ end
57
67
  default = ls.find { |l| l[:default_label] }
58
68
  a[:attribute][:defaultLabel] = (default && default[:id]) || ls.first[:id] unless ls.empty?
59
69
  end
@@ -0,0 +1,178 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2010-2015 GoodData Corporation. All rights reserved.
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ require_relative '../rest/resource'
8
+
9
+ require_relative '../mixins/data_property_reader'
10
+ require_relative '../mixins/links'
11
+ require_relative '../mixins/rest_resource'
12
+ require_relative '../mixins/uri_getter'
13
+
14
+ module GoodData
15
+ class Client < Rest::Resource
16
+ data_property_reader 'id'
17
+
18
+ attr_accessor :domain
19
+
20
+ include Mixin::Links
21
+ include Mixin::UriGetter
22
+
23
+ CLIENT_TEMPLATE = {
24
+ client: {
25
+ id: nil,
26
+ segment: nil,
27
+ project: nil
28
+ }
29
+ }
30
+
31
+ class << self
32
+ def [](id, opts = {})
33
+ domain = opts[:domain]
34
+ segment = opts[:segment]
35
+ fail ArgumentError, 'No :domain specified' if domain.nil?
36
+ fail ArgumentError, 'No :segment specified' if domain.nil?
37
+
38
+ client = domain.client
39
+ fail ArgumentError, 'No client specified' if client.nil?
40
+
41
+ base_uri = domain.segments_uri + "/clients?segment=#{CGI.escape(segment.segment_id)}"
42
+ tenants_uri = id == :all ? base_uri : base_uri + "&name=#{CGI.escape(id)}"
43
+ e = Enumerator.new do |y|
44
+ loop do
45
+ res = client.get tenants_uri
46
+ res['clients']['paging']['next']
47
+ res['clients']['items'].each do |i|
48
+ p = i['client']['project']
49
+ tenant = client.create(GoodData::Client, i.merge('domain' => domain))
50
+ tenant.project = p
51
+ y << tenant
52
+ end
53
+ url = res['clients']['paging']['next']
54
+ break unless url
55
+ end
56
+ end
57
+ id == :all ? e : e.first
58
+ end
59
+
60
+ # Creates new client from parameters passed
61
+ #
62
+ # @param options [Hash] Optional options
63
+ # @return [GoodData::Schedule] New GoodData::Schedule instance
64
+ def create(data = {}, options = {})
65
+ segment = options[:segment]
66
+ domain = segment.domain
67
+ tenant = client.create(GoodData::Client, GoodData::Helpers.deep_stringify_keys(CLIENT_TEMPLATE.merge(domain: domain)), domain: domain)
68
+ tenant.tap do |s|
69
+ s.project = data[:project]
70
+ s.client_id = data[:id]
71
+ s.segment = segment.uri
72
+ end
73
+ end
74
+ end
75
+
76
+ def initialize(data)
77
+ super(data)
78
+ @domain = data.delete('domain')
79
+ @json = data
80
+ end
81
+
82
+ # Segment id getter for the Segment. Called segment_id since id is a reserved word in ruby world
83
+ #
84
+ # @return [String] Segment id
85
+ def client_id
86
+ data['id']
87
+ end
88
+
89
+ def client_id=(a_name)
90
+ data['id'] = a_name
91
+ self
92
+ end
93
+
94
+ # Setter for the project this client has set
95
+ #
96
+ # @param a_project [String|GoodData::Project] Id or an instance of a project
97
+ # @return [GoodData::Cliet] Returns the instance of the client
98
+ def project=(a_project)
99
+ data['project'] = a_project.respond_to?(:uri) ? a_project.uri : a_project
100
+ self
101
+ end
102
+
103
+ # Project URI this client has set
104
+ #
105
+ # @return [String] Returns the URI of the project this client has set
106
+ def project_uri
107
+ data['project']
108
+ end
109
+
110
+ # Project this client has set
111
+ #
112
+ # @return [GoodData::Project] Returns the instance of the client's project
113
+ def project
114
+ client.projects(project_uri) if project?
115
+ end
116
+
117
+ # Returns boolean if client has a project provisioned
118
+ #
119
+ # @return [Boolean] Returns true if client has a project provisioned. False otherwise
120
+ def project?
121
+ project_uri != nil
122
+ end
123
+
124
+ # Reloads the client from the URI
125
+ #
126
+ # @return [GoodData::Client] Returns the updated client object
127
+ def reload!
128
+ res = client.get(uri)
129
+ @json = res
130
+ self
131
+ end
132
+
133
+ # Segment id setter which this client is connected to.
134
+ #
135
+ # @param a_segment [String] Id of the segment.
136
+ # @return [GoodData::Client] Returns the instance of the client
137
+ def segment=(a_segment)
138
+ data['segment'] = a_segment.respond_to?(:uri) ? a_segment.uri : a_segment
139
+ self
140
+ end
141
+
142
+ # Segment this client is connected to.
143
+ #
144
+ # @return [GoodData::Segment] Segment
145
+ def segment
146
+ segment_res = client.get(data['segment'])
147
+ client.create(GoodData::Segment, segment_res)
148
+ end
149
+
150
+ # Segment URI this client is connected to.
151
+ #
152
+ # @return [String] Segment URI
153
+ def segment_uri
154
+ data['segment']
155
+ end
156
+
157
+ # Creates or updates a client instance on the API.
158
+ #
159
+ # @return [GoodData::Client] Client instance
160
+ def save
161
+ if uri
162
+ client.put(uri, json)
163
+ else
164
+ res = client.post(domain.segments_uri + '/clients', json)
165
+ @json = res
166
+ end
167
+ self
168
+ end
169
+
170
+ # Deletes a client instance on the API.
171
+ #
172
+ # @return [GoodData::Client] Segment instance
173
+ def delete
174
+ project.delete if project && !project.deleted?
175
+ client.delete(uri) if uri
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2010-2015 GoodData Corporation. All rights reserved.
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ require_relative './client_synchronization_result_details'
8
+
9
+ require_relative '../mixins/data_property_reader'
10
+ require_relative '../mixins/links'
11
+
12
+ require_relative '../rest/resource'
13
+
14
+ module GoodData
15
+ class ClientSynchronizationResult < Rest::Resource
16
+ include Mixin::Links
17
+
18
+ # Initializes object instance from raw wire JSON
19
+ #
20
+ # @param json Json used for initialization
21
+ def initialize(json, opts = {})
22
+ super(opts)
23
+ @json = json
24
+ end
25
+
26
+ def details
27
+ res = client.get(links['details'])
28
+ client.create(GoodData::ClientSynchronizationResultDetails, res) if res
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2010-2015 GoodData Corporation. All rights reserved.
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ require_relative './client'
8
+
9
+ require_relative '../mixins/data_property_reader'
10
+ require_relative '../mixins/links'
11
+
12
+ require_relative '../rest/resource'
13
+
14
+ module GoodData
15
+ class ClientSynchronizationResultDetails < Rest::Resource
16
+ include Mixin::Links
17
+
18
+ attr_accessor :synchronization_result
19
+
20
+ # Initializes object instance from raw wire JSON
21
+ #
22
+ # @param json Json used for initialization
23
+ def initialize(json, opts = { :synchronization_result => nil })
24
+ super(opts)
25
+ @json = json
26
+ @synchronization_result = opts[:synchronization_result]
27
+ end
28
+
29
+ def items
30
+ data['items']
31
+ end
32
+
33
+ def next
34
+ paging && paging['next']
35
+ end
36
+
37
+ def paging
38
+ data['paging']
39
+ end
40
+ end
41
+ end
@@ -7,7 +7,7 @@
7
7
  require_relative '../rest/resource'
8
8
 
9
9
  module GoodData
10
- class DataWarehouse < GoodData::Rest::Resource
10
+ class DataWarehouse < Rest::Resource
11
11
  class << self
12
12
  CREATE_URL = '/gdc/datawarehouse/instances'
13
13
 
@@ -51,10 +51,6 @@ module GoodData
51
51
  c.create(DataWarehouse, final_json)
52
52
  end
53
53
  end
54
- attr_accessor :json
55
-
56
- alias_method :to_json, :json
57
- alias_method :raw_data, :json
58
54
 
59
55
  def initialize(json)
60
56
  super
@@ -11,7 +11,7 @@ require_relative '../extensions/enumerable'
11
11
  require_relative '../rest/object'
12
12
 
13
13
  module GoodData
14
- class Domain < GoodData::Rest::Object
14
+ class Domain < Rest::Resource
15
15
  attr_reader :name
16
16
 
17
17
  class << self
@@ -274,12 +274,34 @@ module GoodData
274
274
  GoodData::Domain.add_user(data, name, { client: client }.merge(opts))
275
275
  end
276
276
 
277
+ def clients
278
+ clients_uri = "/gdc/domains/#{name}/clients"
279
+ res = client.get(clients_uri)
280
+ res_clients = (res['clients'] && res['clients']['items']) || []
281
+ res_clients.map do |res_client|
282
+ client.create(GoodData::Client, res_client)
283
+ end
284
+ end
285
+
277
286
  alias_method :create_user, :add_user
278
287
 
279
288
  def create_users(list, options = {})
280
289
  GoodData::Domain.create_users(list, name, { client: client }.merge(options))
281
290
  end
282
291
 
292
+ def segments(id = :all)
293
+ GoodData::Segment[id, domain: self]
294
+ end
295
+
296
+ # Creates new segment in current domain from parameters passed
297
+ #
298
+ # @param data [Hash] Data for segment namely :segment_id and :master_project is accepted. Master_project can be given as either a PID or a Project instance
299
+ # @return [GoodData::Segment] New Segment instance
300
+ def create_segment(data)
301
+ segment = GoodData::Segment.create(data, domain: self, client: client)
302
+ segment.save
303
+ end
304
+
283
305
  # Gets user by its login or uri in various shapes
284
306
  # It does not find by other information because that is not unique. If you want to search by name or email please
285
307
  # use fuzzy_get_user.
@@ -334,6 +356,65 @@ module GoodData
334
356
  profiles.map { |p| member?(p, list) }
335
357
  end
336
358
 
359
+ # Returns uri for segments on the domain. This will be removed soon. It is here that for segments the "account" portion of the URI was removed. And not for the rest
360
+ #
361
+ # @return [String] Uri of the segments
362
+ def segments_uri
363
+ "/gdc/domains/#{name}"
364
+ end
365
+
366
+ # Calls Segment#synchronize_clients on all segments and concatenates the results
367
+ #
368
+ # @return [Array] Returns array of results
369
+ def synchronize_clients
370
+ segments.flat_map(&:synchronize_clients)
371
+ end
372
+
373
+ # Runs async process that walks through segments and provisions projects if necessary.
374
+ #
375
+ # @return [Enumerator] Returns Enumerator of results
376
+ def provision_client_projects
377
+ res = client.post(segments_uri + '/provisionClientProjects', nil)
378
+ res = client.poll_on_code(res['asyncTask']['links']['poll'])
379
+ klass = Struct.new('ProvisioningResult', :id, :status, :project_uri)
380
+ Enumerator.new do |y|
381
+ uri = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResult links details))
382
+ loop do
383
+ result = client.get(uri)
384
+ (GoodData::Helpers.get_path(result, %w(clientProjectProvisioningResultDetails items)) || []).each do |item|
385
+ y << klass.new(item['id'], item['status'], item['project'])
386
+ end
387
+ uri = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResultDetails paging next))
388
+ break if uri.nil?
389
+ end
390
+ end
391
+ end
392
+
393
+ def update_clients(data, options = {})
394
+ payload = data.map do |datum|
395
+ {
396
+ :client => {
397
+ :id => datum[:id],
398
+ :segment => segments_uri + '/segments/' + datum[:segment],
399
+ :project => datum[:project]
400
+ }
401
+ }
402
+ end
403
+ if options[:delete_extra] == true
404
+ res = client.post(segments_uri + '/updateClients?deleteExtra=true', updateClients: { items: payload })
405
+ else
406
+ res = client.post(segments_uri + '/updateClients', updateClients: { items: payload })
407
+ end
408
+ data = GoodData::Helpers.get_path(res, ['updateClientsResponse'])
409
+ if data
410
+ result = data.flat_map { |k, v| v.map { |h| GoodData::Helpers.symbolize_keys(h.merge('type' => k)) } }
411
+ result.select { |r| r[:status] == 'DELETED' }.peach { |r| r[:originalProject] && client.delete(r[:originalProject]) }
412
+ result
413
+ else
414
+ []
415
+ end
416
+ end
417
+
337
418
  # Update user in domain
338
419
  #
339
420
  # @param opts [Hash] Data of the user to be updated
@@ -362,6 +443,9 @@ module GoodData
362
443
 
363
444
  alias_method :members, :users
364
445
 
446
+ # Returns uri for the domain.
447
+ #
448
+ # @return [String] Uri of the segments
365
449
  def uri
366
450
  "/gdc/account/domains/#{name}"
367
451
  end