Source code for corvix.web.actions
"""Notification action helpers: dismiss and mark-read against GitHub + storage.
These plain (non-decorated) functions carry the business logic behind the
``/api/v1/notifications/{account_id}/{thread_id}/dismiss`` and ``.../mark-read``
route handlers. ``_require_account`` and ``_build_github_client`` are shared
with the rule-snippet builder.
"""
from __future__ import annotations
import logging
from litestar import Response
from litestar.exceptions import HTTPException
from corvix.config import AppConfig, GitHubAccountConfig
from corvix.env import get_env_value
from corvix.ingestion import GitHubNotificationsClient
from corvix.web.runtime_config import _load_runtime_config
from corvix.web.storage_provider import _get_storage
[docs]
logger = logging.getLogger(__name__)
[docs]
def _require_account(config: AppConfig, account_id: str) -> GitHubAccountConfig:
for account in config.github.accounts:
if account.id == account_id:
return account
msg = f"GitHub account '{account_id}' not found in config."
raise HTTPException(status_code=404, detail=msg)
[docs]
def _build_github_client(config: AppConfig, account: GitHubAccountConfig, token: str) -> GitHubNotificationsClient:
return GitHubNotificationsClient(
token=token,
api_base_url=account.api_base_url,
request_timeout_seconds=config.polling.request_timeout_seconds,
)
[docs]
def _dismiss_notification_impl(account_id: str, thread_id: str) -> Response[None]:
config = _load_runtime_config()
account = _require_account(config=config, account_id=account_id)
try:
token = get_env_value(account.token_env)
except ValueError as error:
raise HTTPException(status_code=500, detail=str(error)) from error
if not token:
msg = f"GitHub token env var '{account.token_env}' (or '{account.token_env}_FILE') is not set."
raise HTTPException(status_code=500, detail=msg)
client = _build_github_client(config=config, account=account, token=token)
try:
client.dismiss_thread(thread_id)
except Exception as error:
logger.exception("Failed to dismiss thread", extra={"thread_id": thread_id})
msg = f"Failed to dismiss thread {thread_id}: {error}"
raise HTTPException(status_code=502, detail=msg) from error
_get_storage().dismiss_record(thread_id=thread_id, account_id=account_id)
return Response(content=None, status_code=204)
[docs]
def _mark_notification_read_impl(account_id: str, thread_id: str) -> Response[None]:
config = _load_runtime_config()
account = _require_account(config=config, account_id=account_id)
try:
token = get_env_value(account.token_env)
except ValueError as error:
raise HTTPException(status_code=500, detail=str(error)) from error
if not token:
msg = f"GitHub token env var '{account.token_env}' (or '{account.token_env}_FILE') is not set."
raise HTTPException(status_code=500, detail=msg)
client = _build_github_client(config=config, account=account, token=token)
try:
client.mark_thread_read(thread_id)
except Exception as error:
logger.exception("Failed to mark thread as read", extra={"thread_id": thread_id})
msg = f"Failed to mark thread {thread_id} as read."
raise HTTPException(status_code=502, detail=msg) from error
_get_storage().mark_record_read(thread_id=thread_id, account_id=account_id)
return Response(content=None, status_code=204)