|
# retoor <retoor@molodetz.nl>
|
|
|
|
import logging
|
|
from datetime import datetime, timezone
|
|
from typing import Any
|
|
|
|
from devplacepy.database import db, get_table
|
|
from devplacepy.push.providers import DEFAULT_PROVIDER
|
|
from devplacepy.utils import generate_uid
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
TABLE = "push_registration"
|
|
|
|
|
|
def table():
|
|
return get_table(TABLE)
|
|
|
|
|
|
def provider_of(registration: dict[str, Any]) -> str:
|
|
return registration.get("provider") or DEFAULT_PROVIDER
|
|
|
|
|
|
def active_for_user(user_uid: str) -> list[dict[str, Any]]:
|
|
return list(table().find(user_uid=user_uid, deleted_at=None))
|
|
|
|
|
|
def register(
|
|
user_uid: str, provider: str, fields: dict[str, Any]
|
|
) -> tuple[dict[str, Any], bool]:
|
|
registrations = table()
|
|
existing = registrations.find_one(
|
|
user_uid=user_uid, provider=provider, deleted_at=None, **fields
|
|
)
|
|
if existing:
|
|
logger.debug("Push subscription already registered for user %s", user_uid)
|
|
return existing, False
|
|
|
|
record = {
|
|
"uid": generate_uid(),
|
|
"user_uid": user_uid,
|
|
"provider": provider,
|
|
"created_at": datetime.now(timezone.utc).isoformat(),
|
|
"deleted_at": None,
|
|
**fields,
|
|
}
|
|
registrations.insert(record)
|
|
logger.info("Registered %s push subscription for user %s", provider, user_uid)
|
|
return record, True
|
|
|
|
|
|
def mark_dead(registration_id: int) -> None:
|
|
table().update(
|
|
{"id": registration_id, "deleted_at": datetime.now(timezone.utc).isoformat()},
|
|
["id"],
|
|
)
|
|
logger.info("Soft-deleted dead push subscription id=%s", registration_id)
|
|
|
|
|
|
def prune(cutoff: str) -> int:
|
|
if TABLE not in db.tables:
|
|
return 0
|
|
rows = list(table().find(deleted_at={"<": cutoff}))
|
|
if not rows:
|
|
return 0
|
|
table().delete(deleted_at={"<": cutoff})
|
|
return len(rows)
|
|
|
|
|
|
def counts() -> dict[str, int]:
|
|
if TABLE not in db.tables:
|
|
return {}
|
|
totals: dict[str, int] = {"dead": 0}
|
|
for row in db.query(
|
|
f"SELECT provider AS provider, deleted_at IS NULL AS live, COUNT(*) AS total "
|
|
f"FROM {TABLE} GROUP BY provider, deleted_at IS NULL"
|
|
):
|
|
provider = row["provider"] or DEFAULT_PROVIDER
|
|
if row["live"]:
|
|
totals[provider] = totals.get(provider, 0) + int(row["total"])
|
|
else:
|
|
totals["dead"] += int(row["total"])
|
|
return totals
|