LocalMate / app /users /router.py
Cuong2004's picture
add user endpoint + image handling
d7a7993
"""User Profile Router."""
from fastapi import APIRouter, HTTPException, Depends, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import text
from app.shared.db.session import get_db
from app.users import Profile, ProfileUpdate, ProfileResponse
router = APIRouter(prefix="/users", tags=["Users"])
@router.get(
"/me",
response_model=ProfileResponse,
summary="Get current user profile",
description="Returns the profile for the authenticated user.",
)
async def get_my_profile(
user_id: str = Query(..., description="User ID (from auth)"),
db: AsyncSession = Depends(get_db),
) -> ProfileResponse:
"""Get current user's profile."""
result = await db.execute(
text("""
SELECT id, full_name, phone, role, locale, avatar_url, created_at, updated_at
FROM profiles
WHERE id = :user_id
"""),
{"user_id": user_id}
)
row = result.fetchone()
if not row:
raise HTTPException(status_code=404, detail="Profile not found")
profile = Profile(
id=str(row.id),
full_name=row.full_name,
phone=row.phone,
role=row.role,
locale=row.locale,
avatar_url=row.avatar_url,
created_at=row.created_at,
updated_at=row.updated_at,
)
return ProfileResponse(profile=profile, message="Profile retrieved")
@router.put(
"/me",
response_model=ProfileResponse,
summary="Update current user profile",
description="Updates the profile for the authenticated user.",
)
async def update_my_profile(
updates: ProfileUpdate,
user_id: str = Query(..., description="User ID (from auth)"),
db: AsyncSession = Depends(get_db),
) -> ProfileResponse:
"""Update current user's profile."""
# Build dynamic update query
update_fields = []
params = {"user_id": user_id}
if updates.full_name is not None:
update_fields.append("full_name = :full_name")
params["full_name"] = updates.full_name
if updates.phone is not None:
update_fields.append("phone = :phone")
params["phone"] = updates.phone
if updates.locale is not None:
update_fields.append("locale = :locale")
params["locale"] = updates.locale
if updates.avatar_url is not None:
update_fields.append("avatar_url = :avatar_url")
params["avatar_url"] = updates.avatar_url
if not update_fields:
raise HTTPException(status_code=400, detail="No fields to update")
update_fields.append("updated_at = NOW()")
query = f"""
UPDATE profiles
SET {', '.join(update_fields)}
WHERE id = :user_id
RETURNING id, full_name, phone, role, locale, avatar_url, created_at, updated_at
"""
result = await db.execute(text(query), params)
await db.commit()
row = result.fetchone()
if not row:
raise HTTPException(status_code=404, detail="Profile not found")
profile = Profile(
id=str(row.id),
full_name=row.full_name,
phone=row.phone,
role=row.role,
locale=row.locale,
avatar_url=row.avatar_url,
created_at=row.created_at,
updated_at=row.updated_at,
)
return ProfileResponse(profile=profile, message="Profile updated")
@router.get(
"/{user_id}",
response_model=ProfileResponse,
summary="Get user profile by ID",
description="Returns the profile for a specific user (admin only).",
)
async def get_profile_by_id(
user_id: str,
db: AsyncSession = Depends(get_db),
) -> ProfileResponse:
"""Get user profile by ID."""
result = await db.execute(
text("""
SELECT id, full_name, phone, role, locale, avatar_url, created_at, updated_at
FROM profiles
WHERE id = :user_id
"""),
{"user_id": user_id}
)
row = result.fetchone()
if not row:
raise HTTPException(status_code=404, detail="Profile not found")
profile = Profile(
id=str(row.id),
full_name=row.full_name,
phone=row.phone,
role=row.role,
locale=row.locale,
avatar_url=row.avatar_url,
created_at=row.created_at,
updated_at=row.updated_at,
)
return ProfileResponse(profile=profile, message="Profile retrieved")