Class: GoodData::Domain

Inherits:
Rest::Resource show all
Defined in:
lib/gooddata/models/domain.rb

Defined Under Namespace

Classes: ProvisioningResult

Instance Attribute Summary collapse

Attributes inherited from Rest::Object

#client, #json, #project

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Mixin::ObjId

#obj_id

Methods inherited from Rest::Object

client, default_client, #saved?

Methods included from Mixin::DataPropertyReader

#data_property_reader

Methods included from Mixin::DataPropertyWriter

#data_property_writer

Methods included from Mixin::MetaPropertyReader

#metadata_property_reader

Methods included from Mixin::MetaPropertyWriter

#metadata_property_writer

Methods included from Mixin::MetaGetter

#meta

Methods included from Mixin::DataGetter

#data

Methods included from Mixin::RootKeyGetter

#root_key

Methods included from Mixin::ContentGetter

#content

Constructor Details

#initialize(domain_name) ⇒ Domain

Returns a new instance of Domain.



274
275
276
# File 'lib/gooddata/models/domain.rb', line 274

def initialize(domain_name)
  @name = domain_name
end

Instance Attribute Details

#nameObject

Returns the value of attribute name.



15
16
17
# File 'lib/gooddata/models/domain.rb', line 15

def name
  @name
end

Class Method Details

.[](domain_name, options = { :client => GoodData.connection }) ⇒ String

Looks for domain

Parameters:

  • domain_name (String)

    Domain name

Returns:

  • (String)

    Domain object instance



24
25
26
27
28
29
# File 'lib/gooddata/models/domain.rb', line 24

def [](domain_name, options = { :client => GoodData.connection })
  return domain_name if domain_name.is_a?(Domain)
  c = client(options)
  fail "Using pseudo-id 'all' is not supported by GoodData::Domain" if domain_name.to_s == 'all'
  c.create(GoodData::Domain, domain_name)
end

.add_user(user_data, name = nil, opts = { :client => GoodData.connection }) ⇒ Object

Adds user to domain

Parameters:

  • domain (String)

    Domain name

  • login (String)

    Login of user to be invited

  • password (String)

    Default preset password

Returns:



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/gooddata/models/domain.rb', line 37

def add_user(user_data, name = nil, opts = { :client => GoodData.connection })
  generated_pass = rand(10E10).to_s
  domain_name = name || user_data[:domain]
  user_data = user_data.to_hash
  data = {
    :login => user_data[:login] || user_data[:email],
    :firstName => user_data[:first_name] || 'FirstName',
    :lastName => user_data[:last_name] || 'LastName',
    :password => user_data[:password] || generated_pass,
    :verifyPassword => user_data[:password] || generated_pass,
    :email => user_data[:email] || user_data[:login]
  }

  # Optional authentication modes
  tmp = user_data[:authentication_modes]
  if tmp
    if tmp.is_a? Array
      data[:authenticationModes] = tmp
    elsif tmp.is_a? String
      data[:authenticationModes] = [tmp]
    end
  end

  # Optional company
  tmp = user_data[:company_name]
  tmp = user_data[:company] if tmp.nil? || tmp.empty?
  data[:companyName] = tmp if tmp && !tmp.empty?

  # Optional country
  tmp = user_data[:country]
  data[:country] = tmp if tmp && !tmp.empty?

  # Optional phone number
  tmp = user_data[:phone]
  tmp = user_data[:phone_number] if tmp.nil? || tmp.empty?
  data[:phoneNumber] = tmp if tmp && !tmp.empty?

  # Optional position
  tmp = user_data[:position]
  data[:position] = tmp if tmp && !tmp.empty?

  # Optional sso provider
  tmp = user_data[:sso_provider]
  data['ssoProvider'] = tmp if tmp && !tmp.empty?

  # Optional timezone
  tmp = user_data[:timezone]
  data[:timezone] = tmp if tmp && !tmp.empty?

  c = client(opts)

  # TODO: It will be nice if the API will return us user just newly created
  begin
    url = "/gdc/account/domains/#{domain_name}/users"
    response = c.post(url, :accountSetting => data)
  rescue RestClient::BadRequest => e
    error = MultiJson.load(e.response)
    error_type = GoodData::Helpers.get_path(error, %w(error errorClass))
    case error_type
    when 'com.gooddata.webapp.service.userprovisioning.LoginNameAlreadyRegisteredException'
      u = Domain.(domain_name, data[:login])
      if u
        response = { 'uri' => u.uri }
      else
        raise GoodData::UserInDifferentDomainError, "User #{data[:login]} is already in different domain"
      end
    when 'com.gooddata.json.validator.exception.MalformedMessageException'
      raise GoodData::MalformedUserError, "User #{data[:login]} is malformed. The message from API is #{GoodData::Helpers.interpolate_error_message(error)}"
    else
      raise GoodData::Helpers.interpolate_error_message(error)
    end
  end

  url = response['uri']
  raw = c.get url

  # TODO: Remove this hack when POST /gdc/account/domains/{domain-name}/users returns full profile
  raw['accountSetting']['links'] = {} unless raw['accountSetting']['links']
  raw['accountSetting']['links']['self'] = response['uri'] unless raw['accountSetting']['links']['self']
  c.create(GoodData::Profile, raw)
