Class: User

Inherits:
BarkestCore::DbTable show all
Includes:
BarkestCore::EmailTester, BarkestCore::NamedModel
Defined in:
app/models/user.rb

Overview

The user class defines the individual users in the application.

Each user can login with their email address, if the domain portion of their email address happens to match an LdapSource, then that LdapSource will be used to authenticate them, otherwise the password_digest stored in the database will be used to authenticate them.

Constant Summary collapse

ANONYMOUS_EMAIL =
'[email protected]'
UNIQUE_STRING_FIELD =
:email

Constants included from BarkestCore::EmailTester

BarkestCore::EmailTester::VALID_EMAIL_REGEX

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from BarkestCore::EmailTester

included, valid_email?

Methods included from BarkestCore::NamedModel

included

Instance Attribute Details

#activation_tokenObject

Gets the temporary token used to activate this user.



34
35
36
# File 'app/models/user.rb', line 34

def activation_token
  @activation_token
end

#remember_tokenObject

Gets the temporary token used to remember this user.



30
31
32
# File 'app/models/user.rb', line 30

def remember_token
  @remember_token
end

#reset_tokenObject

Gets the temporary token used to reset this user’s password.



38
39
40
# File 'app/models/user.rb', line 38

def reset_token
  @reset_token
end

Class Method Details

.anonymousObject

Gets a generic anonymous user.



375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
# File 'app/models/user.rb', line 375

def self.anonymous
  @anonymous = nil if Rails.env.test?
  @anonymous ||=
      begin
        pwd = new_token
        where(email: ANONYMOUS_EMAIL)
            .first_or_create(
                email: ANONYMOUS_EMAIL,
                name: 'Anonymous',
                enabled: false,
                activated: true,
                activated_at: Time.zone.now,
                password: pwd,
                password_confirmation: pwd
            )
      end
end

.digest(string) ⇒ Object

Returns a hash digest of the given string.



297
298
299
300
# File 'app/models/user.rb', line 297

def self.digest(string)
  cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
  BCrypt::Password.create(string, cost: cost)
end

.enabledObject

Gets all of the currently enabled users.



316
317
318
# File 'app/models/user.rb', line 316

def self.enabled
  where(enabled: true, activated: true)
end

.ensure_admin_exists!Object

Generates the necessary system administrator account.

When the database is initially seeded, the only user is the system administrator. The system administrator is **[email protected]** and the password is initially Password1. You should change this immediately once the app is running. You will most likely want to create a completely new admin account and disable the **[email protected]** account.



333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
# File 'app/models/user.rb', line 333

def self.ensure_admin_exists!
  unless where(system_admin: true, enabled: true).count > 0

    msg = "Creating/reactivating default administrator...\n"
    if Rails.application.running?
      Rails.logger.info msg
    else
      print msg
    end

    def_adm_email = '[email protected]'
    def_adm_pass = 'Password1'

    user = User
               .where(
                   email: def_adm_email
               )
               .first_or_create!(
                   name: 'Default Administrator',
                   email: def_adm_email,
                   password: def_adm_pass,
                   password_confirmation: def_adm_pass,
                   enabled: true,
                   system_admin: true,
                   activated: true,
                   activated_at: Time.zone.now
               )

    unless user.enabled? && user.system_admin?
      user.password = def_adm_pass
      user.password_confirmation = def_adm_pass
      user.enabled = true
      user.system_admin = true
      user.activated = true
      user.activated_at = Time.zone.now
      user.save!
    end
  end
end

.knownObject

Gets all known users.



310
311
312
# File 'app/models/user.rb', line 310

def self.known
  where.not(email: ANONYMOUS_EMAIL)
end

.new_tokenObject

Generates a new random token in (url safe) base64.



304
305
306
# File 'app/models/user.rb', line 304

def self.new_token
  SecureRandom.urlsafe_base64(32)
end

.send_disabled_reset_email(email, client_ip = '0.0.0.0') ⇒ Object

Sends a disabled account message when a user requests a password reset.



279
280
281
# File 'app/models/user.rb', line 279

