3391fbc85d
TestResult dataclass + translate_connection_error shared helper in base.py. test_callable field on ServiceDefinition (default None). 7 per-type test_connection routines (qbittorrent, prometheus via Grafana gateway, alertmanager, jellyfin, authentik, ssh_tasks via build_ssh_client, nextcloud). POST /api/services/test endpoint: validation-first (422 on malformed config), dispatch, no-persistence, no-secret-logs. backups has test_callable=None. qBit 'Fails.' → specific auth message (resolves #3 at API layer). Backend: 362 pytest pass (+31 new), ruff clean. Frontend: build green.
61 lines
1.7 KiB
Python
61 lines
1.7 KiB
Python
"""Nextcloud service definition.
|
|
|
|
Nextcloud is included as a proof-of-concept third-party service. It has no
|
|
dashboard widgets yet; its service page holds connection config only.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING, Any
|
|
|
|
import requests
|
|
|
|
from media_library_viewer_api.integrations.base import (
|
|
SecretField,
|
|
ServiceBaseUrl,
|
|
ServiceConfigBase,
|
|
ServiceDefinition,
|
|
TestResult,
|
|
translate_connection_error,
|
|
)
|
|
|
|
if TYPE_CHECKING:
|
|
from media_library_viewer_api.services.settings_store import SettingsStore
|
|
|
|
|
|
def test_connection(
|
|
config: dict[str, Any],
|
|
secrets: dict[str, str],
|
|
store: SettingsStore,
|
|
) -> TestResult:
|
|
"""GET {base_url}/status.php (unauthenticated server probe)."""
|
|
try:
|
|
base_url = str(config.get("base_url") or "").rstrip("/")
|
|
resp = requests.get(f"{base_url}/status.php", timeout=10)
|
|
resp.raise_for_status()
|
|
payload = resp.json()
|
|
version = str(payload.get("version", "") or "connected")
|
|
return TestResult(ok=True, detail="Connected to Nextcloud.", evidence=version)
|
|
except Exception as exc:
|
|
return translate_connection_error(exc, context="Nextcloud")
|
|
|
|
|
|
class NextcloudConfig(ServiceConfigBase):
|
|
"""Non-secret Nextcloud connection config."""
|
|
|
|
base_url: ServiceBaseUrl
|
|
username: str = ""
|
|
|
|
|
|
DEFINITION = ServiceDefinition(
|
|
service_type="nextcloud",
|
|
name="Nextcloud",
|
|
description="Self-hosted files and collaboration.",
|
|
config_model=NextcloudConfig,
|
|
secret_fields=[
|
|
SecretField(key="app_password", label="App password", required=True),
|
|
],
|
|
widget_kinds=[],
|
|
test_callable=test_connection,
|
|
)
|