end

.create_users(list, default_domain = nil, opts = { :client => GoodData.connection, :project => GoodData.project }) ⇒ Array<GoodData::User>

Create users specified in list

Parameters:

  • list (Array<GoodData::Membership>)

    List of users

  • default_domain_name (String)

    Default domain name used when no specified in user

Returns:

  • (Array<GoodData::User>)

    List of users created



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/gooddata/models/domain.rb', line 235

def create_users(list, default_domain = nil, opts = { :client => GoodData.connection, :project => GoodData.project })
  default_domain_name = default_domain.respond_to?(:name) ? default_domain.name : default_domain
  domain = client.domain(default_domain_name)

  # Prepare cache for domain users
  domain_users_cache = Hash[domain.users.map { |u| [u..downcase, u] }]

  list.pmapcat do |user|
    begin
      user_data = user.to_hash.tap { |uh| uh[:login].downcase! }
      domain_user = domain_users_cache[user_data[:login]]
       = user_data[:login]
      if !domain_user
        added_user = domain.add_user(user_data, opts)
        GoodData.logger.info("Added new user=#{} to domain=#{default_domain_name}.")
        [{ type: :successful, :action => :user_added_to_domain, user: added_user }]
      else
        domain_user_data = domain_user.to_hash
        fields_to_check = opts[:fields_to_check] || user_data.keys
        diff = GoodData::Helpers.diff([domain_user.to_hash], [user_data], key: :login, fields: fields_to_check)
        next [] if diff[:changed].empty?
        updated_user = domain.update_user(domain_user.to_hash.merge(user_data.compact), opts)
        GoodData.logger.debug "Updated user=#{} from old properties \
(email=#{domain_user_data[:email]}, sso_provider=#{domain_user_data[:sso_provider]}) \
to new properties (email=#{user_data[:email]}, sso_provider=#{user_data[:sso_provider]}) in domain=#{default_domain_name}."
        [{ type: :successful, :action => :user_changed_in_domain, user: updated_user }]
      end
    rescue RuntimeError => e
      if !domain_user
        GoodData.logger.error("Failed to add user=#{} to domain=#{default_domain_name}. Error: #{e.message}")
      else
        GoodData.logger.error("Failed to update user=#{} in domain=#{default_domain_name}. Error: #{e.message}")
      end
      [{ type: :failed, :user => user, message: e }]
    end
  end
end

.find_user_by_login(domain, login, opts = { :client => GoodData.connection, :project => GoodData.project }) ⇒ GoodData::Profile

Finds user in domain by login

Parameters:

  • domain (String)

    Domain name

  • login (String)

    User login

Returns:



188
189
190
191
192
193
194
195
196
197
# File 'lib/gooddata/models/domain.rb', line 188

def (domain, , opts = { :client => GoodData.connection, :project => GoodData.project })
  c = client(opts)
   = CGI.escape()
  domain = c.domain(domain)
  GoodData.logger.warn("Retrieving particular user \"#{.inspect}\" from domain #{domain.name}")
  url = "#{domain.uri}/users?login=#{}"
  tmp = c.get url
  items = tmp['accountSettings']['items'] if tmp['accountSettings']
  items && !items.empty? ? c.factory.create(GoodData::Profile, items.first) : nil
end

.update_user(user_data, options = { client: GoodData.connection }) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/gooddata/models/domain.rb', line 119

