diff --git a/docs/HTTP_API.md b/docs/HTTP_API.md index ca600ac..3f77d45 100644 --- a/docs/HTTP_API.md +++ b/docs/HTTP_API.md @@ -53,6 +53,17 @@ See [User Management](USERS.md) for full authentication documentation. |--------|------|-------------|------| | `GET` | `/api/0/users` | List all users | Admin | | `GET` | `/api/0/users/me` | Own profile | Authenticated | +| `PUT` | `/api/0/users/me` | Update own profile | Authenticated | + +### Notification Channels + +| Method | Path | Description | Role | +|--------|------|-------------|------| +| `GET` | `/api/0/notification_channel_types` | Channel type schemas | Authenticated | +| `GET` | `/api/0/notification_channels` | List visible channels | Authenticated | +| `POST` | `/api/0/notification_channels` | Create a channel | Authenticated | +| `PUT` | `/api/0/notification_channels/{name}` | Update a channel | Owner or Admin | +| `DELETE` | `/api/0/notification_channels/{name}` | Delete a channel | Owner or Admin | ### Host Management @@ -203,6 +214,101 @@ Changes take effect immediately but are not written back to the config file. Upd --- +--- + +### Notification Channel Endpoints + +Channels are visible to all users by default. Channels marked `private: true` are only visible to their owner. Admins see all channels. + +#### GET /api/0/notification_channel_types +Return the schema for every supported notifier type. Used by the web UI to dynamically render the channel creation form. + +**Response:** +```json +{ + "pushover": { + "label": "Pushover", + "fields": [ + {"key": "token", "label": "App token", "type": "secret", "required": true}, + {"key": "user", "label": "User key", "type": "secret", "required": true}, + {"key": "sound", "label": "Sound", "type": "text", "required": false} + ] + }, + "email": { "label": "E-mail", "fields": [ ... ] }, + ... +} +``` + +--- + +#### GET /api/0/notification_channels +List channels visible to the current user (public channels + own private channels). Admins receive all channels. + +**Response:** +```json +[ + { + "name": "pushover_ops", + "type": "pushover", + "type_label": "Pushover", + "owner": null, + "private": false, + "min_level": "WARNING", + "fields": [ + {"key": "token", "label": "App token", "value": "•••", "sensitive": true}, + {"key": "user", "label": "User key", "value": "•••", "sensitive": true} + ] + } +] +``` + +Sensitive fields (`type: "secret"`) are always returned as `"•••"`. + +--- + +#### POST /api/0/notification_channels +Create a new channel. The creating user becomes the channel's `owner`. + +**Request body:** +```json +{ + "name": "my_pushover", + "type": "pushover", + "token": "app-token", + "user": "user-key", + "min_level": "WARNING", + "private": true +} +``` + +**Response:** `{"ok": true, "name": "my_pushover"}` + +**Status codes:** `200 OK`, `400` (missing required field or unknown type), `409` (name already exists) + +--- + +#### PUT /api/0/notification_channels/{name} +Update an existing channel. Only the channel owner or an admin may update it. + +Secret fields sent as `"•••"` are preserved from the existing config (same pattern as OAuth secrets in the admin config editor). + +**Request body:** same shape as POST, `name` ignored (taken from URL). + +**Response:** `{"ok": true}` + +**Status codes:** `200 OK`, `403 Forbidden`, `404 Not Found` + +--- + +#### DELETE /api/0/notification_channels/{name} +Delete a channel. Only the channel owner or an admin may delete it. + +**Response:** `{"ok": true}` + +**Status codes:** `200 OK`, `403 Forbidden`, `404 Not Found` + +--- + ### Alert Endpoints #### GET /api/0/hosts/{hostname}/alerts diff --git a/docs/NOTIFICATIONS.md b/docs/NOTIFICATIONS.md index fc7f403..3561232 100644 --- a/docs/NOTIFICATIONS.md +++ b/docs/NOTIFICATIONS.md @@ -30,9 +30,17 @@ Set `base_url` so notification links point to your hbd instance: base_url: https://hbd.example.com ``` -### Global channel definitions +### Channel definitions -Define channels once; reference them by name from user configs: +Channels are defined under `notification_channels`. Each entry specifies a delivery type and its credentials. Two optional metadata fields control visibility: + +| Field | Default | Description | +|---|---|---| +| `owner` | *(absent)* | Username who created/owns this channel. Absent = admin-created. | +| `private` | `false` | When `true`, only the owner can see and select this channel. | +| `min_level` | `WARNING` | Minimum alert level this channel receives. | + +**Admin-created channels** (set in the config file or via the admin settings UI) are public by default — all users can select them: ```yaml notification_channels: @@ -41,7 +49,7 @@ notification_channels: type: pushover token: your-app-token user: your-user-key - min_level: WARNING # optional, default: WARNING + min_level: WARNING email_ops: type: email @@ -58,14 +66,14 @@ notification_channels: homeserver: https://matrix.example.org access_token: syt_xxx room_id: "!abc:matrix.example.org" - min_level: CRITICAL # only send critical alerts to this room + min_level: CRITICAL sms_oncall: type: sms_voipms api_user: me@example.com api_password: secret - did: "5551234567" # your voip.ms DID number - dst: "5559876543" # destination number + did: "5551234567" + dst: "5559876543" min_level: CRITICAL signal_ops: @@ -82,9 +90,30 @@ notification_channels: username: heartbeat-bot ``` +**User-created channels** are written by authenticated users through the API or their profile page. They carry an `owner` field and optionally `private: true`: + +```yaml +notification_channels: + + alice_personal: + type: pushover + token: personal-token + user: personal-key + owner: alice # created by alice + private: true # only alice can see this channel +``` + +### Channel visibility + +| Channel | Who can see / select it | +|---|---| +| No `private` field (or `private: false`) | All users | +| `private: true` | Only the `owner` | +| Any channel | Admins always see everything | + ### Users with notification channels -Each user lists which global channels they receive notifications on: +Each user lists which channels they receive notifications on. Users can manage their own selection from the profile page: ```yaml users: @@ -270,6 +299,7 @@ Called once at startup from `main.py`. Pass the running asyncio event loop so Ma - Check that the host has an `owner` or `managers` set - Check that users have `notification_channels` listed - Check that the channel names in user config match keys under `notification_channels:` +- If a user can't select a channel, check whether it is `private: true` and owned by someone else **min_level filtering too aggressive:** - Default is `WARNING` — both WARNING and CRITICAL are sent diff --git a/docs/USERS.md b/docs/USERS.md index e5f114c..777caa0 100644 --- a/docs/USERS.md +++ b/docs/USERS.md @@ -36,7 +36,7 @@ users: bob: full_name: Bob Smith password: pbkdf2:sha256:... - notification_channels: [pushover_standard] + notification_channels: [pushover_standard] # channels bob has selected carol: full_name: Carol Jones @@ -188,6 +188,32 @@ Return the currently authenticated user's profile. --- +#### PUT /api/0/users/me +Update the current user's profile. All fields are optional — send only what you want to change. + +**Update display name and avatar:** +```json +{ "full_name": "Carol Jones", "avatar": "/avatars/carol.png" } +``` + +**Change notification channel selection:** +```json +{ "notification_channels": ["pushover_ops", "email_ops"] } +``` +Only channels visible to the user (public + own private) are accepted; others are silently dropped. + +**Change password:** +```json +{ "password": { "current": "oldpass", "new": "newpass" } } +``` +Requires the correct current password. New password is hashed before storage. + +**Response:** `{"ok": true}` + +**Status codes:** `200 OK`, `400` (missing/invalid field), `401` (unauthenticated), `403` (wrong current password) + +--- + ### Host Access #### GET /api/0/hosts/{hostname}/access