youtube-summarizer/backend/models/user.py

151 lines
5.2 KiB
Python

"""User model for authentication system."""
from sqlalchemy import Column, String, Boolean, DateTime, ForeignKey
from sqlalchemy.orm import relationship
import uuid
from datetime import datetime
from backend.core.database_registry import registry
from backend.models.base import Model
Base = registry.Base
class User(Model):
"""User model for authentication and authorization."""
__tablename__ = "users"
__table_args__ = {"extend_existing": True} # Allow redefinition during imports
# Primary key
id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
# User credentials
email = Column(String(255), unique=True, nullable=False, index=True)
password_hash = Column(String(255), nullable=False)
# User status
is_verified = Column(Boolean, default=False)
is_active = Column(Boolean, default=True)
# Timestamps
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
last_login = Column(DateTime)
# Relationships
refresh_tokens = relationship("backend.models.user.RefreshToken", back_populates="user", cascade="all, delete-orphan")
summaries = relationship("backend.models.summary.Summary", back_populates="user", cascade="all, delete-orphan")
api_keys = relationship("backend.models.user.APIKey", back_populates="user", cascade="all, delete-orphan")
batch_jobs = relationship("backend.models.batch_job.BatchJob", back_populates="user", cascade="all, delete-orphan")
# Enhanced export relationships (Story 4.4)
prompt_templates = relationship("backend.models.prompt_models.PromptTemplate", back_populates="user", cascade="all, delete-orphan")
def __repr__(self):
return f"<User(email='{self.email}', is_verified={self.is_verified})>"
class RefreshToken(Model):
"""Refresh token model for JWT authentication."""
__tablename__ = "refresh_tokens"
__table_args__ = {"extend_existing": True}
# Primary key
id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
# Foreign key to user
user_id = Column(String(36), ForeignKey("users.id"), nullable=False)
# Token data
token_hash = Column(String(255), unique=True, nullable=False, index=True)
expires_at = Column(DateTime, nullable=False)
revoked = Column(Boolean, default=False)
# Metadata
created_at = Column(DateTime, default=datetime.utcnow)
# Relationships
user = relationship("backend.models.user.User", back_populates="refresh_tokens")
def __repr__(self):
return f"<RefreshToken(user_id='{self.user_id}', expires_at={self.expires_at}, revoked={self.revoked})>"
class APIKey(Model):
"""API Key model for programmatic access."""
__tablename__ = "api_keys"
__table_args__ = {"extend_existing": True}
# Primary key
id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
# Foreign key to user
user_id = Column(String(36), ForeignKey("users.id"), nullable=False)
# Key data
name = Column(String(255), nullable=False)
key_hash = Column(String(255), unique=True, nullable=False, index=True)
last_used = Column(DateTime)
# Status
is_active = Column(Boolean, default=True)
expires_at = Column(DateTime)
# Metadata
created_at = Column(DateTime, default=datetime.utcnow)
# Relationships
user = relationship("backend.models.user.User", back_populates="api_keys")
def __repr__(self):
return f"<APIKey(name='{self.name}', user_id='{self.user_id}', is_active={self.is_active})>"
class EmailVerificationToken(Model):
"""Email verification token model."""
__tablename__ = "email_verification_tokens"
__table_args__ = {"extend_existing": True}
# Primary key
id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
# Foreign key to user
user_id = Column(String(36), ForeignKey("users.id"), nullable=False, unique=True)
# Token data
token_hash = Column(String(255), unique=True, nullable=False, index=True)
expires_at = Column(DateTime, nullable=False)
# Metadata
created_at = Column(DateTime, default=datetime.utcnow)
def __repr__(self):
return f"<EmailVerificationToken(user_id='{self.user_id}', expires_at={self.expires_at})>"
class PasswordResetToken(Model):
"""Password reset token model."""
__tablename__ = "password_reset_tokens"
__table_args__ = {"extend_existing": True}
# Primary key
id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
# Foreign key to user
user_id = Column(String(36), ForeignKey("users.id"), nullable=False)
# Token data
token_hash = Column(String(255), unique=True, nullable=False, index=True)
expires_at = Column(DateTime, nullable=False)
used = Column(Boolean, default=False)
# Metadata
created_at = Column(DateTime, default=datetime.utcnow)
def __repr__(self):
return f"<PasswordResetToken(user_id='{self.user_id}', expires_at={self.expires_at}, used={self.used})>"