def update_user(user_data, options = { client: GoodData.connection })
  user_data = user_data.to_hash if user_data.is_a?(GoodData::Profile)
  client = client(options)
  user_data = user_data.to_hash
  # generated_pass = rand(10E10).to_s
  data = {
    :firstName => user_data[:first_name] || 'FirstName',
    :lastName => user_data[:last_name] || 'LastName',
    :email => user_data[:email]
  }

  # Optional authentication modes
  tmp = user_data[:authentication_modes]
  if tmp
    if tmp.is_a? Array
      data[:authenticationModes] = tmp
    elsif tmp.is_a? String
      data[:authenticationModes] = [tmp]
    end
  end

  # Optional company
  tmp = user_data[:company_name]
  tmp = user_data[:company] if tmp.nil? || tmp.empty?
  data[:companyName] = tmp if tmp && !tmp.empty?

  # Optional pass
  tmp = user_data[:password]
  tmp = user_data[:password] if tmp.nil? || tmp.empty?
  data[:password] = tmp if tmp && !tmp.empty?
  data[:verifyPassword] = tmp if tmp && !tmp.empty?

  # Optional country
  tmp = user_data[:country]
  data[:country] = tmp if tmp && !tmp.empty?

  # Optional phone number
  tmp = user_data[:phone]
  tmp = user_data[:phone_number] if tmp.nil? || tmp.empty?
  data[:phoneNumber] = tmp if tmp && !tmp.empty?

  # Optional position
  tmp = user_data[:position]
  data[:position] = tmp if tmp && !tmp.empty?

  # Optional sso provider
  tmp = user_data[:sso_provider]
  data['ssoProvider'] = tmp if tmp

  # Optional timezone
  tmp = user_data[:timezone]
  data[:timezone] = tmp if tmp && !tmp.empty?

  # TODO: It will be nice if the API will return us user just newly created
  url = user_data.delete(:uri)
  data.delete(:password) if client.user.uri == url
  response = client.put(url, :accountSetting => data)

  # TODO: Remove this hack when POST /gdc/account/domains/{domain-name}/users returns full profile
  response['accountSetting']['links'] = {} unless response['accountSetting']['links']
  response['accountSetting']['links']['self'] = url unless response['accountSetting']['links']['self']
  client.create(GoodData::Profile, response)
end

.users(domain, id = :all, opts = {}) ⇒ Object

Returns list of users for domain specified TODO: Review opts[:limit] functionality

Parameters:

  • domain (String)

    Domain to list the users for

  • opts (Hash) (defaults to: {})

    Options.

Options Hash (opts):

  • :offset (Number)

    The subject

  • :limit (Number)

    From address



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/gooddata/models/domain.rb', line 205

def users(domain, id = :all, opts = {})
  client = client(opts)
  domain = client.domain(domain)
  if id == :all
    GoodData.logger.warn("Retrieving all users from domain #{domain.name}")
    Enumerator.new do |y|
      page_limit = opts[:page_limit] || 1000
      offset = opts[:offset] || 0
      loop do
        begin
          tmp = client(opts).get("#{domain.uri}/users", params: { offset: offset, limit: page_limit })
        end

        tmp['accountSettings']['items'].each do |user_data|
          user = client.create(GoodData::Profile, user_data)
          y << user if user
        end
        break if tmp['accountSettings']['items'].count < page_limit
        offset += page_limit
      end
    end
  else
    (domain, id)
  end
end

Instance Method Details

#add_user(data, opts = {}) ⇒ Object Also known as: create_user

Adds user to domain

Example

GoodData.connect '[email protected]' 'your-password' domain = project.domain('domain-name') domain.add_user 'joe.doe@example', 'sup3rS3cr3tP4ssW0rtH'

Parameters:

  • login (String)

    Login of user to be invited

  • password (String)

    Default preset password

Returns:



290
291
292
293
# File 'lib/gooddata/models/domain.rb', line 290

def add_user(data, opts = {})
  # data[:domain] = name
  GoodData::Domain.add_user(data, name, { client: client }.merge(opts))
end

#clients(id = :all) ⇒ Object

Returns all the clients defined in all segments defined in domain. Alternatively id of a client can be provided in which case it returns just that client if it exists.

Parameters:

  • id (String) (defaults to: :all)

    Id of client that you are looking for

Returns:



302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/gooddata/models/domain.rb', line 302