def self.send_disabled_reset_email(email, client_ip = '0.0.0.0')
  BarkestCore::UserMailer::invalid_password_reset(email: email, message: 'The account attached to this email address has been disabled.', client_ip: client_ip).deliver_now
end

.send_inactive_reset_email(email, client_ip = '0.0.0.0') ⇒ Object

Sends a non-activated account message when a user requests a password reset.



285
286
287
# File 'app/models/user.rb', line 285

def self.send_inactive_reset_email(email, client_ip = '0.0.0.0')
  BarkestCore::UserMailer::invalid_password_reset(email: email, message: 'The account attached to this email has not yet been activated.', client_ip: client_ip).deliver_now
end

.send_ldap_reset_email(email, client_ip = '0.0.0.0') ⇒ Object

Sends a message informing the user we cannot change LDAP passwords.



291
292
293
# File 'app/models/user.rb', line 291

def self.send_ldap_reset_email(email, client_ip = '0.0.0.0')
  BarkestCore::UserMailer::invalid_password_reset(email: email, message: 'The account attached to this email is an LDAP account.  This application cannot change passwords on an LDAP account.', client_ip: client_ip).deliver_now
end

.send_missing_reset_email(email, client_ip = '0.0.0.0') ⇒ Object

Sends a missing account message when a user requests a password reset.



273
274
275
# File 'app/models/user.rb', line 273

def self.send_missing_reset_email(email, client_ip = '0.0.0.0')
  BarkestCore::UserMailer::invalid_password_reset(email: email, client_ip: client_ip).deliver_now
end

.sortedObject

Sorts the users by name.



322
323
324
# File 'app/models/user.rb', line 322

def self.sorted
  order(name: :asc)
end

Instance Method Details

#activateObject

Marks the user as activated and removes the activation digest from the user model.



166
167
168
169
170
171
172
# File 'app/models/user.rb', line 166

def activate
  update_columns(
      activated: true,
      activated_at: Time.zone.now,
      activation_digest: nil
  )
end

#anonymous?Boolean

Is this the anonymous user?

Returns:

  • (Boolean)


198
199
200
# File 'app/models/user.rb', line 198

def anonymous?
  email == ANONYMOUS_EMAIL
end

#authenticated?(attribute, token) ⇒ Boolean

Determines if the supplied token digests to the stored digest in the user model.

Returns:

  • (Boolean)


128
129
130
131
132
133
# File 'app/models/user.rb', line 128

def authenticated?(attribute, token)
  return false unless respond_to?("#{attribute}_digest")
  digest = send("#{attribute}_digest")
  return false if digest.blank?
  BCrypt::Password.new(digest).is_password?(token)
end

#create_reset_digestObject

Creates a reset token and stores the digest to the user model.



182
183
184
185
186
187
188
# File 'app/models/user.rb', line 182

def create_reset_digest
  self.reset_token = User.new_token
  update_columns(
      reset_digest: User.digest(reset_token),
      reset_sent_at: Time.zone.now
  )
end

#disable(other_user, reason) ⇒ Object

Disables the user.

The other_user is required, cannot be the current user, and must be a system administrator. The reason is technically optional, but should be provided.



140
141
142
143
144
145
146
147
148
149
150
# File 'app/models/user.rb', line 140

def disable(other_user, reason)
  return false unless other_user && other_user.system_admin?
  return false if other_user == self

  update_columns(
      disabled_by_id: other_user.id,
      disabled_at: Time.zone.now,
      disabled_reason: reason,
      enabled: false
  )
end

#effective_groups(refresh = false) ⇒ Object

Gets the effective group membership of this user.



86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'app/models/user.rb', line 86

def effective_groups(refresh = false)
  @effective_groups = nil if refresh
  @effective_groups ||= if system_admin?
                        AccessGroup.all.map{ |g| g.to_s.upcase }
                      else
                        groups
                            .collect{ |g| g.effective_groups }
                            .flatten
                            .inject([]){ |memo,item| memo << item unless memo.include?(item); memo }
                      end
                          .map{ |g| g.to_s.upcase }
                          .sort
end

#enableObject

Enables the user and removes any previous disable information.



154
155
156
157
158
159
160
161
# File 'app/models/user.rb', line 154

