Browse Source

feat(pushover): add integration with pushover.net

Sergio Moura 1 year ago
parent
commit
3387201634
32 changed files with 510 additions and 6 deletions
  1. 14 0
      internal/database/migrations.go
  2. 21 0
      internal/integration/integration.go
  3. 138 0
      internal/integration/pushover/pushover.go
  4. 12 0
      internal/locale/translations/de_DE.json
  5. 12 0
      internal/locale/translations/el_EL.json
  6. 12 0
      internal/locale/translations/en_US.json
  7. 12 0
      internal/locale/translations/es_ES.json
  8. 12 0
      internal/locale/translations/fi_FI.json
  9. 12 0
      internal/locale/translations/fr_FR.json
  10. 12 0
      internal/locale/translations/hi_IN.json
  11. 12 0
      internal/locale/translations/id_ID.json
  12. 12 0
      internal/locale/translations/it_IT.json
  13. 12 0
      internal/locale/translations/ja_JP.json
  14. 12 0
      internal/locale/translations/nl_NL.json
  15. 12 0
      internal/locale/translations/pl_PL.json
  16. 12 0
      internal/locale/translations/pt_BR.json
  17. 12 0
      internal/locale/translations/ru_RU.json
  18. 12 0
      internal/locale/translations/tr_TR.json
  19. 12 0
      internal/locale/translations/uk_UA.json
  20. 12 0
      internal/locale/translations/zh_CN.json
  21. 12 0
      internal/locale/translations/zh_TW.json
  22. 2 0
      internal/model/feed.go
  23. 5 0
      internal/model/integration.go
  24. 6 2
      internal/storage/feed.go
  25. 5 1
      internal/storage/feed_query_builder.go
  26. 23 3
      internal/storage/integration.go
  27. 21 0
      internal/template/templates/views/edit_feed.html
  28. 25 0
      internal/template/templates/views/integrations.html
  29. 2 0
      internal/ui/feed_edit.go
  30. 12 0
      internal/ui/form/feed.go
  31. 15 0
      internal/ui/form/integration.go
  32. 5 0
      internal/ui/integration_show.go

+ 14 - 0
internal/database/migrations.go

@@ -994,4 +994,18 @@ var migrations = []func(tx *sql.Tx, driver string) error{
 		_, err = tx.Exec(`ALTER TABLE feeds ADD COLUMN webhook_url text default '';`)
 		return err
 	},
+	func(tx *sql.Tx, _ string) (err error) {
+		sql := `
+			ALTER TABLE integrations ADD COLUMN pushover_enabled bool default 'f';
+			ALTER TABLE integrations ADD COLUMN pushover_user text default '';
+			ALTER TABLE integrations ADD COLUMN pushover_token text default '';
+			ALTER TABLE integrations ADD COLUMN pushover_device text default '';
+			ALTER TABLE integrations ADD COLUMN pushover_prefix text default '';
+
+			ALTER TABLE feeds ADD COLUMN pushover_enabled bool default 'f';
+			ALTER TABLE feeds ADD COLUMN pushover_priority int default '0';
+		`
+		_, err = tx.Exec(sql)
+		return err
+	},
 }

+ 21 - 0
internal/integration/integration.go

@@ -23,6 +23,7 @@ import (
 	"miniflux.app/v2/internal/integration/omnivore"
 	"miniflux.app/v2/internal/integration/pinboard"
 	"miniflux.app/v2/internal/integration/pocket"
+	"miniflux.app/v2/internal/integration/pushover"
 	"miniflux.app/v2/internal/integration/raindrop"
 	"miniflux.app/v2/internal/integration/readeck"
 	"miniflux.app/v2/internal/integration/readwise"
@@ -577,6 +578,26 @@ func PushEntries(feed *model.Feed, entries model.Entries, userIntegrations *mode
 		}
 	}
 
