feat: harden notification stack and switch logging selectors to icon grid

Notifications:
- Add shared http_base, redact, and SSRF hardening modules
- Refactor dispatcher, queue, receiver and per-provider clients
  (telegram, discord, email, matrix, ntfy, slack, webhook) to use
  the shared base, with bounded queue and redacted error logs
- Tests for ssrf, redact, http_base, queue bounds, dispatcher
  aggregation, telegram media partition, email and matrix clients

Frontend:
- Settings: log level / log format selectors now use IconGridSelect
  with per-option icons and i18n descriptions
- Minor providers page and entity-cache store updates

Tooling:
- Document code-review-graph MCP usage in CLAUDE.md
- Ignore .code-review-graph/, register .mcp.json
This commit is contained in:
2026-05-07 13:53:26 +03:00
parent 5bd63a2191
commit 0eb899afb9
33 changed files with 2623 additions and 1033 deletions
@@ -218,6 +218,19 @@ async def get_supported_locales(
return locales or ["en"]
@router.get("/external-url")
async def get_external_url(
user: User = Depends(get_current_user),
session: AsyncSession = Depends(get_session),
):
"""Return the configured external base URL (available to all users).
Used by the UI to render absolute provider webhook URLs. Returns empty
string when unset so the UI falls back to the relative path.
"""
return {"external_url": (await get_setting(session, "external_url")).rstrip("/")}
async def _reregister_webhooks(
session: AsyncSession, base_url: str, secret: str
) -> None: