gooddata 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -1
  3. data/CHANGELOG.markdown +6 -0
  4. data/README.md +1 -0
  5. data/gooddata.gemspec +2 -1
  6. data/lib/gooddata.rb +4 -1
  7. data/lib/gooddata/bricks/base_downloader.rb +33 -19
  8. data/lib/gooddata/bricks/middleware/bulk_salesforce_middleware.rb +49 -25
  9. data/lib/gooddata/bricks/middleware/restforce_middleware.rb +36 -33
  10. data/lib/gooddata/cli/commands/project_cmd.rb +6 -4
  11. data/lib/gooddata/client.rb +1 -1
  12. data/lib/gooddata/commands/api.rb +1 -1
  13. data/lib/gooddata/commands/auth.rb +1 -1
  14. data/lib/gooddata/connection.rb +13 -10
  15. data/lib/gooddata/core/connection.rb +1 -1
  16. data/lib/gooddata/core/user.rb +11 -3
  17. data/lib/gooddata/exceptions/validation_error.rb +12 -0
  18. data/lib/gooddata/extensions/extensions.rb +6 -0
  19. data/lib/gooddata/goodzilla/goodzilla.rb +2 -2
  20. data/lib/gooddata/helpers/csv_helper.rb +57 -0
  21. data/lib/gooddata/{helpers.rb → helpers/global_helpers.rb} +0 -0
  22. data/lib/gooddata/helpers/helpers.rb +6 -0
  23. data/lib/gooddata/models/domain.rb +134 -24
  24. data/lib/gooddata/models/membership.rb +402 -0
  25. data/lib/gooddata/models/metadata.rb +64 -7
  26. data/lib/gooddata/models/metadata/attribute.rb +27 -12
  27. data/lib/gooddata/models/metadata/column.rb +1 -1
  28. data/lib/gooddata/models/metadata/dashboard.rb +7 -6
  29. data/lib/gooddata/models/metadata/display_form.rb +17 -2
  30. data/lib/gooddata/models/metadata/fact.rb +13 -7
  31. data/lib/gooddata/models/metadata/metric.rb +9 -9
  32. data/lib/gooddata/models/metadata/report.rb +7 -8
  33. data/lib/gooddata/models/metadata/report_definition.rb +10 -11
  34. data/lib/gooddata/models/metadata/schema.rb +1 -1
  35. data/lib/gooddata/models/model.rb +1 -1
  36. data/lib/gooddata/models/process.rb +44 -25
  37. data/lib/gooddata/models/profile.rb +365 -13
  38. data/lib/gooddata/models/project.rb +245 -35
  39. data/lib/gooddata/models/project_blueprint.rb +42 -18
  40. data/lib/gooddata/models/project_creator.rb +4 -1
  41. data/lib/gooddata/models/project_role.rb +7 -7
  42. data/lib/gooddata/models/schedule.rb +17 -1
  43. data/lib/gooddata/models/schema_blueprint.rb +19 -2
  44. data/lib/gooddata/version.rb +1 -1
  45. data/out.txt +0 -0
  46. data/spec/data/users.csv +12 -0
  47. data/spec/helpers/connection_helper.rb +1 -0
  48. data/spec/helpers/csv_helper.rb +12 -0
  49. data/spec/helpers/project_helper.rb +1 -1
  50. data/spec/integration/full_project_spec.rb +136 -3
  51. data/spec/spec_helper.rb +9 -0
  52. data/spec/unit/commands/command_user_spec.rb +1 -1
  53. data/spec/unit/extensions/hash_spec.rb +19 -0
  54. data/spec/unit/godzilla/goodzilla_spec.rb +15 -0
  55. data/spec/unit/helpers/csv_helper_spec.rb +18 -0
  56. data/spec/unit/models/domain_spec.rb +47 -4
  57. data/spec/unit/models/md_object_spec.rb +8 -0
  58. data/spec/unit/models/membership_spec.rb +128 -0
  59. data/spec/unit/models/metadata_spec.rb +38 -0
  60. data/spec/unit/models/profile_spec.rb +212 -0
  61. data/spec/unit/models/project_blueprint_spec.rb +35 -8
  62. data/spec/unit/models/project_role_spec.rb +6 -6
  63. data/spec/unit/models/project_spec.rb +226 -13
  64. data/spec/unit/models/schedule_spec.rb +58 -0
  65. data/tmp/.gitkeepme +0 -0
  66. metadata +36 -11
  67. data/lib/gooddata/models/account_settings.rb +0 -124
  68. data/lib/gooddata/models/user.rb +0 -165
  69. data/spec/unit/models/account_settings_spec.rb +0 -28
  70. data/spec/unit/models/user_spec.rb +0 -16