def enable
  update_columns(
      disabled_by_id: nil,
      disabled_at: nil,
      disabled_reason: nil,
      enabled: true
  )
end

#failed_login_streakObject

Gets the failed logins for a user since the last successful login.



216
217
218
219
220
221
222
223
224
225
# File 'app/models/user.rb', line 216

def 
   ||=
      begin
        results = .where.not(successful: true)
        if 
          results = results.where('created_at > ?', .created_at)
        end
        results.order(created_at: :desc)
      end
end

#forgetObject

Removes the remember digest from the user model.



122
123
124
# File 'app/models/user.rb', line 122

def forget
  update_attribute(:remember_digest, nil)
end

#has_any_group?(*group_list) ⇒ Boolean

Does this user have the equivalent of one or more of these groups?

Returns:

  • (Boolean)


102
103
104
105
106
107
108
109
110
111
# File 'app/models/user.rb', line 102

def has_any_group?(*group_list)
  return true if system_admin?

  group_list.each do |group|
    group = group.to_s.upcase
    return true if effective_groups.include?(group)
  end

  false
end

#last_failed_loginObject

Gets the last failed login for this user.



210
211
212
# File 'app/models/user.rb', line 210

def 
   ||= .where.not(successful: true).order(created_at: :desc).first
end

#last_successful_loginObject

Gets the last successful login for this user.



204
205
206
# File 'app/models/user.rb', line 204

def 
   ||= .where(successful: true).order(created_at: :desc).first
end

#partial_emailObject

Gets the email address in a partially obfuscated fashion.



66
67
68
69
70
71
72
73
74
75
76
# File 'app/models/user.rb', line 66

def partial_email
  uid,_,domain = email.partition('@')
  if uid.length < 4
    uid = '*' * uid.length
  elsif uid.length < 8
    uid = uid[0..2] + ('*' * (uid.length - 3))
  else
    uid = uid[0..2] + ('*' * (uid.length - 6)) + uid[-3..-1]
  end
  "#{uid}@#{domain}"
end

#password_reset_expired?Boolean

Was the password reset requested more than 2 hours ago?

Returns:

  • (Boolean)


192
193
194
# File 'app/models/user.rb', line 192

def password_reset_expired?
  reset_sent_at.nil? || reset_sent_at < 2.hours.ago
end

#rememberObject

Generates a remember token and saves the digest to the user model.



115
116
117
118
# File 'app/models/user.rb', line 115

def remember
  self.remember_token = User.new_token
  update_attribute(:remember_digest, User.digest(self.remember_token))
end

#send_activation_email(client_ip = '0.0.0.0') ⇒ Object

Sends the activation email to the user.



176
177
178
# File 'app/models/user.rb', line 176

def send_activation_email(client_ip = '0.0.0.0')
  BarkestCore::UserMailer.(user: self, client_ip: client_ip).deliver_now
end

#send_password_reset_email(client_ip = '0.0.0.0') ⇒ Object

Sends the password reset email to the user.



267
268
269
# File 'app/models/user.rb', line 267

def send_password_reset_email(client_ip = '0.0.0.0')
  BarkestCore::UserMailer.password_reset(user: self, client_ip: client_ip).deliver_now
end

#settings(reload = false) ⇒ Object



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'app/models/user.rb', line 227

def settings(reload = false)
  @settings = nil if reload
  @settings ||=
      begin
        h = SystemConfig.get("user_#{id}") || {}
        h.instance_variable_set :@user_id, id

        def h.save
          SystemConfig.set "user_#{@user_id}", self
        end

        def h.method_missing(m,*a,&b)
          x = (/^([A-Z][A-Z0-9_]*)(=)?$/i).match(m.to_s)
          if x
            key = x[1].to_sym
            if x[2] == '='
              val = a ? a.first : nil
              self[key] = val
              return val
            else
              return self[key]
            end
          end
          super m, *a, &b
        end

        def h.[](key)
          super key.to_sym
        end

        def h.[]=(key, value)
          super key.to_sym, value
        end

        h
      end
end

#system_admin?Boolean

Is the user a system administrator?

Returns:

  • (Boolean)


80
81
82
# File 'app/models/user.rb', line 80

def system_admin?
  enabled && system_admin
end