feat(points): P2 step 3 - 注册送50积分 #1945
@@ -13,7 +13,7 @@ from typing import Optional
|
||||
import jwt
|
||||
from app.auth import AuthenticatedUser, blacklist_token, get_current_user
|
||||
from app.config import settings
|
||||
from app.dependencies import get_auth_email_service, get_auth_session_store, get_user_repository
|
||||
from app.dependencies import get_auth_email_service, get_auth_session_store, get_db_session, get_user_repository
|
||||
from fastapi import APIRouter, Depends, Header, HTTPException, Request, status
|
||||
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||
from pydantic import BaseModel, EmailStr, field_validator
|
||||
@@ -126,6 +126,7 @@ async def register(
|
||||
request: RegisterRequest,
|
||||
user_repository: UserRepository = Depends(get_user_repository),
|
||||
email_service=Depends(get_auth_email_service),
|
||||
db=Depends(get_db_session),
|
||||
) -> RegisterResponse:
|
||||
use_case = RegisterUserUseCase(
|
||||
user_repository=user_repository,
|
||||
@@ -143,6 +144,22 @@ async def register(
|
||||
if error or response is None:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=_translate_auth_error(error))
|
||||
|
||||
# 新用户注册赠送 50 积分(失败不影响注册)
|
||||
if settings.points_enabled:
|
||||
try:
|
||||
from packages.domain.points_service import PointsService
|
||||
_svc = PointsService()
|
||||
_svc.add_points(
|
||||
user_id=response.user_id,
|
||||
amount=50,
|
||||
source="task_reward",
|
||||
db=db,
|
||||
description="新用户注册赠送",
|
||||
)
|
||||
except Exception as _bonus_err:
|
||||
import logging
|
||||
logging.getLogger(__name__).warning("注册送积分失败: user_id=%s err=%s", response.user_id, _bonus_err)
|
||||
|
||||
return RegisterResponse(
|
||||
user_id=response.user_id,
|
||||
email=response.email,
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
"""注册送积分单元测试 (#1895 P2 step 3)"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_settings(monkeypatch):
|
||||
"""默认关闭 points_enabled,不影响现有用例。"""
|
||||
from app.config import settings
|
||||
|
||||
monkeypatch.setattr(settings, "points_enabled", False)
|
||||
return settings
|
||||
|
||||
|
||||
class TestRegisterBonusPoints:
|
||||
@pytest.mark.asyncio
|
||||
async def test_bonus_when_enabled(self, mock_settings):
|
||||
"""开启积分时注册成功送50分。"""
|
||||
from app.api.routes import auth
|
||||
from app.api.routes.auth import RegisterRequest
|
||||
|
||||
mock_settings.points_enabled = True
|
||||
|
||||
mock_uc = MagicMock()
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.user_id = "new-user-1"
|
||||
mock_resp.email = "n***@example.com"
|
||||
mock_resp.username = "newuser"
|
||||
mock_resp.display_name = "New User"
|
||||
mock_uc.execute.return_value = (mock_resp, None)
|
||||
|
||||
mock_svc = MagicMock()
|
||||
|
||||
def _mock_uc_cls(*args, **kwargs):
|
||||
return mock_uc
|
||||
|
||||
db = MagicMock()
|
||||
|
||||
with (
|
||||
patch("app.api.routes.auth.RegisterUserUseCase", side_effect=_mock_uc_cls),
|
||||
patch("packages.domain.points_service.PointsService", return_value=mock_svc),
|
||||
):
|
||||
req = RegisterRequest(email="n***@example.com", password="Secret123!", username="newuser")
|
||||
resp = await auth.register(request=req, user_repository=MagicMock(), email_service=MagicMock(), db=db)
|
||||
assert resp.user_id == "new-user-1"
|
||||
mock_svc.add_points.assert_called_once()
|
||||
call_kwargs = mock_svc.add_points.call_args.kwargs
|
||||
assert call_kwargs["user_id"] == "new-user-1"
|
||||
assert call_kwargs["amount"] == 50
|
||||
assert call_kwargs["source"] == "task_reward"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_no_bonus_when_disabled(self, mock_settings):
|
||||
"""关闭积分时不送分。"""
|
||||
from app.api.routes import auth
|
||||
from app.api.routes.auth import RegisterRequest
|
||||
|
||||
mock_uc = MagicMock()
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.user_id = "new-user-2"
|
||||
mock_resp.email = "n***@example.com"
|
||||
mock_resp.username = "newuser2"
|
||||
mock_resp.display_name = "New User 2"
|
||||
mock_uc.execute.return_value = (mock_resp, None)
|
||||
|
||||
def _mock_uc_cls(*args, **kwargs):
|
||||
return mock_uc
|
||||
|
||||
db = MagicMock()
|
||||
with (
|
||||
patch("app.api.routes.auth.RegisterUserUseCase", side_effect=_mock_uc_cls),
|
||||
patch("packages.domain.points_service.PointsService") as MockSvc,
|
||||
):
|
||||
req = RegisterRequest(email="n***@example.com", password="Secret123!", username="newuser2")
|
||||
resp = await auth.register(request=req, user_repository=MagicMock(), email_service=MagicMock(), db=db)
|
||||
MockSvc.assert_not_called()
|
||||
assert resp.user_id == "new-user-2"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_bonus_failure_does_not_break_register(self, mock_settings):
|
||||
"""送积分失败不应影响注册流程。"""
|
||||
from app.api.routes import auth
|
||||
from app.api.routes.auth import RegisterRequest
|
||||
|
||||
mock_settings.points_enabled = True
|
||||
mock_uc = MagicMock()
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.user_id = "new-user-3"
|
||||
mock_resp.email = "n***@example.com"
|
||||
mock_resp.username = "newuser3"
|
||||
mock_resp.display_name = "New User 3"
|
||||
mock_uc.execute.return_value = (mock_resp, None)
|
||||
|
||||
mock_svc = MagicMock()
|
||||
mock_svc.add_points.side_effect = Exception("DB error")
|
||||
|
||||
def _mock_uc_cls(*args, **kwargs):
|
||||
return mock_uc
|
||||
|
||||
db = MagicMock()
|
||||
with (
|
||||
patch("app.api.routes.auth.RegisterUserUseCase", side_effect=_mock_uc_cls),
|
||||
patch("packages.domain.points_service.PointsService", return_value=mock_svc),
|
||||
):
|
||||
req = RegisterRequest(email="n***@example.com", password="Secret123!", username="newuser3")
|
||||
resp = await auth.register(request=req, user_repository=MagicMock(), email_service=MagicMock(), db=db)
|
||||
assert resp.user_id == "new-user-3"
|
||||
@@ -19,6 +19,13 @@ from packages.application.generation_tasks import (
|
||||
from packages.domain import GenerationTask
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _disable_points_gate(monkeypatch):
|
||||
"""默认关闭积分闸门,避免影响既有用例。"""
|
||||
monkeypatch.setattr(_pg_module, "_points_gate_enabled", lambda: False)
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _disable_points_gate(monkeypatch):
|
||||
"""默认关闭积分闸门,避免影响既有用例。"""
|
||||
|
||||
Reference in New Issue
Block a user