+	if userIntegrations.PushoverEnabled && feed.PushoverEnabled {
+		slog.Debug("Sending new entries to Pushover",
+			slog.Int64("user_id", userIntegrations.UserID),
+			slog.Int("nb_entries", len(entries)),
+			slog.Int64("feed_id", feed.ID),
+		)
+
+		client := pushover.New(
+			userIntegrations.PushoverUser,
+			userIntegrations.PushoverToken,
+			feed.PushoverPriority,
+			userIntegrations.PushoverDevice,
+			userIntegrations.PushoverPrefix,
+		)
+
+		if err := client.SendMessages(feed, entries); err != nil {
+			slog.Warn("Unable to send new entries to Pushover", slog.Any("error", err))
+		}
+	}
+
 	// Integrations that only support sending individual entries
 	if userIntegrations.TelegramBotEnabled {
 		for _, entry := range entries {

+ 138 - 0
internal/integration/pushover/pushover.go

@@ -0,0 +1,138 @@
+// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package pushover // import "miniflux.app/v2/internal/integration/pushover"
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"log/slog"
+	"net/http"
+	"strings"
+	"time"
+
+	"miniflux.app/v2/internal/model"
+	"miniflux.app/v2/internal/version"
+)
+
+const (
+	defaultClientTimeout = 10 * time.Second
+	defaultPushoverURL   = "https://api.pushover.net"
+)
+
+type Client struct {
+	prefix string
+
+	token  string
+	user   string
+	device string
+
+	priority int
+}
+
+type Message struct {
+	Token string `json:"token"`
+	User  string `json:"user"`
+
+	Title    string `json:"title"`
+	Message  string `json:"message"`
+	Priority int    `json:"priority"`
+
+	URL      string `json:"url"`
+	URLTitle string `json:"url_title"`
+	Device   string `json:"device,omitempty"`
+}
+
+type ErrorResponse struct {
+	User    string   `json:"user"`
+	Errors  []string `json:"errors"`
+	Status  int      `json:"status"`
+	Request string   `json:"request"`
+}
+
+func New(user, token string, priority int, device, urlPrefix string) *Client {
+	if urlPrefix == "" {
+		urlPrefix = defaultPushoverURL
+	}
+	if priority < -2 {
+		priority = -2
+	}
+	if priority > 2 {
+		priority = 2
+	}
+
+	return &Client{
+		user:     user,
+		token:    token,
+		device:   device,
+		prefix:   urlPrefix,
+		priority: priority,
+	}
+}
+
+func (c *Client) SendMessages(feed *model.Feed, entries model.Entries) error {
+	if c.token == "" || c.user == "" {
+		return fmt.Errorf("pushover token and user are required")
+	}
+	for _, entry := range entries {
+		msg := &Message{
+			User:   c.user,
+			Token:  c.token,
+			Device: c.device,
+
+			Message:  entry.Title,
+			Title:    feed.Title,
+			Priority: c.priority,
+			URL:      entry.URL,
+		}
+
+		slog.Debug("Sending Pushover message",
+			slog.Int("priority", msg.Priority),
+			slog.String("message", msg.Message),
+			slog.String("entry_url", msg.URL),
+		)
+
+		if err := c.makeRequest(msg); err != nil {
+			return fmt.Errorf("c.makeRequest: %w", err)
+		}
+	}
+
+	return nil
+}
+
+func (c *Client) makeRequest(payload *Message) error {
+	jsonData, err := json.Marshal(payload)
+	if err != nil {
+		return fmt.Errorf("json.Marshal: %w", err)
+	}
+	url := c.prefix + "/1/messages.json"
+	req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(jsonData))
+	if err != nil {
+		return fmt.Errorf("http.NewRequest: %w", err)
+	}
+
+	req.Header.Add("Content-Type", "application/json")
+	req.Header.Set("User-Agent", "Miniflux/"+version.Version)
+
+	httpClient := &http.Client{Timeout: defaultClientTimeout}
+	resp, err := httpClient.Do(req)
+	if err != nil {
+		return fmt.Errorf("httpClient.Do: %w", err)
+	}
+	defer resp.Body.Close()
+
+	if resp.StatusCode >= http.StatusBadRequest {
+		errorMessage := resp.Status
+
+		var errResp ErrorResponse
+		if err := json.NewDecoder(resp.Body).Decode(&errResp); err != nil {
+			if len(errResp.Errors) > 0 {
+				errorMessage = strings.Join(errResp.Errors, ",")
+			}
+		}
+
+		return fmt.Errorf("pushover API error (%d): %s", resp.StatusCode, errorMessage)
+	}
+
+	return nil
+}

+ 12 - 0
internal/locale/translations/de_DE.json

@@ -357,6 +357,13 @@
     "form.feed.label.ntfy_default_priority": "Normale Ntfy-Priorität",
     "form.feed.label.ntfy_low_priority": "Niedrige Ntfy-Priorität",
     "form.feed.label.ntfy_min_priority": "Niedrigste Ntfy-Priorität",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.integration.cubox_activate": "Einträge in Cubox speichern",
     "form.integration.cubox_api_link": "Cubox-API-Link",
     "form.feed.fieldset.general": "Allgemein",
@@ -519,6 +526,11 @@
     "form.integration.discord_webhook_link": "Discord-Webhook-URL",
     "form.integration.slack_activate": "Einträge zu Slack pushen",
     "form.integration.slack_webhook_link": "Slack-Webhook-URL",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.api_key.label.description": "API-Schlüsselbezeichnung",
     "form.submit.loading": "Lade...",
     "form.submit.saving": "Speichern...",

+ 12 - 0
internal/locale/translations/el_EL.json

@@ -361,6 +361,13 @@
     "form.feed.label.ntfy_default_priority": "Ntfy default priority",
     "form.feed.label.ntfy_low_priority": "Ntfy low priority",
     "form.feed.label.ntfy_min_priority": "Ntfy min priority",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.integration.cubox_activate": "Save entries to Cubox",
     "form.integration.cubox_api_link": "Cubox API link",
     "form.category.label.title": "Τίτλος",
