diff --git a/INSTALL.md b/INSTALL.md index 6bfee27..53d5185 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -2,7 +2,7 @@ ## Prerequisites -- Nextcloud 28+ with the **Talk** app enabled +- Nextcloud 33 with the **Talk** app enabled - PHP 8.1+ - Access to the Nextcloud server (SSH or direct file access) @@ -123,7 +123,7 @@ Apprise sends a different JSON format (`title`, `body`, `type`, `attachments`) - **"talk-bot user not found"** — The `talk-bot` user doesn't exist. Re-run Step 1. - **"Bot password not configured"** — You haven't entered the bot password in the admin settings, or it was cleared. Re-enter it in Step 3. - **Messages not appearing** — Check the Nextcloud log (`data/nextcloud.log` or Settings → Admin → Logging) for errors from the `nc_bot_webhooks` app. -- **Image upload fails** — Verify the bot user has file storage quota and the `NCbotwebhooks-images` folder can be created. +- **Image upload fails** — Verify the bot user has file storage quota and the `nc_bot_webhooks-images` folder can be created. ## Security Notes diff --git a/README.md b/README.md index ecc9bde..b941b18 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ Accepts Discord webhook-compatible JSON payloads (embeds, fields, images) and Ap - [Security](#security) - [Debug Endpoint](#debug-endpoint) - [Logging](#logging) +- [Integrations](#integrations) + - [Home Assistant](#home-assistant) - [Troubleshooting](#troubleshooting) --- @@ -196,6 +198,7 @@ Apprise also supports form-encoded payloads. The app auto-detects the content ty | `subject` / `title` (Apprise) | Used as bold title line | | `body` (Apprise) | Sent as message body | | `attachments[].path` (Apprise) | Downloaded, uploaded to NC, shared inline | +| `type` (Apprise) | Maps to icon: ✅ success, ⚠️ warning, ❌ error, none for info/image | ### Sender name resolution @@ -262,6 +265,81 @@ php occ nc_bot_webhooks:debug:disable --- +## Integrations + +### Home Assistant + +Use the built-in `rest_command` integration to send notifications from Home Assistant to Nextcloud Talk. + +#### 1. Define the REST command + +Add this to your Home Assistant `configuration.yaml`: + +```yaml +rest_command: + notify_nextcloud_apprise: + url: "https:///apps/nc_bot_webhooks/apprise-webhook//notify/" + method: post + content_type: application/json + payload: > + {{ { + 'message': message, + 'sender_name': sender_name | default('Webhook Bot'), + 'subject': subject | default('Notification'), + 'type': type | default('info'), + 'attachments': attachments | default([]) + } | to_json }} +``` + +Replace `` and `` with your values from the Nextcloud admin settings. + +#### 2. Call the command from an automation or script + +**Text-only notification:** + +```yaml +action: rest_command.notify_nextcloud_apprise +data: + message: "Garbage collection complete" + sender_name: "HA - Valetudo" + subject: "Vacuum" + type: info +``` + +**Notification with a remote image attachment:** + +```yaml +action: rest_command.notify_nextcloud_apprise +data: + message: "{{ title | default('Notification') }} => {{ message | default('') }}" + sender_name: "HA - Valetudo" + subject: "{{ title | default('Notification') }}" + type: image + attachments: + - path: https:///local/camera.glados_vacuum_camera.jpg +``` + +The app will download the image from the URL, upload it to the bot user's storage, create a public link, and embed it inline in the Talk message. + +**Direct file upload (multipart/form-data):** + +To send a file directly from Home Assistant (e.g., a sensor-generated image or log), use `data` with `Content-Type: multipart/form-data`. The app accepts files under the key `file01`: + +```yaml +action: rest_command.notify_nextcloud_apprise +data: + message: "Sensor snapshot" + subject: "Camera" + type: image + content_type: multipart/form-data + data: + file01: !secret camera_image_path +``` + +> **Note:** When using `multipart/form-data`, the app reads the uploaded file from `$_FILES['file01']` on the server side. The file is uploaded directly to the bot user's storage without needing an intermediate HTTP download step. + +--- + ## Logging Responses include a `X-Webhook-Status` header: diff --git a/agent.md b/agent.md index 0abbec3..1b7a77c 100644 --- a/agent.md +++ b/agent.md @@ -186,10 +186,10 @@ public function __construct( | Method | Lines | Purpose | |---|---|---| | `mapPayload(array)` | ~548-583 | Maps Discord webhook JSON to Talk message text. Extracts: `content`, embed `title` (bold), embed `description`, embed `fields` (name: value). Joins with `\n\n`. | -| `mapApprisePayload(array, roomToken)` | ~608-766 | Maps Apprise JSON to internal format. Handles: `body`, `title`/`subject` as message, `type` prefix ([Info], [Success], [Warning], [Error]), `attachments` (remote URL, local file, base64), `type=image` special case. Returns `{message, senderName, displayName, richObjects}`. | +| `mapApprisePayload(array, roomToken)` | ~608-766 | Maps Apprise JSON to internal format. Handles: `body`, `title`/`subject` as message, `type` → icon (✅ success, ⚠️ warning, ❌ error; none for info/image), `attachments` (remote URL, local file, base64), `type=image` special case. Returns `{message, senderName, displayName, richObjects, typeIcon}`. | | `getSenderName(array)` | ~588-593 | Returns `username` from Discord payload, or config default | | `getSenderNameDefault()` | ~598-600 | Returns config `sender_name` default | -| `prependDisplayName(string, string)` | ~540-546 | Prepends `🤖 **{name}**\n\n` to message. Since Talk doesn't support per-message avatars. | +| `prependDisplayName(string, string, string)` | ~540-546 | Prepends `{typeIcon}🤖 **{name}**\n\n` to message. `typeIcon` is ✅/⚠️/❌ for success/warning/error types, empty for info/image. Since Talk doesn't support per-message avatars. | **Apprise attachment formats handled:** 1. **Remote URL**: `attachment['url']` → download → upload → rich object @@ -197,6 +197,12 @@ public function __construct( 3. **Base64**: `attachment['base64']` → decode → upload → rich object 4. **type=image**: special case — uses `attachment` (string URL) or `attachments` (array) as image URLs directly +**Type icon mapping:** +- `success` → ✅ +- `warning` → ⚠️ +- `error` → ❌ +- `info` / `image` / missing → no icon (empty string) + **Base64 attachment format** (from Apprise library JSON method): ```json { @@ -688,13 +694,19 @@ Apprise sends webhook payloads in several formats depending on the transport: **Content types handled:** 1. `application/json` — direct JSON parse -2. `multipart/form-data` — `$_POST` +2. `multipart/form-data` — `$_POST` (files in `$_FILES['file01']`) 3. `application/x-www-form-urlencoded` — `parse_str()` **Apprise URL schemes:** - `discord://` → uses Discord webhook format - `apprises://` → uses Apprise format with `notify` in path: `/apprise-webhook/{room}/notify/{token}` +**Type field:** The `type` field maps to an icon displayed before the bot name: +- `success` → ✅ +- `warning` → ⚠️ +- `error` → ❌ +- `info` / `image` / missing → no icon + ### Discord Webhook API Discord webhooks send JSON with these fields: @@ -930,6 +942,10 @@ Each candidate is verified via `information_schema.tables` + test query. ### Functional +3. **Link preview suppression removed:** Nextcloud Talk generates link previews server-side. URL suppression via angle brackets (``) does not work. This feature was removed. + +### Functional (continued) + 6. **avatar_url ignored:** NCTalk doesn't support per-message avatars. `username` is embedded as sender name instead. 7. **actorDisplayName mismatch:** If bot's display name changes in the room, messages will be silently dropped. `getBotDisplayNameForRoom()` resolves this on each message. diff --git a/architecture.md b/architecture.md index 6d54000..de08a09 100644 --- a/architecture.md +++ b/architecture.md @@ -201,7 +201,7 @@ In Talk 14+, the `actorDisplayName` field in the Chat API **must match** the bot ### Sender name embedding -Since NCTalk doesn't support per-message avatars, the app prepends a bold emoji-prefixed sender name line to the message text: +Since NCTalk doesn't support per-message avatars, the app prepends a type-icon (for Apprise) + emoji-prefixed sender name line to the message text: ``` 🤖 **CI Bot** @@ -209,6 +209,16 @@ Since NCTalk doesn't support per-message avatars, the app prepends a bold emoji- Build #1234 passed ``` +For Apprise with a `type` field: + +``` +⚠️ 🤖 **CI Bot** + +Build #1234 failed +``` + +Icons: ✅ (success), ⚠️ (warning), ❌ (error). Info and image types have no icon. + This preserves the visual identity of the sending service within Talk's message rendering. ### Auth token storage