"""签到 endpoint。 路由前缀 `/api/v1/signin`: GET /status 今日签到状态 + 14 天档位 POST / 执行今日签到 POST /boost 签到后看广告膨胀金币 """ from __future__ import annotations import logging from fastapi import APIRouter, HTTPException, status from app.api.deps import CurrentUser, DbSession from app.repositories import ad_reward as crud_ad from app.repositories import signin as crud_signin from app.repositories import wallet as crud_wallet from app.schemas.welfare import ( SigninBoostRequest, SigninBoostResultOut, SigninResultOut, SigninStatusOut, ) logger = logging.getLogger("shagua.signin") router = APIRouter(prefix="/api/v1/signin", tags=["signin"]) @router.get("/status", response_model=SigninStatusOut, summary="今日签到状态") def signin_status(user: CurrentUser, db: DbSession) -> SigninStatusOut: st = crud_signin.get_status(db, user.id) return SigninStatusOut.model_validate(st, from_attributes=True) @router.post("", response_model=SigninResultOut, summary="执行今日签到") def do_signin(user: CurrentUser, db: DbSession) -> SigninResultOut: try: record, balance = crud_signin.do_signin(db, user.id) except crud_signin.AlreadySignedError as e: raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="already signed today") from e logger.info( "signin ok user_id=%d day=%d streak=%d coin=%d", user.id, record.cycle_day, record.streak, record.coin_awarded, ) return SigninResultOut( coin_awarded=record.coin_awarded, cycle_day=record.cycle_day, streak=record.streak, coin_balance=balance, ) @router.post("/boost", response_model=SigninBoostResultOut, summary="签到后看广告膨胀金币") def boost_signin( payload: SigninBoostRequest, user: CurrentUser, db: DbSession ) -> SigninBoostResultOut: if not payload.ad_ref_id: raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="ad reward required") ad_rec = crud_ad.find_by_trans(db, payload.ad_ref_id) if ( ad_rec is None or ad_rec.user_id != user.id or ad_rec.reward_scene != "signin_boost" or ad_rec.status != "granted" ): raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="ad reward not verified") record = crud_signin.boost_by_ad_ref(db, user.id, payload.ad_ref_id) if record is None: raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="signin boost not granted") acc = crud_wallet.get_or_create_account(db, user.id) balance = acc.coin_balance logger.info( "signin boost ok user_id=%d date=%s coin=%d", user.id, record.signin_date, record.coin_awarded, ) return SigninBoostResultOut( coin_awarded=record.coin_awarded, coin_balance=balance, signin_date=record.signin_date.isoformat(), )