Initial commit: site monorepo with API, web, and infra.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user