gooddata 0.6.3 → 0.6.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -1
- data/CHANGELOG.markdown +6 -0
- data/README.md +1 -0
- data/gooddata.gemspec +2 -1
- data/lib/gooddata.rb +4 -1
- data/lib/gooddata/bricks/base_downloader.rb +33 -19
- data/lib/gooddata/bricks/middleware/bulk_salesforce_middleware.rb +49 -25
- data/lib/gooddata/bricks/middleware/restforce_middleware.rb +36 -33
- data/lib/gooddata/cli/commands/project_cmd.rb +6 -4
- data/lib/gooddata/client.rb +1 -1
- data/lib/gooddata/commands/api.rb +1 -1
- data/lib/gooddata/commands/auth.rb +1 -1
- data/lib/gooddata/connection.rb +13 -10
- data/lib/gooddata/core/connection.rb +1 -1
- data/lib/gooddata/core/user.rb +11 -3
- data/lib/gooddata/exceptions/validation_error.rb +12 -0
- data/lib/gooddata/extensions/extensions.rb +6 -0
- data/lib/gooddata/goodzilla/goodzilla.rb +2 -2
- data/lib/gooddata/helpers/csv_helper.rb +57 -0
- data/lib/gooddata/{helpers.rb → helpers/global_helpers.rb} +0 -0
- data/lib/gooddata/helpers/helpers.rb +6 -0
- data/lib/gooddata/models/domain.rb +134 -24
- data/lib/gooddata/models/membership.rb +402 -0
- data/lib/gooddata/models/metadata.rb +64 -7
- data/lib/gooddata/models/metadata/attribute.rb +27 -12
- data/lib/gooddata/models/metadata/column.rb +1 -1
- data/lib/gooddata/models/metadata/dashboard.rb +7 -6
- data/lib/gooddata/models/metadata/display_form.rb +17 -2
- data/lib/gooddata/models/metadata/fact.rb +13 -7
- data/lib/gooddata/models/metadata/metric.rb +9 -9
- data/lib/gooddata/models/metadata/report.rb +7 -8
- data/lib/gooddata/models/metadata/report_definition.rb +10 -11
- data/lib/gooddata/models/metadata/schema.rb +1 -1
- data/lib/gooddata/models/model.rb +1 -1
- data/lib/gooddata/models/process.rb +44 -25
- data/lib/gooddata/models/profile.rb +365 -13
- data/lib/gooddata/models/project.rb +245 -35
- data/lib/gooddata/models/project_blueprint.rb +42 -18
- data/lib/gooddata/models/project_creator.rb +4 -1
- data/lib/gooddata/models/project_role.rb +7 -7
- data/lib/gooddata/models/schedule.rb +17 -1
- data/lib/gooddata/models/schema_blueprint.rb +19 -2
- data/lib/gooddata/version.rb +1 -1
- data/out.txt +0 -0
- data/spec/data/users.csv +12 -0
- data/spec/helpers/connection_helper.rb +1 -0
- data/spec/helpers/csv_helper.rb +12 -0
- data/spec/helpers/project_helper.rb +1 -1
- data/spec/integration/full_project_spec.rb +136 -3
- data/spec/spec_helper.rb +9 -0
- data/spec/unit/commands/command_user_spec.rb +1 -1
- data/spec/unit/extensions/hash_spec.rb +19 -0
- data/spec/unit/godzilla/goodzilla_spec.rb +15 -0
- data/spec/unit/helpers/csv_helper_spec.rb +18 -0
- data/spec/unit/models/domain_spec.rb +47 -4
- data/spec/unit/models/md_object_spec.rb +8 -0
- data/spec/unit/models/membership_spec.rb +128 -0
- data/spec/unit/models/metadata_spec.rb +38 -0
- data/spec/unit/models/profile_spec.rb +212 -0
- data/spec/unit/models/project_blueprint_spec.rb +35 -8
- data/spec/unit/models/project_role_spec.rb +6 -6
- data/spec/unit/models/project_spec.rb +226 -13
- data/spec/unit/models/schedule_spec.rb +58 -0
- data/tmp/.gitkeepme +0 -0
- metadata +36 -11
- data/lib/gooddata/models/account_settings.rb +0 -124
- data/lib/gooddata/models/user.rb +0 -165
- data/spec/unit/models/account_settings_spec.rb +0 -28
- 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
|
-
|
6
|
-
|
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
|
-
|
10
|
-
|
11
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
22
|
-
|
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
|
-
|
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
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
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
|
-
|
254
|
-
|
255
|
-
|
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
|
-
|
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
|
-
|
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 =
|
304
|
-
|
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'].
|
496
|
+
tmp['projectRoles']['roles'].map do |role_url|
|
430
497
|
json = GoodData.get role_url
|
431
|
-
|
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::
|
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.
|