feat(nc-webhook): receive Nextcloud file events instead of polling

The watchfiles-based watcher works but duplicates Nextcloud's own
notion of "this file changed." NC has a webhook_listeners app that
can POST file events to an external URL. This adds the mule side of
that handshake.

- POST /api/v1/internal/nc-webhook authenticates a Bearer token
  (NEXTCLOUD_WEBHOOK_SECRET, hmac.compare_digest) and dispatches the
  same scan_folder / handle_file_deletion machinery the watcher used.
- Handles NodeCreated, NodeWritten, NodeDeleted, NodeRenamed.
  Renamed is mapped to delete-old + scan-new-parent. Maps NC's
  /admin/files/... path to the bind-mounted /nextcloud-users/admin/files/...
- backend/scripts/register_nc_webhooks.py is the idempotent
  registrar: lists existing webhooks, deletes any pointing at the
  target URL, then POSTs four fresh ones via OCS.
- Sets the env passthrough on backend + all workers in compose so
  the same secret is available wherever the registrar might run.

watch_folders stays in place for now — webhooks become primary, the
watcher is a belt-and-suspenders fallback. Drop the watcher in a
follow-up once webhooks are proven reliable on this NC instance.
This commit is contained in:
Claudio
2026-05-11 12:19:59 +02:00
parent d24c64e0a0
commit 362fbc6d83
4 changed files with 358 additions and 1 deletions

View File

@@ -97,6 +97,7 @@ services:
# but mutating endpoints fail with a clear error.
- NEXTCLOUD_USERS_ROOT=${NEXTCLOUD_USERS_ROOT:-/nextcloud-users}
- NEXTCLOUD_BASE_URL=${NEXTCLOUD_BASE_URL:-}
- NEXTCLOUD_WEBHOOK_SECRET=${NEXTCLOUD_WEBHOOK_SECRET:-}
- LOG_LEVEL=${LOG_LEVEL:-INFO}
- TZ=${TZ:-UTC}
depends_on:
@@ -160,6 +161,7 @@ services:
- PHOTO_DIRS=/photos
- NEXTCLOUD_USERS_ROOT=${NEXTCLOUD_USERS_ROOT:-/nextcloud-users}
- NEXTCLOUD_BASE_URL=${NEXTCLOUD_BASE_URL:-}
- NEXTCLOUD_WEBHOOK_SECRET=${NEXTCLOUD_WEBHOOK_SECRET:-}
- LOG_LEVEL=${LOG_LEVEL:-INFO}
- TZ=${TZ:-UTC}
# NullPool — see app/database.py for rationale.
@@ -215,6 +217,7 @@ services:
- PHOTO_DIRS=/photos
- NEXTCLOUD_USERS_ROOT=${NEXTCLOUD_USERS_ROOT:-/nextcloud-users}
- NEXTCLOUD_BASE_URL=${NEXTCLOUD_BASE_URL:-}
- NEXTCLOUD_WEBHOOK_SECRET=${NEXTCLOUD_WEBHOOK_SECRET:-}
- LOG_LEVEL=${LOG_LEVEL:-INFO}
- TZ=${TZ:-UTC}
- MULITA_CELERY_WORKER=1
@@ -258,6 +261,7 @@ services:
- PHOTO_DIRS=/photos
- NEXTCLOUD_USERS_ROOT=${NEXTCLOUD_USERS_ROOT:-/nextcloud-users}
- NEXTCLOUD_BASE_URL=${NEXTCLOUD_BASE_URL:-}
- NEXTCLOUD_WEBHOOK_SECRET=${NEXTCLOUD_WEBHOOK_SECRET:-}
- LOG_LEVEL=${LOG_LEVEL:-INFO}
- TZ=${TZ:-UTC}
- MULITA_CELERY_WORKER=1