aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/database/migrations.go9
-rw-r--r--internal/integration/integration.go34
-rw-r--r--internal/integration/shaarli/shaarli.go91
-rw-r--r--internal/locale/translations/de_DE.json3
-rw-r--r--internal/locale/translations/el_EL.json3
-rw-r--r--internal/locale/translations/en_US.json3
-rw-r--r--internal/locale/translations/es_ES.json3
-rw-r--r--internal/locale/translations/fi_FI.json3
-rw-r--r--internal/locale/translations/fr_FR.json3
-rw-r--r--internal/locale/translations/hi_IN.json3
-rw-r--r--internal/locale/translations/id_ID.json3
-rw-r--r--internal/locale/translations/it_IT.json3
-rw-r--r--internal/locale/translations/ja_JP.json3
-rw-r--r--internal/locale/translations/nl_NL.json3
-rw-r--r--internal/locale/translations/pl_PL.json3
-rw-r--r--internal/locale/translations/pt_BR.json3
-rw-r--r--internal/locale/translations/ru_RU.json3
-rw-r--r--internal/locale/translations/tr_TR.json3
-rw-r--r--internal/locale/translations/uk_UA.json35
-rw-r--r--internal/locale/translations/zh_CN.json3
-rw-r--r--internal/locale/translations/zh_TW.json3
-rw-r--r--internal/model/integration.go3
-rw-r--r--internal/storage/integration.go21
-rw-r--r--internal/template/templates/views/integrations.html21
-rw-r--r--internal/ui/form/integration.go9
-rw-r--r--internal/ui/integration_show.go3
26 files changed, 256 insertions, 21 deletions
diff --git a/internal/database/migrations.go b/internal/database/migrations.go
index 59d08012..f238993c 100644
--- a/internal/database/migrations.go
+++ b/internal/database/migrations.go
@@ -743,4 +743,13 @@ var migrations = []func(tx *sql.Tx) error{
_, err = tx.Exec(sql)
return err
},
+ func(tx *sql.Tx) (err error) {
+ sql := `
+ ALTER TABLE integrations ADD COLUMN shaarli_enabled bool default 'f';
+ ALTER TABLE integrations ADD COLUMN shaarli_url text default '';
+ ALTER TABLE integrations ADD COLUMN shaarli_api_secret text default '';
+ `
+ _, err = tx.Exec(sql)
+ return err
+ },
}
diff --git a/internal/integration/integration.go b/internal/integration/integration.go
index 1b47638e..98bda702 100644
--- a/internal/integration/integration.go
+++ b/internal/integration/integration.go
@@ -15,6 +15,7 @@ import (
"miniflux.app/v2/internal/integration/pinboard"
"miniflux.app/v2/internal/integration/pocket"
"miniflux.app/v2/internal/integration/readwise"
+ "miniflux.app/v2/internal/integration/shaarli"
"miniflux.app/v2/internal/integration/shiori"
"miniflux.app/v2/internal/integration/telegrambot"
"miniflux.app/v2/internal/integration/wallabag"
@@ -25,7 +26,7 @@ import (
// SendEntry sends the entry to third-party providers when the user click on "Save".
func SendEntry(entry *model.Entry, integration *model.Integration) {
if integration.PinboardEnabled {
- logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Pinboard", entry.ID, entry.URL, integration.UserID)
+ logger.Debug("[Integration] Sending entry #%d %q for user #%d to Pinboard", entry.ID, entry.URL, integration.UserID)
client := pinboard.NewClient(integration.PinboardToken)
err := client.AddBookmark(
@@ -41,7 +42,7 @@ func SendEntry(entry *model.Entry, integration *model.Integration) {
}
if integration.InstapaperEnabled {
- logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Instapaper", entry.ID, entry.URL, integration.UserID)
+ logger.Debug("[Integration] Sending entry #%d %q for user #%d to Instapaper", entry.ID, entry.URL, integration.UserID)
client := instapaper.NewClient(integration.InstapaperUsername, integration.InstapaperPassword)
if err := client.AddURL(entry.URL, entry.Title); err != nil {
@@ -50,7 +51,7 @@ func SendEntry(entry *model.Entry, integration *model.Integration) {
}
if integration.WallabagEnabled {
- logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Wallabag", entry.ID, entry.URL, integration.UserID)
+ logger.Debug("[Integration] Sending entry #%d %q for user #%d to Wallabag", entry.ID, entry.URL, integration.UserID)
client := wallabag.NewClient(
integration.WallabagURL,
@@ -67,7 +68,7 @@ func SendEntry(entry *model.Entry, integration *model.Integration) {
}
if integration.NotionEnabled {
- logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Notion", entry.ID, entry.URL, integration.UserID)
+ logger.Debug("[Integration] Sending entry #%d %q for user #%d to Notion", entry.ID, entry.URL, integration.UserID)
client := notion.NewClient(
integration.NotionToken,
@@ -79,7 +80,7 @@ func SendEntry(entry *model.Entry, integration *model.Integration) {
}
if integration.NunuxKeeperEnabled {
- logger.Debug("[Integration] Sending Entry #%d %q for User #%d to NunuxKeeper", entry.ID, entry.URL, integration.UserID)
+ logger.Debug("[Integration] Sending entry #%d %q for user #%d to NunuxKeeper", entry.ID, entry.URL, integration.UserID)
client := nunuxkeeper.NewClient(
integration.NunuxKeeperURL,
@@ -92,7 +93,7 @@ func SendEntry(entry *model.Entry, integration *model.Integration) {
}
if integration.EspialEnabled {
- logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Espial", entry.ID, entry.URL, integration.UserID)
+ logger.Debug("[Integration] Sending entry #%d %q for user #%d to Espial", entry.ID, entry.URL, integration.UserID)
client := espial.NewClient(
integration.EspialURL,
@@ -105,7 +106,7 @@ func SendEntry(entry *model.Entry, integration *model.Integration) {
}
if integration.PocketEnabled {
- logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Pocket", entry.ID, entry.URL, integration.UserID)
+ logger.Debug("[Integration] Sending entry #%d %q for user #%d to Pocket", entry.ID, entry.URL, integration.UserID)
client := pocket.NewClient(config.Opts.PocketConsumerKey(integration.PocketConsumerKey), integration.PocketAccessToken)
if err := client.AddURL(entry.URL, entry.Title); err != nil {
@@ -114,7 +115,7 @@ func SendEntry(entry *model.Entry, integration *model.Integration) {
}
if integration.LinkdingEnabled {
- logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Linkding", entry.ID, entry.URL, integration.UserID)
+ logger.Debug("[Integration] Sending entry #%d %q for user #%d to Linkding", entry.ID, entry.URL, integration.UserID)
client := linkding.NewClient(
integration.LinkdingURL,
@@ -128,7 +129,7 @@ func SendEntry(entry *model.Entry, integration *model.Integration) {
}
if integration.ReadwiseEnabled {
- logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Readwise Reader", entry.ID, entry.URL, integration.UserID)
+ logger.Debug("[Integration] Sending entry #%d %q for user #%d to Readwise Reader", entry.ID, entry.URL, integration.UserID)
client := readwise.NewClient(
integration.ReadwiseAPIKey,
@@ -140,7 +141,7 @@ func SendEntry(entry *model.Entry, integration *model.Integration) {
}
if integration.ShioriEnabled {
- logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Shiori", entry.ID, entry.URL, integration.UserID)
+ logger.Debug("[Integration] Sending entry #%d %q for user #%d to Shiori", entry.ID, entry.URL, integration.UserID)
client := shiori.NewClient(
integration.ShioriURL,
@@ -152,6 +153,19 @@ func SendEntry(entry *model.Entry, integration *model.Integration) {
logger.Error("[Integration] Unable to send entry #%d to Shiori for user #%d: %v", entry.ID, integration.UserID, err)
}
}
+
+ if integration.ShaarliEnabled {
+ logger.Debug("[Integration] Sending entry #%d %q for user #%d to Shaarli", entry.ID, entry.URL, integration.UserID)
+
+ client := shaarli.NewClient(
+ integration.ShaarliURL,
+ integration.ShaarliAPISecret,
+ )
+
+ if err := client.AddLink(entry.URL, entry.Title); err != nil {
+ logger.Error("[Integration] Unable to send entry #%d to Shaarli for user #%d: %v", entry.ID, integration.UserID, err)
+ }
+ }
}
// PushEntries pushes an entry array to third-party providers during feed refreshes.
diff --git a/internal/integration/shaarli/shaarli.go b/internal/integration/shaarli/shaarli.go
new file mode 100644
index 00000000..d88e3cf4
--- /dev/null
+++ b/internal/integration/shaarli/shaarli.go
@@ -0,0 +1,91 @@
+// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package shaarli // import "miniflux.app/v2/internal/integration/shaarli"
+
+import (
+ "bytes"
+ "crypto/hmac"
+ "crypto/sha512"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "strings"
+ "time"
+
+ "miniflux.app/v2/internal/url"
+ "miniflux.app/v2/internal/version"
+)
+
+const defaultClientTimeout = 10 * time.Second
+
+type Client struct {
+ baseURL string
+ apiSecret string
+}
+
+func NewClient(baseURL, apiSecret string) *Client {
+ return &Client{baseURL: baseURL, apiSecret: apiSecret}
+}
+
+func (c *Client) AddLink(entryURL, entryTitle string) error {
+ if c.baseURL == "" || c.apiSecret == "" {
+ return fmt.Errorf("shaarli: missing base URL or API secret")
+ }
+
+ apiEndpoint, err := url.JoinBaseURLAndPath(c.baseURL, "/api/v1/links")
+ if err != nil {
+ return fmt.Errorf("shaarli: invalid API endpoint: %v", err)
+ }
+
+ requestBody, err := json.Marshal(&addLinkRequest{
+ URL: entryURL,
+ Title: entryTitle,
+ Private: true,
+ })
+
+ if err != nil {
+ return fmt.Errorf("shaarli: unable to encode request body: %v", err)
+ }
+
+ request, err := http.NewRequest("POST", apiEndpoint, bytes.NewReader(requestBody))
+ if err != nil {
+ return fmt.Errorf("shaarli: unable to create request: %v", err)
+ }
+
+ request.Header.Set("Content-Type", "application/json")
+ request.Header.Set("Accept", "application/json")
+ request.Header.Set("User-Agent", "Miniflux/"+version.Version)
+ request.Header.Set("Authorization", "Bearer "+c.generateBearerToken())
+
+ httpClient := &http.Client{Timeout: defaultClientTimeout}
+ response, err := httpClient.Do(request)
+ if err != nil {
+ return fmt.Errorf("shaarli: unable to send request: %v", err)
+ }
+ defer response.Body.Close()
+
+ if response.StatusCode != http.StatusCreated {
+ return fmt.Errorf("shaarli: unable to add link: url=%s status=%d", apiEndpoint, response.StatusCode)
+ }
+
+ return nil
+}
+
+func (c *Client) generateBearerToken() string {
+ header := strings.TrimRight(base64.URLEncoding.EncodeToString([]byte(`{"typ":"JWT", "alg":"HS256"}`)), "=")
+ payload := strings.TrimRight(base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf(`{"iat": %d}`, time.Now().Unix()))), "=")
+
+ mac := hmac.New(sha512.New, []byte(c.apiSecret))
+ mac.Write([]byte(header + "." + payload))
+ signature := strings.TrimRight(base64.URLEncoding.EncodeToString(mac.Sum(nil)), "=")
+
+ return header + "." + payload + "." + signature
+}
+
+type addLinkRequest struct {
+ URL string `json:"url"`
+ Title string `json:"title"`
+ Private bool `json:"private"`
+}
diff --git a/internal/locale/translations/de_DE.json b/internal/locale/translations/de_DE.json
index 4455d53e..46d8b727 100644
--- a/internal/locale/translations/de_DE.json
+++ b/internal/locale/translations/de_DE.json
@@ -385,6 +385,9 @@
"form.integration.shiori_endpoint": "Shiori API-Endpunkt",
"form.integration.shiori_username": "Shiori Benutzername",
"form.integration.shiori_password": "Shiori Passwort",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "API-Schlüsselbezeichnung",
"form.submit.loading": "Lade...",
"form.submit.saving": "Speichern...",
diff --git a/internal/locale/translations/el_EL.json b/internal/locale/translations/el_EL.json
index e3928be5..1e8509fb 100644
--- a/internal/locale/translations/el_EL.json
+++ b/internal/locale/translations/el_EL.json
@@ -385,6 +385,9 @@
"form.integration.shiori_endpoint": "Τελικό σημείο Shiori",
"form.integration.shiori_username": "Όνομα Χρήστη Shiori",
"form.integration.shiori_password": "Κωδικός Πρόσβασης Shiori",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "Ετικέτα κλειδιού API",
"form.submit.loading": "Φόρτωση...",
"form.submit.saving": "Αποθήκευση...",
diff --git a/internal/locale/translations/en_US.json b/internal/locale/translations/en_US.json
index 66a4762d..85ac803d 100644
--- a/internal/locale/translations/en_US.json
+++ b/internal/locale/translations/en_US.json
@@ -385,6 +385,9 @@
"form.integration.shiori_endpoint": "Shiori API Endpoint",
"form.integration.shiori_username": "Shiori Username",
"form.integration.shiori_password": "Shiori Password",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "API Key Label",
"form.submit.loading": "Loading…",
"form.submit.saving": "Saving…",
diff --git a/internal/locale/translations/es_ES.json b/internal/locale/translations/es_ES.json
index 09a28fd4..22017cf4 100644
--- a/internal/locale/translations/es_ES.json
+++ b/internal/locale/translations/es_ES.json
@@ -385,6 +385,9 @@
"form.integration.shiori_endpoint": "Extremo de API de Shiori",
"form.integration.shiori_username": "Nombre de usuario de Shiori",
"form.integration.shiori_password": "Contraseña de Shiori",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "Etiqueta de clave API",
"form.submit.loading": "Cargando...",
"form.submit.saving": "Guardando...",
diff --git a/internal/locale/translations/fi_FI.json b/internal/locale/translations/fi_FI.json
index 00c731ef..37fa74f5 100644
--- a/internal/locale/translations/fi_FI.json
+++ b/internal/locale/translations/fi_FI.json
@@ -385,6 +385,9 @@
"form.integration.shiori_endpoint": "Shiori API Endpoint",
"form.integration.shiori_username": "Shiori Username",
"form.integration.shiori_password": "Shiori Password",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "API Key Label",
"form.submit.loading": "Ladataan...",
"form.submit.saving": "Tallennetaan...",
diff --git a/internal/locale/translations/fr_FR.json b/internal/locale/translations/fr_FR.json
index 23044dd9..13668ae3 100644
--- a/internal/locale/translations/fr_FR.json
+++ b/internal/locale/translations/fr_FR.json
@@ -385,6 +385,9 @@
"form.integration.shiori_endpoint": "URL de l'API de Shiori",
"form.integration.shiori_username": "Nom d'utilisateur de Shiori",
"form.integration.shiori_password": "Mot de passe de Shiori",
+ "form.integration.shaarli_activate": "Sauvegarder les articles vers Shaarli",
+ "form.integration.shaarli_endpoint": "URL de l'API de Shaarli",
+ "form.integration.shaarli_api_secret": "Clé d'API de Shaarli API",
"form.api_key.label.description": "Libellé de la clé d'API",
"form.submit.loading": "Chargement...",
"form.submit.saving": "Sauvegarde en cours...",
diff --git a/internal/locale/translations/hi_IN.json b/internal/locale/translations/hi_IN.json
index 888e6a3a..f2c124c3 100644
--- a/internal/locale/translations/hi_IN.json
+++ b/internal/locale/translations/hi_IN.json
@@ -385,6 +385,9 @@
"form.integration.shiori_endpoint": "Shiori API Endpoint",
"form.integration.shiori_username": "Shiori Username",
"form.integration.shiori_password": "Shiori Password",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "एपीआई कुंजी लेबल",
"form.submit.loading": "लोड हो रहा है...",
"form.submit.saving": "सहेजा जा रहा है...",
diff --git a/internal/locale/translations/id_ID.json b/internal/locale/translations/id_ID.json
index 4934ed57..05108450 100644
--- a/internal/locale/translations/id_ID.json
+++ b/internal/locale/translations/id_ID.json
@@ -382,6 +382,9 @@
"form.integration.shiori_endpoint": "Shiori API Endpoint",
"form.integration.shiori_username": "Shiori Username",
"form.integration.shiori_password": "Shiori Password",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "Label Kunci API",
"form.submit.loading": "Memuat...",
"form.submit.saving": "Menyimpan...",
diff --git a/internal/locale/translations/it_IT.json b/internal/locale/translations/it_IT.json
index f292f8c2..68903209 100644
--- a/internal/locale/translations/it_IT.json
+++ b/internal/locale/translations/it_IT.json
@@ -385,6 +385,9 @@
"form.integration.shiori_endpoint": "Endpoint dell'API di Shiori",
"form.integration.shiori_username": "Nome utente dell'account Shiori",
"form.integration.shiori_password": "Password dell'account Shiori",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "Etichetta chiave API",
"form.submit.loading": "Caricamento in corso...",
"form.submit.saving": "Salvataggio in corso...",
diff --git a/internal/locale/translations/ja_JP.json b/internal/locale/translations/ja_JP.json
index 18044a71..5cc3a362 100644
--- a/internal/locale/translations/ja_JP.json
+++ b/internal/locale/translations/ja_JP.json
@@ -385,6 +385,9 @@
"form.integration.shiori_endpoint": "Shiori の API Endpoint",
"form.integration.shiori_username": "Shiori の ユーザー名",
"form.integration.shiori_password": "Shiori の パスワード",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "API キーラベル",
"form.submit.loading": "読み込み中…",
"form.submit.saving": "保存中…",
diff --git a/internal/locale/translations/nl_NL.json b/internal/locale/translations/nl_NL.json
index 033c58ed..d8bb7d21 100644
--- a/internal/locale/translations/nl_NL.json
+++ b/internal/locale/translations/nl_NL.json
@@ -385,6 +385,9 @@
"form.integration.shiori_endpoint": "Shiori URL",
"form.integration.shiori_username": "Shiori gebruikersnaam",
"form.integration.shiori_password": "Shiori wachtwoord",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "API-sleutellabel",
"form.submit.loading": "Laden...",
"form.submit.saving": "Opslaag...",
diff --git a/internal/locale/translations/pl_PL.json b/internal/locale/translations/pl_PL.json
index c8e22131..fe40c6c0 100644
--- a/internal/locale/translations/pl_PL.json
+++ b/internal/locale/translations/pl_PL.json
@@ -387,6 +387,9 @@
"form.integration.shiori_endpoint": "Shiori URL",
"form.integration.shiori_username": "Login do Shiori",
"form.integration.shiori_password": "Hasło do Shiori",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "Etykieta klucza API",
"form.submit.loading": "Ładowanie...",
"form.submit.saving": "Zapisywanie...",
diff --git a/internal/locale/translations/pt_BR.json b/internal/locale/translations/pt_BR.json
index 0b796060..db9fea56 100644
--- a/internal/locale/translations/pt_BR.json
+++ b/internal/locale/translations/pt_BR.json
@@ -385,6 +385,9 @@
"form.integration.shiori_endpoint": "Endpoint da API do Shiori",
"form.integration.shiori_username": "Nome de usuário do Shiori",
"form.integration.shiori_password": "Senha do Shiori",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "Etiqueta da chave de API",
"form.submit.loading": "Carregando...",
"form.submit.saving": "Salvando...",
diff --git a/internal/locale/translations/ru_RU.json b/internal/locale/translations/ru_RU.json
index 8ad3af8e..1580322c 100644
--- a/internal/locale/translations/ru_RU.json
+++ b/internal/locale/translations/ru_RU.json
@@ -387,6 +387,9 @@
"form.integration.shiori_endpoint": "Конечная точка Shiori API",
"form.integration.shiori_username": "Имя пользователя Shiori",
"form.integration.shiori_password": "Пароль Shiori",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "Описание API-ключа",
"form.submit.loading": "Загрузка…",
"form.submit.saving": "Сохранение…",
diff --git a/internal/locale/translations/tr_TR.json b/internal/locale/translations/tr_TR.json
index d4774b91..6d70f842 100644
--- a/internal/locale/translations/tr_TR.json
+++ b/internal/locale/translations/tr_TR.json
@@ -385,6 +385,9 @@
"form.integration.shiori_endpoint": "Shiori API Uç Noktası",
"form.integration.shiori_username": "Shiori Kullanıcı Adı",
"form.integration.shiori_password": "Shiori Parolası",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "API Anahtar Etiketi",
"form.submit.loading": "Yükleniyor...",
"form.submit.saving": "Kaydediliyor...",
diff --git a/internal/locale/translations/uk_UA.json b/internal/locale/translations/uk_UA.json
index b0d3c569..6008884f 100644
--- a/internal/locale/translations/uk_UA.json
+++ b/internal/locale/translations/uk_UA.json
@@ -105,7 +105,11 @@
"page.feeds.last_check": "Остання перевірка:",
"page.feeds.unread_counter": "Кількість непрочитаних записів",
"page.feeds.read_counter": "Кількість прочитаних записів",
- "page.feeds.error_count": ["%d помилка", "%d помилки", "%d помилок"],
+ "page.feeds.error_count": [
+ "%d помилка",
+ "%d помилки",
+ "%d помилок"
+ ],
"page.history.title": "Історія",
"page.import.title": "Імпорт",
"page.search.title": "Результати пошуку",
@@ -384,6 +388,9 @@
"form.integration.shiori_endpoint": "Shiori API Endpoint",
"form.integration.shiori_username": "Shiori Username",
"form.integration.shiori_password": "Shiori Password",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "Назва ключа API",
"form.submit.loading": "Завантаження...",
"form.submit.saving": "Зберігаю...",
@@ -395,13 +402,29 @@
"%d хвилини тому",
"%d хвилин тому"
],
- "time_elapsed.hours": ["%d годину тому", "%d години тому", "%d годин тому"],
- "time_elapsed.days": ["%d день тому", "%d дні тому", "%d днів тому"],
- "time_elapsed.weeks": ["%d тиждень тому", "%d тижня тому", "%d тижнів тому"],
+ "time_elapsed.hours": [
+ "%d годину тому",
+ "%d години тому",
+ "%d годин тому"
+ ],
+ "time_elapsed.days": [
+ "%d день тому",
+ "%d дні тому",
+ "%d днів тому"
+ ],
+ "time_elapsed.weeks": [
+ "%d тиждень тому",
+ "%d тижня тому",
+ "%d тижнів тому"
+ ],
"time_elapsed.months": [
"%d місяць тому",
"%d місяця тому",
"%d місяців тому"
],
- "time_elapsed.years": ["%d рік тому", "%d роки тому", "%d років тому"]
-}
+ "time_elapsed.years": [
+ "%d рік тому",
+ "%d роки тому",
+ "%d років тому"
+ ]
+} \ No newline at end of file
diff --git a/internal/locale/translations/zh_CN.json b/internal/locale/translations/zh_CN.json
index 6034e23b..e985b2c3 100644
--- a/internal/locale/translations/zh_CN.json
+++ b/internal/locale/translations/zh_CN.json
@@ -383,6 +383,9 @@
"form.integration.shiori_endpoint": "Shiori API Endpoint",
"form.integration.shiori_username": "Shiori 用户名",
"form.integration.shiori_password": "Shiori 密码",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "API密钥标签",
"form.submit.loading": "载入中…",
"form.submit.saving": "保存中…",
diff --git a/internal/locale/translations/zh_TW.json b/internal/locale/translations/zh_TW.json
index b32f8758..a762bb98 100644
--- a/internal/locale/translations/zh_TW.json
+++ b/internal/locale/translations/zh_TW.json
@@ -385,6 +385,9 @@
"form.integration.shiori_endpoint": "Shiori API Endpoint",
"form.integration.shiori_username": "Shiori Username",
"form.integration.shiori_password": "Shiori Password",
+ "form.integration.shaarli_activate": "Save articles to Shaarli",
+ "form.integration.shaarli_endpoint": "Shaarli URL",
+ "form.integration.shaarli_api_secret": "Shaarli API Secret",
"form.api_key.label.description": "API金鑰標籤",
"form.submit.loading": "載入中…",
"form.submit.saving": "儲存中…",
diff --git a/internal/model/integration.go b/internal/model/integration.go
index 28a0da9a..c00be86f 100644
--- a/internal/model/integration.go
+++ b/internal/model/integration.go
@@ -61,4 +61,7 @@ type Integration struct {
ShioriURL string
ShioriUsername string
ShioriPassword string
+ ShaarliEnabled bool
+ ShaarliURL string
+ ShaarliAPISecret string
}
diff --git a/internal/storage/integration.go b/internal/storage/integration.go
index 61ecc679..c68168d0 100644
--- a/internal/storage/integration.go
+++ b/internal/storage/integration.go
@@ -164,7 +164,10 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) {
shiori_enabled,
shiori_url,
shiori_username,
- shiori_password
+ shiori_password,
+ shaarli_enabled,
+ shaarli_url,
+ shaarli_api_secret
FROM
integrations
WHERE
@@ -228,6 +231,9 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) {
&integration.ShioriURL,
&integration.ShioriUsername,
&integration.ShioriPassword,
+ &integration.ShaarliEnabled,
+ &integration.ShaarliURL,
+ &integration.ShaarliAPISecret,
)
switch {
case err == sql.ErrNoRows:
@@ -299,9 +305,12 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error {
shiori_enabled=$52,
shiori_url=$53,
shiori_username=$54,
- shiori_password=$55
+ shiori_password=$55,
+ shaarli_enabled=$56,
+ shaarli_url=$57,
+ shaarli_api_secret=$58
WHERE
- user_id=$56
+ user_id=$59
`
_, err := s.db.Exec(
query,
@@ -360,6 +369,9 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error {
integration.ShioriURL,
integration.ShioriUsername,
integration.ShioriPassword,
+ integration.ShaarliEnabled,
+ integration.ShaarliURL,
+ integration.ShaarliAPISecret,
integration.UserID,
)
@@ -391,7 +403,8 @@ func (s *Storage) HasSaveEntry(userID int64) (result bool) {
pocket_enabled='t' OR
linkding_enabled='t' OR
apprise_enabled='t' OR
- shiori_enabled='t'
+ shiori_enabled='t' OR
+ shaarli_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 f26d399f..255bc825 100644
--- a/internal/template/templates/views/integrations.html
+++ b/internal/template/templates/views/integrations.html
@@ -325,6 +325,25 @@
</div>
</details>
+ <details {{ if .form.ShaarliEnabled }}open{{ end }}>
+ <summary>Shaarli</summary>
+ <div class="form-section">
+ <label>
+ <input type="checkbox" name="shaarli_enabled" value="1" {{ if .form.ShaarliEnabled }}checked{{ end }}> {{ t "form.integration.shaarli_activate" }}
+ </label>
+
+ <label for="form-shaarli-url">{{ t "form.integration.shaarli_endpoint" }}</label>
+ <input type="url" name="shaarli_url" id="form-shaarli-url" value="{{ .form.ShaarliURL }}" placeholder="https://shaarli.example.org" spellcheck="false">
+
+ <label for="form-shaarli-api-secret">{{ t "form.integration.shaarli_api_secret" }}</label>
+ <input type="password" name="shaarli_api_secret" id="form-shaarli-api-secret" value="{{ .form.ShaarliAPISecret }}" autocomplete="new-password">
+
+ <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.ShioriEnabled }}open{{ end }}>
<summary>Shiori</summary>
<div class="form-section">
@@ -339,7 +358,7 @@
<input type="text" name="shiori_username" id="form-shiori-username" value="{{ .form.ShioriUsername }}" spellcheck="false">
<label for="form-shiori-password">{{ t "form.integration.shiori_password" }}</label>
- <input type="password" name="shiori_password" id="form-shiori-password" value="{{ .form.ShioriPassword }}" spellcheck="false">
+ <input type="password" name="shiori_password" id="form-shiori-password" value="{{ .form.ShioriPassword }}" autocomplete="new-password">
<div class="buttons">
<button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.saving" }}">{{ t "action.update" }}</button>
diff --git a/internal/ui/form/integration.go b/internal/ui/form/integration.go
index 5a332f28..53ff9202 100644
--- a/internal/ui/form/integration.go
+++ b/internal/ui/form/integration.go
@@ -66,6 +66,9 @@ type IntegrationForm struct {
ShioriURL string
ShioriUsername string
ShioriPassword string
+ ShaarliEnabled bool
+ ShaarliURL string
+ ShaarliAPISecret string
}
// Merge copy form values to the model.
@@ -123,6 +126,9 @@ func (i IntegrationForm) Merge(integration *model.Integration) {
integration.ShioriURL = i.ShioriURL
integration.ShioriUsername = i.ShioriUsername
integration.ShioriPassword = i.ShioriPassword
+ integration.ShaarliEnabled = i.ShaarliEnabled
+ integration.ShaarliURL = i.ShaarliURL
+ integration.ShaarliAPISecret = i.ShaarliAPISecret
}
// NewIntegrationForm returns a new IntegrationForm.
@@ -183,5 +189,8 @@ func NewIntegrationForm(r *http.Request) *IntegrationForm {
ShioriURL: r.FormValue("shiori_url"),
ShioriUsername: r.FormValue("shiori_username"),
ShioriPassword: r.FormValue("shiori_password"),
+ ShaarliEnabled: r.FormValue("shaarli_enabled") == "1",
+ ShaarliURL: r.FormValue("shaarli_url"),
+ ShaarliAPISecret: r.FormValue("shaarli_api_secret"),
}
}
diff --git a/internal/ui/integration_show.go b/internal/ui/integration_show.go
index b1985d51..7a30a043 100644
--- a/internal/ui/integration_show.go
+++ b/internal/ui/integration_show.go
@@ -81,6 +81,9 @@ func (h *handler) showIntegrationPage(w http.ResponseWriter, r *http.Request) {
ShioriURL: integration.ShioriURL,
ShioriUsername: integration.ShioriUsername,
ShioriPassword: integration.ShioriPassword,
+ ShaarliEnabled: integration.ShaarliEnabled,
+ ShaarliURL: integration.ShaarliURL,
+ ShaarliAPISecret: integration.ShaarliAPISecret,
}
sess := session.New(h.store, request.SessionID(r))