class User < ApplicationRecord include Auditable has_secure_password has_many :assigned_organizations, class_name: "Organization", foreign_key: :assigned_user_id, dependent: :nullify, inverse_of: :assigned_user has_many :assigned_opportunities, class_name: "Opportunity", foreign_key: :assigned_user_id, dependent: :nullify, inverse_of: :assigned_user has_many :assigned_tasks, class_name: "Task", foreign_key: :assigned_user_id, dependent: :nullify, inverse_of: :assigned_user has_many :activities, dependent: :nullify has_many :user_projects, dependent: :destroy has_many :projects, through: :user_projects has_many :api_tokens, dependent: :destroy ROLES = %w[admin user].freeze validates :email, presence: true, uniqueness: { case_sensitive: false }, format: { with: URI::MailTo::EMAIL_REGEXP } validates :first_name, :last_name, presence: true validates :role, inclusion: { in: ROLES } validates :password, length: { minimum: 8 }, if: -> { password.present? } validate :must_keep_at_least_one_active_admin before_validation :normalize_email before_destroy :prevent_destroying_last_admin scope :active, -> { where(active: true) } scope :admins, -> { where(role: "admin") } scope :active_admins, -> { active.admins } def admin? role == "admin" end def full_name "#{first_name} #{last_name}" end def last_active_admin? admin? && active? && self.class.active_admins.where.not(id: id).none? end def can_be_deactivated? return true unless admin? && active? !last_active_admin? end def can_be_destroyed? !last_active_admin? end def accessible_projects return Project.active.ordered if admin? Project.active.ordered .joins(:user_projects) .where(user_projects: { user_id: id, enabled: true }) end def can_access_project?(project) return true if admin? return false if project.nil? user_projects.exists?(project_id: project.id, enabled: true) end def enable_project!(project) up = user_projects.find_or_initialize_by(project: project) up.enabled = true up.save! end def disable_project!(project) up = user_projects.find_or_initialize_by(project: project) up.enabled = false up.save! end def project_enabled?(project) return true if admin? user_projects.exists?(project_id: project.id, enabled: true) end def generate_password_reset_token! update!( password_reset_token: SecureRandom.urlsafe_base64(32), password_reset_sent_at: Time.current ) end def password_reset_token_valid? password_reset_token.present? && password_reset_sent_at.present? && password_reset_sent_at > 2.hours.ago end def clear_password_reset_token! update!(password_reset_token: nil, password_reset_sent_at: nil) end private def normalize_email self.email = email.to_s.strip.downcase end def must_keep_at_least_one_active_admin return if new_record? was_active_admin = role_in_database == "admin" && active_in_database != false return unless was_active_admin deactivating = will_save_change_to_active? && !active? demoting = will_save_change_to_role? && role != "admin" return unless deactivating || demoting return if self.class.active_admins.where.not(id: id).exists? errors.add(:base, "Deve restare almeno un amministratore attivo. Crea o promuovi un altro admin prima.") end def prevent_destroying_last_admin return unless last_active_admin? errors.add(:base, "Non puoi eliminare l'unico amministratore attivo.") throw :abort end end