from datetime import datetime, timedelta, timezone from typing import Optional import bcrypt import jwt from fastapi import Depends, HTTPException, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from .config import get_settings from .database import get_db from .models import Admin security = HTTPBearer() def hash_password(password: str) -> str: return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode() def verify_password(password: str, hashed: str) -> bool: return bcrypt.checkpw(password.encode(), hashed.encode()) def create_token(admin_id: int, username: str) -> str: settings = get_settings() expire = datetime.now(timezone.utc) + timedelta(hours=settings.jwt_expire_hours) payload = {"sub": str(admin_id), "username": username, "exp": expire} return jwt.encode(payload, settings.jwt_secret, algorithm=settings.jwt_algorithm) def decode_token(token: str) -> Optional[dict]: settings = get_settings() try: return jwt.decode(token, settings.jwt_secret, algorithms=[settings.jwt_algorithm]) except jwt.PyJWTError: return None async def get_current_admin( credentials: HTTPAuthorizationCredentials = Depends(security), db: AsyncSession = Depends(get_db), ) -> Admin: payload = decode_token(credentials.credentials) if not payload: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token") admin_id = int(payload.get("sub", 0)) result = await db.execute(select(Admin).where(Admin.id == admin_id, Admin.is_active == True)) admin = result.scalar_one_or_none() if not admin: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Admin not found") return admin