@@ -519,6 +526,11 @@
     "form.integration.discord_webhook_link": "Discord Webhook link",
     "form.integration.slack_activate": "Push entries to Slack",
     "form.integration.slack_webhook_link": "Slack Webhook link",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.api_key.label.description": "Ετικέτα κλειδιού API",
     "form.submit.loading": "Φόρτωση...",
     "form.submit.saving": "Αποθήκευση...",

+ 12 - 0
internal/locale/translations/en_US.json

@@ -357,6 +357,13 @@
     "form.feed.label.ntfy_default_priority": "Ntfy default priority",
     "form.feed.label.ntfy_low_priority": "Ntfy low priority",
     "form.feed.label.ntfy_min_priority": "Ntfy min priority",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.feed.fieldset.general": "General",
     "form.feed.fieldset.rules": "Rules",
     "form.feed.fieldset.network_settings": "Network Settings",
@@ -519,6 +526,11 @@
     "form.integration.discord_webhook_link": "Discord Webhook link",
     "form.integration.slack_activate": "Push entries to Slack",
     "form.integration.slack_webhook_link": "Slack Webhook link",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.api_key.label.description": "API Key Label",
     "form.submit.loading": "Loading…",
     "form.submit.saving": "Saving…",

+ 12 - 0
internal/locale/translations/es_ES.json

@@ -357,6 +357,13 @@
     "form.feed.label.ntfy_default_priority": "Prioridad predeterminada a Ntfy",
     "form.feed.label.ntfy_low_priority": "Prioridad baja a Ntfy",
     "form.feed.label.ntfy_min_priority": "Prioridad mínima a Ntfy",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.integration.cubox_activate": "Save entries to Cubox",
     "form.integration.cubox_api_link": "Cubox API link",
     "form.feed.fieldset.general": "General",
@@ -519,6 +526,11 @@
     "form.integration.discord_webhook_link": "URL de la Webhook de Discord",
     "form.integration.slack_activate": "Enviar artículos a Slack",
     "form.integration.slack_webhook_link": "URL de la Webhook de Slack",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.api_key.label.description": "Etiqueta de clave API",
     "form.submit.loading": "Cargando...",
     "form.submit.saving": "Guardando...",

+ 12 - 0
internal/locale/translations/fi_FI.json

@@ -357,6 +357,13 @@
     "form.feed.label.ntfy_default_priority": "Ntfy default priority",
     "form.feed.label.ntfy_low_priority": "Ntfy low priority",
     "form.feed.label.ntfy_min_priority": "Ntfy min priority",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.integration.cubox_activate": "Save entries to Cubox",
     "form.integration.cubox_api_link": "Cubox API link",
     "form.feed.fieldset.general": "General",
@@ -519,6 +526,11 @@
     "form.integration.discord_webhook_link": "Discord Webhook link",
     "form.integration.slack_activate": "Push entries to Slack",
     "form.integration.slack_webhook_link": "Slack Webhook link",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.api_key.label.description": "API Key Label",
     "form.submit.loading": "Ladataan...",
     "form.submit.saving": "Tallennetaan...",

+ 12 - 0
internal/locale/translations/fr_FR.json

@@ -357,6 +357,13 @@
     "form.feed.label.ntfy_default_priority": "Priorité par défaut de notification",
     "form.feed.label.ntfy_low_priority": "Priorité basse de notification",
     "form.feed.label.ntfy_min_priority": "Priorité minimale de notification",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.integration.cubox_activate": "Save entries to Cubox",
     "form.integration.cubox_api_link": "Cubox API link",
     "form.feed.fieldset.general": "Général",
@@ -519,6 +526,11 @@
     "form.integration.discord_webhook_link": "URL du Webhook Discord",
     "form.integration.slack_activate": "Envoyer les articles vers Slack",
     "form.integration.slack_webhook_link": "URL du Webhook Slack",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.api_key.label.description": "Libellé de la clé d'API",
     "form.submit.loading": "Chargement...",
     "form.submit.saving": "Sauvegarde en cours...",

+ 12 - 0
internal/locale/translations/hi_IN.json

@@ -357,6 +357,13 @@
     "form.feed.label.ntfy_default_priority": "Ntfy default priority",
     "form.feed.label.ntfy_low_priority": "Ntfy low priority",
     "form.feed.label.ntfy_min_priority": "Ntfy min priority",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.integration.cubox_activate": "Save entries to Cubox",
     "form.integration.cubox_api_link": "Cubox API link",
     "form.feed.fieldset.general": "General",
@@ -519,6 +526,11 @@
     "form.integration.discord_webhook_link": "Discord Webhook link",
     "form.integration.slack_activate": "Push entries to Slack",
     "form.integration.slack_webhook_link": "Slack Webhook link",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.api_key.label.description": "एपीआई कुंजी लेबल",
     "form.submit.loading": "लोड हो रहा है...",
     "form.submit.saving": "सहेजा जा रहा है...",

