summaryrefslogtreecommitdiff
path: root/app/models/user.rb
blob: 9e8cbc0f236d7db2dd8d37a1d52a5b70e9bcb00a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
118
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
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 => (GsParameter.get('MINIMUM_PIN_LENGTH').nil? ? 4 : GsParameter.get('MINIMUM_PIN_LENGTH')), 
    :maximum => (GsParameter.get('MAXIMUM_PIN_LENGTH').nil? ? 10 : GsParameter.get('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

  after_save :become_a_member_of_default_user_groups

  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
      phone.resync
    end
  end

  # Normaly a new user should become a member of default user groups.
  #
  def become_a_member_of_default_user_groups
    UserGroup.where(:id => GsParameter.get('DEFAULT_USER_GROUPS_IDS')).each do |user_group|
      user_group.user_group_memberships.create(:user_id => self.id)
    end
  end

end