def clients(id = :all)
  clients_uri = "/gdc/domains/#{name}/clients"
  res = client.get(clients_uri)
  res_clients = (res['clients'] && res['clients']['items']) || []
  if id == :all
    res_clients.map { |res_client| client.create(GoodData::Client, res_client) }
  else
    find_result = res_clients.find { |c| c['client']['id'] == id }
    fail "Client with id #{id} was not found" unless find_result
    client.create(GoodData::Client, find_result)
  end
end

#create_segment(data) ⇒ GoodData::Segment

Creates new segment in current domain from parameters passed

Parameters:

  • data (Hash)

    Data for segment namely :segment_id and :master_project is accepted. Master_project can be given as either a PID or a Project instance

Returns:



329
330
331
332
# File 'lib/gooddata/models/domain.rb', line 329

def create_segment(data)
  segment = GoodData::Segment.create(data, domain: self, client: client)
  segment.save
end

#create_users(list, options = {}) ⇒ Object



317
318
319
# File 'lib/gooddata/models/domain.rb', line 317

def create_users(list, options = {})
  GoodData::Domain.create_users(list, name, { client: client }.merge(options))
end

#find_user_by_login(login) ⇒ GoodData::Profile

Finds user in domain by login

Parameters:

  • login (String)

    User login

Returns:



357
358
359
# File 'lib/gooddata/models/domain.rb', line 357

def ()
  GoodData::Domain.(self, , client: client)
end

#get_user(name, user_list = users) ⇒ GoodDta::Membership

Gets user by its login or uri in various shapes It does not find by other information because that is not unique. If you want to search by name or email please use fuzzy_get_user.

Parameters:

  • name (String)

    Name to look for

  • user_list (Array<GoodData::User>) (defaults to: users)

    Optional cached list of users used for look-ups

Returns:

  • (GoodDta::Membership)

    User



341
342
343
344
345
346
347
348
349
350
351
# File 'lib/gooddata/models/domain.rb', line 341

def get_user(name, user_list = users)
  return member(name, user_list) if name.instance_of?(GoodData::Membership)
  return member(name, user_list) if name.instance_of?(GoodData::Profile)
  name = name.is_a?(Hash) ? name[:login] || name[:uri] : name
  return nil unless name
  name.downcase!
  user_list.find do |user|
    user.uri && user.uri.downcase == name ||
      user. && user..downcase == name
  end
end

#member(profile, list = members) ⇒ GoodData::Profile

Gets membership for profile specified

Parameters:

Returns:



366
367
368
369
370
371
372
373
# File 'lib/gooddata/models/domain.rb', line 366

def member(profile, list = members)
  if profile.is_a? String
    return list.find do |m|
      m.uri == profile || m. == profile
    end
  end
  list.find { |m| m. == profile. }
end

#member?(profile, list = members) ⇒ Boolean

Checks if the profile is member of project

Parameters:

Returns:

  • (Boolean)

    true if is member else false



380
381
382
# File 'lib/gooddata/models/domain.rb', line 380

def member?(profile, list = members)
  !member(profile, list).nil?
end

#members?(profiles, list = members) ⇒ Boolean

Returns:

  • (Boolean)


384
385
386
# File 'lib/gooddata/models/domain.rb', line 384

def members?(profiles, list = members)
  profiles.map { |p| member?(p, list) }
end

#provision_client_projects(segments = nil) ⇒ Enumerator

Runs async process that walks through segments and provisions projects if necessary.

Returns:

  • (Enumerator)

    Returns Enumerator of results



405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
# File 'lib/gooddata/models/domain.rb', line 405

def provision_client_projects(segments = nil)
  body = if segments
           {
             provisionClientProjects: {
               segments: segments.is_a?(Array) ? segments : [segments]
             }
           }
         end

  res = client.post(segments_uri + '/provisionClientProjects', body)
  res = client.poll_on_code(res['asyncTask']['links']['poll'])
  failed_count = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResult failed count), 0)
  created_count = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResult created count), 0)
  return Enumerator.new([]) if failed_count + created_count == 0 # rubocop:disable Style/NumericPredicate
  Enumerator.new do |y|
    uri = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResult links details))
    loop do
      result = client.get(uri)
      (GoodData::Helpers.get_path(result, %w(clientProjectProvisioningResultDetails items)) || []).each do |item|
        y << ProvisioningResult.new(item['id'], item['status'], item['project'], item['error'])
      end
      uri = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResultDetails paging next))
      break if uri.nil?
    end
  end
