forge/backend/app/models/user.py
DJP 7a804e896d Initial commit - FORGE AI unified platform
Features:
- Image generation (OpenAI, Gemini, Leonardo, Bria, Stability, Flux)
- Nano Banana iterative editing
- Video generation and upscaling
- Audio TTS, STT, sound effects (ElevenLabs)
- Text prompt studio and alt text
- User authentication with JWT/cookies
- Admin panel with voice management
- Job queue with Celery
- PostgreSQL + Redis backend
- Next.js 15 + FastAPI architecture

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2025-12-09 20:39:00 -05:00

48 lines
2 KiB
Python

"""User Model"""
from sqlalchemy import Column, String, Boolean, DateTime
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
import uuid
from passlib.context import CryptContext
from app.database import Base
# Configure bcrypt password hashing
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
class User(Base):
__tablename__ = "users"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
azure_oid = Column(String(255), unique=True, nullable=True)
email = Column(String(255), unique=True, nullable=False)
hashed_password = Column(String(255), nullable=True) # Nullable for SSO users
display_name = Column(String(255))
avatar_url = Column(String)
role = Column(String(50), default="user")
department = Column(String(255))
is_active = Column(Boolean, default=True)
last_login_at = Column(DateTime(timezone=True))
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
def verify_password(self, password: str) -> bool:
"""Verify a password against the hash"""
if not self.hashed_password:
return False
# Truncate to 72 bytes for bcrypt compatibility
password_bytes = password.encode('utf-8')[:72].decode('utf-8', errors='ignore')
return pwd_context.verify(password_bytes, self.hashed_password)
@staticmethod
def hash_password(password: str) -> str:
"""Hash a password (truncate to 72 bytes for bcrypt compatibility)"""
# bcrypt has a 72-byte limit on passwords
password_bytes = password.encode('utf-8')[:72].decode('utf-8', errors='ignore')
return pwd_context.hash(password_bytes)
# Relationships
projects = relationship("Project", back_populates="user")
assets = relationship("Asset", back_populates="user")
jobs = relationship("Job", back_populates="user")