Files
PolyWeather/scripts/check_weekly_reward_status.py
T

194 lines
6.4 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
from __future__ import annotations
import argparse
import os
import sqlite3
from datetime import datetime, timedelta, timezone
from typing import Optional
try:
from zoneinfo import ZoneInfo
except Exception:
ZoneInfo = None # type: ignore[assignment]
def compute_target_week_key(
now_local: datetime,
settle_weekday: int,
settle_hour: int,
settle_minute: int,
) -> str:
week_start = (now_local - timedelta(days=now_local.isoweekday() - 1)).replace(
hour=0,
minute=0,
second=0,
microsecond=0,
)
settle_dt = week_start + timedelta(days=settle_weekday - 1)
settle_dt = settle_dt.replace(
hour=settle_hour,
minute=settle_minute,
second=0,
microsecond=0,
)
ref = now_local - timedelta(days=7 if now_local >= settle_dt else 14)
iso_year, iso_week, _ = ref.isocalendar()
return f"{iso_year}-W{iso_week:02d}"
def resolve_tz(tz_name: str):
if ZoneInfo is None:
return timezone(timedelta(hours=8)), "UTC+08:00"
try:
return ZoneInfo(tz_name), tz_name
except Exception:
return ZoneInfo("Asia/Shanghai"), "Asia/Shanghai"
def get_candidates(conn: sqlite3.Connection, week_key: str, limit: int):
conn.row_factory = sqlite3.Row
rows = conn.execute(
"""
SELECT *
FROM (
SELECT
u.telegram_id,
u.username,
lower(trim(COALESCE(u.supabase_user_id, ''))) AS supabase_user_id,
COALESCE(u.points, 0) AS points,
COALESCE(u.message_count, 0) AS message_count,
COALESCE(a.points,
CASE
WHEN u.weekly_points_week = ? THEN COALESCE(u.weekly_points, 0)
ELSE 0
END
) AS weekly_points
FROM users u
LEFT JOIN weekly_points_archive a
ON a.telegram_id = u.telegram_id
AND a.week_key = ?
) ranked
WHERE weekly_points > 0
ORDER BY weekly_points DESC, points DESC, message_count DESC, telegram_id ASC
LIMIT ?
""",
(week_key, week_key, max(1, int(limit))),
).fetchall()
return [dict(r) for r in rows]
def get_settle_run(conn: sqlite3.Connection, week_key: str) -> Optional[sqlite3.Row]:
conn.row_factory = sqlite3.Row
return conn.execute(
"""
SELECT week_key, settled_at, winners_count
FROM weekly_reward_runs
WHERE week_key = ?
LIMIT 1
""",
(week_key,),
).fetchone()
def get_recent_runs(conn: sqlite3.Connection, limit: int = 5):
conn.row_factory = sqlite3.Row
rows = conn.execute(
"""
SELECT week_key, settled_at, winners_count
FROM weekly_reward_runs
ORDER BY settled_at DESC
LIMIT ?
""",
(max(1, int(limit)),),
).fetchall()
return [dict(r) for r in rows]
def get_recent_payouts(conn: sqlite3.Connection, limit: int = 20):
conn.row_factory = sqlite3.Row
rows = conn.execute(
"""
SELECT week_key, telegram_id, username, rank, points_bonus, pro_days, pro_granted, pro_error, created_at
FROM weekly_reward_payouts
ORDER BY created_at DESC
LIMIT ?
""",
(max(1, int(limit)),),
).fetchall()
return [dict(r) for r in rows]
def main() -> int:
parser = argparse.ArgumentParser(description="Check PolyWeather weekly reward settlement status.")
parser.add_argument("--db", default=os.getenv("POLYWEATHER_DB_PATH", "data/polyweather.db"))
parser.add_argument("--timezone", default=os.getenv("POLYWEATHER_WEEKLY_REWARD_TIMEZONE", "Asia/Shanghai"))
parser.add_argument("--settle-weekday", type=int, default=int(os.getenv("POLYWEATHER_WEEKLY_REWARD_SETTLE_WEEKDAY", "1")))
parser.add_argument("--settle-hour", type=int, default=int(os.getenv("POLYWEATHER_WEEKLY_REWARD_SETTLE_HOUR", "0")))
parser.add_argument("--settle-minute", type=int, default=int(os.getenv("POLYWEATHER_WEEKLY_REWARD_SETTLE_MINUTE", "5")))
parser.add_argument("--top", type=int, default=10)
args = parser.parse_args()
settle_weekday = min(7, max(1, int(args.settle_weekday)))
settle_hour = min(23, max(0, int(args.settle_hour)))
settle_minute = min(59, max(0, int(args.settle_minute)))
tz, tz_label = resolve_tz(str(args.timezone).strip() or "Asia/Shanghai")
now_local = datetime.now(tz)
week_key = compute_target_week_key(
now_local,
settle_weekday=settle_weekday,
settle_hour=settle_hour,
settle_minute=settle_minute,
)
print("=== Weekly Reward Status ===")
print(f"db={args.db}")
print(f"now_local={now_local.isoformat()}")
print(f"timezone={tz_label}")
print(f"settle_rule=weekday:{settle_weekday} time:{settle_hour:02d}:{settle_minute:02d}")
print(f"target_week={week_key}")
with sqlite3.connect(args.db) as conn:
run = get_settle_run(conn, week_key)
print(f"settled={bool(run)}")
if run:
print(f"settled_at={run['settled_at']} winners_count={run['winners_count']}")
candidates = get_candidates(conn, week_key, args.top)
print(f"candidates={len(candidates)}")
for idx, row in enumerate(candidates, start=1):
print(
f" {idx}. {row.get('username')} "
f"(tg={row.get('telegram_id')}, weekly={row.get('weekly_points')}, total={row.get('points')})"
)
print("\nrecent_runs:")
runs = get_recent_runs(conn, limit=5)
if not runs:
print(" (none)")
else:
for row in runs:
print(
f" - {row.get('week_key')} settled_at={row.get('settled_at')} "
f"winners={row.get('winners_count')}"
)
print("\nrecent_payouts:")
payouts = get_recent_payouts(conn, limit=20)
if not payouts:
print(" (none)")
else:
for row in payouts:
print(
f" - week={row.get('week_key')} rank={row.get('rank')} "
f"user={row.get('username')} tg={row.get('telegram_id')} "
f"+{row.get('points_bonus')}pts +{row.get('pro_days')}dPro "
f"pro_granted={row.get('pro_granted')}"
)
return 0
if __name__ == "__main__":
raise SystemExit(main())