@@ -1,32 +1,384 @@
1
1
  # encoding: UTF-8
2
2
 
3
+ require_relative 'project'
4
+
3
5
  module GoodData
6
+ # Account settings representation with some added sugar
4
7
  class Profile
5
- private_class_method :new
6
- attr_reader :user, :json
8
+ attr_reader :json
9
+
10
+ EMPTY_OBJECT = {
11
+ 'accountSetting' => {
12
+ 'companyName' => nil,
13
+ 'country' => nil,
14
+ 'created' => nil,
15
+ 'firstName' => nil,
16
+ 'lastName' => nil,
17
+ 'login' => nil,
18
+ 'phoneNumber' => nil,
19
+ 'position' => nil,
20
+ 'timezone' => nil,
21
+ 'updated' => nil,
22
+ 'links' => {
23
+ 'projects' => nil,
24
+ 'self' => nil
25
+ },
26
+ 'email' => nil,
27
+ 'authenticationModes' => []
28
+ }
29
+ }
30
+
31
+ ASSIGNABLE_MEMBERS = [
32
+ :company,
33
+ :country,
34
+ :email,
35
+ :login,
36
+ :first_name,
37
+ :last_name,
38
+ :phone,
39
+ :position,
40
+ :timezone
41
+ ]
7
42
 
8
43
  class << self
9
- def load
10
- # GoodData.logger.info "Loading user profile..."
11
- Profile.send 'new'
44
+ # Apply changes to object.
45
+ #
46
+ # @param obj [GoodData::Profile] Object to be modified
47
+ # @param changes [Hash] Hash with modifications
48
+ # @return [GoodData::Profile] Modified object
49
+ def apply(obj, changes)
50
+ changes.each do |param, val|
51
+ next unless ASSIGNABLE_MEMBERS.include? param
52
+ obj.send("#{param}=", val)
53
+ end
54
+ obj
55
+ end
56
+
57
+ # Creates new instance from hash with attributes
58
+ #
59
+ # @param attributes [Hash] Hash with initial attributes
60
+ # @return [GoodData::Profile] New profile instance
61
+ def create(attributes)
62
+ json = EMPTY_OBJECT.dup
63
+ res = GoodData::Profile.new(json)
64
+
65
+ attributes.each do |k, v|
66
+ res.send("#{k}=", v) if ASSIGNABLE_MEMBERS.include? k
67
+ end
68
+
69
+ res.save!
70
+ res
71
+ end
72
+
73
+ # Gets user currently logged in
74
+ # @return [GoodData::Profile] User currently logged-in
75
+ def current
76
+ json = GoodData.get GoodData.connection.user['profile']
77
+ GoodData::Profile.new(json)
78
+ end
79
+
80
+ # Gets hash representing diff of profiles
81
+ #
82
+ # @param user1 [GoodData::Profile] Original user
83
+ # @param user2 [GoodData::Profile] User to compare with
84
+ # @return [Hash] Hash representing diff
85
+ def diff(user1, user2)
86
+ res = {}
87
+ ASSIGNABLE_MEMBERS.each do |k|
88
+ l_value = user1.send("#{k}")
89
+ r_value = user2.send("#{k}")
90
+ res[k] = r_value if l_value != r_value
91
+ end
92
+ res
93
+ end
94
+
95
+ def diff_list(list1, list2)
96
+ tmp = Hash[list1.map { |v| [v.email, v] }]
97
+
98
+ res = {
99
+ :added => [],
100
+ :removed => [],
101
+ :changed => []
102
+ }
103
+
104
+ list2.each do |user_new|
105
+ user_existing = tmp[user_new.email]
106
+ if user_existing.nil?
107
+ res[:added] << user_new
108
+ next
109
+ end
110
+
111
+ if user_existing != user_new
112
+ diff = self.diff(user_existing, user_new)
113
+ res[:changed] << {
114
+ :user => user_existing,
115
+ :diff => diff
116
+ }
117
+ end
118
+ end
119
+
120
+ tmp = Hash[list2.map { |v| [v.email, v] }]
121
+ list1.each do |user_existing|
122
+ user_new = tmp[user_existing.email]
123
+ if user_new.nil?
124
+ res[:removed] << user_existing
125
+ next
126
+ end
127
+ end
128
+
129
+ res
130
+ end
131
+ end
132
+
133
+ # Creates new instance
134
+ #
135
+ # @return [Profile] New Profile instance
136
+ def initialize(json)
137
+ @json = json
138
+ @dirty = false
139
+ end
140
+
141
+ # Checks objects for equality
142
+ #
143
+ # @param right [GoodData::Profile] Project to compare with
144
+ # @return [Boolean] True if same else false
145
+ def ==(other)
146
+ res = true
147
+ ASSIGNABLE_MEMBERS.each do |k|
148
+ l_val = send("#{k}")
149
+ r_val = other.send("#{k}")
150
+ res = false if l_val != r_val
12
151
  end
