111 lines
4.4 KiB
Python
111 lines
4.4 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from typing import Any
|
|
|
|
|
|
class AlertRepositoryMixin:
|
|
def save_alert(
|
|
self,
|
|
user_id: int,
|
|
kind: str,
|
|
title: str,
|
|
content: str,
|
|
available_date: str,
|
|
code: str,
|
|
dedupe_key: str,
|
|
) -> int:
|
|
now = datetime.now().astimezone().isoformat(timespec="seconds")
|
|
with self.connect() as connection:
|
|
connection.execute(
|
|
"""
|
|
INSERT INTO alerts
|
|
(user_id, kind, title, content, available_date, code, dedupe_key,
|
|
is_read, created_at, updated_at)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?)
|
|
ON CONFLICT(user_id, dedupe_key) DO UPDATE SET
|
|
title=excluded.title, content=excluded.content,
|
|
available_date=excluded.available_date, updated_at=excluded.updated_at
|
|
""",
|
|
(
|
|
int(user_id), kind, title, content, available_date, code,
|
|
dedupe_key, now, now,
|
|
),
|
|
)
|
|
row = connection.execute(
|
|
"SELECT id FROM alerts WHERE user_id = ? AND dedupe_key = ?",
|
|
(int(user_id), dedupe_key),
|
|
).fetchone()
|
|
return int(row["id"])
|
|
|
|
def list_alerts(
|
|
self, user_id: int, as_of: str, unread_only: bool = False, limit: int = 100
|
|
) -> list[dict[str, Any]]:
|
|
with self.connect() as connection:
|
|
if unread_only:
|
|
rows = connection.execute(
|
|
"""
|
|
SELECT id, kind, title, content, available_date, code, is_read,
|
|
created_at, updated_at, read_at
|
|
FROM alerts
|
|
WHERE user_id = ? AND available_date <= ? AND is_read = 0
|
|
ORDER BY available_date DESC, id DESC LIMIT ?
|
|
""",
|
|
(int(user_id), as_of, max(1, min(300, int(limit)))),
|
|
).fetchall()
|
|
else:
|
|
rows = connection.execute(
|
|
"""
|
|
SELECT id, kind, title, content, available_date, code, is_read,
|
|
created_at, updated_at, read_at
|
|
FROM alerts WHERE user_id = ?
|
|
ORDER BY CASE WHEN available_date > ? THEN 0 ELSE 1 END,
|
|
is_read, available_date, id DESC LIMIT ?
|
|
""",
|
|
(int(user_id), as_of, max(1, min(300, int(limit)))),
|
|
).fetchall()
|
|
return [{**dict(row), "is_read": bool(row["is_read"])} for row in rows]
|
|
|
|
def count_unread_alerts(self, user_id: int, as_of: str) -> int:
|
|
with self.connect() as connection:
|
|
row = connection.execute(
|
|
"""
|
|
SELECT COUNT(*) AS total FROM alerts
|
|
WHERE user_id = ? AND available_date <= ? AND is_read = 0
|
|
""",
|
|
(int(user_id), as_of),
|
|
).fetchone()
|
|
return int(row["total"] if row else 0)
|
|
|
|
def mark_alert_read(self, user_id: int, alert_id: int) -> bool:
|
|
now = datetime.now().astimezone().isoformat(timespec="seconds")
|
|
with self.connect() as connection:
|
|
cursor = connection.execute(
|
|
"""
|
|
UPDATE alerts SET is_read = 1, read_at = ?, updated_at = ?
|
|
WHERE id = ? AND user_id = ?
|
|
""",
|
|
(now, now, int(alert_id), int(user_id)),
|
|
)
|
|
return cursor.rowcount > 0
|
|
|
|
def mark_all_alerts_read(self, user_id: int, as_of: str) -> int:
|
|
now = datetime.now().astimezone().isoformat(timespec="seconds")
|
|
with self.connect() as connection:
|
|
cursor = connection.execute(
|
|
"""
|
|
UPDATE alerts SET is_read = 1, read_at = ?, updated_at = ?
|
|
WHERE user_id = ? AND available_date <= ? AND is_read = 0
|
|
""",
|
|
(now, now, int(user_id), as_of),
|
|
)
|
|
return int(cursor.rowcount)
|
|
|
|
def delete_alert(self, user_id: int, alert_id: int) -> bool:
|
|
with self.connect() as connection:
|
|
cursor = connection.execute(
|
|
"DELETE FROM alerts WHERE id = ? AND user_id = ?",
|
|
(int(alert_id), int(user_id)),
|
|
)
|
|
return cursor.rowcount > 0
|