2024-02-02 09:05:04 -06:00
|
|
|
class User < ApplicationRecord
|
|
|
|
has_secure_password
|
2024-02-02 16:06:55 +00:00
|
|
|
|
2024-02-02 09:05:04 -06:00
|
|
|
belongs_to :family
|
2024-10-03 14:42:22 -04:00
|
|
|
has_many :sessions, dependent: :destroy
|
2024-02-05 22:19:23 +08:00
|
|
|
accepts_nested_attributes_for :family
|
2024-02-02 09:05:04 -06:00
|
|
|
|
|
|
|
validates :email, presence: true, uniqueness: true
|
2024-10-03 14:42:22 -04:00
|
|
|
validate :ensure_valid_profile_image
|
2024-02-02 16:06:55 +00:00
|
|
|
normalizes :email, with: ->(email) { email.strip.downcase }
|
2024-02-02 09:05:04 -06:00
|
|
|
|
2024-04-27 05:59:02 -07:00
|
|
|
normalizes :first_name, :last_name, with: ->(value) { value.strip.presence }
|
|
|
|
|
2024-04-25 07:54:56 -04:00
|
|
|
enum :role, { member: "member", admin: "admin" }, validate: true
|
|
|
|
|
2024-04-30 18:38:33 +01:00
|
|
|
has_one_attached :profile_image do |attachable|
|
2024-10-08 14:25:34 -05:00
|
|
|
attachable.variant :thumbnail, resize_to_fill: [ 300, 300 ]
|
2024-04-30 18:38:33 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
validate :profile_image_size
|
|
|
|
|
2024-02-02 09:05:04 -06:00
|
|
|
generates_token_for :password_reset, expires_in: 15.minutes do
|
|
|
|
password_salt&.last(10)
|
|
|
|
end
|
2024-04-13 09:28:45 -04:00
|
|
|
|
2024-04-27 05:59:02 -07:00
|
|
|
def display_name
|
|
|
|
[ first_name, last_name ].compact.join(" ").presence || email
|
|
|
|
end
|
|
|
|
|
|
|
|
def initial
|
|
|
|
(display_name&.first || email.first).upcase
|
|
|
|
end
|
|
|
|
|
2024-04-13 09:28:45 -04:00
|
|
|
def acknowledge_upgrade_prompt(commit_sha)
|
|
|
|
update!(last_prompted_upgrade_commit_sha: commit_sha)
|
|
|
|
end
|
|
|
|
|
|
|
|
def acknowledge_upgrade_alert(commit_sha)
|
|
|
|
update!(last_alerted_upgrade_commit_sha: commit_sha)
|
|
|
|
end
|
|
|
|
|
|
|
|
def has_seen_upgrade_prompt?(upgrade)
|
|
|
|
last_prompted_upgrade_commit_sha == upgrade.commit_sha
|
|
|
|
end
|
|
|
|
|
|
|
|
def has_seen_upgrade_alert?(upgrade)
|
|
|
|
last_alerted_upgrade_commit_sha == upgrade.commit_sha
|
|
|
|
end
|
2024-04-30 16:40:31 +01:00
|
|
|
|
|
|
|
# Deactivation
|
|
|
|
validate :can_deactivate, if: -> { active_changed? && !active }
|
|
|
|
after_update_commit :purge_later, if: -> { saved_change_to_active?(from: true, to: false) }
|
|
|
|
|
|
|
|
def deactivate
|
|
|
|
update active: false, email: deactivated_email
|
|
|
|
end
|
|
|
|
|
|
|
|
def can_deactivate
|
|
|
|
if admin? && family.users.count > 1
|
2024-08-13 01:38:58 +01:00
|
|
|
errors.add(:base, :cannot_deactivate_admin_with_other_users)
|
2024-04-30 16:40:31 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def purge_later
|
|
|
|
UserPurgeJob.perform_later(self)
|
|
|
|
end
|
|
|
|
|
|
|
|
def purge
|
|
|
|
if last_user_in_family?
|
|
|
|
family.destroy
|
|
|
|
else
|
|
|
|
destroy
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
2024-10-03 14:42:22 -04:00
|
|
|
def ensure_valid_profile_image
|
|
|
|
return unless profile_image.attached?
|
|
|
|
|
|
|
|
unless profile_image.content_type.in?(%w[image/jpeg image/png])
|
|
|
|
errors.add(:profile_image, "must be a JPEG or PNG")
|
|
|
|
profile_image.purge
|
|
|
|
end
|
|
|
|
end
|
2024-04-30 16:40:31 +01:00
|
|
|
|
2024-08-23 10:06:24 -04:00
|
|
|
def last_user_in_family?
|
|
|
|
family.users.count == 1
|
|
|
|
end
|
2024-04-30 16:40:31 +01:00
|
|
|
|
2024-08-23 10:06:24 -04:00
|
|
|
def deactivated_email
|
|
|
|
email.gsub(/@/, "-deactivated-#{SecureRandom.uuid}@")
|
|
|
|
end
|
2024-04-30 18:38:33 +01:00
|
|
|
|
2024-08-23 10:06:24 -04:00
|
|
|
def profile_image_size
|
|
|
|
if profile_image.attached? && profile_image.byte_size > 5.megabytes
|
|
|
|
errors.add(:profile_image, :invalid_file_size, max_megabytes: 5)
|
|
|
|
end
|
2024-04-30 18:38:33 +01:00
|
|
|
end
|
2024-02-02 09:05:04 -06:00
|
|
|
end
|