lib/gooddata/models/profile.rb
# encoding: UTF-8
#
# Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.
require 'pmap'
require_relative '../rest/object'
require_relative 'project'
module GoodData
class Profile < Rest::Resource
attr_reader :user, :json
EMPTY_OBJECT = {
'accountSetting' => {
'companyName' => nil,
'country' => nil,
'created' => nil,
'firstName' => nil,
'lastName' => nil,
'login' => nil,
'phoneNumber' => nil,
'position' => nil,
'timezone' => nil,
'updated' => nil,
'language' => nil,
'links' => {
'projects' => nil,
'self' => nil
},
'email' => nil,
'authenticationModes' => []
}
}
ASSIGNABLE_MEMBERS = [
:company,
:country,
:email,
:login,
:first_name,
:last_name,
:phone,
:position,
:timezone,
:language
]
PROFILE_PATH = '/gdc/account/profile/%s'
class << self
# Get profile by ID or URI
#
# @param id ID or URI of user to be found
# @param [Hash] opts Additional optional options
# @option opts [GoodData::Rest::Client] :client Client used for communication with server
# @return GoodData::Profile User Profile
def [](id, opts = { client: GoodData.connection })
return id if id.instance_of?(GoodData::Profile) || id.respond_to?(:profile?) && id.profile?
if id.to_s !~ %r{^(\/gdc\/account\/profile\/)?[a-zA-Z\d]+$}
fail(ArgumentError, 'wrong type of argument. Should be either profile ID or path')
end
id = id.match(/[a-zA-Z\d]+$/)[0] if id =~ %r{/}
c = client(opts)
fail ArgumentError, 'No :client specified' if c.nil?
response = c.get(PROFILE_PATH % id)
c.factory.create(Profile, response)
end
# Creates new instance from hash with attributes
#
# @param attributes [Hash] Hash with initial attributes
# @return [GoodData::Profile] New profile instance
def create(attributes)
res = create_object(attributes)
res.save!
res
end
def create_object(attributes)
json = GoodData::Helpers.deep_dup(EMPTY_OBJECT)
json['accountSetting']['links']['self'] = attributes[:uri] if attributes[:uri]
res = client.create(GoodData::Profile, json)
attributes.each do |k, v|
res.send("#{k}=", v) if ASSIGNABLE_MEMBERS.include? k
end
res
end
def diff(item1, item2)
x = diff_list([item1], [item2])
return {} if x[:changed].empty?
x[:changed].first[:diff]
end
def diff_list(list1, list2)
GoodData::Helpers.diff(list1, list2, key: :login)
end
# Gets user currently logged in
# @return [GoodData::Profile] User currently logged-in
def current
client.user
end
end
# Creates new instance
#
# @return [Profile] New Profile instance
def initialize(json)
@json = json
@dirty = false
end
# Checks objects for equality
#
# @param right [GoodData::Profile] Project to compare with
# @return [Boolean] True if same else false
def ==(other)
return false unless other.respond_to?(:to_hash)
to_hash == other.to_hash
end
# Checks objects for non-equality
#
# @param right [GoodData::Profile] Project to compare with
# @return [Boolean] True if different else false
def !=(other)
!(self == other)
end
# Apply changes to object.
#
# @param changes [Hash] Hash with modifications
# @return [GoodData::Profile] Modified object
# def apply(changes)
# GoodData::Profile.apply(self, changes)
# end
# Gets the company name
#
# @return [String] Company name
def company
@json['accountSetting']['companyName'] || ''
end
# Set the company name
#
# @param val [String] Company name to be set
def company=(val)
@dirty ||= company != val
@json['accountSetting']['companyName'] = val
end
# Gets the language
#
# @return [String] Language
def language
@json['accountSetting']['language'] || 'en-US'
end
# Set the language
#
# @param val [String] Language to be set
def language=(val)
@dirty ||= language != val
@json['accountSetting']['language'] = val
end
# Gets the country
#
# @return [String] Country
def country
@json['accountSetting']['country'] || ''
end
# Set the country
#
# @param val [String] Country to be set
def country=(val)
@dirty ||= country != val
@json['accountSetting']['country'] = val
end
# Gets date when created
#
# @return [DateTime] Created date
def created
DateTime.parse(@json['accountSetting']['created'])
end
# Deletes this account settings
def delete
client.delete uri
end
# Gets hash representing diff of profiles
#
# @param user [GoodData::Profile] Another profile to compare with
# @return [Hash] Hash representing diff
def diff(user)
GoodData::Profile.diff(self, user)
end
# Gets the email
#
# @return [String] Email address
def email
@json['accountSetting']['email'].is_a?(String) ? @json['accountSetting']['email'].downcase : ''
end
# Set the email
#
# @param val [String] Email to be set
def email=(val)
@dirty ||= email != val
@json['accountSetting']['email'] = val
end
# Gets the first name
#
# @return [String] First name
def first_name
@json['accountSetting']['firstName'] || ''
end
# Set the first name
#
# @param val [String] First name to be set
def first_name=(val)
@dirty ||= first_name != val
@json['accountSetting']['firstName'] = val
end
# Get full name
#
# @return String Full Name
# NOTE: This can be tricky to implement correctly for i18n
def full_name
"#{first_name} #{last_name}"
end
alias_method :title, :full_name
# Gets the last name
#
# @return [String] Last name
def last_name
@json['accountSetting']['lastName'] || ''
end
# Set the last name
#
# @param val [String] Last name to be set
def last_name=(val)
@dirty ||= last_name != val
@json['accountSetting']['lastName'] = val
end
# Gets the login
#
# @return [String] Login
def login
@json['accountSetting']['login'] || ''
end
# Set the login
#
# @param val [String] Login to be set
def login=(val)
@dirty ||= login != val
@json['accountSetting']['login'] = val
end
# Gets the resource identifier
#
# @return [String] Resource identifier
def obj_id
uri.split('/').last
end
alias_method :account_setting_id, :obj_id
# Gets the phone
#
# @return [String] Phone
def phone
@json['accountSetting']['phoneNumber'] || ''
end
alias_method :phone_number, :phone
# Set the phone
#
# @param val [String] Phone to be set
def phone=(val)
@dirty ||= phone != val
@json['accountSetting']['phoneNumber'] = val
end
alias_method :phone_number=, :phone=
# Gets the position in company
#
# @return [String] Position in company
def position
@json['accountSetting']['position'] || ''
end
# Set the position
#
# @param val [String] Position to be set
def position=(val)
@dirty ||= position != val
@json['accountSetting']['position'] = val
end
# Gets the array of projects
# @param limit [Integer] maximum number of projects to get.
# @param offset [Integer] offset of the first project, start from 0.
# @return [Array<GoodData::Project>] Array of project where account settings belongs to
def projects(limit = nil, offset = nil)
url = @json['accountSetting']['links']['projects']
all_projects = []
raise ArgumentError, 'Params limit and offset are expected' if !offset.nil? && limit.nil?
if limit.nil?
url += "?limit=500"
loop do
projects = client.get url
projects['projects']['items'].each do |project|
all_projects << client.create(GoodData::Project, project)
end
if !projects['projects']['paging'].nil? && !projects['projects']['paging']['next'].nil?
url = projects['projects']['paging']['next']
else
break
end
end
else
limit = [limit, 500].min if limit.is_a?(Integer) && limit > 0
url += "?limit=#{limit}"
url += "&offset=#{offset}" if !offset.nil? && offset.is_a?(Integer) && offset > 0
projects = client.get url
projects['projects']['items'].each do |project|
all_projects << client.create(GoodData::Project, project)
end
end
all_projects
end
# Saves object if dirty, clears dirty flag
def save!
if @dirty
raw = @json.dup
raw['accountSetting'].delete('login')
if uri && !uri.empty?
url = "/gdc/account/profile/#{obj_id}"
@json = client.put url, raw
@dirty = false
end
end
self
end
# Gets the preferred timezone
#
# @return [String] Preferred timezone
def timezone
@json['accountSetting']['timezone'] || ''
end
# Set the timezone
#
# @param val [String] Timezone to be set
def timezone=(val)
@dirty ||= timezone != val
@json['accountSetting']['timezone'] = val
end
# Gets the date when updated
#
# @return [DateTime] Updated date
def updated
DateTime.parse(@json['accountSetting']['updated'])
end
# Gets the resource REST URI
#
# @return [String] Resource URI
def uri
GoodData::Helpers.get_path(@json, %w(accountSetting links self))
end
def data
data = @json || {}
data['accountSetting'] || {}
end
def links
data['links'] || {}
end
def content
keys = (data.keys - ['links'])
data.slice(*keys)
end
def name
(first_name || '') + (last_name || '')
end
def password
@json['accountSetting']['password']
end
def password=(a_password)
@dirty = true
@json['accountSetting']['password'] = a_password
end
def sso_provider
@json['accountSetting']['ssoProvider']
end
def sso_provider=(an_sso_provider)
@dirty = true
@json['accountSetting']['ssoProvider'] = an_sso_provider
end
def authentication_modes
@json['accountSetting']['authenticationModes'].map { |x| x.downcase.to_sym }
end
def authentication_modes=(modes)
modes = Array(modes)
@dirty = true
@json['accountSetting']['authenticationModes'] = modes.map { |x| x.to_s.upcase }
end
def to_hash
tmp = GoodData::Helpers.symbolize_keys(content.merge(uri: uri))
[
[:companyName, :company],
[:phoneNumber, :phone],
[:firstName, :first_name],
[:lastName, :last_name],
[:authenticationModes, :authentication_modes],
[:ssoProvider, :sso_provider]
].each do |vals|
wire, rb = vals
tmp[rb] = tmp[wire]
tmp.delete(wire)
end
tmp
end
def create_channel
GoodData::ChannelConfiguration.create(to: email, title: email, client: client)
end
def channels
GoodData::ChannelConfiguration.all(client: client)
end
end
end