+ 12 - 0
internal/locale/translations/id_ID.json

@@ -347,6 +347,13 @@
     "form.feed.label.ntfy_default_priority": "Ntfy default priority",
     "form.feed.label.ntfy_low_priority": "Ntfy low priority",
     "form.feed.label.ntfy_min_priority": "Ntfy min priority",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.integration.cubox_activate": "Save entries to Cubox",
     "form.integration.cubox_api_link": "Cubox API link",
     "form.feed.fieldset.general": "General",
@@ -509,6 +516,11 @@
     "form.integration.discord_webhook_link": "Discord Webhook link",
     "form.integration.slack_activate": "Push entries to Slack",
     "form.integration.slack_webhook_link": "Slack Webhook link",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.api_key.label.description": "Label Kunci API",
     "form.submit.loading": "Memuat...",
     "form.submit.saving": "Menyimpan...",

+ 12 - 0
internal/locale/translations/it_IT.json

@@ -357,6 +357,13 @@
     "form.feed.label.ntfy_default_priority": "Ntfy default priority",
     "form.feed.label.ntfy_low_priority": "Ntfy low priority",
     "form.feed.label.ntfy_min_priority": "Ntfy min priority",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.integration.cubox_activate": "Save entries to Cubox",
     "form.integration.cubox_api_link": "Cubox API link",
     "form.feed.fieldset.general": "General",
@@ -519,6 +526,11 @@
     "form.integration.discord_activate": "Push entries to Discord",
     "form.integration.discord_webhook_link": "Discord Webhook link",
     "form.integration.slack_activate": "Push entries to Slack",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.integration.slack_webhook_link": "Slack Webhook link",
     "form.submit.loading": "Caricamento in corso...",
     "form.submit.saving": "Salvataggio in corso...",

+ 12 - 0
internal/locale/translations/ja_JP.json

@@ -347,6 +347,13 @@
     "form.feed.label.ntfy_default_priority": "Ntfy default priority",
     "form.feed.label.ntfy_low_priority": "Ntfy low priority",
     "form.feed.label.ntfy_min_priority": "Ntfy min priority",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.integration.cubox_activate": "Save entries to Cubox",
     "form.integration.cubox_api_link": "Cubox API link",
     "form.feed.fieldset.general": "General",
@@ -508,6 +515,11 @@
     "form.integration.discord_activate": "Push entries to Discord",
     "form.integration.discord_webhook_link": "Discord Webhook link",
     "form.integration.slack_activate": "Slack entries to Discord",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.integration.slack_webhook_link": "Slack Webhook link",
     "form.api_key.label.description": "API キーラベル",
     "form.submit.loading": "読み込み中…",

+ 12 - 0
internal/locale/translations/nl_NL.json

@@ -357,6 +357,13 @@
     "form.feed.label.ntfy_default_priority": "Ntfy standaard prioriteit",
     "form.feed.label.ntfy_low_priority": "Ntfy lage prioriteit",
     "form.feed.label.ntfy_min_priority": "Ntfy minimale prioriteit",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.integration.cubox_activate": "Save entries to Cubox",
     "form.integration.cubox_api_link": "Cubox API link",
     "form.feed.fieldset.general": "Algemeen",
@@ -519,6 +526,11 @@
     "form.integration.discord_webhook_link": "Discord Webhook link",
     "form.integration.slack_activate": "Artikelen opslaan in Slack",
     "form.integration.slack_webhook_link": "Slack Webhook link",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.api_key.label.description": "API-sleutel omschrijving",
     "form.submit.loading": "Laden...",
     "form.submit.saving": "Opslaan...",

+ 12 - 0
internal/locale/translations/pl_PL.json

@@ -367,6 +367,13 @@
     "form.feed.label.ntfy_default_priority": "Domyślny priorytet ntfy",
     "form.feed.label.ntfy_low_priority": "Niski priorytet ntfy",
     "form.feed.label.ntfy_min_priority": "Minimalny priorytet ntfy",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.integration.cubox_activate": "Zapisuj wpisy w Cubox",
     "form.integration.cubox_api_link": "Łącze API Cubox",
     "form.feed.fieldset.general": "Ogólne",
@@ -529,6 +536,11 @@
     "form.integration.discord_webhook_link": "Adres URL webhooka Discord",
     "form.integration.slack_activate": "Przesyłaj wpisy do Slack",
     "form.integration.slack_webhook_link": "Adres URL webhooka Slack",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.api_key.label.description": "Etykieta klucza API",
     "form.submit.loading": "Ładowanie…",
     "form.submit.saving": "Zapisywanie…",

+ 12 - 0
internal/locale/translations/pt_BR.json

@@ -357,6 +357,13 @@
     "form.feed.label.ntfy_default_priority": "Ntfy default priority",
     "form.feed.label.ntfy_low_priority": "Ntfy low priority",
     "form.feed.label.ntfy_min_priority": "Ntfy min priority",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.integration.cubox_activate": "Save entries to Cubox",
     "form.integration.cubox_api_link": "Cubox API link",
     "form.feed.fieldset.general": "General",
