import hashlib from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy import text from sqlalchemy.orm import Session try: # For module mode: `uvicorn app.main:app` from app.db import get_db from app.schemas.auth import LoginRequest, LoginResponse from app.security import create_access_token except ModuleNotFoundError: # For script mode: `python app/main.py` or VS Code "Run Python File" from db import get_db from schemas.auth import LoginRequest, LoginResponse from security import create_access_token router = APIRouter(prefix="/auth", tags=["auth"]) @router.post("/login", response_model=LoginResponse) def login(payload: LoginRequest, db: Session = Depends(get_db)) -> LoginResponse: with db.begin(): row = ( db.execute( text( """ SELECT ua.id AS user_auth_id, ua.user_id, ua.password_hash, ua.status AS auth_status, u.status AS user_status FROM chat_user_auth ua JOIN chat_user u ON u.id = ua.user_id WHERE ua.auth_type = 6 AND ua.auth_identifier = :username LIMIT 1 """ ), {"username": payload.username}, ) .mappings() .first() ) if not row: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="invalid username or password", ) if int(row["auth_status"]) != 1 or int(row["user_status"]) != 1: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="account is disabled", ) # Seed data currently stores sha256; migrate to bcrypt/argon2 in production. password_hash = hashlib.sha256(payload.password.encode("utf-8")).hexdigest() if not row["password_hash"] or password_hash != row["password_hash"]: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="invalid username or password", ) db.execute( text( """ UPDATE chat_user_auth SET last_login_at = CURRENT_TIMESTAMP(3), updated_at = CURRENT_TIMESTAMP(3) WHERE id = :user_auth_id """ ), {"user_auth_id": int(row["user_auth_id"])}, ) db.execute( text( """ UPDATE chat_user SET last_login_at = CURRENT_TIMESTAMP(3), updated_at = CURRENT_TIMESTAMP(3) WHERE id = :user_id """ ), {"user_id": int(row["user_id"])}, ) access_token, expires_in = create_access_token(user_id=int(row["user_id"])) return LoginResponse( access_token=access_token, expires_in=expires_in, user_id=int(row["user_id"]), )