Class: Incline::User

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/incline/user.rb

Overview

This class represents an application user.

Constant Summary collapse

ANONYMOUS_EMAIL =
'[email protected]'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#activation_tokenObject

Returns the value of attribute activation_token.



27
28
29
# File 'app/models/incline/user.rb', line 27

def activation_token
  @activation_token
end

#recaptchaObject

Returns the value of attribute recaptcha.



24
25
26
# File 'app/models/incline/user.rb', line 24

def recaptcha
  @recaptcha
end

#remember_tokenObject

Returns the value of attribute remember_token.



26
27
28
# File 'app/models/incline/user.rb', line 26

def remember_token
  @remember_token
end

#reset_tokenObject

Returns the value of attribute reset_token.



28
29
30
# File 'app/models/incline/user.rb', line 28

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
392
393
# File 'app/models/incline/user.rb', line 375

def self.anonymous
  @anonymous = nil if Rails.env.test? # always start fresh in test environment.
  @anonymous ||=
      Incline::Recaptcha::pause_for do
        pwd = new_token
        User
            .where(email: ANONYMOUS_EMAIL)
            .first_or_create!(
                email: ANONYMOUS_EMAIL,
                name: 'Anonymous',
                enabled: false,
                activated: true,
                activated_at: Time.now,
                password: pwd,
                password_confirmation: pwd,
                recaptcha: 'na'
            )
      end
end

.digest(string) ⇒ Object

Returns a hash digest of the given string.



297
298
299
300
# File 'app/models/incline/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

.ensure_admin_exists!Object

Generates the necessary system administrator account.

When the database is initially seeded, the only user is the system administrator.

The absolute default is **[email protected]** with a password of Password1. These values will be used if they are not overridden for the current environment.

You can override this by setting the default_admin property in “config/secrets.yml”.

# config/secrets.yml
development:
  default_admin:
    email: [email protected]
    password: Password1

Regardless of whether you use the absolute defaults or create your own, you will want to change the password on first login.



327
328
329
330
331
332
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/incline/user.rb', line 327

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 = (Rails.application.secrets[:default_admin] || {}).symbolize_keys

    def_adm_email = def_adm[:email] || '[email protected]'
    def_adm_pass = def_adm[:password] || 'Password1'

    user = Incline::Recaptcha::pause_for do
      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.now,
              recaptcha: 'na'
          )
    end


    unless user.activated? && 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.now
      user.save!
    end
  end
end

.new_tokenObject

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



304
305
306
# File 'app/models/incline/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.



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

def self.send_disabled_reset_email(email, client_ip = '0.0.0.0')
  Incline::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.



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

def self.send_inactive_reset_email(email, client_ip = '0.0.0.0')
  Incline::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_missing_reset_email(email, client_ip = '0.0.0.0') ⇒ Object

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



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

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

Instance Method Details

#activateObject

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



201
202
203
204
205
206
207
# File 'app/models/incline/user.rb', line 201

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

#anonymous?Boolean

Is this the anonymous user?

Returns:

  • (Boolean)


233
234
235
# File 'app/models/incline/user.rb', line 233

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)


164
165
166
167
168
169
# File 'app/models/incline/user.rb', line 164

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.



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

def create_reset_digest
  self.reset_token = Incline::User::new_token
  update_columns(
      reset_digest: Incline::User::digest(reset_token),
      reset_sent_at: Time.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.



176
177
178
179
180
181
182
183
184
185
186
# File 'app/models/incline/user.rb', line 176

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

  update_columns(
      disabled_by: other_user.email,
      disabled_at: Time.now,
      disabled_reason: reason,
      enabled: false
  ) && refresh_comments
end

#effective_groups(refresh = false) ⇒ Object

Gets the effective group membership of this user.



124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'app/models/incline/user.rb', line 124

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
                        end
                            .map{ |g| g.to_s.upcase }
                            .uniq
                            .sort
end

#enableObject

Enables the user and removes any previous disable information.



190
191
192
193
194
195
196
197
# File 'app/models/incline/user.rb', line 190

def enable
  update_columns(
      disabled_by: nil,
      disabled_at: nil,
      disabled_reason: nil,
      enabled: true
  ) && refresh_comments
end

#enabledObject

Gets all of the currently enabled users.



78
# File 'app/models/incline/user.rb', line 78

scope :enabled, ->{ where(enabled: true, activated: true) }

#failed_login_streakObject

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



251
252
253
254
255
256
257
258
259
260
# File 'app/models/incline/user.rb', line 251

def 
  @failed_login_streak ||=
      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.



158
159
160
# File 'app/models/incline/user.rb', line 158

def forget
  update_attribute(:remember_digest, nil)
end

#formatted_emailObject

Gets the email formatted with the name.



103
104
105
# File 'app/models/incline/user.rb', line 103

def formatted_email
  "#{name} <#{email}>"
end

#group_idsObject

Gets the IDs for the groups that the user explicitly belongs to.



109
110
111
# File 'app/models/incline/user.rb', line 109

def group_ids
  groups.map{|g| g.id}
end

#group_ids=(values) ⇒ Object

Sets the IDs for the groups that the user explicitly belongs to.



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

def group_ids=(values)
  values ||= []
  values = [ values ] unless values.is_a?(::Array)
  values = values.reject{|v| v.blank?}.map{|v| v.to_i}
  self.groups = Incline::AccessGroup.where(id: values).to_a
end

#has_any_group?(*group_list) ⇒ Boolean

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

Returns:

  • (Boolean)


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

def has_any_group?(*group_list)
  return :system_admin if system_admin?
  return false if anonymous?

  r = group_list.select{|g| effective_groups.include?(g.upcase)}

  r.blank? ? false : r
end

#knownObject

Gets all known users.



74
# File 'app/models/incline/user.rb', line 74

scope :known, ->{ where.not(email: ANONYMOUS_EMAIL) }

#last_failed_loginObject

Gets the last failed login for this user.



245
246
247
# File 'app/models/incline/user.rb', line 245

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

#last_successful_loginObject

Gets the last successful login for this user.



239
240
241
# File 'app/models/incline/user.rb', line 239

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

#partial_emailObject

Gets the email address in a partially obfuscated fashion.



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

def partial_email
  @partial_email ||=
      begin
        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
end

#password_reset_expired?Boolean

Was the password reset requested more than 2 hours ago?

Returns:

  • (Boolean)


227
228
229
# File 'app/models/incline/user.rb', line 227

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

#refresh_commentsObject

Generates some brief comments about the user account and stores them in the comments attribute.

This gets updated automatically on every login attempt.



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

def refresh_comments
  update_columns :comments => generate_comments
  comments
end

#rememberObject

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



151
152
153
154
# File 'app/models/incline/user.rb', line 151

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

#send_activation_email(client_ip = '0.0.0.0') ⇒ Object

Sends the activation email to the user.



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

def send_activation_email(client_ip = '0.0.0.0')
  Incline::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.



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

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

#sortedObject

Sorts the users by name.



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

scope :sorted, ->{ order(name: :asc) }

#to_sObject

Gets the formatted email for this user.



397
398
399
# File 'app/models/incline/user.rb', line 397

def to_s
  formatted_email
end