@@ -519,6 +526,11 @@
     "form.integration.discord_webhook_link": "Discord Webhook link",
     "form.integration.slack_activate": "Slack entries to Discord",
     "form.integration.slack_webhook_link": "Slack Webhook link",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.api_key.label.description": "Etiqueta da chave de API",
     "form.submit.loading": "Carregando...",
     "form.submit.saving": "Salvando...",

+ 12 - 0
internal/locale/translations/ru_RU.json

@@ -367,6 +367,13 @@
     "form.feed.label.ntfy_default_priority": "Ntfy default priority",
     "form.feed.label.ntfy_low_priority": "Ntfy low priority",
     "form.feed.label.ntfy_min_priority": "Ntfy min priority",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.integration.cubox_activate": "Save entries to Cubox",
     "form.integration.cubox_api_link": "Cubox API link",
     "form.feed.fieldset.general": "General",
@@ -529,6 +536,11 @@
     "form.integration.discord_webhook_link": "Ссылка на Discord Webhook",
     "form.integration.slack_activate": "Отправить статьи в Slack",
     "form.integration.slack_webhook_link": "Ссылка на Slack Webhook",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.api_key.label.description": "Описание API-ключа",
     "form.submit.loading": "Загрузка…",
     "form.submit.saving": "Сохранение…",

+ 12 - 0
internal/locale/translations/tr_TR.json

@@ -288,12 +288,24 @@
   "form.feed.label.ntfy_default_priority": "Ntfy default priority",
   "form.feed.label.ntfy_low_priority": "Ntfy low priority",
   "form.feed.label.ntfy_min_priority": "Ntfy min priority",
+  "form.feed.label.pushover_activate": "Push entries to pushover.net",
+  "form.feed.label.pushover_priority": "Pushover message priority",
+  "form.feed.label.pushover_max_priority": "Pushover max priority",
+  "form.feed.label.pushover_high_priority": "Pushover high priority",
+  "form.feed.label.pushover_default_priority": "Pushover default priority",
+  "form.feed.label.pushover_low_priority": "Pushover low priority",
+  "form.feed.label.pushover_min_priority": "Pushover min priority",
   "form.integration.cubox_activate": "Save entries to Cubox",
   "form.integration.cubox_api_link": "Cubox API link",
   "form.integration.discord_activate": "Makaleleri Discord'a gönder",
   "form.integration.discord_webhook_link": "Discord hizmet Webhook'lerinin virgülle ayrılmış listesi",
   "form.integration.slack_activate": "Makaleleri Slack'a gönder",
   "form.integration.slack_webhook_link": "Slack hizmet Webhook'lerinin virgülle ayrılmış listesi",
+  "form.integration.pushover_activate": "Push entries to pushover",
+  "form.integration.pushover_token": "Pushover token",
+  "form.integration.pushover_user": "Pushover user",
+  "form.integration.pushover_device": "Pushover device (optional)",
+  "form.integration.pushover_prefix": "Pushover prefix (optional)",
   "form.prefs.fieldset.application_settings": "Uygulama Ayarları",
   "form.prefs.fieldset.authentication_settings": "Kimlik Doğrulama Ayarları",
   "form.prefs.fieldset.reader_settings": "Okuyucu Ayarları",

+ 12 - 0
internal/locale/translations/uk_UA.json

@@ -367,6 +367,13 @@
     "form.feed.label.ntfy_default_priority": "Ntfy default priority",
     "form.feed.label.ntfy_low_priority": "Ntfy low priority",
     "form.feed.label.ntfy_min_priority": "Ntfy min priority",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.integration.cubox_activate": "Save entries to Cubox",
     "form.integration.cubox_api_link": "Cubox API link",
     "form.category.label.title": "Назва",
@@ -529,6 +536,11 @@
     "form.integration.discord_webhook_link": "Discord Webhook link",
     "form.integration.slack_activate": "Slack entries to Discord",
     "form.integration.slack_webhook_link": "Slack Webhook link",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.api_key.label.description": "Назва ключа API",
     "form.submit.loading": "Завантаження...",
     "form.submit.saving": "Зберігаю...",

+ 12 - 0
internal/locale/translations/zh_CN.json

@@ -347,6 +347,13 @@
     "form.feed.label.ntfy_default_priority": "Ntfy默认优先级",
     "form.feed.label.ntfy_low_priority": "Ntfy低优先级",
     "form.feed.label.ntfy_min_priority": "Ntfy最低优先级",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.integration.cubox_activate": "保存文章到 Cubox",
     "form.integration.cubox_api_link": "Cubox API 链接",
     "form.feed.fieldset.general": "通用",
@@ -509,6 +516,11 @@
     "form.integration.discord_webhook_link": "Discord Webhook link",
     "form.integration.slack_activate": "将新文章推送到 Slack",
     "form.integration.slack_webhook_link": "Slack Webhook link",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.api_key.label.description": "API密钥标签",
     "form.submit.loading": "载入中…",
     "form.submit.saving": "保存中…",

