feat: /signup returns access_token
This commit is contained in:
@@ -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(
|
||||
|
||||
info = UserInfo(
|
||||
username=user.username,
|
||||
telegram_id=user.telegram_id,
|
||||
referal_code=user.referal_code,
|
||||
bonus_balance=user.balance,
|
||||
).model_dump(),
|
||||
status_code=201,
|
||||
)
|
||||
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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user