# encoding: utf-8
module PassaporteWeb
# Represents an Identity on PassaporteWeb, i.e. a person. When you sign up for PassaporteWeb, your 'account'
# there is an Identity.
class Identity
include Attributable
ATTRIBUTES = [:accounts, :birth_date, :country, :cpf, :email, :first_name, :gender, :is_active, :language, :last_name, :nickname, :notifications, :send_myfreecomm_news, :send_partner_news, :services, :timezone, :update_info_url, :uuid, :password, :password2, :must_change_password, :inhibit_activation_message, :tos]
UPDATABLE_ATTRIBUTES = [:first_name, :last_name, :nickname, :cpf, :birth_date, :gender, :send_myfreecomm_news, :send_partner_news, :country, :language, :timezone]
CREATABLE_ATTRIBUTES = *(UPDATABLE_ATTRIBUTES + [:email, :password, :password2, :must_change_password, :tos])
attr_accessor *UPDATABLE_ATTRIBUTES
attr_reader *(ATTRIBUTES - UPDATABLE_ATTRIBUTES)
attr_reader :errors
# Finds an Identity by it's UUID. Returns the Identity instance with all fields set if successful.
# Raises a RestClient::ResourceNotFound exception if no Identity exists with the supplied
# UUID.
#
# If include_expired_accounts is passed as true, brings information about all
# accounts the Identity is related, regardless of the account's expiration date.
#
# If include_other_services is passed as true, brings information about accounts
# of all services the Identity is related to (not just the current logged in service / application).
#
# API method: /accounts/api/identities/:uuid/
#
# API documentation: https://app.passaporteweb.com.br/static/docs/usuarios.html#get-accounts-api-identities-uuid
def self.find(uuid, include_expired_accounts=false, include_other_services=false)
response = Http.get(
"/accounts/api/identities/#{uuid}/",
{include_expired_accounts: include_expired_accounts, include_other_services: include_other_services}
)
attributes_hash = MultiJson.decode(response.body)
load_identity(attributes_hash)
end
# Finds an Identity by it's email (emails are unique on PassaporteWeb). Returns the Identity instance
# with all fields set if successful. Raises a RestClient::ResourceNotFound exception if no
# Identity exists with the supplied email.
#
# If include_expired_accounts is passed as true, brings information about all
# accounts the Identity is related, regardless of the account's expiration date.
#
# If include_other_services is passed as true, brings information about accounts
# of all services the Identity is related to (not just the current logged in service / application).
#
# API method: GET /accounts/api/identities/?email=:email
#
# API documentation: https://app.passaporteweb.com.br/static/docs/usuarios.html#get-accounts-api-identities-email-email
def self.find_by_email(email, include_expired_accounts=false, include_other_services=false)
response = Http.get(
"/accounts/api/identities/",
{email: email, include_expired_accounts: include_expired_accounts, include_other_services: include_other_services}
)
attributes_hash = MultiJson.decode(response.body)
load_identity(attributes_hash)
end
# Checks if an Identity exists on PassaporteWeb and if the password is correct. Returns an instance of
# Identity for the supplied email if the password is correct (although with only basic attributes set).
# Returns false if the password is wrong or if no Identity exists on PassaporteWeb with
# the supplied email. Use it to validate that a user is who he says he is.
#
# API method: GET /accounts/api/auth/
#
# API documentation: https://app.passaporteweb.com.br/static/docs/usuarios.html#get-accounts-api-auth
def self.authenticate(email, password)
response = Http.custom_auth_get(
email,
password,
"/accounts/api/auth/"
)
raise "unexpected response: #{response.code} - #{response.body}" unless response.code == 200
attributes_hash = MultiJson.decode(response.body)
load_identity(attributes_hash)
rescue *[RestClient::Unauthorized] => e
false
end
# Checks if the supplied password is correct for the current Identity. Returns true if the
# password matches or false if the password is wrong. Use it to validate that a user is who
# he says he is.
#
# API method: GET /accounts/api/auth/
#
# API documentation: https://app.passaporteweb.com.br/static/docs/usuarios.html#get-accounts-api-auth
def authenticate(password)
raise ArgumentError, "email must be set" if (self.email.nil? || self.email.to_s.empty?)
response = Http.custom_auth_get(
self.email,
password,
"/accounts/api/auth/"
)
raise "unexpected response: #{response.code} - #{response.body}" unless response.code == 200
true
rescue *[RestClient::Unauthorized] => e
false
end
# Instanciates a new Identity with the supplied attributes. Only the attributes listed
# on Identity::CREATABLE_ATTRIBUTES are used when creating an Identity and
# on Identity::UPDATABLE_ATTRIBUTES are used when updating an Identity.
#
# Example:
#
# identity = PassaporteWeb::Identity.new(
# email: 'fulano@detal.com.br',
# password: '123456',
# password2: '123456',
# must_change_password: false,
# tos: true,
# first_name: 'Fulano',
# last_name: 'de Tal',
# nickname: 'Fulaninho',
# cpf: '342.766.570-40',
# birth_date: '1983-04-19',
# gender: 'M',
# send_myfreecomm_news: true,
# send_partner_news: false,
# country: 'Brasil',
# language: 'pt_BR',
# timezone: 'GMT-3'
# )
def initialize(attributes={})
set_attributes(attributes)
@errors = {}
end
# Returns a hash with all attribures of the identity.
def attributes
ATTRIBUTES.inject({}) do |hash, attribute|
hash[attribute] = self.send(attribute)
hash
end
end
# Compares one Identity with another, returns true if they have the same UUID.
def ==(other)
self.uuid == other.uuid
end
# Returns true if both Identity are the same object.
def ===(other)
self.object_id == other.object_id
end
# Saves the Identity on PassaporteWeb, creating it if new or updating it if existing. Returns true
# if successfull or false if not. In case of failure, it will fill the errors attribute
# with the reason for the failure to save the object.
#
# The attributes first_name, last_name, cpf and inhibit_activation_message
# are optional. password2 and password fields are required even if the parameter
# must_change_password is used.
#
# API methods:
# * POST /accounts/api/create/ (on create)
# * PUT /accounts/api/identities/:uuid/ (on update)
#
# API documentation:
# * https://app.passaporteweb.com.br/static/docs/usuarios.html#post-accounts-api-create
# * https://app.passaporteweb.com.br/static/docs/usuarios.html#get-accounts-api-identities-email-email
#
# Example:
#
# identity = Identity.find_by_email('foo@bar.com')
# identity.save # => true
# identity.cpf = '12'
# identity.save # => false
# identity.errors # => {"cpf" => ["Certifique-se de que o valor tenha no mÃnimo 11 caracteres (ele possui 2)."]}
def save
# TODO validar atributos?
response = (persisted? ? update : create)
raise "unexpected response: #{response.code} - #{response.body}" unless response.code == 200
attributes_hash = MultiJson.decode(response.body)
set_attributes(attributes_hash)
@persisted = true
@errors = {}
true
rescue *[RestClient::Conflict, RestClient::BadRequest] => e
@errors = MultiJson.decode(e.response.body)
false
end
def persisted?
!self.uuid.nil? && @persisted == true
end
private
def self.load_identity(attributes)
identity = self.new(attributes)
identity.instance_variable_set(:@persisted, true)
identity
end
def create
Http.post("/accounts/api/create/", create_body)
end
def update
Http.put("/accounts/api/identities/#{self.uuid}/", update_body)
end
def update_body
self.attributes.select { |key, value| UPDATABLE_ATTRIBUTES.include?(key) && !value.nil? }
end
def create_body
self.attributes.select { |key, value| CREATABLE_ATTRIBUTES.include?(key) && !value.nil? }
end
end
end