+ 12 - 0
internal/locale/translations/zh_TW.json

@@ -347,6 +347,13 @@
     "form.feed.label.ntfy_default_priority": "Ntfy 預設優先順序",
     "form.feed.label.ntfy_low_priority": "Ntfy 低優先順序",
     "form.feed.label.ntfy_min_priority": "Ntfy 最低優先順序",
+    "form.feed.label.pushover_activate": "Push entries to pushover.net",
+    "form.feed.label.pushover_priority": "Pushover message priority",
+    "form.feed.label.pushover_max_priority": "Pushover max priority",
+    "form.feed.label.pushover_high_priority": "Pushover high priority",
+    "form.feed.label.pushover_default_priority": "Pushover default priority",
+    "form.feed.label.pushover_low_priority": "Pushover low priority",
+    "form.feed.label.pushover_min_priority": "Pushover min priority",
     "form.integration.cubox_activate": "儲存文章到 Cubox",
     "form.integration.cubox_api_link": "Cubox API 連結",
     "form.feed.fieldset.general": "通用",
@@ -509,6 +516,11 @@
     "form.integration.discord_webhook_link": "Discord Webhook 連結",
     "form.integration.slack_activate": "推送文章到 Slack",
     "form.integration.slack_webhook_link": "Slack Webhook 連結",
+    "form.integration.pushover_activate": "Push entries to pushover",
+    "form.integration.pushover_token": "Pushover token",
+    "form.integration.pushover_user": "Pushover user",
+    "form.integration.pushover_device": "Pushover device (optional)",
+    "form.integration.pushover_prefix": "Pushover prefix (optional)",
     "form.api_key.label.description": "API 金鑰標籤",
     "form.submit.loading": "載入中…",
     "form.submit.saving": "儲存中…",

+ 2 - 0
internal/model/feed.go

