diff options
author | 2023-09-08 22:45:17 -0700 | |
---|---|---|
committer | 2023-09-09 13:11:42 -0700 | |
commit | 48f6885f4472efbe0e23f990ae8d4545f9a6a73d (patch) | |
tree | a05b35013e65f95013f90006b07870ddaeaf4065 /internal/integration | |
parent | 32d33104a4934771ca99b1bcfe55bd0e4e88809b (diff) | |
download | v2-48f6885f4472efbe0e23f990ae8d4545f9a6a73d.tar.gz v2-48f6885f4472efbe0e23f990ae8d4545f9a6a73d.tar.zst v2-48f6885f4472efbe0e23f990ae8d4545f9a6a73d.zip |
Add generic webhook integration
Diffstat (limited to 'internal/integration')
-rw-r--r-- | internal/integration/integration.go | 69 | ||||
-rw-r--r-- | internal/integration/webhook/webhook.go | 64 |
2 files changed, 104 insertions, 29 deletions
diff --git a/internal/integration/integration.go b/internal/integration/integration.go index 65d005d8..07b70308 100644 --- a/internal/integration/integration.go +++ b/internal/integration/integration.go @@ -19,6 +19,7 @@ import ( "miniflux.app/v2/internal/integration/shiori" "miniflux.app/v2/internal/integration/telegrambot" "miniflux.app/v2/internal/integration/wallabag" + "miniflux.app/v2/internal/integration/webhook" "miniflux.app/v2/internal/logger" "miniflux.app/v2/internal/model" ) @@ -168,45 +169,55 @@ func SendEntry(entry *model.Entry, integration *model.Integration) { } } -// PushEntries pushes an entry array to third-party providers during feed refreshes. -func PushEntries(entries model.Entries, integration *model.Integration) { - if integration.MatrixBotEnabled { - logger.Debug("[Integration] Sending %d entries for User #%d to Matrix", len(entries), integration.UserID) +// PushEntries pushes a list of entries to activated third-party providers during feed refreshes. +func PushEntries(feed *model.Feed, entries model.Entries, userIntegrations *model.Integration) { + if userIntegrations.MatrixBotEnabled { + logger.Debug("[Integration] Sending %d entries for User #%d to Matrix", len(entries), userIntegrations.UserID) - err := matrixbot.PushEntries(entries, integration.MatrixBotURL, integration.MatrixBotUser, integration.MatrixBotPassword, integration.MatrixBotChatID) + err := matrixbot.PushEntries(entries, userIntegrations.MatrixBotURL, userIntegrations.MatrixBotUser, userIntegrations.MatrixBotPassword, userIntegrations.MatrixBotChatID) if err != nil { logger.Error("[Integration] push entries to matrix bot failed: %v", err) } } -} -// PushEntry pushes an entry to third-party providers during feed refreshes. -func PushEntry(entry *model.Entry, feed *model.Feed, integration *model.Integration) { - if integration.TelegramBotEnabled { - logger.Debug("[Integration] Sending Entry %q for User #%d to Telegram", entry.URL, integration.UserID) + if userIntegrations.WebhookEnabled { + logger.Debug("[Integration] Sending %d entries for User #%d to Webhook URL: %s", len(entries), userIntegrations.UserID, userIntegrations.WebhookURL) - err := telegrambot.PushEntry(entry, integration.TelegramBotToken, integration.TelegramBotChatID) - if err != nil { - logger.Error("[Integration] push entry to telegram bot failed: %v", err) + webhookClient := webhook.NewClient(userIntegrations.WebhookURL, userIntegrations.WebhookSecret) + if err := webhookClient.SendWebhook(entries); err != nil { + logger.Error("[Integration] sending entries to webhook failed: %v", err) } } - if integration.AppriseEnabled { - logger.Debug("[Integration] Sending Entry %q for User #%d to apprise", entry.URL, integration.UserID) - - var appriseServiceURLs string - if len(feed.AppriseServiceURLs) > 0 { - appriseServiceURLs = feed.AppriseServiceURLs - } else { - appriseServiceURLs = integration.AppriseServicesURL - } - - client := apprise.NewClient( - appriseServiceURLs, - integration.AppriseURL, - ) - if err := client.SendNotification(entry); err != nil { - logger.Error("[Integration] push entry to apprise failed: %v", err) + // Integrations that only support sending individual entries + if userIntegrations.TelegramBotEnabled || userIntegrations.AppriseEnabled { + for _, entry := range entries { + if userIntegrations.TelegramBotEnabled { + logger.Debug("[Integration] Sending Entry %q for User #%d to Telegram", entry.URL, userIntegrations.UserID) + + err := telegrambot.PushEntry(entry, userIntegrations.TelegramBotToken, userIntegrations.TelegramBotChatID) + if err != nil { + logger.Error("[Integration] push entry to telegram bot failed: %v", err) + } + } + + if userIntegrations.AppriseEnabled { + logger.Debug("[Integration] Sending Entry %q for User #%d to apprise", entry.URL, userIntegrations.UserID) + + appriseServiceURLs := userIntegrations.AppriseURL + if feed.AppriseServiceURLs != "" { + appriseServiceURLs = feed.AppriseServiceURLs + } + + client := apprise.NewClient( + userIntegrations.AppriseServicesURL, + appriseServiceURLs, + ) + + if err := client.SendNotification(entry); err != nil { + logger.Error("[Integration] push entry to apprise failed: %v", err) + } + } } } } diff --git a/internal/integration/webhook/webhook.go b/internal/integration/webhook/webhook.go new file mode 100644 index 00000000..65f5fa8c --- /dev/null +++ b/internal/integration/webhook/webhook.go @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package webhook // import "miniflux.app/v2/internal/integration/webhook" + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "time" + + "miniflux.app/v2/internal/crypto" + "miniflux.app/v2/internal/model" + "miniflux.app/v2/internal/version" +) + +const defaultClientTimeout = 10 * time.Second + +type Client struct { + webhookURL string + webhookSecret string +} + +func NewClient(webhookURL, webhookSecret string) *Client { + return &Client{webhookURL, webhookSecret} +} + +func (c *Client) SendWebhook(entries model.Entries) error { + if c.webhookURL == "" { + return fmt.Errorf(`webhook: missing webhook URL`) + } + + if len(entries) == 0 { + return nil + } + + requestBody, err := json.Marshal(entries) + if err != nil { + return fmt.Errorf("webhook: unable to encode request body: %v", err) + } + + request, err := http.NewRequest(http.MethodPost, c.webhookURL, bytes.NewReader(requestBody)) + if err != nil { + return fmt.Errorf("webhook: unable to create request: %v", err) + } + + request.Header.Set("Content-Type", "application/json") + request.Header.Set("User-Agent", "Miniflux/"+version.Version) + request.Header.Set("X-Miniflux-Signature", crypto.GenerateSHA256Hmac(c.webhookSecret, requestBody)) + + httpClient := &http.Client{Timeout: defaultClientTimeout} + response, err := httpClient.Do(request) + if err != nil { + return fmt.Errorf("webhook: unable to send request: %v", err) + } + defer response.Body.Close() + + if response.StatusCode >= 400 { + return fmt.Errorf("webhook: incorrect response status code: url=%s status=%d", c.webhookURL, response.StatusCode) + } + + return nil +} |