from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from app.crud import crud_user from app.database import get_db from app.dependencies import get_admin, get_current_user from app.models.user import User from app.schemas.user import PushTokenUpdate, UserCreate, UserOut from app.services import notification_service router = APIRouter(prefix="/users", tags=["users"]) @router.get("", response_model=list[UserOut]) async def list_users( status: str | None = None, role: str | None = None, skip: int = 0, limit: int = 50, _admin: User = Depends(get_admin), db: AsyncSession = Depends(get_db), ): return await crud_user.list_all(db, status=status, role=role, skip=skip, limit=limit) @router.get("/{user_id}", response_model=UserOut) async def get_user( user_id: str, _admin: User = Depends(get_admin), db: AsyncSession = Depends(get_db), ): user = await crud_user.get(db, user_id) if not user: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) return user @router.post("", response_model=UserOut, status_code=status.HTTP_201_CREATED) async def create_user( body: UserCreate, _admin: User = Depends(get_admin), db: AsyncSession = Depends(get_db), ): if await crud_user.get_by_email(db, body.email): raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Email already registered") return await crud_user.create( db, email=body.email, password=body.password, full_name=body.full_name, phone=body.phone, role=body.role, status="approved", ) @router.patch("/{user_id}/approve", response_model=UserOut) async def approve_user( user_id: str, admin: User = Depends(get_admin), db: AsyncSession = Depends(get_db), ): user = await crud_user.get(db, user_id) if not user: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) user = await crud_user.set_status(db, user, "approved") await notification_service.send_push_notification( db=db, user=user, title="Welcome!", body="Your account has been approved. You can now access the app.", notif_type="account_approved", ) return user @router.patch("/{user_id}/reject", response_model=UserOut) async def reject_user( user_id: str, _admin: User = Depends(get_admin), db: AsyncSession = Depends(get_db), ): user = await crud_user.get(db, user_id) if not user: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) return await crud_user.set_status(db, user, "rejected") @router.patch("/{user_id}/push-token", status_code=status.HTTP_204_NO_CONTENT) async def update_push_token( user_id: str, body: PushTokenUpdate, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): if str(current_user.id) != user_id and current_user.role != "admin": raise HTTPException(status_code=status.HTTP_403_FORBIDDEN) user = await crud_user.get(db, user_id) if not user: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) await crud_user.set_push_token(db, user, body.expo_push_token)