feat: /signup returns access_token

This commit is contained in:
2026-09-04 21:21:20 +07:00
parent 27e2f58956
commit 429c961ace
4 changed files with 27 additions and 20 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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(

View File

@@ -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):