Files
2026-08-11 22:07:55 +08:00

119 lines
3.7 KiB
Python

"""Countdown timer management — duration-based, once-only."""
import time
from backend.time_util import isoformat as tz_isoformat
from flask import current_app
from backend.models import get_db
def _uid() -> int:
"""Resolve the current user (request session or scheduler thread)."""
try:
from backend.auth import current_user_id
return current_user_id() or 0
except Exception:
return 0
def get_countdowns(user_id: int = None) -> list:
if user_id is None:
user_id = _uid()
db = get_db(current_app.config["DB_PATH"])
rows = [dict(r) for r in db.execute(
"SELECT * FROM countdowns WHERE user_id=? ORDER BY id DESC", (user_id,)
).fetchall()]
db.close()
return rows
def add_countdown(label: str, duration_seconds: int,
enabled: bool = True, sound: str = "default", user_id: int = None) -> dict:
if user_id is None:
user_id = _uid()
end_ts = str(time.time() + duration_seconds)
db = get_db(current_app.config["DB_PATH"])
cur = db.execute(
"INSERT INTO countdowns (user_id, label, duration_seconds, end_time, enabled, sound) "
"VALUES (?, ?, ?, ?, ?, ?)",
(user_id, label, duration_seconds, end_ts, 1 if enabled else 0, sound)
)
db.commit()
row = dict(db.execute("SELECT * FROM countdowns WHERE id=?", (cur.lastrowid,)).fetchone())
db.close()
return row
def update_countdown(cd_id: int, label: str = None, duration_seconds: int = None,
enabled: bool = None, sound: str = None, user_id: int = None):
if user_id is None:
user_id = _uid()
db = get_db(current_app.config["DB_PATH"])
fields = []
vals = []
if duration_seconds is not None:
fields.append("duration_seconds=?")
vals.append(duration_seconds)
fields.append("end_time=?")
vals.append(str(time.time() + duration_seconds))
for key, val in [("label", label),
("enabled", 1 if enabled else 0 if enabled is not None else None),
("sound", sound)]:
if val is not None:
fields.append(f"{key}=?")
vals.append(val)
ok = False
if fields:
vals.append(user_id)
vals.append(cd_id)
cur = db.execute(f"UPDATE countdowns SET {', '.join(fields)} WHERE user_id=? AND id=?", vals)
db.commit()
ok = cur.rowcount > 0
db.close()
return ok
def delete_countdown(cd_id: int, user_id: int = None) -> bool:
if user_id is None:
user_id = _uid()
db = get_db(current_app.config["DB_PATH"])
cur = db.execute("DELETE FROM countdowns WHERE user_id=? AND id=?", (user_id, cd_id))
db.commit()
db.close()
return cur.rowcount > 0
def check_countdowns(user_id: int = None) -> list:
"""Check for countdowns whose end_time has passed. Auto-disable after trigger."""
if user_id is None:
user_id = _uid()
now_ts = str(time.time())
db = get_db(current_app.config["DB_PATH"])
rows = db.execute(
"SELECT * FROM countdowns WHERE user_id=? AND enabled=1 AND end_time <= ? AND end_time != ''",
(user_id, now_ts)
).fetchall()
triggered = []
for r in rows:
cd_id = r["id"]
triggered.append(dict(r))
db.execute("UPDATE countdowns SET enabled=0 WHERE user_id=? AND id=?", (user_id, cd_id))
db.commit()
db.close()
if triggered:
current_app.logger.info(
f"Countdowns triggered: {[c['label'] for c in triggered]}"
)
current_app.event_bus.publish("countdown_triggered", {
"countdowns": triggered,
"ts": tz_isoformat(),
}, user_id=user_id)
return triggered