summaryrefslogtreecommitdiff
path: root/app/models/user.rb
diff options
context:
space:
mode:
authorStefan Wintermeyer <stefan.wintermeyer@amooma.de>2012-12-17 12:01:45 +0100
committerStefan Wintermeyer <stefan.wintermeyer@amooma.de>2012-12-17 12:01:45 +0100
commitb80bd744ad873f6fc43018bc4bfb90677de167bd (patch)
tree072c4b0e33d442528555b82c415f5e7a1712b2b0 /app/models/user.rb
parent3e706c2025ecc5523e81ad649639ef2ff75e7bac (diff)
Start of GS5.
Diffstat (limited to 'app/models/user.rb')
-rw-r--r--app/models/user.rb208
1 files changed, 208 insertions, 0 deletions
diff --git a/app/models/user.rb b/app/models/user.rb
new file mode 100644
index 0000000..2d0256f
--- /dev/null
+++ b/app/models/user.rb
@@ -0,0 +1,208 @@
+require 'digest/sha2'
+
+class User < ActiveRecord::Base
+ after_create :create_a_default_phone_book, :if => :'is_native != false'
+
+ # Sync other nodes when this is a cluster.
+ #
+ after_create :create_on_other_gs_nodes
+ after_destroy :destroy_on_other_gs_nodes
+ after_update :update_on_other_gs_nodes
+
+ attr_accessible :user_name, :email, :password, :password_confirmation,
+ :first_name, :middle_name, :last_name, :male,
+ :image, :current_tenant_id, :language_id,
+ :new_pin, :new_pin_confirmation, :send_voicemail_as_email_attachment,
+ :importer_checksum, :gs_node_id
+
+ attr_accessor :new_pin, :new_pin_confirmation
+
+ before_validation {
+ # If the PIN and PIN confirmation are left blank in the GUI
+ # then the user/admin does not want to change the PIN.
+ if self.new_pin.blank? && self.new_pin_confirmation.blank?
+ self.new_pin = nil
+ self.new_pin_confirmation = nil
+ end
+ }
+
+ validates_length_of [:new_pin, :new_pin_confirmation],
+ :minimum => MINIMUM_PIN_LENGTH, :maximum => MAXIMUM_PIN_LENGTH,
+ :allow_blank => true, :allow_nil => true
+ validates_format_of [:new_pin, :new_pin_confirmation],
+ :with => /^[0-9]+$/,
+ :allow_blank => true, :allow_nil => true,
+ :message => "must be numeric."
+
+ validates_confirmation_of :new_pin, :if => :'pin_changed?'
+ before_save :hash_new_pin, :if => :'pin_changed?'
+
+ has_secure_password
+
+ validates_presence_of :password, :password_confirmation, :on => :create, :if => :'password_digest.blank?'
+ validates_presence_of :email
+ validates_presence_of :last_name
+ validates_presence_of :first_name
+ validates_presence_of :user_name
+
+ validates_uniqueness_of :user_name, :case_sensitive => false
+ validates_uniqueness_of :email, :allow_nil => true, :case_sensitive => false
+
+ validates_length_of :user_name, :within => 0..50
+
+ validates_presence_of :uuid
+ validates_uniqueness_of :uuid
+
+ # Associations:
+ #
+ has_many :tenant_memberships, :dependent => :destroy
+ has_many :tenants, :through => :tenant_memberships
+
+ has_many :user_group_memberships, :dependent => :destroy, :uniq => true
+ has_many :user_groups, :through => :user_group_memberships
+
+ has_many :phone_books, :as => :phone_bookable, :dependent => :destroy
+ has_many :phone_book_entries, :through => :phone_books
+
+ has_many :phones, :as => :phoneable
+ has_many :sip_accounts, :as => :sip_accountable, :dependent => :destroy
+ has_many :phone_numbers, :through => :sip_accounts
+
+ has_many :conferences, :as => :conferenceable, :dependent => :destroy
+
+ has_many :fax_accounts, :as => :fax_accountable, :dependent => :destroy
+
+ has_many :system_messages, :dependent => :destroy
+
+ has_many :auto_destroy_access_authorization_phone_numbers, :class_name => 'PhoneNumber', :foreign_key => 'access_authorization_user_id', :dependent => :destroy
+
+ belongs_to :current_tenant, :class_name => 'Tenant'
+ validates_presence_of :current_tenant, :if => Proc.new{ |user| user.current_tenant_id }
+
+ belongs_to :language
+ validates_presence_of :language_id
+ validates_presence_of :language
+
+ validate :current_tenant_is_included_in_tenants, :if => Proc.new{ |user| user.current_tenant_id }
+
+ belongs_to :gs_node
+
+ # Avatar like photo
+ mount_uploader :image, ImageUploader
+
+ before_save :format_email_and_user_name
+
+ before_destroy :destroy_or_logout_phones
+
+ def destroy
+ clean_whitelist_entries
+ super
+ end
+
+ def pin_changed?
+ ! @new_pin.blank?
+ end
+
+ def sip_domain
+ if self.current_tenant
+ return self.current_tenant.sip_domain
+ end
+ return nil
+ end
+
+ def to_s
+ max_first_name_length = 10
+ max_last_name_length = 20
+ if self.first_name.blank?
+ self.last_name.strip
+ else
+ "#{self.first_name.strip} #{self.last_name.strip}"
+ end
+ end
+
+ def self.find_user_by_phone_number( number, tenant )
+ tenant = Tenant.where( :id => tenant.id ).first
+ if tenant
+ if tenant.sip_domain
+ user = tenant.sip_domain.sip_accounts.
+ joins(:phone_numbers).
+ where(:phone_numbers => { :number => number }).
+ first.
+ try(:sip_accountable)
+ if user.class.name == 'User'
+ return user
+ end
+ end
+ end
+ return nil
+ end
+
+ def authenticate_by_pin?( entered_pin )
+ self.pin_hash == Digest::SHA2.hexdigest( "#{self.pin_salt}#{entered_pin}" )
+ end
+
+
+ private
+
+ def hash_new_pin
+ if @new_pin \
+ && @new_pin_confirmation \
+ && @new_pin_confirmation == @new_pin
+ self.pin_salt = SecureRandom.base64(8)
+ self.pin_hash = Digest::SHA2.hexdigest(self.pin_salt + @new_pin)
+ end
+ end
+
+ def format_email_and_user_name
+ self.email = self.email.downcase.strip if !self.email.blank?
+ self.user_name = self.user_name.downcase.strip if !self.user_name.blank?
+ end
+
+ # Create a personal phone book for this user:
+ def create_a_default_phone_book
+ private_phone_book = self.phone_books.find_or_create_by_name_and_description(
+ I18n.t('phone_books.private_phone_book.name', :resource => self.to_s),
+ I18n.t('phone_books.private_phone_book.description')
+ )
+ end
+
+ # Check if a current_tenant_id is possible tenant_membership wise.
+ def current_tenant_is_included_in_tenants
+ if !self.tenants.include?(Tenant.find(self.current_tenant_id))
+ errors.add(:current_tenant_id, "is not possible (no TenantMembership)")
+ end
+ end
+
+ # Make sure that there are no whitelist entries with phone_numbers of
+ # a just destroyed user.
+ #
+ def clean_whitelist_entries
+ phone_numbers = PhoneNumber.where( :phone_numberable_type => 'Whitelist').
+ where( :number => self.phone_numbers.map{ |x| x.number } )
+ phone_numbers.each do |phone_number|
+ if phone_number.phone_numberable.whitelistable.class == Callthrough
+ whitelist = Whitelist.find(phone_number.phone_numberable)
+ phone_number.destroy
+ if whitelist.phone_numbers.count == 0
+ # Very lickly that this Whitelist doesn't make sense any more.
+ #
+ whitelist.destroy
+ end
+ end
+ end
+ end
+
+ # Make sure that a tenant phone goes back to the tenant and doesn't
+ # get deleted with this user.
+ #
+ def destroy_or_logout_phones
+ self.phones.each do |phone|
+ if phone.sip_accounts.where(:sip_accountable_type => 'Tenant').count > 0
+ phone.user_logout
+ else
+ phone.destroy
+ end
+ end
+ end
+
+end