"""看激励视频观看时长 CRUD(每日总时长防刷)。 前端 onAdClose 上报本次观看秒数 → add_watch_seconds 落库 + 返回当日累计; watched_seconds_today 给"时长闸"(发奖 / 展示前)判断当天是否已达 50 分钟上限。 鉴权接口已确保 user 存在(JWT),故不做 UnknownUser 校验。 """ from __future__ import annotations from sqlalchemy import func, select from sqlalchemy.orm import Session from app.core.rewards import MAX_SINGLE_WATCH_SECONDS, cn_today from app.models.ad_watch_log import AdWatchLog def watched_seconds_today(db: Session, user_id: int, *, today: str | None = None) -> int: """该用户今日(北京时间)累计观看秒数。coalesce 防无记录时 SUM 返 None。""" d = today or cn_today().isoformat() return db.execute( select(func.coalesce(func.sum(AdWatchLog.watch_seconds), 0)).where( AdWatchLog.user_id == user_id, AdWatchLog.watch_date == d, ) ).scalar_one() def add_watch_seconds(db: Session, user_id: int, seconds: int) -> int: """记一次观看时长,返回当日累计秒数。 seconds 夹 [0, MAX_SINGLE_WATCH_SECONDS] 防前端报异常大值(刷时长无意义,但夹紧更稳)。 """ clamped = max(0, min(int(seconds), MAX_SINGLE_WATCH_SECONDS)) today = cn_today().isoformat() db.add(AdWatchLog(user_id=user_id, watch_seconds=clamped, watch_date=today)) db.commit() return watched_seconds_today(db, user_id, today=today)