"""看激励视频观看时长 CRUD(旧版每日总时长字段)。 前端 onAdClose 上报本次观看秒数 → add_watch_seconds 落库 + 返回当日累计; 当前产品只保留每日 500 次上限,DAILY_AD_WATCH_SECONDS_LIMIT=0 时不再用本累计做发奖拦截。 鉴权接口已确保 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)