| """ |
| User model for email/password authentication. |
| |
| No OAuth. No plaintext passwords — only Werkzeug password hashes are stored. |
| """ |
|
|
| from datetime import datetime |
|
|
| from werkzeug.security import generate_password_hash, check_password_hash |
|
|
| from auth.db import db |
|
|
|
|
| class User(db.Model): |
| __tablename__ = "users" |
|
|
| id = db.Column(db.Integer, primary_key=True) |
| email = db.Column(db.String(255), unique=True, nullable=False, index=True) |
| password_hash = db.Column(db.String(255), nullable=False) |
| created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False) |
|
|
| |
| chat_sessions = db.relationship( |
| "ChatSession", backref="user", lazy=True, cascade="all, delete-orphan" |
| ) |
|
|
| def set_password(self, raw_password: str) -> None: |
| self.password_hash = generate_password_hash(raw_password) |
|
|
| def check_password(self, raw_password: str) -> bool: |
| return check_password_hash(self.password_hash, raw_password) |
|
|
| def to_dict(self) -> dict: |
| return { |
| "id": self.id, |
| "email": self.email, |
| "created_at": self.created_at.isoformat(), |
| } |
|
|
| def __repr__(self) -> str: |
| return f"<User id={self.id} email={self.email}>" |
|
|