Files
sure/app/models/invitation.rb
Juan José Mata 705b5a8b26 First cut of a simplified "intro" UI layout (#265)
* First cut of a simplified "intro" UI layout

* Linter

* Add guest role and intro-only access

* Fix guest role UI defaults (#940)

Use enum predicate to avoid missing role helper.

* Remove legacy user role mapping (#941)

Drop the unused user role references in role normalization
and SSO role mapping forms to avoid implying a role that
never existed.

Refs: #0

* Remove role normalization (#942)

Remove role normalization

Roles are now stored directly without legacy mappings.

* Revert role mapping logic

* Remove `normalize_role_settings`

* Remove unnecessary migration

* Make `member` the default

* Broken `.erb`

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
2026-02-09 11:09:25 +01:00

64 lines
1.7 KiB
Ruby

class Invitation < ApplicationRecord
include Encryptable
belongs_to :family
belongs_to :inviter, class_name: "User"
# Encrypt sensitive fields if ActiveRecord encryption is configured
if encryption_ready?
encrypts :token, deterministic: true
encrypts :email, deterministic: true, downcase: true
end
validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
validates :role, presence: true, inclusion: { in: %w[admin member guest] }
validates :token, presence: true, uniqueness: true
validates_uniqueness_of :email, scope: :family_id, message: "has already been invited to this family"
validate :inviter_is_admin
before_validation :generate_token, on: :create
before_create :set_expiration
scope :pending, -> { where(accepted_at: nil).where("expires_at > ?", Time.current) }
scope :accepted, -> { where.not(accepted_at: nil) }
def pending?
accepted_at.nil? && expires_at > Time.current
end
def accept_for(user)
return false if user.blank?
return false unless pending?
return false unless emails_match?(user)
transaction do
user.update!(family_id: family_id, role: role.to_s)
update!(accepted_at: Time.current)
end
true
end
private
def emails_match?(user)
inv_email = email.to_s.strip.downcase
usr_email = user.email.to_s.strip.downcase
inv_email.present? && usr_email.present? && inv_email == usr_email
end
def generate_token
loop do
self.token = SecureRandom.hex(32)
break unless self.class.exists?(token: token)
end
end
def set_expiration
self.expires_at = 3.days.from_now
end
def inviter_is_admin
inviter.admin?
end
end