feat: webhook payload history — store and display recent incoming payloads

Backend:
- WebhookPayloadLog model (provider_id, method, headers, body, status, extracted_fields, error_message)
- Auto-log payloads in generic_webhook() with matched/unmatched/error status
- Auto-prune beyond max_stored_payloads per provider
- Header filtering (only Content-Type, User-Agent, X-* stored; no Authorization)
- GET/DELETE /api/providers/{id}/webhook-logs endpoints
- store_payloads + max_stored_payloads in WebhookProviderConfig

Frontend:
- WebhookPayloadHistory.svelte — expandable log viewer with status badges, JSON body, headers, extracted fields
- payloadHistory flag on webhook provider descriptor
- max_stored_payloads config field (0 = disabled)
- Password confirmation field on change password modal
- i18n keys for webhook logs (en + ru)
This commit is contained in:
2026-03-28 13:54:54 +03:00
parent c41182ffd0
commit 6113a0039c
13 changed files with 459 additions and 5 deletions
+34
View File
@@ -133,6 +133,8 @@
"authMode": "Authentication Mode",
"authModeHint": "Choose hmac_sha256, bearer_token, or none",
"genericWebhookSecretHint": "Secret for HMAC-SHA256 or Bearer token authentication. Leave empty for no authentication.",
"maxStoredPayloads": "Max stored payloads",
"maxStoredPayloadsHint": "Number of recent payloads to keep for debugging (0 = disabled, max 100)",
"webhookSecretRequired": "Webhook secret is required",
"apiToken": "API Token",
"apiTokenHint": "Optional. Needed for connection testing and repository listing.",
@@ -152,11 +154,29 @@
"gpRefreshTokenKeep": "Refresh Token (leave empty to keep current)",
"gpRefreshTokenHint": "Obtain from Google OAuth Playground (developers.google.com/oauthplayground) with the Photos Library API scope.",
"gpAllFieldsRequired": "Client ID, Client Secret, and Refresh Token are all required",
"storePayloads": "Store incoming payloads",
"storePayloadsHint": "Save recent webhook request bodies for debugging",
"maxStoredPayloads": "Max stored payloads",
"maxStoredPayloadsHint": "Number of recent payloads to keep (1-100)",
"testAndSave": "Test & Save",
"saveWithoutTest": "Save without testing",
"selectType": "Select a provider type",
"testFailed": "Connection test failed"
},
"webhookLogs": {
"title": "Recent Payloads",
"empty": "No payloads recorded yet",
"clear": "Clear history",
"confirmClear": "Clear all stored payloads for this provider?",
"statusMatched": "Matched",
"statusUnmatched": "Unmatched",
"statusError": "Error",
"headers": "Headers",
"body": "Request Body",
"extractedFields": "Extracted Fields",
"errorMessage": "Error",
"cleared": "Payload history cleared"
},
"notificationTracker": {
"title": "Notification Trackers",
"description": "Monitor albums for changes",
@@ -951,6 +971,20 @@
"providerGooglePhotos": "Google Photos albums & shared libraries",
"providerWebhook": "Receive events via HTTP POST"
},
"webhookLogs": {
"title": "Recent Payloads",
"empty": "No payloads recorded yet",
"clear": "Clear history",
"confirmClear": "Clear all stored payloads for this provider?",
"statusMatched": "Matched",
"statusUnmatched": "Unmatched",
"statusError": "Error",
"headers": "Headers",
"body": "Request Body",
"extractedFields": "Extracted Fields",
"errorMessage": "Error",
"cleared": "Payload history cleared"
},
"error": {
"notFound": "Page not found",
"goHome": "Go home"
+34
View File
@@ -133,6 +133,8 @@
"authMode": "Режим аутентификации",
"authModeHint": "Выберите hmac_sha256, bearer_token или none",
"genericWebhookSecretHint": "Секрет для HMAC-SHA256 или Bearer token аутентификации. Оставьте пустым для режима без аутентификации.",
"maxStoredPayloads": "Макс. сохранённых запросов",
"maxStoredPayloadsHint": "Количество сохраняемых запросов для отладки (0 = отключено, макс. 100)",
"webhookSecretRequired": "Секрет вебхука обязателен",
"apiToken": "API токен",
"apiTokenHint": "Необязательно. Нужен для проверки подключения и получения списка репозиториев.",
@@ -152,11 +154,29 @@
"gpRefreshTokenKeep": "Refresh Token (оставьте пустым для сохранения текущего)",
"gpRefreshTokenHint": "Получите через Google OAuth Playground (developers.google.com/oauthplayground) с областью Photos Library API.",
"gpAllFieldsRequired": "Client ID, Client Secret и Refresh Token обязательны",
"storePayloads": "Сохранять входящие данные",
"storePayloadsHint": "Сохранять тела недавних вебхук-запросов для отладки",
"maxStoredPayloads": "Макс. сохранённых запросов",
"maxStoredPayloadsHint": "Количество сохраняемых запросов (1-100)",
"testAndSave": "Проверить и сохранить",
"saveWithoutTest": "Сохранить без проверки",
"selectType": "Выберите тип провайдера",
"testFailed": "Ошибка проверки подключения"
},
"webhookLogs": {
"title": "Последние запросы",
"empty": "Записей пока нет",
"clear": "Очистить историю",
"confirmClear": "Очистить все сохранённые запросы для этого провайдера?",
"statusMatched": "Совпадение",
"statusUnmatched": "Не совпало",
"statusError": "Ошибка",
"headers": "Заголовки",
"body": "Тело запроса",
"extractedFields": "Извлечённые поля",
"errorMessage": "Ошибка",
"cleared": "История запросов очищена"
},
"notificationTracker": {
"title": "Трекеры уведомлений",
"description": "Отслеживание изменений в альбомах",
@@ -951,6 +971,20 @@
"providerGooglePhotos": "Альбомы и общие библиотеки Google Фото",
"providerWebhook": "Приём событий через HTTP POST"
},
"webhookLogs": {
"title": "Последние запросы",
"empty": "Записей пока нет",
"clear": "Очистить историю",
"confirmClear": "Очистить все сохранённые запросы для этого провайдера?",
"statusMatched": "Совпадение",
"statusUnmatched": "Не совпало",
"statusError": "Ошибка",
"headers": "Заголовки",
"body": "Тело запроса",
"extractedFields": "Извлечённые поля",
"errorMessage": "Ошибка",
"cleared": "История запросов очищена"
},
"error": {
"notFound": "Страница не найдена",
"goHome": "На главную"