gooddata 0.6.3 → 0.6.4
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 +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.
|