152
+ res
153
+ end
154
+
155
+ # Checks objects for non-equality
156
+ #
157
+ # @param right [GoodData::Profile] Project to compare with
158
+ # @return [Boolean] True if different else false
159
+ def !=(other)
160
+ !(self == other)
161
+ end
162
+
163
+ # Apply changes to object.
164
+ #
165
+ # @param changes [Hash] Hash with modifications
166
+ # @return [GoodData::Profile] Modified object
167
+ def apply(changes)
168
+ GoodData::Profile.apply(self, changes)
169
+ end
170
+
171
+ # Gets the company name
172
+ #
173
+ # @return [String] Company name
174
+ def company
175
+ @json['accountSetting']['companyName'] || ''
176
+ end
177
+
178
+ # Set the company name
179
+ #
180
+ # @param val [String] Company name to be set
181
+ def company=(val)
182
+ @dirty ||= company != val
183
+ @json['accountSetting']['companyName'] = val
184
+ end
185
+
186
+ # Gets the country
187
+ #
188
+ # @return [String] Country
189
+ def country
190
+ @json['accountSetting']['country'] || ''
191
+ end
192
+
193
+ # Set the country
194
+ #
195
+ # @param val [String] Country to be set
196
+ def country=(val)
197
+ @dirty ||= country != val
198
+ @json['accountSetting']['country'] = val
13
199
  end
14
200
 
201
+ # Gets date when created
202
+ #
203
+ # @return [DateTime] Created date
204
+ def created
205
+ DateTime.parse(@json['accountSetting']['created'])
206
+ end
207
+
208
+ # Deletes this account settings
209
+ def delete
210
+ GoodData.delete uri
211
+ end
212
+
213
+ # Gets hash representing diff of profiles
214
+ #
215
+ # @param user [GoodData::Profile] Another profile to compare with
216
+ # @return [Hash] Hash representing diff
217
+ def diff(user)
218
+ GoodData::Profile.diff(self, user)
219
+ end
220
+
221
+ # Gets the email
222
+ #
223
+ # @return [String] Email address
224
+ def email
225
+ @json['accountSetting']['email'] || ''
226
+ end
227
+
228
+ # Set the email
229
+ #
230
+ # @param val [String] Email to be set
231
+ def email=(val)
232
+ @dirty ||= email != val
233
+ @json['accountSetting']['email'] = val
234
+ end
235
+
236
+ # Gets the first name
237
+ #
238
+ # @return [String] First name
239
+ def first_name
240
+ @json['accountSetting']['firstName'] || ''
241
+ end
242
+
243
+ # Set the first name
244
+ #
245
+ # @param val [String] First name to be set
246
+ def first_name=(val)
247
+ @dirty ||= first_name != val
248
+ @json['accountSetting']['firstName'] = val
249
+ end
250
+
251
+ # Gets the last name
252
+ #
253
+ # @return [String] Last name
254
+ def last_name
255
+ @json['accountSetting']['lastName'] || ''
256
+ end
257
+
258
+ # Set the last name
259
+ #
260
+ # @param val [String] Last name to be set
261
+ def last_name=(val)
262
+ @dirty ||= last_name != val
263
+ @json['accountSetting']['lastName'] = val
264
+ end
265
+
266
+ # Gets the login
267
+ #
268
+ # @return [String] Login
269
+ def login
270
+ @json['accountSetting']['login'] || ''
271
+ end
272
+
273
+ # Set the login
274
+ #
275
+ # @param val [String] Login to be set
276
+ def login=(val)
277
+ @dirty ||= login != val
278
+ @json['accountSetting']['login'] = val
279
+ end
280
+
281
+ # Get full name
282
+ #
283
+ # @return [String] Full name
284
+ def name
285
+ "#{first_name} #{last_name}"
286
+ end
287
+
288
+ # Gets the resource identifier
289
+ #
290
+ # @return [String] Resource identifier
291
+ def obj_id
292
+ uri.split('/').last
293
+ end
294
+
295
+ alias_method :account_setting_id, :obj_id
296
+
297
+ # Gets the phone
298
+ #
299
+ # @return [String] Phone
300
+ def phone
301
+ @json['accountSetting']['phone'] || ''
302
+ end
303
+
304
+ # Set the phone
305
+ #
306
+ # @param val [String] Phone to be set
307
+ def phone=(val)
308
+ @dirty ||= phone != val
309
+ @json['accountSetting']['phone'] = val
310
+ end
311
+
312
+ # Gets the position in company
313
+ #
314
+ # @return [String] Position in company
315
+ def position
316
+ @json['accountSetting']['position'] || ''
317
+ end
318
+
319
+ # Set the position
320
+ #
321
+ # @param val [String] Position to be set
322
+ def position=(val)
323
+ @dirty ||= position != val
324
+ @json['accountSetting']['position'] = val
325
+ end
326
+
327
+ # Gets the array of projects
328
+ #
329
+ # @return [Array<GoodData::Project>] Array of project where account settings belongs to
15
330
  def projects
