feat: add Apprise sidecar user/admin notifications
This commit is contained in:
@@ -34,6 +34,7 @@ from ..db import (
|
||||
update_request_cache_title,
|
||||
repair_request_cache_titles,
|
||||
delete_non_admin_users,
|
||||
get_user_notification_settings,
|
||||
)
|
||||
from ..runtime import get_runtime_settings
|
||||
from ..clients.sonarr import SonarrClient
|
||||
@@ -49,6 +50,7 @@ from ..services.user_cache import (
|
||||
save_jellyfin_users_cache,
|
||||
save_jellyseerr_users_cache,
|
||||
)
|
||||
from ..services.notifications import send_apprise_notification
|
||||
import logging
|
||||
from ..logging_config import configure_logging
|
||||
from ..routers import requests as requests_router
|
||||
@@ -64,6 +66,7 @@ SENSITIVE_KEYS = {
|
||||
"radarr_api_key",
|
||||
"prowlarr_api_key",
|
||||
"qbittorrent_password",
|
||||
"apprise_api_key",
|
||||
}
|
||||
|
||||
URL_SETTING_KEYS = {
|
||||
@@ -74,6 +77,7 @@ URL_SETTING_KEYS = {
|
||||
"radarr_base_url",
|
||||
"prowlarr_base_url",
|
||||
"qbittorrent_base_url",
|
||||
"apprise_base_url",
|
||||
}
|
||||
|
||||
SETTING_KEYS: List[str] = [
|
||||
@@ -101,6 +105,8 @@ SETTING_KEYS: List[str] = [
|
||||
"qbittorrent_password",
|
||||
"log_level",
|
||||
"log_file",
|
||||
"apprise_base_url",
|
||||
"apprise_api_key",
|
||||
"requests_sync_ttl_minutes",
|
||||
"requests_poll_interval_seconds",
|
||||
"requests_delta_sync_interval_minutes",
|
||||
@@ -608,6 +614,72 @@ async def list_users() -> Dict[str, Any]:
|
||||
users = [user for user in get_all_users() if user.get("role") == "admin" or user.get("auth_provider") == "jellyseerr"]
|
||||
return {"users": users}
|
||||
|
||||
@router.get("/notifications/users")
|
||||
async def list_notification_users() -> Dict[str, Any]:
|
||||
users = get_all_users()
|
||||
results: list[Dict[str, Any]] = []
|
||||
for user in users:
|
||||
username = user.get("username") or ""
|
||||
settings = get_user_notification_settings(username)
|
||||
results.append(
|
||||
{
|
||||
"username": username,
|
||||
"role": user.get("role"),
|
||||
"authProvider": user.get("auth_provider"),
|
||||
"jellyseerrUserId": user.get("jellyseerr_user_id"),
|
||||
"isBlocked": bool(user.get("is_blocked")),
|
||||
"notifyEnabled": bool(settings.get("enabled")),
|
||||
"notifyCount": len(settings.get("urls") or []),
|
||||
}
|
||||
)
|
||||
return {"users": results}
|
||||
|
||||
@router.post("/notifications/send")
|
||||
async def send_notifications(payload: Dict[str, Any]) -> Dict[str, Any]:
|
||||
usernames = payload.get("usernames")
|
||||
message = payload.get("message")
|
||||
title = payload.get("title") or "Magent admin message"
|
||||
if not isinstance(usernames, list) or not usernames:
|
||||
raise HTTPException(status_code=400, detail="Select at least one user.")
|
||||
if not isinstance(message, str) or not message.strip():
|
||||
raise HTTPException(status_code=400, detail="Message cannot be empty.")
|
||||
|
||||
results: list[Dict[str, Any]] = []
|
||||
counts = {"sent": 0, "skipped": 0, "failed": 0}
|
||||
for raw_username in usernames:
|
||||
if not isinstance(raw_username, str) or not raw_username.strip():
|
||||
results.append({"username": str(raw_username), "status": "invalid"})
|
||||
counts["failed"] += 1
|
||||
continue
|
||||
username = raw_username.strip()
|
||||
user = get_user_by_username(username)
|
||||
if not user:
|
||||
results.append({"username": username, "status": "not_found"})
|
||||
counts["failed"] += 1
|
||||
continue
|
||||
if user.get("is_blocked"):
|
||||
results.append({"username": username, "status": "blocked"})
|
||||
counts["skipped"] += 1
|
||||
continue
|
||||
settings = get_user_notification_settings(username)
|
||||
if not settings.get("enabled"):
|
||||
results.append({"username": username, "status": "disabled"})
|
||||
counts["skipped"] += 1
|
||||
continue
|
||||
urls = settings.get("urls") or []
|
||||
if not urls:
|
||||
results.append({"username": username, "status": "no_targets"})
|
||||
counts["skipped"] += 1
|
||||
continue
|
||||
ok = send_apprise_notification(urls, str(title).strip() or "Magent admin message", message.strip())
|
||||
if ok:
|
||||
results.append({"username": username, "status": "sent"})
|
||||
counts["sent"] += 1
|
||||
else:
|
||||
results.append({"username": username, "status": "failed"})
|
||||
counts["failed"] += 1
|
||||
return {"results": results, **counts}
|
||||
|
||||
@router.get("/users/summary")
|
||||
async def list_users_summary() -> Dict[str, Any]:
|
||||
users = [user for user in get_all_users() if user.get("role") == "admin" or user.get("auth_provider") == "jellyseerr"]
|
||||
|
||||
Reference in New Issue
Block a user