From 429c961aceb02c10b7430057e739949faa777b9f Mon Sep 17 00:00:00 2001 From: hexdev Date: Fri, 4 Sep 2026 21:21:20 +0700 Subject: [PATCH] feat: /signup returns access_token --- routes/auth.py | 31 ++++++++++++++++++------------- schemas/login.py | 2 +- services/users.py | 6 +++--- tests/test_auth_routes.py | 8 +++++--- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/routes/auth.py b/routes/auth.py index e3e65a6..83a9f6c 100644 --- a/routes/auth.py +++ b/routes/auth.py @@ -1,5 +1,4 @@ from fastapi import APIRouter, Depends, HTTPException -from fastapi.responses import JSONResponse from core.secrets import ( estimate_password_strength, @@ -10,7 +9,7 @@ from core.secrets import ( from db.session import UnitOfWork, get_uow from repositories.sessions import SessionsRepository from repositories.users import UserRepository -from schemas.login import UserLogin, UserLoginData, UserTokens +from schemas.login import AuthenticatedUser, UserLoginData, UserTokens from schemas.providers import ProvidersType from schemas.registration import UserRegistration from schemas.user import UserInfo @@ -20,9 +19,10 @@ from services.users import authorize_user router = APIRouter(prefix="/auth") -@router.post("/signup") -async def signup(req: UserRegistration, uow: UnitOfWork = Depends(get_uow)): +@router.post("/signup", response_model=AuthenticatedUser) +async def signup(req: UserRegistration, uow: UnitOfWork = Depends(get_uow)) -> AuthenticatedUser: users_repo = UserRepository(uow) + sessions_repo = SessionsRepository(uow) if req.provider == "credentials": if not req.username or not req.password: @@ -44,19 +44,24 @@ async def signup(req: UserRegistration, uow: UnitOfWork = Depends(get_uow)): username=req.username, hashed_password=password_hash, referal_id=referal_id ) await uow.commit() - return JSONResponse( - UserInfo( - username=user.username, - telegram_id=user.telegram_id, - referal_code=user.referal_code, - bonus_balance=user.balance, - ).model_dump(), - status_code=201, + + info = UserInfo( + username=user.username, + telegram_id=user.telegram_id, + referal_code=user.referal_code, + bonus_balance=user.balance, + ) + user_login = await authorize_user(sessions_repo, user, req.provider) + return AuthenticatedUser( + access_token=user_login.access_token, + refresh_token=user_login.refresh_token, + expires_at=user_login.expires_at, + user=info, ) raise HTTPException(status_code=400, detail="Unsupported provider") -@router.post("/login", response_model=UserLogin) +@router.post("/login", response_model=AuthenticatedUser) async def login(req: UserLoginData, uow: UnitOfWork = Depends(get_uow)): users_repo = UserRepository(uow) sessions_repo = SessionsRepository(uow) diff --git a/schemas/login.py b/schemas/login.py index df76fae..faff64d 100644 --- a/schemas/login.py +++ b/schemas/login.py @@ -16,7 +16,7 @@ class UserLoginData(BaseModel): telegram: TelegramData | None = None -class UserLogin(BaseModel): +class AuthenticatedUser(BaseModel): access_token: str refresh_token: str expires_at: float diff --git a/services/users.py b/services/users.py index 6b6c152..e08db1d 100644 --- a/services/users.py +++ b/services/users.py @@ -1,21 +1,21 @@ from core.secrets import generate_pair, hash_refresh_token from db.models.users import User from repositories.sessions import SessionsRepository -from schemas.login import UserLogin +from schemas.login import AuthenticatedUser from schemas.providers import ProvidersType from schemas.user import UserInfo async def authorize_user( sessions_repo: SessionsRepository, user: User, iss: ProvidersType -) -> UserLogin: +) -> AuthenticatedUser: key_pair = generate_pair(user.id, iss) refresh_token_hash = hash_refresh_token(key_pair.refresh_token) await sessions_repo.create(user_id=user.id, refresh_token_hash=refresh_token_hash, iss=iss) - return UserLogin( + return AuthenticatedUser( access_token=key_pair.access_token, refresh_token=key_pair.refresh_token, user=UserInfo( diff --git a/tests/test_auth_routes.py b/tests/test_auth_routes.py index 5272924..f886407 100644 --- a/tests/test_auth_routes.py +++ b/tests/test_auth_routes.py @@ -49,15 +49,17 @@ def test_signup_rejects_weak_password(client): def test_signup_accepts_unknown_referral_code(client): created_user = SimpleNamespace( - username="alice", telegram_id=None, referal_code="new-code", balance=0 + id=1, username="alice", telegram_id=None, referal_code="new-code", balance=0 ) repository = SimpleNamespace( get_user_by_username=AsyncMock(return_value=None), get_user_by_ref_code=AsyncMock(return_value=None), create=AsyncMock(return_value=created_user), ) + sessions_repository = SimpleNamespace(create=AsyncMock(return_value=None)) with ( patch("routes.auth.UserRepository", return_value=repository), + patch("routes.auth.SessionsRepository", return_value=sessions_repository), patch("routes.auth.estimate_password_strength", return_value=True), patch("routes.auth.hash_password", return_value="hashed"), ): @@ -71,11 +73,11 @@ def test_signup_accepts_unknown_referral_code(client): }, ) - assert response.status_code == 201 + assert response.status_code == 200 repository.create.assert_awaited_once_with( username="alice", hashed_password="hashed", referal_id=None ) - assert response.json()["referal_code"] == "new-code" + assert response.json()["user"]["referal_code"] == "new-code" def test_login_distinguishes_unknown_user_and_bad_password(client):