16
- @json['accountSetting']['links']['projects']
331
+ res = []
332
+
333
+ projects = GoodData.get @json['accountSetting']['links']['projects']
334
+ projects['projects'].each do |project|
335
+ res << GoodData::Project.new(project)
336
+ end
337
+
338
+ res
17
339
  end
18
340
 
19
- alias_method :to_json, :json
341
+ # Saves object if dirty, clears dirty flag
342
+ def save!
343
+ if @dirty
344
+ raw = @json.dup
345
+ raw['accountSetting'].delete('login')
20
346
 
21
- def [](key, options = {})
22
- @json['accountSetting'][key]
347
+ if uri && !uri.empty?
348
+ url = "/gdc/account/profile/#{obj_id}"
349
+ @json = GoodData.put url, raw
350
+ @dirty = false
351
+ end
352
+ end
23
353
  end
24
354
 
25
- private
355
+ # Gets the preferred timezone
356
+ #
357
+ # @return [String] Preferred timezone
358
+ def timezone
359
+ @json['accountSetting']['timezone'] || ''
360
+ end
361
+
362
+ # Set the timezone
363
+ #
364
+ # @param val [String] Timezone to be set
365
+ def timezone=(val)
366
+ @dirty ||= timezone != val
367
+ @json['accountSetting']['timezone'] = val
368
+ end
369
+
370
+ # Gets the date when updated
371
+ #
372
+ # @return [DateTime] Updated date
373
+ def updated
374
+ DateTime.parse(@json['accountSetting']['updated'])
375
+ end
26
376
 
27
- def initialize
28
- @json = GoodData.get GoodData.connection.user['profile']
29
- @user = @json['accountSetting']['firstName'] + ' ' + @json['accountSetting']['lastName']
377
+ # Gets the resource REST URI
378
+ #
379
+ # @return [String] Resource URI
380
+ def uri
381
+ @json['accountSetting']['links']['self']
30
382
  end
31
383
  end
32
384
  end
@@ -1,5 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
+ require 'csv'
3
4
  require 'zip'
4
5
  require 'fileutils'
5
6
 
@@ -21,10 +22,7 @@ module GoodData
21
22
  # Returns an array of all projects accessible by
22
23
  # current user
23
24
  def all
24
- json = GoodData.get GoodData.profile.projects
25
- json['projects'].map do |project|
26
- Project.new project
27
- end
25
+ GoodData.profile.projects
28
26
  end
29
27
 
30
28
  # Returns a Project object identified by given string
@@ -74,7 +72,7 @@ module GoodData
74
72
  'driver' => attributes[:driver] || 'Pg'
75
73
  }
76
74
  }
77
- }
75
+ }
78
76
 
79
77
  json['project']['meta']['projectTemplate'] = attributes[:template] if attributes[:template] && !attributes[:template].empty?
80
78
  project = Project.new json
@@ -98,6 +96,23 @@ module GoodData
98
96
  sleep 3
