First Push
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user