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
@@ -0,0 +1,12 @@
1
+ # encoding: UTF-8
2
+
3
+ module GoodData
4
+ # Project Not Found
5
+ class ValidationError < RuntimeError
6
+ DEFAULT_MSG = 'Validation has failed'
7
+
8
+ def initialize(msg = DEFAULT_MSG)
9
+ super(msg)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ # encoding: UTF-8
2
+
3
+ base = Pathname(__FILE__).dirname.expand_path
4
+ Dir.glob(base + '*.rb').each do |file|
5
+ require_relative file
6
+ end
@@ -6,7 +6,7 @@ module GoodData
6
6
  # @param a_maql_string Input MAQL string
7
7
  # @return [Array<String>] List of IDS
8
8
  def self.get_ids(a_maql_string)
9
- a_maql_string.scan(/!\[([^\"]+)\]/).flatten
9
+ a_maql_string.scan(/!\[([^\"\]]+)\]/).flatten.uniq
10
10
  end
11
11
 
12
12
  # Get Facts from MAQL string
@@ -67,7 +67,7 @@ module GoodData
67
67
  metric = interpolated[:facts].reduce(metric) { |a, e| a.sub("#\"#{e[0]}\"", "[#{e[1]}]") }
68
68
  metric = interpolated[:attributes].reduce(metric) { |a, e| a.sub("@\"#{e[0]}\"", "[#{e[1]}]") }
69
69
  metric = interpolated[:metrics].reduce(metric) { |a, e| a.sub("?\"#{e[0]}\"", "[#{e[1]}]") }
70
- metric = interpolated_ids.reduce(metric) { |a, e| a.sub("![#{e[0]}]", "[#{e[1]}]") }
70
+ metric = interpolated_ids.reduce(metric) { |a, e| a.gsub("![#{e[0]}]", "[#{e[1]}]") }
71
71
  metric
72
72
  end
73
73
  end
@@ -0,0 +1,57 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'csv'
4
+
5
+ module GoodData
6
+ module Helpers
7
+ class Csv
8
+ class << self
9
+ # Read data from CSV
10
+ #
11
+ # @param [Hash] opts
12
+ # @option opts [String] :path File to read data from
13
+ # @option opts [Boolean] :header File to read data from
14
+ # @return Array of rows with loaded data
15
+ def read(opts)
16
+ path = opts[:path]
17
+ res = []
18
+
19
+ line = 0
20
+
21
+ CSV.foreach(path) do |row|
22
+ line += 1
23
+ next if opts[:header] && line == 1
24
+
25
+ if block_given?
26
+ data = yield row
27
+ else
28
+ data = row
29
+ end
30
+
31
+ res << data if data
32
+ end
33
+
34
+ res
35
+ end
36
+
37
+ # Write data to CSV
38
+ # @option opts [String] :path File to write data to
39
+ # @option opts [Array] :data Mandatory array of data to write
40
+ # @option opts [String] :header Optional Header row
41
+ def write(opts, &block)
42
+ path = opts[:path]
43
+ header = opts[:header]
44
+ data = opts[:data]
45
+
46
+ CSV.open(path, 'w') do |csv|
47
+ csv << header unless header.nil?
48
+ data.each do |entry|
49
+ res = yield entry
50
+ csv << res if res
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,6 @@
1
+ # encoding: UTF-8
2
+
3
+ base = Pathname(__FILE__).dirname.expand_path
4
+ Dir.glob(base + '*.rb').each do |file|
5
+ require_relative file
6
+ end
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require_relative 'account_settings'
3
+ require_relative 'profile'
4
4
 
5
5
  module GoodData
6
6
  class Domain
@@ -24,34 +24,76 @@ module GoodData
24
24
  # @param login [String] Login of user to be invited
25
25
  # @param password [String] Default preset password
26
26
  # @return [Object] Raw response
27
- def add_user(domain, login, password)
27
+ def add_user(opts)
28
+ generated_pass = rand(10E10).to_s
28
29
  data = {
29
- :accountSetting => {
30
- :login => login,
31
- :firstName => 'FirstName',
32
- :lastName => 'LastName',
33
- :password => password,
34
- :verifyPassword => password,
35
- :email => login
36
- }
30
+ :login => opts[:login],
31
+ :firstName => opts[:first_name] || 'FirstName',
32
+ :lastName => opts[:last_name] || 'LastName',
33
+ :password => opts[:password] || generated_pass,
34
+ :verifyPassword => opts[:password] || generated_pass,
35
+ :email => opts[:login]
37
36
  }
38
37
 
39
- url = "/gdc/account/domains/#{domain}/users"
40
- GoodData.post(url, data)
38
+ # Optional authentication modes
39
+ tmp = opts[:authentication_modes]
40
+ if tmp
41
+ if tmp.kind_of? Array
42
+ data[:authenticationModes] = tmp
43
+ elsif tmp.kind_of? String
44
+ data[:authenticationModes] = [tmp]
45
+ end
46
+ end
47
+
48
+ # Optional company
49
+ tmp = opts[:company_name]
50
+ tmp = opts[:company] if tmp.nil? || tmp.empty?
51
+ data[:companyName] = tmp if tmp && !tmp.empty?
52
+
53
+ # Optional country
54
+ tmp = opts[:country]
55
+ data[:country] = tmp if tmp && !tmp.empty?
56
+
57
+ # Optional phone number
58
+ tmp = opts[:phone]
59
+ tmp = opts[:phone_number] if tmp.nil? || tmp.empty?
60
+ data[:phoneNumber] = tmp if tmp && !tmp.empty?
61
+
62
+ # Optional position
63
+ tmp = opts[:position]
64
+ data[:position] = tmp if tmp && !tmp.empty?
65
+
66
+ # Optional sso provider
67
+ tmp = opts[:sso_provider]
68
+ data['ssoProvider'] = tmp if tmp && !tmp.empty?
69
+
70
+ # Optional timezone
71
+ tmp = opts[:timezone]
72
+ data[:timezone] = tmp if tmp && !tmp.empty?
73
+
74
+ # TODO: It will be nice if the API will return us user just newly created
75
+ url = "/gdc/account/domains/#{opts[:domain]}/users"
76
+ response = GoodData.post(url, :accountSetting => data)
77
+
78
+ raw = GoodData.get response['uri']
79
+
80
+ # TODO: Remove this hack when POST /gdc/account/domains/{domain-name}/users returns full profile
81
+ raw['accountSetting']['links'] = {} unless raw['accountSetting']['links']
82
+ raw['accountSetting']['links']['self'] = response['uri'] unless raw['accountSetting']['links']['self']
83
+
84
+ GoodData::Profile.new(raw)
41
85
  end
42
86
 
43
87
  # Finds user in domain by login
44
88
  #
45
89
  # @param domain [String] Domain name
46
90
  # @param login [String] User login
47
- # @return [GoodData::AccountSettings] User account settings
91
+ # @return [GoodData::Profile] User profile
48
92
  def find_user_by_login(domain, login)
49
93
  url = "/gdc/account/domains/#{domain}/users?login=#{login}"
50
94
  tmp = GoodData.get url
51
95
  items = tmp['accountSettings']['items'] if tmp['accountSettings']
52
- if items && items.length > 0
53
- return GoodData::AccountSettings.new(items.first)
54
- end
96
+ return GoodData::Profile.new(items.first) if items && items.length > 0
55
97
  nil
56
98
  end
57
99
 
@@ -60,18 +102,81 @@ module GoodData
60
102
  # @param [Hash] opts Options.
61
103
  # @option opts [Number] :offset The subject
62
104
  # @option opts [Number] :limit From address
105
+ # TODO: Review opts[:limit] functionality
63
106
  def users(domain, opts = USERS_OPTIONS)
64
107
  result = []
65
108
 
66
109
  options = USERS_OPTIONS.merge(opts)
67
-
68
- tmp = GoodData.get("/gdc/account/domains/#{domain}/users?offset=#{options[:offset]}&limit=#{options[:limit]}")
69
- tmp['accountSettings']['items'].each do |account|
70
- result << GoodData::AccountSettings.new(account)
110
+ offset = 0 || options[:offset]
111
+ uri = "/gdc/account/domains/#{domain}/users?offset=#{offset}&limit=#{options[:limit]}"
112
+ loop do
113
+ break unless uri
114
+ tmp = GoodData.get(uri)
115
+ tmp['accountSettings']['items'].each do |account|
116
+ result << GoodData::Profile.new(account)
117
+ end
118
+ uri = tmp['accountSettings']['paging']['next']
71
119
  end
72
120
 
73
121
  result
74
122
  end
123
+
124
+ # Create users specified in list
125
+ # @param [Array<GoodData::Membership>] list List of users
126
+ # @param [String] default_domain_name Default domain name used when no specified in user
127
+ # @return [Array<GoodData::User>] List of users created
128
+ def users_create(list, default_domain = nil)
129
+ default_domain_name = default_domain.respond_to?(:name) ? default_domain.name : default_domain
130
+ domains = {}
131
+ list.map do |user|
132
+ # TODO: Add user here
133
+ domain_name = user.json['user']['content']['domain'] || default_domain_name
134
+
135
+ # Lookup for domain in cache'
136
+ domain = domains[domain_name]
137
+
138
+ # Get domain info from REST, add to cache
139
+ if domain.nil?
140
+ domain = {
141
+ :domain => GoodData::Domain[domain_name],
142
+ :users => GoodData::Domain[domain_name].users
143
+ }
144
+
145
+ domain[:users_map] = Hash[domain[:users].map { |u| [u.email, u] }]
146
+ domains[domain_name] = domain
147
+ end
148
+
149
+ # Check if user exists in domain
150
+ domain_user = domain[:users_map][user.email]
151
+
152
+ # Create domain user if needed
153
+ unless domain_user
154
+ password = user.json['user']['content']['password']
155
+
156
+ # Fill necessary user data
157
+ user_data = {
158
+ :login => user.login,
159
+ :firstName => user.first_name,
160
+ :lastName => user.last_name,
161
+ :password => password,
162
+ :verifyPassword => password,
163
+ :email => user.login
164
+ }
165
+
166
+ tmp = user.json['user']['content']['sso_provider']
167
+ user_data[:sso_provider] = tmp if tmp && !tmp.empty?
168
+
169
+ tmp = user.json['user']['content']['authentication_modes']
170
+ user_data[:authentication_modes] = tmp && !tmp.empty?
171
+
172
+ # Add created user to cache
173
+ domain_user = domain[:domain].add_user(user_data)
174
+ domain[:users] << domain_user
175
+ domain[:users_map][user.email] = domain_user
176
+ end
177
+ domain_user
178
+ end
179
+ end
75
180
  end
76
181
 
77
182
  def initialize(domain_name)
@@ -90,14 +195,15 @@ module GoodData
90
195
  # domain = GoodData::Domain['gooddata-tomas-korcak']
91
196
  # domain.add_user 'joe.doe@example', 'sup3rS3cr3tP4ssW0rtH'
92
197
  #
93
- def add_user(login, password)
94
- GoodData::Domain.add_user(name, login, password)
198
+ def add_user(opts)
199
+ opts[:domain] = name
200
+ GoodData::Domain.add_user(opts)
95
201
  end
96
202
 
97
203
  # Finds user in domain by login
98
204
  #
99
205
  # @param login [String] User login
100
- # @return [GoodData::AccountSettings] User account settings
206
+ # @return [GoodData::Profile] User account settings
101
207
  def find_user_by_login(login)
102
208
  GoodData::Domain.find_user_by_login(name, login)
103
209
  end
@@ -107,7 +213,7 @@ module GoodData
107
213
  # @param [Hash] opts Additional user listing options.
108
214
  # @option opts [Number] :offset Offset to start listing from
109
215
  # @option opts [Number] :limit Limit of users to be listed
110
- # @return [Array<GoodData::AccountSettings>] List of user account settings
216
+ # @return [Array<GoodData::Profile>] List of user account settings
111
217
  #
112
218
  # Example
113
219
  #
@@ -119,6 +225,10 @@ module GoodData
119
225
  GoodData::Domain.users(name, opts)
120
226
  end
121
227
 
228
+ def users_create(list)
229
+ GoodData::Domain.users_create(list, name)
230
+ end
231
+
122
232
  private
123
233
 
124
234
  # Private setter of domain name. Used by constructor not available for external users.
@@ -0,0 +1,402 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'multi_json'
4
+
5
+ require_relative 'project'
6
+ require_relative 'project_role'
7
+
8
+ module GoodData
9
+ class Membership
10
+ attr_reader :json
11
+
12
+ ASSIGNABLE_MEMBERS = [
13
+ :email,
14
+ :first_name,
15
+ :last_name,
16
+ :login,
17
+ :phone,
18
+ :status,
19
+ :title
20
+ ]
21
+
22
+ class << self
23
+ # Apply changes to object.
24
+ #
25
+ # @param obj [GoodData::User] Object to be modified
26
+ # @param changes [Hash] Hash with modifications
27
+ # @return [GoodData::User] Modified object
28
+ def apply(obj, changes)
29
+ changes.each do |param, val|
30
+ next unless ASSIGNABLE_MEMBERS.include? param
31
+ obj.send("#{param}=", val)
32
+ end
33
+ obj
34
+ end
35
+
36
+ # Gets hash representing diff of users
37
+ #
38
+ # @param user1 [GoodData::User] Original user
39
+ # @param user2 [GoodData::User] User to compare with
40
+ # @return [Hash] Hash representing diff
41
+ def diff(user1, user2)
42
+ res = {}
43
+ ASSIGNABLE_MEMBERS.each do |k|
44
+ l_value = user1.send("#{k}")
45
+ r_value = user2.send("#{k}")
46
+ res[k] = r_value if l_value != r_value
47
+ end
48
+ res
49
+ end
50
+
51
+ def diff_list(list1, list2)
52
+ tmp = Hash[list1.map { |v| [v.email, v] }]
53
+
54
+ res = {
55
+ :added => [],
56
+ :removed => [],
57
+ :changed => [],
58
+ :same => []
59
+ }
60
+
61
+ list2.each do |user_new|
62
+ user_existing = tmp[user_new.email]
63
+ if user_existing.nil?
64
+ res[:added] << user_new
65
+ next
66
+ end
67
+
68
+ if user_existing != user_new
69
+ diff = self.diff(user_existing, user_new)
70
+ res[:changed] << {
71
+ :user => user_existing,
72
+ :diff => diff
73
+ }
74
+ else
75
+ res[:same] << user_existing
76
+ end
77
+ end
78
+
79
+ tmp = Hash[list2.map { |v| [v.email, v] }]
80
+ list1.each do |user_existing|
81
+ user_new = tmp[user_existing.email]
82
+ if user_new.nil?
83
+ res[:removed] << user_existing
84
+ next
85
+ end
86
+ end
87
+
88
+ res
89
+ end
90
+ end
91
+
92
+ def initialize(json)
93
+ @json = json
94
+ end
95
+
96
+ # Checks objects for equality
97
+ #
98
+ # @param right [GoodData::User] Project to compare with
99
+ # @return [Boolean] True if same else false
100
+ def ==(other)
101
+ res = true
102
+ ASSIGNABLE_MEMBERS.each do |k|
103
+ l_val = send("#{k}")
104
+ r_val = other.send("#{k}")
105
+ res = false if l_val != r_val
106
+ end
107
+ res
108
+ end
109
+
110
+ # Checks objects for non-equality
111
+ #
112
+ # @param right [GoodData::User] Project to compare with
113
+ # @return [Boolean] True if different else false
114
+ def !=(other)
115
+ !(self == other)
116
+ end
117
+
118
+ # Apply changes to object.
119
+ #
120
+ # @param changes [Hash] Hash with modifications
121
+ # @return [GoodData::User] Modified object
122
+ def apply(changes)
123
+ GoodData::User.apply(self, changes)
124
+ end
125
+
126
+ # Gets author (person who created) of this object
127
+ #
128
+ # @return [String] Author
129
+ def author
130
+ url = @json['user']['meta']['author']
131
+ data = GoodData.get url
132
+ GoodData::Membership.new(data)
133
+ end
134
+
135
+ # Gets the contributor
136
+ #
137
+ # @return [String] Contributor
138
+ def contributor
139
+ url = @json['user']['meta']['contributor']
140
+ data = GoodData.get url
141
+ GoodData::Membership.new(data)
142
+ end
143
+
144
+ # Gets date when created
145
+ #
146
+ # @return [DateTime] Created date
147
+ def created
148
+ Time.parse(@json['user']['meta']['created'])
149
+ end
150
+
151
+ # Gets hash representing diff of users
152
+ #
153
+ # @param user [GoodData::User] Another profile to compare with
154
+ # @return [Hash] Hash representing diff
155
+ def diff(user)
156
+ GoodData::User.diff(self, user)
157
+ end
158
+
159
+ # Gets the email
160
+ #
161
+ # @return [String] Email address
162
+ def email
163
+ @json['user']['content']['email'] || ''
164
+ end
165
+
166
+ # Sets the email
167
+ #
168
+ # @param new_email [String] New email to be assigned
169
+ def email=(new_email)
170
+ @json['user']['content']['email'] = new_email
171
+ end
172
+
173
+ # Gets the first name
174
+ #
175
+ # @return [String] First name
176
+ def first_name
177
+ @json['user']['content']['firstname'] || ''
178
+ end
179
+
180
+ # Sets the first name
181
+ #
182
+ # @param new_first_name [String] New first name to be assigned
183
+ def first_name=(new_first_name)
184
+ @json['user']['content']['firstname'] = new_first_name
185
+ end
186
+
187
+ # Gets the invitations
188
+ #
189
+ # @return [Array<GoodData::Invitation>] List of invitations
190
+ def invitations
191
+ res = []
192
+
193
+ tmp = GoodData.get @json['user']['links']['invitations']
194
+ tmp['invitations'].each do |invitation|
195
+ # TODO: Something is missing here
196
+ end
197
+
198
+ res
199
+ end
200
+
201
+ # Gets the last name
202
+ #
203
+ # @return [String] Last name
204
+ def last_name
205
+ @json['user']['content']['lastname'] || ''
206
+ end
207
+
208
+ # Sets the last name
209
+ #
210
+ # @param new_last_name [String] New last name to be assigned
211
+ def last_name=(new_last_name)
212
+ @json['user']['content']['lastname'] = new_last_name
213
+ end
214
+
215
+ # Gets the login
216
+ #
217
+ # @return [String] Login
218
+ def login
219
+ @json['user']['content']['login'] || ''
220
+ end
221
+
222
+ # Sets the last name
223
+ #
224
+ # @param new_login [String] New login to be assigned
225
+ def login=(new_login)
226
+ @json['user']['content']['login'] = new_login
227
+ end
228
+
229
+ # Gets user raw object ID
230
+ #
231
+ # @return [String] Raw Object ID
232
+ def obj_id
233
+ uri.split('/').last
234
+ end
235
+
236
+ # Gets the permissions
237
+ #
238
+ # @return [Hash] Hash with permissions
239
+ def permissions
240
+ res = {}
241
+
242
+ tmp = GoodData.get @json['user']['links']['permissions']
243
+ tmp['associatedPermissions']['permissions'].each do |permission_name, permission_value|
244
+ res[permission_name] = permission_value
245
+ end
246
+
247
+ res
248
+ end
249
+
250
+ # Gets the phone number
251
+ #
252
+ # @return [String] Phone number
253
+ def phone
254
+ @json['user']['content']['phonenumber'] || ''
255
+ end
256
+
257
+ # Sets the phone number
258
+ #
259
+ # @param new_phone_number [String] New phone number to be assigned
260
+ def phone=(new_phone_number)
261
+ @json['user']['content']['phonenumber'] = new_phone_number
262
+ end
263
+
264
+ # Gets profile of this membership
265
+ def profile
266
+ raw = GoodData.get @json['user']['links']['self']
267
+ GoodData::Profile.new(raw)
268
+ end
269
+
270
+ # Gets URL of profile membership
271
+ def profile_url
272
+ @json['user']['links']['self']
273
+ end
274
+
275
+ # Gets project which this membership relates to
276
+ def project
277
+ raw = GoodData.get project_url
278
+ GoodData::Project.new(raw)
279
+ end
280
+
281
+ # Gets project id
282
+ def project_id
283
+ @json['user']['links']['roles'].split('/')[3]
284
+ end
285
+
286
+ # Gets project url
287
+ def project_url
288
+ @json['user']['links']['roles'].split('/')[0..3].join('/')
289
+ end
290
+
291
+ # Gets the projects of user
292
+ #
293
+ # @return [Array<GoodData::Project>] Array of projets
294
+ def projects
295
+ res = []
296
+
297
+ tmp = GoodData.get @json['user']['links']['projects']
298
+ tmp['projects'].each do |project_meta|
299
+ project_uri = project_meta['project']['links']['self']
300
+ project = GoodData.get project_uri
301
+ res << GoodData::Project.new(project)
302
+ end
303
+
304
+ res
305
+ end
306
+
307
+ # Gets first role
308
+ def role
309
+ roles.first
310
+ end
311
+
312
+ # Gets the project roles of user
313
+ #
314
+ # @return [Array<GoodData::ProjectRole>] Array of project roles
315
+ def roles
316
+ res = []
317
+
318
+ tmp = GoodData.get @json['user']['links']['roles']
319
+ tmp['associatedRoles']['roles'].each do |role_uri|
320
+ role = GoodData.get role_uri
321
+ res << GoodData::ProjectRole.new(role)
322
+ end
323
+
324
+ res
325
+ end
326
+
327
+ # Gets the status
328
+ #
329
+ # @return [String] Status
330
+ def status
331
+ @json['user']['content']['status'] || ''
332
+ end
333
+
334
+ # Sets the status
335
+ #
336
+ # @param new_status [String] New phone number to be assigned
337
+ def status=(new_status)
338
+ @json['user']['content']['status'] = new_status
339
+ end
340
+
341
+ # Gets the title
342
+ #
343
+ # @return [String] User title
344
+ def title
345
+ @json['user']['meta']['title'] || ''
346
+ end
347
+
348
+ # Sets the title
349
+ #
350
+ # @param new_title [String] New title to be assigned
351
+ def title=(new_title)
352
+ @json['user']['content']['title'] = new_title
353
+ end
354
+
355
+ # Gets the date when updated
356
+ #
357
+ # @return [DateTime] Date of last update
358
+ def updated
359
+ DateTime.parse(@json['user']['meta']['updated'])
360
+ end
361
+
362
+ # Gets the object URI
363
+ #
364
+ # @return [String] Object URI
365
+ def uri
366
+ @json['user']['links']['self']
367
+ end
368
+
369
+ # Enables membership
370
+ #
371
+ # @return result from post execution
372
+ def enable
373
+ self.status = 'enabled'
374
+ end
375
+
376
+ # Disables membership
377
+ #
378
+ # @return result from post execution
379
+ def disable
380
+ self.status = 'disabled'
381
+ end
382
+
383
+ private
384
+
385
+ # Sets status to 'ENABLED' or 'DISABLED'
386
+ def status=(new_status)
387
+ payload = {
388
+ 'user' => {
389
+ 'content' => {
390
+ 'status' => new_status.to_s.upcase,
391
+ 'userRoles' => @json['user']['content']['userRoles']
392
+ },
393
+ 'links' => {
394
+ 'self' => uri
395
+ }
396
+ }
397
+ }
398
+
399
+ @json = GoodData.post("/gdc/projects/#{project_id}/users", payload)
400
+ end
401
+ end
402
+ end