99
97
  project
100
98
  end
99
+
100
+ # Takes one CSV line and creates hash from data extracted
101
+ #
102
+ # @param row CSV row
103
+ def user_csv_import(row)
104
+ {
105
+ 'user' => {
106
+ 'content' => {
107
+ 'email' => row[0],
108
+ 'login' => row[1],
109
+ 'firstname' => row[2],
110
+ 'lastname' => row[3]
111
+ },
112
+ 'meta' => {}
113
+ }
114
+ }
115
+ end
101
116
  end
102
117
 
103
118
  # Creates a data set within the project
@@ -139,13 +154,6 @@ module GoodData
139
154
  @json['project']['meta']['author']
140
155
  end
141
156
 
142
- # Adds user to project
143
- #
144
- # TODO: Discuss with @fluke777 if is not #invite sufficient
145
- def add_user(email_address, domain)
146
- fail 'Not implemented'
147
- end
148
-
149
157
  # Returns web interface URI of project
150
158
  #
151
159
  # @return [String] Project URL
@@ -218,7 +226,7 @@ module GoodData
218
226
  #
219
227
  # @return [DateTime] Date time when created
220
228
  def created
221
- DateTime.parse(@json['meta']['created'])
229
+ DateTime.parse(@json['project']['meta']['created'])
222
230
  end
223
231
 
224
232
  # Gets ruby wrapped raw project JSON data
@@ -234,6 +242,13 @@ module GoodData
234
242
  end
235
243
  end
236
244
 
245
+ # Gets processes for the project
246
+ #
247
+ # @return [Array<GoodData::Process>] Processes for the current project
248
+ def processes
249
+ GoodData::Process.all
250
+ end
251
+
237
252
  # Deletes project
238
253
  def delete
239
254
  fail "Project '#{title}' with id #{uri} is already deleted" if state == :deleted
@@ -249,10 +264,11 @@ module GoodData
249
264
  #
250
265
  # @param [String] role_name Title of role to look for
251
266
  # @return [GoodData::ProjectRole] Project role if found
252
- def get_role_by_identifier(role_name)
253
- tmp = roles
254
- tmp.each do |role|
255
- return role if role.identifier.downcase == role_name.downcase
267
+ def get_role_by_identifier(role_name, role_list = roles)
268
+ role_name = role_name.downcase.gsub(/role$/, '')
269
+ role_list.each do |role|
270
+ tmp_role_name = role.identifier.downcase.gsub(/role$/, '')
271
+ return role if tmp_role_name == role_name
256
272
  end
257
273
  nil
258
274
  end
@@ -261,9 +277,8 @@ module GoodData
261
277
  #
262
278
  # @param [String] role_summary Summary of role to look for
263
279
  # @return [GoodData::ProjectRole] Project role if found
264
- def get_role_by_summary(role_summary)
265
- tmp = roles
266
- tmp.each do |role|
280
+ def get_role_by_summary(role_summary, role_list = roles)
281
+ role_list.each do |role|
267
282
  return role if role.summary.downcase == role_summary.downcase
268
283
  end
269
284
  nil
@@ -273,14 +288,47 @@ module GoodData
273
288
  #
274
289
  # @param [String] role_title Title of role to look for
275
290
  # @return [GoodData::ProjectRole] Project role if found
276
- def get_role_by_title(role_title)
277
- tmp = roles
278
- tmp.each do |role|
291
+ def get_role_by_title(role_title, role_list = roles)
292
+ role_list.each do |role|
279
293
  return role if role.title.downcase == role_title.downcase
280
294
  end
281
295
  nil
282
296
  end
283
297
 
298
+ # Gets project role
299
+ #
300
+ # @param [String] role_title Title of role to look for
301
+ # @return [GoodData::ProjectRole] Project role if found
302
+ def get_role(role_name, role_list = roles)
303
+ return role_name if role_name.is_a? GoodData::ProjectRole
304
+
305
+ role_name.downcase!
306
+ role_list.each do |role|
307
+ return role if role.uri == role_name ||
308
+ role.identifier.downcase == role_name ||
309
+ role.identifier.downcase.gsub(/role$/, '') == role_name ||
310
+ role.title.downcase == role_name ||
311
+ role.summary.downcase == role_name
312
+ end
313
+ nil
314
+ end
315
+
316
+ # Gets user by its email, full_name, login or uri
317
+ #
318
+ # @param [String] name Name to look for
319
+ # @param [Array<GoodData::User>]user_list Optional cached list of users used for look-ups
320
+ # @return [GoodDta::Membership] User
321
+ def get_user(name, user_list = users)
322
+ return name if name.instance_of?(GoodData::Membership)
323
+ name.downcase!
324
+ user_list.each do |user|
325
+ return user if user.uri.downcase == name ||
326
+ user.login.downcase == name ||
327
+ user.email.downcase == name
328
+ end
329
+ nil
330
+ end
331
+
284
332
  # Initializes object instance from raw wire JSON
