feat: add Apprise sidecar user/admin notifications
This commit is contained in:
@@ -150,7 +150,10 @@ def init_db() -> None:
|
||||
last_login_at TEXT,
|
||||
is_blocked INTEGER NOT NULL DEFAULT 0,
|
||||
jellyfin_password_hash TEXT,
|
||||
last_jellyfin_auth_at TEXT
|
||||
last_jellyfin_auth_at TEXT,
|
||||
notify_enabled INTEGER NOT NULL DEFAULT 0,
|
||||
notify_urls TEXT,
|
||||
notify_updated_at TEXT
|
||||
)
|
||||
"""
|
||||
)
|
||||
@@ -264,6 +267,20 @@ def init_db() -> None:
|
||||
conn.execute("ALTER TABLE users ADD COLUMN jellyseerr_user_id INTEGER")
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
try:
|
||||
conn.execute(
|
||||
"ALTER TABLE users ADD COLUMN notify_enabled INTEGER NOT NULL DEFAULT 0"
|
||||
)
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
try:
|
||||
conn.execute("ALTER TABLE users ADD COLUMN notify_urls TEXT")
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
try:
|
||||
conn.execute("ALTER TABLE users ADD COLUMN notify_updated_at TEXT")
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
try:
|
||||
conn.execute("ALTER TABLE requests_cache ADD COLUMN requested_by_id INTEGER")
|
||||
except sqlite3.OperationalError:
|
||||
@@ -474,6 +491,75 @@ def get_user_by_id(user_id: int) -> Optional[Dict[str, Any]]:
|
||||
"last_jellyfin_auth_at": row[10],
|
||||
}
|
||||
|
||||
|
||||
def get_user_notification_settings(username: str) -> Dict[str, Any]:
|
||||
if not username:
|
||||
return {"enabled": False, "urls": []}
|
||||
with _connect() as conn:
|
||||
row = conn.execute(
|
||||
"""
|
||||
SELECT notify_enabled, notify_urls
|
||||
FROM users
|
||||
WHERE username = ? COLLATE NOCASE
|
||||
""",
|
||||
(username,),
|
||||
).fetchone()
|
||||
if not row:
|
||||
return {"enabled": False, "urls": []}
|
||||
enabled = bool(row[0])
|
||||
urls_raw = row[1]
|
||||
urls: list[str] = []
|
||||
if isinstance(urls_raw, str) and urls_raw.strip():
|
||||
try:
|
||||
parsed = json.loads(urls_raw)
|
||||
if isinstance(parsed, list):
|
||||
urls = [str(item).strip() for item in parsed if str(item).strip()]
|
||||
except json.JSONDecodeError:
|
||||
urls = [urls_raw.strip()]
|
||||
return {"enabled": enabled, "urls": urls}
|
||||
|
||||
|
||||
def set_user_notification_settings(username: str, enabled: bool, urls: list[str]) -> None:
|
||||
if not username:
|
||||
return
|
||||
urls_payload = json.dumps(urls, ensure_ascii=True)
|
||||
updated_at = datetime.now(timezone.utc).isoformat()
|
||||
with _connect() as conn:
|
||||
conn.execute(
|
||||
"""
|
||||
UPDATE users
|
||||
SET notify_enabled = ?, notify_urls = ?, notify_updated_at = ?
|
||||
WHERE username = ? COLLATE NOCASE
|
||||
""",
|
||||
(1 if enabled else 0, urls_payload, updated_at, username),
|
||||
)
|
||||
|
||||
|
||||
def get_admin_notification_targets() -> list[Dict[str, Any]]:
|
||||
with _connect() as conn:
|
||||
rows = conn.execute(
|
||||
"""
|
||||
SELECT username, notify_urls
|
||||
FROM users
|
||||
WHERE role = 'admin' AND notify_enabled = 1
|
||||
ORDER BY username COLLATE NOCASE
|
||||
"""
|
||||
).fetchall()
|
||||
results: list[Dict[str, Any]] = []
|
||||
for row in rows:
|
||||
username, urls_raw = row
|
||||
urls: list[str] = []
|
||||
if isinstance(urls_raw, str) and urls_raw.strip():
|
||||
try:
|
||||
parsed = json.loads(urls_raw)
|
||||
if isinstance(parsed, list):
|
||||
urls = [str(item).strip() for item in parsed if str(item).strip()]
|
||||
except json.JSONDecodeError:
|
||||
urls = [urls_raw.strip()]
|
||||
if urls:
|
||||
results.append({"username": username, "urls": urls})
|
||||
return results
|
||||
|
||||
def get_all_users() -> list[Dict[str, Any]]:
|
||||
with _connect() as conn:
|
||||
rows = conn.execute(
|
||||
@@ -499,7 +585,6 @@ def get_all_users() -> list[Dict[str, Any]]:
|
||||
)
|
||||
return results
|
||||
|
||||
|
||||
def delete_non_admin_users() -> int:
|
||||
with _connect() as conn:
|
||||
cursor = conn.execute(
|
||||
|
||||
Reference in New Issue
Block a user