Files
shaguabijia-app-server/app/api/v1/tasks.py
T
linkeyu 7bf04f2655 功能:新增风控监控与处置能力 (#174)
## 修改内容
- 新增短信、一键登录、比价三类风控事件与规则聚合
- 新增管理员忽略、封禁、解封、重置报警和阈值配置接口
- 风险列表返回当前有效限制的 restriction_id,供后台已封禁视图解除
- 在短信/一键登录、比价、任务领奖、提现链路接入风险记录与限制
- 新增通用行为流水、风险事件、主体限制模型及 Alembic 迁移
- 新增本地演示数据脚本与风控测试

## 验证
- ruff check:通过
- Alembic 全新 SQLite upgrade head / downgrade -1:通过
- 风控测试:通过,覆盖封禁列表 restriction_id 与解除链路
- 全量测试:532 passed,8 failed;其中 7 项在干净 origin/main 独立复现,另 1 项独立复跑通过,未发现本分支新增回归

---------

Co-authored-by: unknown <798648091@qq.com>
Reviewed-on: #174
Co-authored-by: linkeyu <linkeyu@wonderable.ai>
Co-committed-by: linkeyu <linkeyu@wonderable.ai>
2026-07-25 17:56:23 +08:00

56 lines
1.9 KiB
Python

"""一次性任务 endpoint。
路由前缀 `/api/v1/tasks`:
GET / 任务及领取状态(如"打开消息提醒")
POST /{task_key}/claim 领取任务奖励
"""
from __future__ import annotations
import logging
from fastapi import APIRouter, HTTPException, status
from app.api.deps import CurrentUser, DbSession
from app.repositories import risk as risk_repo
from app.repositories import task as crud_task
from app.schemas.welfare import TaskClaimResultOut, TaskListOut, TaskOut
logger = logging.getLogger("shagua.tasks")
router = APIRouter(prefix="/api/v1/tasks", tags=["tasks"])
@router.get("", response_model=TaskListOut, summary="任务及领取状态")
def list_tasks(user: CurrentUser, db: DbSession) -> TaskListOut:
states = crud_task.list_tasks(db, user.id)
return TaskListOut(
items=[
TaskOut(task_key=s.task_key, coin=s.coin, claimed=s.claimed)
for s in states
]
)
@router.post(
"/{task_key}/claim",
response_model=TaskClaimResultOut,
summary="领取任务奖励",
)
def claim_task(task_key: str, user: CurrentUser, db: DbSession) -> TaskClaimResultOut:
if risk_repo.is_restricted(
db,
subject_type="user",
subject_id=str(user.id),
scope=risk_repo.SCOPE_ECONOMIC_ACCOUNT,
):
raise HTTPException(status_code=403, detail="账号存在异常,该功能暂不可用")
try:
coin, balance = crud_task.claim_task(db, user.id, task_key)
except crud_task.UnknownTaskError as e:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="unknown task") from e
except crud_task.AlreadyClaimedError as e:
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="task already claimed") from e
logger.info("task claimed user_id=%d key=%s coin=%d", user.id, task_key, coin)
return TaskClaimResultOut(task_key=task_key, coin_awarded=coin, coin_balance=balance)