@@ -56,6 +56,8 @@ type Feed struct {
 	WebhookURL                  string    `json:"webhook_url"`
 	NtfyEnabled                 bool      `json:"ntfy_enabled"`
 	NtfyPriority                int       `json:"ntfy_priority"`
+	PushoverEnabled             bool      `json:"pushover_enabled,omitempty"`
+	PushoverPriority            int       `json:"pushover_priority,omitempty"`
 
 	// Non-persisted attributes
 	Category *Category `json:"category,omitempty"`

+ 5 - 0
internal/model/integration.go

@@ -111,4 +111,9 @@ type Integration struct {
 	DiscordWebhookLink               string
 	SlackEnabled                     bool
 	SlackWebhookLink                 string
+	PushoverEnabled                  bool
+	PushoverUser                     string
+	PushoverToken                    string
+	PushoverDevice                   string
+	PushoverPrefix                   string
 }

+ 6 - 2
internal/storage/feed.go

@@ -360,9 +360,11 @@ func (s *Storage) UpdateFeed(feed *model.Feed) (err error) {
 			disable_http2=$29,
 			description=$30,
 			ntfy_enabled=$31,
-			ntfy_priority=$32
+			ntfy_priority=$32,
+			pushover_enabled=$33,
+			pushover_priority=$34
 		WHERE
-			id=$33 AND user_id=$34
+			id=$35 AND user_id=$36
 	`
 	_, err = s.db.Exec(query,
 		feed.FeedURL,
@@ -397,6 +399,8 @@ func (s *Storage) UpdateFeed(feed *model.Feed) (err error) {
 		feed.Description,
 		feed.NtfyEnabled,
 		feed.NtfyPriority,
+		feed.PushoverEnabled,
+		feed.PushoverPriority,
 		feed.ID,
 		feed.UserID,
 	)

+ 5 - 1
internal/storage/feed_query_builder.go

@@ -168,7 +168,9 @@ func (f *FeedQueryBuilder) GetFeeds() (model.Feeds, error) {
 			f.webhook_url,
 			f.disable_http2,
 			f.ntfy_enabled,
-			f.ntfy_priority
+			f.ntfy_priority,
+			f.pushover_enabled,
+			f.pushover_priority
 		FROM
 			feeds f
 		LEFT JOIN
@@ -240,6 +242,8 @@ func (f *FeedQueryBuilder) GetFeeds() (model.Feeds, error) {
 			&feed.DisableHTTP2,
 			&feed.NtfyEnabled,
 			&feed.NtfyPriority,
+			&feed.PushoverEnabled,
+			&feed.PushoverPriority,
 		)
 
 		if err != nil {

+ 23 - 3
internal/storage/integration.go

@@ -214,7 +214,12 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) {
 			discord_enabled,
 			discord_webhook_link,
 			slack_enabled,
-			slack_webhook_link
+			slack_webhook_link,
+			pushover_enabled,
+			pushover_user,
+			pushover_token,
+			pushover_device,
+			pushover_prefix
 		FROM
 			integrations
 		WHERE
@@ -328,6 +333,11 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) {
 		&integration.DiscordWebhookLink,
 		&integration.SlackEnabled,
 		&integration.SlackWebhookLink,
+		&integration.PushoverEnabled,
+		&integration.PushoverUser,
+		&integration.PushoverToken,
+		&integration.PushoverDevice,
+		&integration.PushoverPrefix,
 	)
 	switch {
 	case err == sql.ErrNoRows:
@@ -449,9 +459,14 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error {
 			discord_enabled=$102,
 			discord_webhook_link=$103,
 			slack_enabled=$104,
-			slack_webhook_link=$105
+			slack_webhook_link=$105,
+			pushover_enabled=$106,
+			pushover_user=$107,
+			pushover_token=$108,
+			pushover_device=$109,
+			pushover_prefix=$110
 		WHERE
-			user_id=$106
+			user_id=$111
 	`
 	_, err := s.db.Exec(
 		query,
@@ -560,6 +575,11 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error {
 		integration.DiscordWebhookLink,
 		integration.SlackEnabled,
 		integration.SlackWebhookLink,
+		integration.PushoverEnabled,
+		integration.PushoverUser,
+		integration.PushoverToken,
+		integration.PushoverDevice,
+		integration.PushoverPrefix,
 		integration.UserID,
 	)
 

+ 21 - 0
internal/template/templates/views/edit_feed.html

@@ -209,6 +209,27 @@
                 </select>
             </details>
 
+            <details {{ if .form.PushoverEnabled }}open{{ end }}>
+                <summary>Pushover</summary>
+                <label><input type="checkbox" name="pushover_enabled" value="1" {{ if .form.PushoverEnabled }}checked{{ end }}> {{ t "form.feed.label.pushover_activate" }}</label>
+                <div class="form-label-row">
+                    <label for="form-pushover-priority">
+                        {{ t "form.feed.label.pushover_priority" }}
+                    </label>
+                    &nbsp;
+                    <a href="https://pushover.net/api#priority" target="_blank">
+                        {{ icon "external-link" }}
+                    </a>
+                </div>
+                <select id="form-pushover-priority" name="pushover_priority">
+                    <option value="2" {{ if eq .form.PushoverPriority 2 }}selected{{ end }}>2 - {{ t "form.feed.label.pushover_max_priority" }}</option>
+                    <option value="1" {{ if eq .form.PushoverPriority 1 }}selected{{ end }}>1 - {{ t "form.feed.label.pushover_high_priority" }}</option>
+                    <option value="0" {{ if eq .form.PushoverPriority 0 }}selected{{ end }}>0 - {{ t "form.feed.label.pushover_default_priority" }}</option>
+                    <option value="-1" {{ if eq .form.PushoverPriority -1 }}selected{{ end }}>-1 - {{ t "form.feed.label.pushover_low_priority" }}</option>
+                    <option value="-2" {{ if eq .form.PushoverPriority -2 }}selected{{ end }}>-2 - {{ t "form.feed.label.pushover_min_priority" }}</option>
+                </select>
+            </details>
+
             <details {{ if .form.WebhookURL }}open{{ end }}>
                 <summary>Webhook</summary>
                 <div class="form-label-row">

+ 25 - 0
internal/template/templates/views/integrations.html

@@ -412,6 +412,31 @@
         </div>
     </details>
 
+    <details {{ if .form.PushoverEnabled }}open{{ end }}>
+        <summary>Pushover</summary>
+        <div class="form-section">
+            <label>
+                <input type="checkbox" name="pushover_enabled" value="1" {{ if .form.PushoverEnabled }}checked{{ end }}> {{ t "form.integration.pushover_activate" }}
+            </label>
+
+            <label for="form-pushover-token">{{ t "form.integration.pushover_token" }}</label>
+            <input type="text" name="pushover_token" id="form-pushover-token" value="{{ .form.PushoverToken }}" spellcheck="false">
+
+            <label for="form-pushover-user">{{ t "form.integration.pushover_user" }}</label>
+            <input type="text" name="pushover_user" id="form-pushover-user" value="{{ .form.PushoverUser }}" spellcheck="false">
+
+            <label for="form-pushover-device">{{ t "form.integration.pushover_device" }}</label>
+            <input type="text" name="pushover_device" id="form-pushover-device" value="{{ .form.PushoverDevice }}" spellcheck="false">
+
+            <label for="form-pushover-prefix">{{ t "form.integration.pushover_prefix" }}</label>
+            <input type="text" name="pushover_prefix" id="form-pushover-prefix" value="{{ .form.PushoverPrefix }}" spellcheck="false" placeholder="https://api.pushover.net">
+
+            <div class="buttons">
+                <button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.saving" }}">{{ t "action.update" }}</button>
+            </div>
+        </div>
+    </details>
+
     <details {{ if .form.RaindropEnabled }}open{{ end }}>
         <summary>Raindrop</summary>
         <div class="form-section">

+ 2 - 0
internal/ui/feed_edit.go

@@ -67,6 +67,8 @@ func (h *handler) showEditFeedPage(w http.ResponseWriter, r *http.Request) {
 		DisableHTTP2:                feed.DisableHTTP2,
 		NtfyEnabled:                 feed.NtfyEnabled,
 		NtfyPriority:                feed.NtfyPriority,
+		PushoverEnabled:             feed.PushoverEnabled,
+		PushoverPriority:            feed.PushoverPriority,
 	}
 
 	sess := session.New(h.store, request.SessionID(r))

+ 12 - 0
internal/ui/form/feed.go

@@ -39,6 +39,8 @@ type FeedForm struct {
 	DisableHTTP2                bool
 	NtfyEnabled                 bool
 	NtfyPriority                int
+	PushoverEnabled             bool
+	PushoverPriority            int
 }
 
 // Merge updates the fields of the given feed.
@@ -71,6 +73,8 @@ func (f FeedForm) Merge(feed *model.Feed) *model.Feed {
 	feed.DisableHTTP2 = f.DisableHTTP2
 	feed.NtfyEnabled = f.NtfyEnabled
 	feed.NtfyPriority = f.NtfyPriority
+	feed.PushoverEnabled = f.PushoverEnabled
+	feed.PushoverPriority = f.PushoverPriority
 	return feed
 }
 
@@ -84,6 +88,12 @@ func NewFeedForm(r *http.Request) *FeedForm {
 	if err != nil {
 		ntfyPriority = 0
 	}
+
+	pushoverPriority, err := strconv.Atoi(r.FormValue("pushover_priority"))
+	if err != nil {
+		pushoverPriority = 0
+	}
+
 	return &FeedForm{
 		FeedURL:                     r.FormValue("feed_url"),
 		SiteURL:                     r.FormValue("site_url"),
@@ -111,5 +121,7 @@ func NewFeedForm(r *http.Request) *FeedForm {
 		DisableHTTP2:                r.FormValue("disable_http2") == "1",
 		NtfyEnabled:                 r.FormValue("ntfy_enabled") == "1",
 		NtfyPriority:                ntfyPriority,
+		PushoverEnabled:             r.FormValue("pushover_enabled") == "1",
+		PushoverPriority:            pushoverPriority,
 	}
 }

+ 15 - 0
internal/ui/form/integration.go

@@ -117,6 +117,11 @@ type IntegrationForm struct {
 	DiscordWebhookLink               string
 	SlackEnabled                     bool
 	SlackWebhookLink                 string
+	PushoverEnabled                  bool
+	PushoverUser                     string
+	PushoverToken                    string
+	PushoverDevice                   string
+	PushoverPrefix                   string
 }
 
 // Merge copy form values to the model.
@@ -223,6 +228,11 @@ func (i IntegrationForm) Merge(integration *model.Integration) {
 	integration.DiscordWebhookLink = i.DiscordWebhookLink
 	integration.SlackEnabled = i.SlackEnabled
 	integration.SlackWebhookLink = i.SlackWebhookLink
+	integration.PushoverEnabled = i.PushoverEnabled
+	integration.PushoverUser = i.PushoverUser
+	integration.PushoverToken = i.PushoverToken
+	integration.PushoverDevice = i.PushoverDevice
+	integration.PushoverPrefix = i.PushoverPrefix
 }
 
 // NewIntegrationForm returns a new IntegrationForm.
@@ -332,6 +342,11 @@ func NewIntegrationForm(r *http.Request) *IntegrationForm {
 		DiscordWebhookLink:               r.FormValue("discord_webhook_link"),
 		SlackEnabled:                     r.FormValue("slack_enabled") == "1",
 		SlackWebhookLink:                 r.FormValue("slack_webhook_link"),
+		PushoverEnabled:                  r.FormValue("pushover_enabled") == "1",
+		PushoverUser:                     r.FormValue("pushover_user"),
+		PushoverToken:                    r.FormValue("pushover_token"),
+		PushoverDevice:                   r.FormValue("pushover_device"),
+		PushoverPrefix:                   r.FormValue("pushover_prefix"),
 	}
 }
 

+ 5 - 0
internal/ui/integration_show.go

@@ -131,6 +131,11 @@ func (h *handler) showIntegrationPage(w http.ResponseWriter, r *http.Request) {
 		DiscordWebhookLink:               integration.DiscordWebhookLink,
 		SlackEnabled:                     integration.SlackEnabled,
 		SlackWebhookLink:                 integration.SlackWebhookLink,
+		PushoverEnabled:                  integration.PushoverEnabled,
+		PushoverUser:                     integration.PushoverUser,
+		PushoverToken:                    integration.PushoverToken,
+		PushoverDevice:                   integration.PushoverDevice,
+		PushoverPrefix:                   integration.PushoverPrefix,
 	}
 
 	sess := session.New(h.store, request.SessionID(r))