285
333
  #
286
334
  # @param json Json used for initialization
@@ -300,9 +348,8 @@ module GoodData
300
348
 
301
349
  role_url = nil
302
350
  if role.index('/gdc/') != 0
303
- tmp = get_role_by_identifier(role)
304
- tmp = get_role_by_title(role) if tmp.nil?
305
- role_url = tmp['url'] if tmp
351
+ tmp = get_role(role)
352
+ role_url = tmp.uri if tmp
306
353
  else
307
354
  role_url = role if role_url.nil?
308
355
  end
@@ -352,6 +399,29 @@ module GoodData
352
399
  @md ||= Links.new GoodData.get(data['links']['metadata'])
353
400
  end
354
401
 
402
+ # Gets membership for profile specified
403
+ #
404
+ # @param [GoodData::Profile] profile - Profile to be checked
405
+ # @param [Array<GoodData::Membership>] list Optional list of members to check against
406
+ # @return [GoodData::Membership] Membership if found
407
+ def member(profile, list = members)
408
+ if profile.is_a? String
409
+ return list.find do |m|
410
+ m.uri == profile || m.login == profile
411
+ end
412
+ end
413
+ list.find { |m| m.login == profile.login }
414
+ end
415
+
416
+ # Checks if the profile is member of project
417
+ #
418
+ # @param [GoodData::Profile] profile - Profile to be checked
419
+ # @param [Array<GoodData::Membership>] list Optional list of members to check against
420
+ # @return [Boolean] true if is member else false
421
+ def member?(profile, list = members)
422
+ !member(profile, list).nil?
423
+ end
424
+
355
425
  # Gets raw resource ID
356
426
  #
357
427
  # @return [String] Raw resource ID
@@ -422,16 +492,11 @@ module GoodData
422
492
  # @return [Array<GoodData::ProjectRole>] List of roles
423
493
  def roles
424
494
  url = "/gdc/projects/#{pid}/roles"
425
-
426
- res = []
427
-
428
495
  tmp = GoodData.get(url)
429
- tmp['projectRoles']['roles'].each do |role_url|
496
+ tmp['projectRoles']['roles'].map do |role_url|
430
497
  json = GoodData.get role_url
431
- res << GoodData::ProjectRole.new(json)
498
+ GoodData::ProjectRole.new(json)
432
499
  end
433
-
434
- res
435
500
  end
436
501
 
437
502
  # Saves project
@@ -498,7 +563,7 @@ module GoodData
498
563
  #
499
564
  # @return [DateTime] Date time of last update
500
565
  def updated
501
- DateTime.parse(@json['meta']['updated'])
566
+ DateTime.parse(@json['project']['meta']['updated'])
502
567
  end
503
568
 
504
569
  # Uploads file to project
@@ -521,12 +586,157 @@ module GoodData
521
586
 
522
587
  tmp = GoodData.get @json['project']['links']['users']
523
588
  tmp['users'].map do |user|
524
- res << GoodData::User.new(user)
589
+ res << GoodData::Membership.new(user)
525
590
  end
526
591
 
527
592
  res
528
593
  end
529
594
 
