from datetime import date from typing import Optional from sqlalchemy import Column, Integer, String, Boolean, DateTime, Date, func from sqlalchemy.dialects.postgresql import ENUM from sqlalchemy.orm import relationship import enum from app.database import Base class UserRole(str, enum.Enum): """User role for moderation and access control.""" USER = "user" MODERATOR = "moderator" ADMIN = "admin" class User(Base): __tablename__ = "users" id = Column(Integer, primary_key=True, index=True) username = Column(String(50), unique=True, index=True, nullable=False) email = Column(String(120), unique=True, index=True, nullable=False) hashed_password = Column(String(255), nullable=False) date_of_birth = Column(Date, nullable=True) is_active = Column(Boolean, default=True) role = Column( ENUM(UserRole, name="user_role", create_type=False), default=UserRole.USER, nullable=False, ) banned_until = Column(DateTime(timezone=True), nullable=True) suspended_until = Column(DateTime(timezone=True), nullable=True) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) sessions = relationship("Session", back_populates="user", cascade="all, delete-orphan") worlds = relationship("World", back_populates="owner") assets = relationship("Asset", back_populates="owner") @property def is_adult(self) -> bool: """Return True if the user is 18 or older based on date_of_birth.""" if self.date_of_birth is None: return False today = date.today() age = today.year - self.date_of_birth.year # Adjust if birthday hasn't occurred yet this year if (today.month, today.day) < (self.date_of_birth.month, self.date_of_birth.day): age -= 1 return age >= 18