Add Shaarli integration
This commit is contained in:
parent
28df0b119e
commit
9f465fd70d
26 changed files with 256 additions and 21 deletions
|
@ -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
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
91
internal/integration/shaarli/shaarli.go
Normal file
91
internal/integration/shaarli/shaarli.go
Normal file
|
@ -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"`
|
||||
}
|
|
@ -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...",
|
||||
|
|
|
@ -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": "Αποθήκευση...",
|
||||
|
|
|
@ -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…",
|
||||
|
|
|
@ -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...",
|
||||
|
|
|
@ -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...",
|
||||
|
|
|
@ -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...",
|
||||
|
|
|
@ -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": "सहेजा जा रहा है...",
|
||||
|
|
|
@ -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...",
|
||||
|
|
|
@ -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...",
|
||||
|
|
|
@ -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": "保存中…",
|
||||
|
|
|
@ -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...",
|
||||
|
|
|
@ -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...",
|
||||
|
|
|
@ -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...",
|
||||
|
|
|
@ -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": "Сохранение…",
|
||||
|
|
|
@ -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...",
|
||||
|
|
|
@ -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 років тому"
|
||||
]
|
||||
}
|
|
@ -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": "保存中…",
|
||||
|
|
|
@ -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": "儲存中…",
|
||||
|
|
|
@ -61,4 +61,7 @@ type Integration struct {
|
|||
ShioriURL string
|
||||
ShioriUsername string
|
||||
ShioriPassword string
|
||||
ShaarliEnabled bool
|
||||
ShaarliURL string
|
||||
ShaarliAPISecret string
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in a new issue