595
+ alias_method :members, :users
596
+
597
+ def users_create(list, role_list = roles)
598
+ domains = {}
599
+ list.map do |user|
600
+ # TODO: Add user here
601
+ domain_name = user.json['user']['content']['domain']
602
+
603
+ # Lookup for domain in cache'
604
+ domain = domains[domain_name]
605
+
606
+ # Get domain info from REST, add to cache
607
+ if domain.nil?
608
+ domain = {
609
+ :domain => GoodData::Domain[domain_name],
610
+ :users => GoodData::Domain[domain_name].users
611
+ }
612
+
613
+ domain[:users_map] = Hash[domain[:users].map { |u| [u.email, u] }]
614
+ domains[domain_name] = domain
615
+ end
616
+
617
+ # Check if user exists in domain
618
+ domain_user = domain[:users_map][user.email]
619
+ fail ArgumentError, "Trying to add user '#{user.login}' which is not valid user in domain '#{domain_name}'" if domain_user.nil?
620
+
621
+ # Lookup for role
622
+ role_name = user.json['user']['content']['role'] || 'readOnlyUser'
623
+ role = get_role(role_name, role_list)
624
+ fail ArgumentError, "Invalid role name specified '#{role_name}' for user '#{user.email}'" if role.nil?
625
+
626
+ # Assign user project role
627
+ set_user_roles(domain_user, [role.uri], role_list)
628
+ end
629
+ end
630
+
631
+ # Imports users from CSV
632
+ #
633
+ # # Features
634
+ # - Create new users
635
+ # - Delete old users
636
+ # - Update existing users
637
+ #
638
+ # CSV Format
639
+ # TODO: Describe CSV Format here
640
+ #
641
+ # @param path CSV file to be loaded
642
+ # @param opts Optional additional options
643
+ def users_import(new_users, domain = nil)
644
+ # Diff users
645
+ diff = GoodData::Membership.diff_list(users, new_users)
646
+
647
+ # Create domain users
648
+ GoodData::Domain.users_create(diff[:added], domain)
649
+
650
+ # Create new users
651
+ role_list = roles
652
+ users_create(diff[:added], role_list)
653
+
654
+ # Get changed users objects from hash
655
+ list = diff[:changed].map do |user|
656
+ user[:user]
657
+ end
658
+
659
+ # Join list of changed users with 'same' users
660
+ list = list.zip(diff[:same]).flatten.compact
661
+
662
+ new_users_map = Hash[new_users.map { |u| [u.email, u] }]
663
+
664
+ # Create list with user, desired_roles hashes
665
+ list = list.map do |user|
666
+ {
667
+ :user => user,
668
+ :roles => new_users_map[user.email].json['user']['content']['role'].split(' ').map { |r| r.downcase }.sort
669
+ }
670
+ end
671
+
672
+ # Update existing users
673
+ set_users_roles(list, role_list)
674
+
675
+ # Remove old users
676
+ users_remove(diff[:removed])
677
+ end
678
+
679
+ # Disable users
680
+ #
681
+ # @param list List of users to be disabled
682
+ def users_remove(list)
683
+ list.map do |user|
684
+ user.disable
685
+ end
686
+ end
687
+
688
+ # Update user
689
+ #
690
+ # @param user User to be updated
691
+ # @param desired_roles Roles to be assigned to user
692
+ # @param role_list Optional cached list of roles used for lookups
693
+ def set_user_roles(user, desired_roles, role_list = roles)
694
+ if user.is_a? String
695
+ user = get_user(user)
696
+ fail ArgumentError, "Invalid user '#{user}' specified" if user.nil?
697
+ end
698
+
699
+ desired_roles = [desired_roles] unless desired_roles.is_a? Array
700
+
701
+ roles = desired_roles.map do |role_name|
702
+ role = get_role(role_name, role_list)
703
+ fail ArgumentError, "Invalid role '#{role_name}' specified for user '#{user.email}'" if role.nil?
704
+ role.uri
705
+ end
706
+
707
+ url = "#{uri}/users"
708
+ payload = {
709
+ 'user' => {
710
+ 'content' => {
711
+ 'status' => 'ENABLED',
712
+ 'userRoles' => roles
713
+ },
714
+ 'links' => {
715
+ 'self' => user.uri
716
+ }
717
+ }
718
+ }
719
+
720
+ GoodData.post url, payload
721
+ end
722
+
723
+ alias_method :add_user, :set_user_roles
724
+
725
+ # Update list of users
726
+ #
727
+ # @param list List of users to be updated
728
+ # @param role_list Optional list of cached roles to prevent unnecessary server round-trips
729
+ def set_users_roles(list, role_list = roles)
730
+ list.map do |user_hash|
731
+ user = user_hash[:user]
732
+ roles = user_hash[:role] || user_hash[:roles]
733
+ {
734
+ :user => user,
735
+ :result => set_user_roles(user, roles, role_list)
736
+ }
737
+ end
738
+ end
739
+
530
740
  # Run validation on project
531
741
  # Valid settins for validation are (default all):
532
742
  # ldm - Checks the consistency of LDM objects.