import bcrypt from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from database import get_db from models.user import User from schemas.auth import LoginRequest, TokenResponse from pydantic import BaseModel as _PydanticBase class LoginByIdRequest(_PydanticBase): waiter_id: int pin: str from schemas.user import UserOut from routers.deps import get_current_user, make_token, decode_token, blacklist_token router = APIRouter() @router.post("/login", response_model=TokenResponse) def login(body: LoginRequest, db: Session = Depends(get_db)): user = db.query(User).filter(User.username == body.username, User.is_active == True).first() if not user or not bcrypt.checkpw(body.pin.encode(), user.pin_hash.encode()): raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials") token = make_token(user) return TokenResponse(access_token=token, user=UserOut.model_validate(user)) @router.post("/login-by-id", response_model=TokenResponse) def login_by_id(body: LoginByIdRequest, db: Session = Depends(get_db)): """Login using waiter id + PIN (used by the waiter-picker login screen).""" user = db.query(User).filter(User.id == body.waiter_id, User.is_active == True).first() if not user or not bcrypt.checkpw(body.pin.encode(), user.pin_hash.encode()): raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Λανθασμένο PIN") token = make_token(user) return TokenResponse(access_token=token, user=UserOut.model_validate(user)) @router.post("/refresh", response_model=TokenResponse) def refresh(token: str, db: Session = Depends(get_db)): payload = decode_token(token) user = db.query(User).filter(User.id == int(payload["sub"]), User.is_active == True).first() if not user: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found") blacklist_token(token) new_token = make_token(user) return TokenResponse(access_token=new_token, user=UserOut.model_validate(user)) @router.post("/logout") def logout(token: str): blacklist_token(token) return {"status": "logged out"} @router.get("/me", response_model=UserOut) def me(user: User = Depends(get_current_user)): return user # ─── Public waiter list (login screen — no auth required) ──────────────────── from pydantic import BaseModel as _BaseModel class PublicWaiterOut(_BaseModel): id: int full_name: str | None nickname: str | None avatar_url: str | None on_shift: bool model_config = {"from_attributes": True} @router.get("/waiters", response_model=list[PublicWaiterOut]) def public_waiter_list(db: Session = Depends(get_db)): """Public endpoint — returns active waiters with on-shift flag. No auth required.""" from models.shift import WaiterShift waiters = db.query(User).filter(User.role == "waiter", User.is_active == True).all() on_shift_ids = { row.waiter_id for row in db.query(WaiterShift).filter(WaiterShift.ended_at == None).all() } return [ PublicWaiterOut( id=w.id, full_name=w.full_name, nickname=w.nickname, avatar_url=w.avatar_url, on_shift=w.id in on_shift_ids, ) for w in waiters ]