class Identity < CouchRest::Model::Base include LoginFormatValidation use_database :identities belongs_to :user property :address, LocalEmail property :destination, Email property :keys, HashWithIndifferentAccess property :cert_fingerprints, Hash validates :address, presence: true validate :address_available validates :destination, presence: true, if: :enabled? validates :destination, uniqueness: {scope: :address} validate :address_local_email validate :destination_email design do own_path = Pathname.new(File.dirname(__FILE__)) load_views(own_path.join('..', 'designs', 'identity'), nil) view :by_user_id view :by_address_and_destination view :by_address end def self.address_starts_with(query) self.by_address.startkey(query).endkey(query + "\ufff0") end def self.for(user, attributes = {}) find_for(user, attributes) || build_for(user, attributes) end def self.find_for(user, attributes = {}) attributes.reverse_merge! attributes_from_user(user) id = find_by_address_and_destination attributes.values_at(:address, :destination) return id if id && id.user == user end def self.build_for(user, attributes = {}) attributes.reverse_merge! attributes_from_user(user) Identity.new(attributes) end def self.create_for(user, attributes = {}) identity = build_for(user, attributes) identity.save identity end def self.disable_all_for(user) Identity.by_user_id.key(user.id).each do |identity| identity.disable # if the identity is not unique anymore because the destination # was reset to nil we destroy it. identity.save || identity.destroy end end def self.destroy_all_for(user) Identity.by_user_id.key(user.id).each do |identity| identity.destroy end end def self.destroy_all_disabled Identity.disabled.each do |identity| identity.destroy end end def self.attributes_from_user(user) { user_id: user.id, address: user.email_address, destination: user.email_address } end def status return :blocked if disabled? case destination when address :main_email when /@#{APP_CONFIG[:domain]}\Z/i, :alias else :forward end end def enabled? self.user_id end def disabled? !enabled? end def actions if enabled? [] # [:show, :edit] else [:destroy] end end def disable self.destination = nil self.user_id = nil end def keys read_attribute('keys') || HashWithIndifferentAccess.new end def set_key(type, key) return if keys[type] == key.to_s write_attribute('keys', keys.merge(type => key.to_s)) end def cert_fingerprints read_attribute('cert_fingerprints') || Hash.new end def register_cert(cert) expiry = cert.expiry.to_date.to_s write_attribute 'cert_fingerprints', cert_fingerprints.merge(cert.fingerprint => expiry) end # for LoginFormatValidation def login address.handle if address.present? end protected def address_available blocking_identities = Identity.by_address.key(address).all blocking_identities.delete self if self.user blocking_identities.reject! { |other| other.user == self.user } end if blocking_identities.any? errors.add :address, :taken end end def address_local_email # caught by presence validation return if address.blank? return if address.valid? address.errors.each do |attribute, error| self.errors.add(:address, error) end end def destination_email # caught by presence validation or this identity is disabled return if destination.blank? return if destination.valid? destination.errors.each do |attribute, error| self.errors.add(:destination, error) end end ActiveSupport.run_load_hooks(:identity, self) end