mirror of
https://github.com/karpathy/nanochat.git
synced 2026-06-17 03:29:09 +00:00
- Alembic async migrations: users, conversations, messages, is_favorited - FastAPI auth service: Google + GitHub OAuth, RS256 JWT, refresh cookie - /auth/me, /auth/refresh, /auth/validate (service-to-service) - rate limiting 10/min on OAuth routes, CORS locked to FRONTEND_URL Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
47 lines
1.3 KiB
Python
47 lines
1.3 KiB
Python
"""User profile routes (GET /auth/me, PUT /auth/me)."""
|
|
from __future__ import annotations
|
|
|
|
from fastapi import APIRouter, Depends
|
|
from pydantic import BaseModel, Field
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from ..database import get_session
|
|
from ..middleware.auth_middleware import AuthContext, require_user
|
|
from ..services import user_service
|
|
|
|
router = APIRouter(prefix="/auth", tags=["users"])
|
|
|
|
|
|
class UserProfile(BaseModel):
|
|
id: str
|
|
email: str
|
|
name: str | None
|
|
avatar_url: str | None
|
|
provider: str
|
|
provider_id: str
|
|
created_at: str | None
|
|
updated_at: str | None
|
|
last_login_at: str | None
|
|
|
|
|
|
class ProfileUpdate(BaseModel):
|
|
name: str | None = Field(default=None, max_length=255)
|
|
avatar_url: str | None = Field(default=None, max_length=2048)
|
|
|
|
|
|
@router.get("/me", response_model=UserProfile)
|
|
async def me(ctx: AuthContext = Depends(require_user)) -> UserProfile:
|
|
return UserProfile(**ctx.user.to_dict())
|
|
|
|
|
|
@router.put("/me", response_model=UserProfile)
|
|
async def update_me(
|
|
payload: ProfileUpdate,
|
|
ctx: AuthContext = Depends(require_user),
|
|
session: AsyncSession = Depends(get_session),
|
|
) -> UserProfile:
|
|
user = await user_service.update_profile(
|
|
session, ctx.user, name=payload.name, avatar_url=payload.avatar_url
|
|
)
|
|
return UserProfile(**user.to_dict())
|