end

#segments(id = :all) ⇒ Object



321
322
323
# File 'lib/gooddata/models/domain.rb', line 321

def segments(id = :all)
  GoodData::Segment[id, domain: self]
end

#segments_uriString

Returns uri for segments on the domain. This will be removed soon. It is here that for segments the "account" portion of the URI was removed. And not for the rest

Returns:

  • (String)

    Uri of the segments



391
392
393
# File 'lib/gooddata/models/domain.rb', line 391

def segments_uri
  "/gdc/domains/#{name}"
end

#synchronize_clientsArray

Calls Segment#synchronize_clients on all segments and concatenates the results

Returns:

  • (Array)

    Returns array of results



398
399
400
# File 'lib/gooddata/models/domain.rb', line 398

def synchronize_clients
  segments.flat_map(&:synchronize_clients)
end

#update_clients(data, options = {}) ⇒ Object



444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
# File 'lib/gooddata/models/domain.rb', line 444

def update_clients(data, options = {})
  if options[:delete_extra] && options[:delete_extra_in_segments]
    fail 'Options delete_extra and delete_extra_in_segments are mutually exclusive.'
  end

  delete_projects = options[:delete_projects] == false ? false : true
  payload = data.map do |datum|
    {
      :client => {
        :id => datum[:id],
        :segment => segments_uri + '/segments/' + datum[:segment]
      }
    }.tap do |h|
      h[:client][:project] = datum[:project] if datum.key?(:project)
    end
  end
  if options[:delete_extra] == true
    res = client.post(segments_uri + '/updateClients?deleteExtra=true', updateClients: { items: payload })
  elsif options[:delete_extra_in_segments]
    segments_to_delete_in = options[:delete_extra_in_segments]
      .map { |segment| CGI.escape(segment) }
      .join(',')
    uri = segments_uri + "/updateClients?deleteExtraInSegments=#{segments_to_delete_in}"
    res = client.post(uri, updateClients: { items: payload })
  else
    res = client.post(segments_uri + '/updateClients', updateClients: { items: payload })
  end
  data = GoodData::Helpers.get_path(res, ['updateClientsResponse'])
  if data
    result = data.flat_map { |k, v| v.map { |h| GoodData::Helpers.symbolize_keys(h.merge('type' => k)) } }
    result.select { |r| r[:status] == 'DELETED' }.peach { |r| r[:originalProject] && client.delete(r[:originalProject]) } if delete_projects
    result
  else
    []
  end
end

#update_clients_settings(data) ⇒ Object Also known as: add_clients_settings



432
433
434
435
436
437
438
439
440
441
# File 'lib/gooddata/models/domain.rb', line 432

def update_clients_settings(data)
  data.each do |datum|
    client_id = datum[:id]
    settings = datum[:settings]
    settings.each do |setting|
      GoodData::Client.update_setting(setting[:name], setting[:value], domain: self, client_id: client_id)
    end
  end
  nil
end

#update_user(data, options = {}) ⇒ Object

Update user in domain

Parameters:

  • opts (Hash)

    Data of the user to be updated

Returns:



486
487
488
# File 'lib/gooddata/models/domain.rb', line 486

def update_user(data, options = {})
  GoodData::Domain.update_user(data, { client: client }.merge(options))
end

#uriString

Returns uri for the domain.

Returns:

  • (String)

    Uri of the segments



512
513
514
# File 'lib/gooddata/models/domain.rb', line 512

def uri
  "/gdc/account/domains/#{name}"
end

#users(id = :all, opts = {}) ⇒ Array<GoodData::Profile> Also known as: members

List users in domain

Example

GoodData.connect '[email protected]' 'your-password' domain = GoodData::Domain['gooddata-tomas-korcak'] pp domain.users

Parameters:

  • opts (Hash) (defaults to: {})

    Additional user listing options.

Options Hash (opts):

  • :offset (Number)

    Offset to start listing from

  • :limit (Number)

    Limit of users to be listed

Returns:



503
504
505
# File 'lib/gooddata/models/domain.rb', line 503

def users(id = :all, opts = {})
  GoodData::Domain.users(name, id, opts.merge(client: client))
end