diff --git a/go.mod b/go.mod index 98571347..90bee95c 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/abadojack/whatlanggo v1.0.1 github.com/coreos/go-oidc/v3 v3.8.0 github.com/go-webauthn/webauthn v0.9.4 + github.com/google/uuid v1.4.0 github.com/gorilla/mux v1.8.1 github.com/lib/pq v1.10.9 github.com/prometheus/client_golang v1.17.0 @@ -32,7 +33,6 @@ require ( github.com/fxamacker/cbor/v2 v2.5.0 // indirect github.com/go-jose/go-jose/v3 v3.0.1 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/google/uuid v1.4.0 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect diff --git a/internal/database/migrations.go b/internal/database/migrations.go index 8931772b..be3bef84 100644 --- a/internal/database/migrations.go +++ b/internal/database/migrations.go @@ -825,4 +825,13 @@ var migrations = []func(tx *sql.Tx) error{ `) return }, + func(tx *sql.Tx) (err error) { + sql := ` + ALTER TABLE integrations ADD COLUMN omnivore_enabled bool default 'f'; + ALTER TABLE integrations ADD COLUMN omnivore_api_key text default ''; + ALTER TABLE integrations ADD COLUMN omnivore_url text default ''; + ` + _, err = tx.Exec(sql) + return + }, } diff --git a/internal/integration/integration.go b/internal/integration/integration.go index 5caba729..5d0c98df 100644 --- a/internal/integration/integration.go +++ b/internal/integration/integration.go @@ -14,6 +14,7 @@ import ( "miniflux.app/v2/internal/integration/matrixbot" "miniflux.app/v2/internal/integration/notion" "miniflux.app/v2/internal/integration/nunuxkeeper" + "miniflux.app/v2/internal/integration/omnivore" "miniflux.app/v2/internal/integration/pinboard" "miniflux.app/v2/internal/integration/pocket" "miniflux.app/v2/internal/integration/readwise" @@ -287,6 +288,23 @@ func SendEntry(entry *model.Entry, userIntegrations *model.Integration) { ) } } + if userIntegrations.OmnivoreEnabled { + slog.Debug("Sending entry to Omnivore", + slog.Int64("user_id", userIntegrations.UserID), + slog.Int64("entry_id", entry.ID), + slog.String("entry_url", entry.URL), + ) + + client := omnivore.NewClient(userIntegrations.OmnivoreAPIKey, userIntegrations.OmnivoreURL) + if err := client.SaveUrl(entry.URL); err != nil { + slog.Error("Unable to send entry to Omnivore", + slog.Int64("user_id", userIntegrations.UserID), + slog.Int64("entry_id", entry.ID), + slog.String("entry_url", entry.URL), + slog.Any("error", err), + ) + } + } } // PushEntries pushes a list of entries to activated third-party providers during feed refreshes. diff --git a/internal/integration/omnivore/omnivore.go b/internal/integration/omnivore/omnivore.go new file mode 100644 index 00000000..0f876c60 --- /dev/null +++ b/internal/integration/omnivore/omnivore.go @@ -0,0 +1,101 @@ +// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package omnivore // import "miniflux.app/v2/internal/integration/omnivore" + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "time" + + "github.com/google/uuid" + + "miniflux.app/v2/internal/version" +) + +const defaultClientTimeout = 10 * time.Second + +const defaultApiEndpoint = "https://api-prod.omnivore.app/api/graphql" + +var mutation = ` +mutation SaveUrl($input: SaveUrlInput!) { + saveUrl(input: $input) { + ... on SaveSuccess { + url + clientRequestId + } + ... on SaveError { + errorCodes + message + } + } +} +` + +type SaveUrlInput struct { + ClientRequestId string `json:"clientRequestId"` + Source string `json:"source"` + Url string `json:"url"` +} + +type Client interface { + SaveUrl(url string) error +} + +type client struct { + wrapped *http.Client + apiEndpoint string + apiToken string +} + +func NewClient(apiToken string, apiEndpoint string) Client { + if apiEndpoint == "" { + apiEndpoint = defaultApiEndpoint + } + + return &client{wrapped: &http.Client{Timeout: defaultClientTimeout}, apiEndpoint: apiEndpoint, apiToken: apiToken} +} + +func (c *client) SaveUrl(url string) error { + var payload = map[string]interface{}{ + "query": mutation, + "variables": map[string]interface{}{ + "input": map[string]interface{}{ + "clientRequestId": uuid.New().String(), + "source": "api", + "url": url, + }, + }, + } + b, err := json.Marshal(payload) + if err != nil { + return err + } + req, err := http.NewRequest(http.MethodPost, c.apiEndpoint, bytes.NewReader(b)) + if err != nil { + return err + } + + req.Header.Set("Authorization", c.apiToken) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("User-Agent", "Miniflux/"+version.Version) + + resp, err := c.wrapped.Do(req) + if err != nil { + return err + } + + if resp.StatusCode >= 400 { + defer resp.Body.Close() + b, err = io.ReadAll(resp.Body) + if err != nil { + return err + } + return fmt.Errorf("omnivore: failed to save URL: status=%d %s", resp.StatusCode, string(b)) + } + + return nil +} diff --git a/internal/locale/translations/de_DE.json b/internal/locale/translations/de_DE.json index 4f45f1a6..64d32ce3 100644 --- a/internal/locale/translations/de_DE.json +++ b/internal/locale/translations/de_DE.json @@ -384,6 +384,9 @@ "form.integration.nunux_keeper_activate": "Artikel in Nunux Keeper speichern", "form.integration.nunux_keeper_endpoint": "Nunux Keeper API-Endpunkt", "form.integration.nunux_keeper_api_key": "Nunux Keeper API-Schlüssel", + "form.integration.omnivore_activate": "Artikel in Omnivore speichern", + "form.integration.omnivore_url": "Omnivore API-Endpunkt", + "form.integration.omnivore_api_key": "Omnivore API-Schlüssel", "form.integration.espial_activate": "Artikel in Espial speichern", "form.integration.espial_endpoint": "Espial API-Endpunkt", "form.integration.espial_api_key": "Espial API-Schlüssel", @@ -476,4 +479,4 @@ "error.feed_not_found": "This feed does not exist or does not belong to this user.", "error.unable_to_detect_rssbridge": "Unable to detect feed using RSS-Bridge: %v.", "error.feed_format_not_detected": "Unable to detect feed format: %v." -} \ No newline at end of file +} diff --git a/internal/locale/translations/el_EL.json b/internal/locale/translations/el_EL.json index b084f16c..da4059f8 100644 --- a/internal/locale/translations/el_EL.json +++ b/internal/locale/translations/el_EL.json @@ -384,6 +384,9 @@ "form.integration.nunux_keeper_activate": "Αποθήκευση άρθρων στο Nunux Keeper", "form.integration.nunux_keeper_endpoint": "Τελικό σημείο Nunux Keeper API", "form.integration.nunux_keeper_api_key": "Κλειδί API Nunux Keeper", + "form.integration.omnivore_activate": "Αποθήκευση άρθρων στο Omnivore", + "form.integration.omnivore_url": "Τελικό σημείο Omnivore API", + "form.integration.omnivore_api_key": "Κλειδί API Omnivore", "form.integration.espial_activate": "Αποθήκευση άρθρων στο Espial", "form.integration.espial_endpoint": "Τελικό σημείο Espial API", "form.integration.espial_api_key": "Κλειδί API Espial", @@ -476,4 +479,4 @@ "error.feed_not_found": "This feed does not exist or does not belong to this user.", "error.unable_to_detect_rssbridge": "Unable to detect feed using RSS-Bridge: %v.", "error.feed_format_not_detected": "Unable to detect feed format: %v." -} \ No newline at end of file +} diff --git a/internal/locale/translations/en_US.json b/internal/locale/translations/en_US.json index 70131195..ba8d560d 100644 --- a/internal/locale/translations/en_US.json +++ b/internal/locale/translations/en_US.json @@ -384,6 +384,9 @@ "form.integration.nunux_keeper_activate": "Save entries to Nunux Keeper", "form.integration.nunux_keeper_endpoint": "Nunux Keeper API Endpoint", "form.integration.nunux_keeper_api_key": "Nunux Keeper API key", + "form.integration.omnivore_activate": "Save entries to Omnivore", + "form.integration.omnivore_api_key": "Omnivore API key", + "form.integration.omnivore_url": "Omnivore API Endpoint", "form.integration.espial_activate": "Save entries to Espial", "form.integration.espial_endpoint": "Espial API Endpoint", "form.integration.espial_api_key": "Espial API key", diff --git a/internal/locale/translations/es_ES.json b/internal/locale/translations/es_ES.json index bc1ab9a8..2fa208b9 100644 --- a/internal/locale/translations/es_ES.json +++ b/internal/locale/translations/es_ES.json @@ -384,6 +384,9 @@ "form.integration.nunux_keeper_activate": "Enviar artículos a Nunux Keeper", "form.integration.nunux_keeper_endpoint": "Acceso API de Nunux Keeper", "form.integration.nunux_keeper_api_key": "Clave de API de Nunux Keeper", + "form.integration.omnivore_activate": "Enviar artículos a Omnivore", + "form.integration.omnivore_url": "Acceso API de Omnivore", + "form.integration.omnivore_api_key": "Clave de API de Omnivore", "form.integration.espial_activate": "Enviar artículos a Espial", "form.integration.espial_endpoint": "Acceso API de Espial", "form.integration.espial_api_key": "Clave de API de Espial", @@ -476,4 +479,4 @@ "error.feed_not_found": "This feed does not exist or does not belong to this user.", "error.unable_to_detect_rssbridge": "Unable to detect feed using RSS-Bridge: %v.", "error.feed_format_not_detected": "Unable to detect feed format: %v." -} \ No newline at end of file +} diff --git a/internal/locale/translations/fi_FI.json b/internal/locale/translations/fi_FI.json index b9802d99..5d427e0a 100644 --- a/internal/locale/translations/fi_FI.json +++ b/internal/locale/translations/fi_FI.json @@ -384,6 +384,9 @@ "form.integration.nunux_keeper_activate": "Tallenna artikkelit Nunux Keeperiin", "form.integration.nunux_keeper_endpoint": "Nunux Keeper API-päätepiste", "form.integration.nunux_keeper_api_key": "Nunux Keeper API-avain", + "form.integration.omnivore_activate": "Tallenna artikkelit Omnivoreiin", + "form.integration.omnivore_url": "Omnivore API-päätepiste", + "form.integration.omnivore_api_key": "Omnivore API-avain", "form.integration.espial_activate": "Tallenna artikkelit Espialiin", "form.integration.espial_endpoint": "Espial API-päätepiste", "form.integration.espial_api_key": "Espial API-avain", @@ -476,4 +479,4 @@ "error.feed_not_found": "This feed does not exist or does not belong to this user.", "error.unable_to_detect_rssbridge": "Unable to detect feed using RSS-Bridge: %v.", "error.feed_format_not_detected": "Unable to detect feed format: %v." -} \ No newline at end of file +} diff --git a/internal/locale/translations/fr_FR.json b/internal/locale/translations/fr_FR.json index 882b7d41..57f05b99 100644 --- a/internal/locale/translations/fr_FR.json +++ b/internal/locale/translations/fr_FR.json @@ -384,6 +384,9 @@ "form.integration.nunux_keeper_activate": "Sauvegarder les articles vers Nunux Keeper", "form.integration.nunux_keeper_endpoint": "URL de l'API de Nunux Keeper", "form.integration.nunux_keeper_api_key": "Clé d'API de Nunux Keeper", + "form.integration.omnivore_activate": "Sauvegarder les articles vers Omnivore", + "form.integration.omnivore_url": "URL de l'API de Omnivore", + "form.integration.omnivore_api_key": "Clé d'API de Omnivore", "form.integration.espial_activate": "Sauvegarder les articles vers Espial", "form.integration.espial_endpoint": "URL de l'API de Espial", "form.integration.espial_api_key": "Clé d'API de Espial", @@ -476,4 +479,4 @@ "error.feed_not_found": "Impossible de trouver ce flux.", "error.unable_to_detect_rssbridge": "Impossible de détecter un flux RSS en utilisant RSS-Bridge: %v.", "error.feed_format_not_detected": "Impossible de détecter le format du flux : %v." -} \ No newline at end of file +} diff --git a/internal/locale/translations/hi_IN.json b/internal/locale/translations/hi_IN.json index a2961051..3bff399e 100644 --- a/internal/locale/translations/hi_IN.json +++ b/internal/locale/translations/hi_IN.json @@ -384,6 +384,9 @@ "form.integration.nunux_keeper_activate": "विषय-वस्तु को ननक्स कीपर में सहेजें", "form.integration.nunux_keeper_endpoint": "ननक्स कीपर एपीआई समापन बिंदु", "form.integration.nunux_keeper_api_key": "ननक्स कीपर एपीआई कुंजी", + "form.integration.omnivore_activate": "Save entries to Omnivore", + "form.integration.omnivore_api_key": "Omnivore API key", + "form.integration.omnivore_url": "Omnivore API Endpoint", "form.integration.espial_activate": "विषय-वस्तु को जासूसी में सहेजें", "form.integration.espial_endpoint": "जासूसी एपीआई समापन बिंदु", "form.integration.espial_api_key": "जासूसी एपीआई कुंजी", @@ -476,4 +479,4 @@ "error.feed_not_found": "This feed does not exist or does not belong to this user.", "error.unable_to_detect_rssbridge": "Unable to detect feed using RSS-Bridge: %v.", "error.feed_format_not_detected": "Unable to detect feed format: %v." -} \ No newline at end of file +} diff --git a/internal/locale/translations/id_ID.json b/internal/locale/translations/id_ID.json index fc453509..f9c784df 100644 --- a/internal/locale/translations/id_ID.json +++ b/internal/locale/translations/id_ID.json @@ -381,6 +381,9 @@ "form.integration.nunux_keeper_activate": "Simpan artikel ke Nunux Keeper", "form.integration.nunux_keeper_endpoint": "Titik URL API Nunux Keeper", "form.integration.nunux_keeper_api_key": "Kunci API Nunux Keeper", + "form.integration.omnivore_activate": "Simpan artikel ke Omnivore", + "form.integration.omnivore_url": "Titik URL API Omnivore", + "form.integration.omnivore_api_key": "Kunci API Omnivore", "form.integration.espial_activate": "Simpan artikel ke Espial", "form.integration.espial_endpoint": "Titik URL API Espial", "form.integration.espial_api_key": "Kunci API Espial", @@ -467,4 +470,4 @@ "error.feed_not_found": "This feed does not exist or does not belong to this user.", "error.unable_to_detect_rssbridge": "Unable to detect feed using RSS-Bridge: %v.", "error.feed_format_not_detected": "Unable to detect feed format: %v." -} \ No newline at end of file +} diff --git a/internal/locale/translations/it_IT.json b/internal/locale/translations/it_IT.json index fba0b9e2..b9aa5e87 100644 --- a/internal/locale/translations/it_IT.json +++ b/internal/locale/translations/it_IT.json @@ -384,6 +384,9 @@ "form.integration.nunux_keeper_activate": "Salva gli articoli su Nunux Keeper", "form.integration.nunux_keeper_endpoint": "Endpoint dell'API di Nunux Keeper", "form.integration.nunux_keeper_api_key": "API key dell'account Nunux Keeper", + "form.integration.omnivore_activate": "Salva gli articoli su Omnivore", + "form.integration.omnivore_url": "Endpoint dell'API di Omnivore", + "form.integration.omnivore_api_key": "API key dell'account Omnivore", "form.integration.espial_activate": "Salva gli articoli su Espial", "form.integration.espial_endpoint": "Endpoint dell'API di Espial", "form.integration.espial_api_key": "API key dell'account Espial", @@ -476,4 +479,4 @@ "error.feed_not_found": "This feed does not exist or does not belong to this user.", "error.unable_to_detect_rssbridge": "Unable to detect feed using RSS-Bridge: %v.", "error.feed_format_not_detected": "Unable to detect feed format: %v." -} \ No newline at end of file +} diff --git a/internal/locale/translations/ja_JP.json b/internal/locale/translations/ja_JP.json index 15b5f671..df8c081b 100644 --- a/internal/locale/translations/ja_JP.json +++ b/internal/locale/translations/ja_JP.json @@ -384,6 +384,9 @@ "form.integration.nunux_keeper_activate": "Nunux Keeper に記事を保存する", "form.integration.nunux_keeper_endpoint": "Nunux Keeper の API Endpoint", "form.integration.nunux_keeper_api_key": "Nunux Keeper の API key", + "form.integration.omnivore_activate": "Omnivore に記事を保存する", + "form.integration.omnivore_url": "Omnivore の API Endpoint", + "form.integration.omnivore_api_key": "Omnivore の API key", "form.integration.espial_activate": "Espial に記事を保存する", "form.integration.espial_endpoint": "Espial の API Endpoint", "form.integration.espial_api_key": "Espial の API key", @@ -476,4 +479,4 @@ "error.feed_not_found": "This feed does not exist or does not belong to this user.", "error.unable_to_detect_rssbridge": "Unable to detect feed using RSS-Bridge: %v.", "error.feed_format_not_detected": "Unable to detect feed format: %v." -} \ No newline at end of file +} diff --git a/internal/locale/translations/nl_NL.json b/internal/locale/translations/nl_NL.json index 93a37850..a1b71b87 100644 --- a/internal/locale/translations/nl_NL.json +++ b/internal/locale/translations/nl_NL.json @@ -384,6 +384,9 @@ "form.integration.nunux_keeper_activate": "Opslaan naar Nunux Keeper", "form.integration.nunux_keeper_endpoint": "Nunux Keeper URL", "form.integration.nunux_keeper_api_key": "Nunux Keeper API-sleutel", + "form.integration.omnivore_activate": "Opslaan naar Omnivore", + "form.integration.omnivore_url": "Omnivore URL", + "form.integration.omnivore_api_key": "Omnivore API-sleutel", "form.integration.espial_activate": "Opslaan naar Espial", "form.integration.espial_endpoint": "Espial URL", "form.integration.espial_api_key": "Espial API-sleutel", @@ -476,4 +479,4 @@ "error.feed_not_found": "This feed does not exist or does not belong to this user.", "error.unable_to_detect_rssbridge": "Unable to detect feed using RSS-Bridge: %v.", "error.feed_format_not_detected": "Unable to detect feed format: %v." -} \ No newline at end of file +} diff --git a/internal/locale/translations/pl_PL.json b/internal/locale/translations/pl_PL.json index 0b64ac47..8476ed94 100644 --- a/internal/locale/translations/pl_PL.json +++ b/internal/locale/translations/pl_PL.json @@ -387,6 +387,9 @@ "form.integration.nunux_keeper_activate": "Zapisz artykuly do Nunux Keeper", "form.integration.nunux_keeper_endpoint": "Nunux Keeper URL", "form.integration.nunux_keeper_api_key": "Nunux Keeper API key", + "form.integration.omnivore_activate": "Zapisz artykuly do Omnivore", + "form.integration.omnivore_url": "Omnivore URL", + "form.integration.omnivore_api_key": "Omnivore API key", "form.integration.espial_activate": "Zapisz artykuly do Espial", "form.integration.espial_endpoint": "Espial URL", "form.integration.espial_api_key": "Espial API key", @@ -485,4 +488,4 @@ "error.feed_not_found": "This feed does not exist or does not belong to this user.", "error.unable_to_detect_rssbridge": "Unable to detect feed using RSS-Bridge: %v.", "error.feed_format_not_detected": "Unable to detect feed format: %v." -} \ No newline at end of file +} diff --git a/internal/locale/translations/pt_BR.json b/internal/locale/translations/pt_BR.json index c6a432bd..662a9af1 100644 --- a/internal/locale/translations/pt_BR.json +++ b/internal/locale/translations/pt_BR.json @@ -384,6 +384,9 @@ "form.integration.nunux_keeper_activate": "Salvar itens no Nunux Keeper", "form.integration.nunux_keeper_endpoint": "Endpoint de API do Nunux Keeper", "form.integration.nunux_keeper_api_key": "Chave de API do Nunux Keeper", + "form.integration.omnivore_activate": "Salvar itens no Omnivore", + "form.integration.omnivore_url": "Endpoint de API do Omnivore", + "form.integration.omnivore_api_key": "Chave de API do Omnivore", "form.integration.espial_activate": "Salvar itens no Espial", "form.integration.espial_endpoint": "Endpoint de API do Espial", "form.integration.espial_api_key": "Chave de API do Espial", @@ -476,4 +479,4 @@ "error.feed_not_found": "This feed does not exist or does not belong to this user.", "error.unable_to_detect_rssbridge": "Unable to detect feed using RSS-Bridge: %v.", "error.feed_format_not_detected": "Unable to detect feed format: %v." -} \ No newline at end of file +} diff --git a/internal/locale/translations/ru_RU.json b/internal/locale/translations/ru_RU.json index d0f05f73..be71010f 100644 --- a/internal/locale/translations/ru_RU.json +++ b/internal/locale/translations/ru_RU.json @@ -387,6 +387,9 @@ "form.integration.nunux_keeper_activate": "Сохранять статьи в Nunux Keeper", "form.integration.nunux_keeper_endpoint": "Конечная точка Nunux Keeper API", "form.integration.nunux_keeper_api_key": "API-ключ Nunux Keeper", + "form.integration.omnivore_activate": "Сохранять статьи в Omnivore", + "form.integration.omnivore_url": "Конечная точка Omnivore API", + "form.integration.omnivore_api_key": "API-ключ Omnivore", "form.integration.espial_activate": "Сохранять статьи в Espial", "form.integration.espial_endpoint": "Конечная точка Espial API", "form.integration.espial_api_key": "API-ключ Espial", @@ -485,4 +488,4 @@ "error.feed_not_found": "This feed does not exist or does not belong to this user.", "error.unable_to_detect_rssbridge": "Unable to detect feed using RSS-Bridge: %v.", "error.feed_format_not_detected": "Unable to detect feed format: %v." -} \ No newline at end of file +} diff --git a/internal/locale/translations/tr_TR.json b/internal/locale/translations/tr_TR.json index cede44ca..31667057 100644 --- a/internal/locale/translations/tr_TR.json +++ b/internal/locale/translations/tr_TR.json @@ -384,6 +384,9 @@ "form.integration.nunux_keeper_activate": "Makaleleri Nunux Keeper'a kaydet", "form.integration.nunux_keeper_endpoint": "Nunux Keeper API Uç Noktası", "form.integration.nunux_keeper_api_key": "Nunux Keeper API anahtarı", + "form.integration.omnivore_activate": "Makaleleri Omnivore'a kaydet", + "form.integration.omnivore_url": "Omnivore API Uç Noktası", + "form.integration.omnivore_api_key": "Omnivore API anahtarı", "form.integration.espial_activate": "Makaleleri Espial'e kaydet", "form.integration.espial_endpoint": "Espial API Uç Noktası", "form.integration.espial_api_key": "Espial API Anahtarı", @@ -476,4 +479,4 @@ "error.feed_not_found": "This feed does not exist or does not belong to this user.", "error.unable_to_detect_rssbridge": "Unable to detect feed using RSS-Bridge: %v.", "error.feed_format_not_detected": "Unable to detect feed format: %v." -} \ No newline at end of file +} diff --git a/internal/locale/translations/uk_UA.json b/internal/locale/translations/uk_UA.json index 63119dcc..6950cccc 100644 --- a/internal/locale/translations/uk_UA.json +++ b/internal/locale/translations/uk_UA.json @@ -388,6 +388,9 @@ "form.integration.nunux_keeper_activate": "Зберігати статті до Nunux Keeper", "form.integration.nunux_keeper_endpoint": "Nunux Keeper API Endpoint", "form.integration.nunux_keeper_api_key": "Ключ API Nunux Keeper", + "form.integration.omnivore_activate": "Зберігати статті до Omnivore", + "form.integration.omnivore_url": "Omnivore API Endpoint", + "form.integration.omnivore_api_key": "Ключ API Omnivore", "form.integration.espial_activate": "Зберігати статті до Espial", "form.integration.espial_endpoint": "Espial API Endpoint", "form.integration.espial_api_key": "Ключ API Espial", @@ -486,4 +489,4 @@ "error.feed_not_found": "This feed does not exist or does not belong to this user.", "error.unable_to_detect_rssbridge": "Unable to detect feed using RSS-Bridge: %v.", "error.feed_format_not_detected": "Unable to detect feed format: %v." -} \ No newline at end of file +} diff --git a/internal/locale/translations/zh_CN.json b/internal/locale/translations/zh_CN.json index 2fda9744..a3993b80 100644 --- a/internal/locale/translations/zh_CN.json +++ b/internal/locale/translations/zh_CN.json @@ -382,6 +382,9 @@ "form.integration.nunux_keeper_activate": "保存文章到 Nunux Keeper", "form.integration.nunux_keeper_endpoint": "Nunux Keeper API 端点", "form.integration.nunux_keeper_api_key": "Nunux Keeper API 密钥", + "form.integration.omnivore_activate": "保存文章到 Omnivore", + "form.integration.omnivore_url": "Omnivore API 端点", + "form.integration.omnivore_api_key": "Omnivore API 密钥", "form.integration.espial_activate": "保存文章到 Espial", "form.integration.espial_endpoint": "Espial API 端点", "form.integration.espial_api_key": "Espial API 密钥", diff --git a/internal/locale/translations/zh_TW.json b/internal/locale/translations/zh_TW.json index 035cfda3..126f1f5c 100644 --- a/internal/locale/translations/zh_TW.json +++ b/internal/locale/translations/zh_TW.json @@ -384,6 +384,9 @@ "form.integration.nunux_keeper_activate": "儲存文章到 Nunux Keeper", "form.integration.nunux_keeper_endpoint": "Nunux Keeper API 端點", "form.integration.nunux_keeper_api_key": "Nunux Keeper API 金鑰", + "form.integration.omnivore_activate": "儲存文章到 Omnivore", + "form.integration.omnivore_url": "Omnivore API 端點", + "form.integration.omnivore_api_key": "Omnivore API 金鑰", "form.integration.espial_activate": "儲存文章到 Espial", "form.integration.espial_endpoint": "Espial API 端點", "form.integration.espial_api_key": "Espial API 金鑰", @@ -476,4 +479,4 @@ "error.feed_not_found": "This feed does not exist or does not belong to this user.", "error.unable_to_detect_rssbridge": "Unable to detect feed using RSS-Bridge: %v.", "error.feed_format_not_detected": "Unable to detect feed format: %v." -} \ No newline at end of file +} diff --git a/internal/model/integration.go b/internal/model/integration.go index e31ae8fe..7ed3a41d 100644 --- a/internal/model/integration.go +++ b/internal/model/integration.go @@ -73,4 +73,7 @@ type Integration struct { WebhookSecret string RSSBridgeEnabled bool RSSBridgeURL string + OmnivoreEnabled bool + OmnivoreAPIKey string + OmnivoreURL string } diff --git a/internal/storage/integration.go b/internal/storage/integration.go index 54e4f7a4..4ca95d51 100644 --- a/internal/storage/integration.go +++ b/internal/storage/integration.go @@ -176,7 +176,10 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) { webhook_url, webhook_secret, rssbridge_enabled, - rssbridge_url + rssbridge_url, + omnivore_enabled, + omnivore_api_key, + omnivore_url FROM integrations WHERE @@ -252,6 +255,9 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) { &integration.WebhookSecret, &integration.RSSBridgeEnabled, &integration.RSSBridgeURL, + &integration.OmnivoreEnabled, + &integration.OmnivoreAPIKey, + &integration.OmnivoreURL, ) switch { case err == sql.ErrNoRows: @@ -335,9 +341,12 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error { webhook_url=$64, webhook_secret=$65, rssbridge_enabled=$66, - rssbridge_url=$67 + rssbridge_url=$67, + omnivore_enabled=$68, + omnivore_api_key=$69, + omnivore_url=$70 WHERE - user_id=$68 + user_id=$71 ` _, err := s.db.Exec( query, @@ -408,6 +417,9 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error { integration.WebhookSecret, integration.RSSBridgeEnabled, integration.RSSBridgeURL, + integration.OmnivoreEnabled, + integration.OmnivoreAPIKey, + integration.OmnivoreURL, integration.UserID, ) @@ -441,7 +453,8 @@ func (s *Storage) HasSaveEntry(userID int64) (result bool) { apprise_enabled='t' OR shiori_enabled='t' OR shaarli_enabled='t' OR - webhook_enabled='t' + webhook_enabled='t' OR + omnivore_enabled='t' ) ` if err := s.db.QueryRow(query, userID).Scan(&result); err != nil { diff --git a/internal/template/templates/views/integrations.html b/internal/template/templates/views/integrations.html index 4edb98d1..96d62416 100644 --- a/internal/template/templates/views/integrations.html +++ b/internal/template/templates/views/integrations.html @@ -208,6 +208,25 @@ +
+ Omnivore +
+ + + + + + + + +
+ +
+
+
+
Pinboard
diff --git a/internal/ui/form/integration.go b/internal/ui/form/integration.go index 2976ed6d..c232494f 100644 --- a/internal/ui/form/integration.go +++ b/internal/ui/form/integration.go @@ -79,6 +79,9 @@ type IntegrationForm struct { WebhookSecret string RSSBridgeEnabled bool RSSBridgeURL string + OmnivoreEnabled bool + OmnivoreAPIKey string + OmnivoreURL string } // Merge copy form values to the model. @@ -147,6 +150,9 @@ func (i IntegrationForm) Merge(integration *model.Integration) { integration.WebhookURL = i.WebhookURL integration.RSSBridgeEnabled = i.RSSBridgeEnabled integration.RSSBridgeURL = i.RSSBridgeURL + integration.OmnivoreEnabled = i.OmnivoreEnabled + integration.OmnivoreAPIKey = i.OmnivoreAPIKey + integration.OmnivoreURL = i.OmnivoreURL } // NewIntegrationForm returns a new IntegrationForm. @@ -218,6 +224,9 @@ func NewIntegrationForm(r *http.Request) *IntegrationForm { WebhookURL: r.FormValue("webhook_url"), RSSBridgeEnabled: r.FormValue("rssbridge_enabled") == "1", RSSBridgeURL: r.FormValue("rssbridge_url"), + OmnivoreEnabled: r.FormValue("omnivore_enabled") == "1", + OmnivoreAPIKey: r.FormValue("omnivore_api_key"), + OmnivoreURL: r.FormValue("omnivore_url"), } } diff --git a/internal/ui/integration_show.go b/internal/ui/integration_show.go index d27ce412..813a11e1 100644 --- a/internal/ui/integration_show.go +++ b/internal/ui/integration_show.go @@ -93,6 +93,9 @@ func (h *handler) showIntegrationPage(w http.ResponseWriter, r *http.Request) { WebhookSecret: integration.WebhookSecret, RSSBridgeEnabled: integration.RSSBridgeEnabled, RSSBridgeURL: integration.RSSBridgeURL, + OmnivoreEnabled: integration.OmnivoreEnabled, + OmnivoreAPIKey: integration.OmnivoreAPIKey, + OmnivoreURL: integration.OmnivoreURL, } sess := session.New(h.store, request.SessionID(r))