"""User model. Argon2 password hashing, role/trust fields, Flask-Login mixin.""" from datetime import datetime from app.utils.time import utcnow from flask_login import UserMixin from app.extensions import db from app.models.enums import Role, UserStatus, TrustTier from app.utils.security import hash_password, verify_password class User(UserMixin, db.Model): __tablename__ = "users" id = db.Column(db.BigInteger().with_variant(db.Integer, "sqlite"), primary_key=True, autoincrement=True) email = db.Column(db.String(255), unique=True, nullable=False, index=True) password_hash = db.Column(db.String(255), nullable=False) display_name = db.Column(db.String(80), nullable=False) role = db.Column(db.Enum(Role), nullable=False, default=Role.free) status = db.Column(db.Enum(UserStatus), nullable=False, default=UserStatus.active) locale = db.Column(db.String(5), nullable=False, default="en") tier_id = db.Column(db.BigInteger, db.ForeignKey("plans.id"), nullable=True) tier = db.relationship("Plan", back_populates="users") trust_score = db.Column(db.Integer, nullable=False, default=0) trust_tier = db.Column(db.Enum(TrustTier), nullable=False, default=TrustTier.new) verified = db.Column(db.Boolean, nullable=False, default=False) # identity/badge email_verified = db.Column(db.Boolean, nullable=False, default=False) last_login_at = db.Column(db.DateTime, nullable=True) created_at = db.Column(db.DateTime, default=utcnow, nullable=False) updated_at = db.Column(db.DateTime, default=utcnow, onupdate=utcnow, nullable=False) trust_events = db.relationship("TrustEvent", back_populates="user", lazy="dynamic", cascade="all, delete-orphan") # --- password --- def set_password(self, raw): self.password_hash = hash_password(raw) def check_password(self, raw): return verify_password(self.password_hash, raw) # --- RBAC helpers --- @property def is_admin(self): return self.role == Role.admin @property def is_moderator(self): return self.role in (Role.moderator, Role.admin) @property def is_subscriber(self): return self.role == Role.subscriber def has_role(self, *roles): return self.role in roles @property def is_active(self): # Flask-Login uses this to permit login. return self.status == UserStatus.active def __repr__(self): return f""