60 lines
2.0 KiB
Python
60 lines
2.0 KiB
Python
from fastapi import APIRouter, Depends, File, HTTPException, Request, UploadFile
|
|
|
|
from app.core.dependencies import get_current_user
|
|
from app.core.media_signing import build_signed_media_url
|
|
from app.core.redis import check_rate_limit
|
|
from app.modules.media.service import AvatarValidationError
|
|
from app.modules.users.schemas import PasswordChangeIn, UserPatchIn
|
|
from app.modules.users.service import change_password, get_me, update_me, upload_avatar
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
def _profile_response(data: dict) -> dict:
|
|
return {
|
|
"user": {
|
|
"id": data["user"].id,
|
|
"email": data["user"].email,
|
|
"role": data["user"].role,
|
|
"status": data["user"].status,
|
|
},
|
|
"profile": {
|
|
"display_name": data["profile"].display_name,
|
|
"avatar_url": build_signed_media_url(data["profile"].avatar_url),
|
|
},
|
|
}
|
|
|
|
|
|
@router.get("/me")
|
|
async def me_route(current_user=Depends(get_current_user)):
|
|
return _profile_response(get_me(current_user))
|
|
|
|
|
|
@router.patch("/me")
|
|
async def patch_me_route(payload: UserPatchIn, current_user=Depends(get_current_user)):
|
|
return _profile_response(update_me(current_user, payload.display_name))
|
|
|
|
|
|
@router.post("/me/password")
|
|
async def change_password_route(payload: PasswordChangeIn, current_user=Depends(get_current_user)):
|
|
try:
|
|
change_password(current_user, payload.current_password, payload.new_password)
|
|
except ValueError:
|
|
raise HTTPException(status_code=400, detail="INVALID_CURRENT_PASSWORD")
|
|
return {"message": "password_changed"}
|
|
|
|
|
|
@router.post("/me/avatar")
|
|
async def upload_avatar_route(
|
|
request: Request,
|
|
file: UploadFile = File(...),
|
|
current_user=Depends(get_current_user),
|
|
):
|
|
check_rate_limit(f"avatar:{current_user.id}", limit=10, window_seconds=3600)
|
|
content = await file.read()
|
|
try:
|
|
data = upload_avatar(current_user, content)
|
|
except AvatarValidationError as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc))
|
|
return _profile_response(data)
|