120 lines
3.7 KiB
Python
120 lines
3.7 KiB
Python
"""Countdown timer management — duration-based, once-only."""
|
|
import time
|
|
from datetime import datetime, timedelta
|
|
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
|