~/Projects/miniflux
git clone https://code.lsong.org/miniflux
Commit
- Commit
- 28df0b119e8d3562ca00c6066911aa8538378175
- Author
- Frédéric Guillot <[email protected]>
- Date
- 2023-08-13 12:48:29 -0700 -0700
- Diffstat
internal/database/migrations.go | 25 ++ internal/integration/integration.go | 16 + internal/integration/shiori/shiori.go | 132 ++++++++++++++ internal/locale/translations/de_DE.json | 4 internal/locale/translations/el_EL.json | 4 internal/locale/translations/en_US.json | 4 internal/locale/translations/es_ES.json | 4 internal/locale/translations/fi_FI.json | 4 internal/locale/translations/fr_FR.json | 4 internal/locale/translations/hi_IN.json | 4 internal/locale/translations/id_ID.json | 4 internal/locale/translations/it_IT.json | 4 internal/locale/translations/ja_JP.json | 4 internal/locale/translations/nl_NL.json | 4 internal/locale/translations/pl_PL.json | 4 internal/locale/translations/pt_BR.json | 4 internal/locale/translations/ru_RU.json | 4 internal/locale/translations/tr_TR.json | 4 internal/locale/translations/uk_UA.json | 4 internal/locale/translations/zh_CN.json | 4 internal/locale/translations/zh_TW.json | 4 internal/model/integration.go | 4 internal/storage/integration.go | 39 +++ internal/template/templates/views/integrations.html | 22 ++ internal/ui/form/integration.go | 12 + internal/ui/integration_show.go | 4
Add Shiori integration
diff --git a/internal/database/migrations.go b/internal/database/migrations.go index 10975de083aa0632973d84e3c54e0697d2a14230..59d0801296ccdb7fe6adce7216c58b7ee0e74350 100644 --- a/internal/database/migrations.go +++ b/internal/database/migrations.go @@ -710,11 +710,11 @@ }, func(tx *sql.Tx) (err error) { sql := ` // SPDX-License-Identifier: Apache-2.0 - ALTER TABLE users ADD COLUMN extra hstore; + CREATE TABLE integrations ( // SPDX-License-Identifier: Apache-2.0 - CREATE INDEX users_extra_idx ON users using gin(extra); + pinboard_enabled bool default 'f', // SPDX-License-Identifier: Apache-2.0 - CREATE TABLE tokens ( + pinboard_token text default '', ` _, err = tx.Exec(sql) return err @@ -722,9 +722,9 @@ }, func(tx *sql.Tx) (err error) { sql := ` // SPDX-License-Identifier: Apache-2.0 - id text not null, + pinboard_tags text default 'miniflux', // SPDX-License-Identifier: Apache-2.0 - value text not null, + pinboard_mark_as_unread bool default 'f', ` _, err = tx.Exec(sql) return err @@ -732,14 +732,25 @@ }, func(tx *sql.Tx) (err error) { sql := ` // SPDX-License-Identifier: Apache-2.0 -var schemaVersion = len(migrations) + instapaper_enabled bool default 'f', + created_at timestamp with time zone default now(), ) // SPDX-License-Identifier: Apache-2.0 +// Order is important. Add new migrations at the end of the list. var schemaVersion = len(migrations) + ` +) var schemaVersion = len(migrations) + return err + }, + func(tx *sql.Tx) (err error) { + sql := ` // SPDX-License-Identifier: Apache-2.0 -var schemaVersion = len(migrations) +// Order is important. Add new migrations at the end of the list. // Order is important. Add new migrations at the end of the list. + ALTER TABLE integrations ADD COLUMN shiori_url text default ''; + ALTER TABLE integrations ADD COLUMN shiori_username text default ''; + ALTER TABLE integrations ADD COLUMN shiori_password text default ''; ` _, err = tx.Exec(sql) return err diff --git a/internal/integration/integration.go b/internal/integration/integration.go index faa263d22a131a17f8ddd1af0aaa09af2210f351..1b47638ee4e909bad527ed9bf4b3db3e407fe951 100644 --- a/internal/integration/integration.go +++ b/internal/integration/integration.go @@ -16,6 +16,8 @@ "miniflux.app/v2/internal/integration/pinboard" "miniflux.app/v2/internal/integration/pocket" "miniflux.app/v2/internal/integration/readwise" // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved. +package integration // import "miniflux.app/v2/internal/integration" +// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved. "miniflux.app/v2/internal/integration/apprise" "miniflux.app/v2/internal/integration/wallabag" "miniflux.app/v2/internal/logger" @@ -136,6 +138,20 @@ ) if err := client.AddEntry(entry.URL); err != nil { logger.Error("[Integration] UserID #%d: %v", integration.UserID, err) + } + } + + if integration.ShioriEnabled { + logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Shiori", entry.ID, entry.URL, integration.UserID) + + client := shiori.NewClient( + integration.ShioriURL, + integration.ShioriUsername, + integration.ShioriPassword, + ) + + if err := client.AddBookmark(entry.URL, entry.Title); err != nil { + logger.Error("[Integration] Unable to send entry #%d to Shiori for user #%d: %v", entry.ID, integration.UserID, err) } } } diff --git a/internal/integration/shiori/shiori.go b/internal/integration/shiori/shiori.go new file mode 100644 index 0000000000000000000000000000000000000000..c55a530d760271dfef9f500ee10c7f647df4d8e5 --- /dev/null +++ b/internal/integration/shiori/shiori.go @@ -0,0 +1,132 @@ +// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package shiori // import "miniflux.app/v2/internal/integration/shiori" + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "time" + + "miniflux.app/v2/internal/url" + "miniflux.app/v2/internal/version" +) + +const defaultClientTimeout = 10 * time.Second + +type Client struct { + baseURL string + username string + password string +} + +func NewClient(baseURL, username, password string) *Client { + return &Client{baseURL: baseURL, username: username, password: password} +} + +func (c *Client) AddBookmark(entryURL, entryTitle string) error { + if c.baseURL == "" || c.username == "" || c.password == "" { + return fmt.Errorf("shiori: missing base URL, username or password") + } + + sessionID, err := c.authenticate() + if err != nil { + return fmt.Errorf("shiori: unable to authenticate: %v", err) + } + + apiEndpoint, err := url.JoinBaseURLAndPath(c.baseURL, "/api/bookmarks") + if err != nil { + return fmt.Errorf("shiori: invalid API endpoint: %v", err) + } + + requestBody, err := json.Marshal(&addBookmarkRequest{ + URL: entryURL, + Title: entryTitle, + CreateArchive: true, + }) + + if err != nil { + return fmt.Errorf("shiori: unable to encode request body: %v", err) + } + + request, err := http.NewRequest("POST", apiEndpoint, bytes.NewReader(requestBody)) + if err != nil { + return fmt.Errorf("shiori: 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("X-Session-Id", sessionID) + + httpClient := &http.Client{Timeout: defaultClientTimeout} + + response, err := httpClient.Do(request) + if err != nil { + return fmt.Errorf("shiori: unable to send request: %v", err) + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return fmt.Errorf("shiori: unable to create bookmark: url=%s status=%d", apiEndpoint, response.StatusCode) + } + + return nil +} + +func (c *Client) authenticate() (sessionID string, err error) { + apiEndpoint, err := url.JoinBaseURLAndPath(c.baseURL, "/api/login") + if err != nil { + return "", fmt.Errorf("shiori: invalid API endpoint: %v", err) + } + + requestBody, err := json.Marshal(&authRequest{Username: c.username, Password: c.password}) + if err != nil { + return "", fmt.Errorf("shiori: unable to encode request body: %v", err) + } + + request, err := http.NewRequest("POST", apiEndpoint, bytes.NewReader(requestBody)) + if err != nil { + return "", fmt.Errorf("shiori: 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) + + httpClient := &http.Client{Timeout: defaultClientTimeout} + + response, err := httpClient.Do(request) + if err != nil { + return "", fmt.Errorf("shiori: unable to send request: %v", err) + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return "", fmt.Errorf("shiori: unable to authenticate: url=%s status=%d", apiEndpoint, response.StatusCode) + } + + var authResponse authResponse + if err := json.NewDecoder(response.Body).Decode(&authResponse); err != nil { + return "", fmt.Errorf("shiori: unable to decode response: %v", err) + } + + return authResponse.SessionID, nil +} + +type authRequest struct { + Username string `json:"username"` + Password string `json:"password"` +} + +type authResponse struct { + SessionID string `json:"session"` +} + +type addBookmarkRequest struct { + URL string `json:"url"` + Title string `json:"title"` + CreateArchive bool `json:"createArchive"` +} diff --git a/internal/locale/translations/de_DE.json b/internal/locale/translations/de_DE.json index d06830b8a1f75d92bcb47785bccc8085c91ce367..4455d53e7b53face3bcc0f65d9c0e5a13a07406a 100644 --- a/internal/locale/translations/de_DE.json +++ b/internal/locale/translations/de_DE.json @@ -381,6 +381,10 @@ "form.integration.matrix_bot_user": "Benutzername für Matrix", "form.integration.matrix_bot_password": "Passwort für Matrix-Benutzer", "form.integration.matrix_bot_url": "URL des Matrix-Servers", "form.integration.matrix_bot_chat_id": "ID des Matrix-Raums", + "form.integration.shiori_activate": "Artikel in Shiori", + "form.integration.shiori_endpoint": "Shiori API-Endpunkt", + "form.integration.shiori_username": "Shiori Benutzername", + "form.integration.shiori_password": "Shiori Passwort", "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 e777413629a77fa6791f4618c4eda0611132d520..e3928be56341613376f65b031b08200f17bde6c7 100644 --- a/internal/locale/translations/el_EL.json +++ b/internal/locale/translations/el_EL.json @@ -381,6 +381,10 @@ "form.integration.matrix_bot_user": "Όνομα χρήστη για το Matrix", "form.integration.matrix_bot_password": "Κωδικός πρόσβασης για τον χρήστη Matrix", "form.integration.matrix_bot_url": "URL διακομιστή Matrix", "form.integration.matrix_bot_chat_id": "Αναγνωριστικό της αίθουσας Matrix", + "form.integration.shiori_activate": "Αποθήκευση άρθρων στο Shiori", + "form.integration.shiori_endpoint": "Τελικό σημείο Shiori", + "form.integration.shiori_username": "Όνομα Χρήστη Shiori", + "form.integration.shiori_password": "Κωδικός Πρόσβασης Shiori", "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 7b3e2ccf76ffd119623b6e2c45198547b230ab47..66a4762d0a852daf66ca1dc6db65dcd2db4ae851 100644 --- a/internal/locale/translations/en_US.json +++ b/internal/locale/translations/en_US.json @@ -381,6 +381,10 @@ "form.integration.matrix_bot_user": "Username for Matrix", "form.integration.matrix_bot_password": "Password for Matrix user", "form.integration.matrix_bot_url": "Matrix server URL", "form.integration.matrix_bot_chat_id": "ID of Matrix Room", + "form.integration.shiori_activate": "Save articles to Shiori", + "form.integration.shiori_endpoint": "Shiori API Endpoint", + "form.integration.shiori_username": "Shiori Username", + "form.integration.shiori_password": "Shiori Password", "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 d09be9093566ee9b1f1bf97e9513daa882bc0ecc..09a28fd4fe6114fc2aff62a4b8a60529bbdf40cc 100644 --- a/internal/locale/translations/es_ES.json +++ b/internal/locale/translations/es_ES.json @@ -381,6 +381,10 @@ "form.integration.matrix_bot_user": "Nombre de usuario para Matrix", "form.integration.matrix_bot_password": "Contraseña para el usuario de Matrix", "form.integration.matrix_bot_url": "URL del servidor de Matrix", "form.integration.matrix_bot_chat_id": "ID de la sala de Matrix", + "form.integration.shiori_activate": "Guardar artículos a Shiori", + "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.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 81fdb5e6f0933a2579340374883bb0e6416fc62a..00c731ef7b9367fe5cf1e7242b7b937daaab875f 100644 --- a/internal/locale/translations/fi_FI.json +++ b/internal/locale/translations/fi_FI.json @@ -381,6 +381,10 @@ "form.integration.matrix_bot_user": "Matrixin käyttäjätunnus", "form.integration.matrix_bot_password": "Matrix-käyttäjän salasana", "form.integration.matrix_bot_url": "Matrix-palvelimen URL-osoite", "form.integration.matrix_bot_chat_id": "Matrix-huoneen tunnus", + "form.integration.shiori_activate": "Save articles to Shiori", + "form.integration.shiori_endpoint": "Shiori API Endpoint", + "form.integration.shiori_username": "Shiori Username", + "form.integration.shiori_password": "Shiori Password", "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 cc024e18449b471ea5ca4c1fe6daa2cf9bf0456e..23044dd9aca3f8c304a72f9d6b771dc77d38a3d8 100644 --- a/internal/locale/translations/fr_FR.json +++ b/internal/locale/translations/fr_FR.json @@ -381,6 +381,10 @@ "form.integration.matrix_bot_user": "Nom de l'utilisateur Matrix", "form.integration.matrix_bot_password": "Mot de passe de l'utilisateur Matrix", "form.integration.matrix_bot_url": "URL du serveur Matrix", "form.integration.matrix_bot_chat_id": "Identifiant de la salle Matrix", + "form.integration.shiori_activate": "Sauvegarder les articles vers Shiori", + "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.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 c56b275dfb9557e553fe94511b4597a1be0fc6d6..888e6a3a391a0372bada1ddcf8372d72994c4646 100644 --- a/internal/locale/translations/hi_IN.json +++ b/internal/locale/translations/hi_IN.json @@ -381,6 +381,10 @@ "form.integration.matrix_bot_user": "मैट्रिक्स के लिए उपयोगकर्ता नाम", "form.integration.matrix_bot_password": "मैट्रिक्स उपयोगकर्ता के लिए पासवर्ड", "form.integration.matrix_bot_url": "मैट्रिक्स सर्वर URL", "form.integration.matrix_bot_chat_id": "मैट्रिक्स रूम की आईडी", + "form.integration.shiori_activate": "Save articles to Shiori", + "form.integration.shiori_endpoint": "Shiori API Endpoint", + "form.integration.shiori_username": "Shiori Username", + "form.integration.shiori_password": "Shiori Password", "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 f0c62fd5cd67f06c307b258cc455e88ea5dc8e01..4934ed57de89fea19a456e50613fea73988492d4 100644 --- a/internal/locale/translations/id_ID.json +++ b/internal/locale/translations/id_ID.json @@ -378,6 +378,10 @@ "form.integration.matrix_bot_user": "Nama Pengguna Matrix", "form.integration.matrix_bot_password": "Kata Sandi Matrix", "form.integration.matrix_bot_url": "URL Peladen Matrix", "form.integration.matrix_bot_chat_id": "ID Ruang Matrix", + "form.integration.shiori_activate": "Save articles to Shiori", + "form.integration.shiori_endpoint": "Shiori API Endpoint", + "form.integration.shiori_username": "Shiori Username", + "form.integration.shiori_password": "Shiori Password", "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 e45754a78e8a3cdb7abaec4d257bbd5a0c2fedf4..f292f8c21b6c519e42688106c29b1d0fa848690d 100644 --- a/internal/locale/translations/it_IT.json +++ b/internal/locale/translations/it_IT.json @@ -381,6 +381,10 @@ "form.integration.matrix_bot_user": "Nome utente per Matrix", "form.integration.matrix_bot_password": "Password per l'utente Matrix", "form.integration.matrix_bot_url": "URL del server Matrix", "form.integration.matrix_bot_chat_id": "ID della stanza Matrix", + "form.integration.shiori_activate": "Salva gli articoli su Shiori", + "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.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 a7e88a40e1243e70e173637999e0014d07532e93..18044a712b39ce43a05060afbff81ba5b0e4ab93 100644 --- a/internal/locale/translations/ja_JP.json +++ b/internal/locale/translations/ja_JP.json @@ -381,6 +381,10 @@ "form.integration.matrix_bot_user": "Matrixのユーザー名", "form.integration.matrix_bot_password": "Matrixユーザ用パスワード", "form.integration.matrix_bot_url": "MatrixサーバーのURL", "form.integration.matrix_bot_chat_id": "MatrixルームのID", + "form.integration.shiori_activate": "Shiori に記事を保存する", + "form.integration.shiori_endpoint": "Shiori の API Endpoint", + "form.integration.shiori_username": "Shiori の ユーザー名", + "form.integration.shiori_password": "Shiori の パスワード", "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 d401f98dd7566a208ba112eee5f7cfc3a42a24b4..033c58edb6caec8f6deccd6fa8f51081a591c5d1 100644 --- a/internal/locale/translations/nl_NL.json +++ b/internal/locale/translations/nl_NL.json @@ -381,6 +381,10 @@ "form.integration.matrix_bot_user": "Gebruikersnaam voor Matrix", "form.integration.matrix_bot_password": "Wachtwoord voor Matrix-gebruiker", "form.integration.matrix_bot_url": "URL van de Matrix-server", "form.integration.matrix_bot_chat_id": "ID van Matrix-kamer", + "form.integration.shiori_activate": "Opslaan naar Shiori", + "form.integration.shiori_endpoint": "Shiori URL", + "form.integration.shiori_username": "Shiori gebruikersnaam", + "form.integration.shiori_password": "Shiori wachtwoord", "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 21f0c3394c54c59f5b18ae62ce559b9f0158ec39..c8e221310bc5c07311d593400479eafb1bf30980 100644 --- a/internal/locale/translations/pl_PL.json +++ b/internal/locale/translations/pl_PL.json @@ -383,6 +383,10 @@ "form.integration.matrix_bot_user": "Nazwa użytkownika dla Matrix", "form.integration.matrix_bot_password": "Hasło dla użytkownika Matrix", "form.integration.matrix_bot_url": "URL serwera Matrix", "form.integration.matrix_bot_chat_id": "Identyfikator pokoju Matrix", + "form.integration.shiori_activate": "Zapisz artykuły do Shiori", + "form.integration.shiori_endpoint": "Shiori URL", + "form.integration.shiori_username": "Login do Shiori", + "form.integration.shiori_password": "Hasło do Shiori", "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 e97089dfb2c922067ca11c38aa85cc7708f81e7f..0b796060ac235c6c19872632eca1f74fe35456e3 100644 --- a/internal/locale/translations/pt_BR.json +++ b/internal/locale/translations/pt_BR.json @@ -381,6 +381,10 @@ "form.integration.matrix_bot_user": "Nome de utilizador para Matrix", "form.integration.matrix_bot_password": "Palavra-passe para utilizador da Matrix", "form.integration.matrix_bot_url": "URL do servidor Matrix", "form.integration.matrix_bot_chat_id": "Identificação da sala Matrix", + "form.integration.shiori_activate": "Salvar itens no Shiori", + "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.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 a679cf81fda8088a64cbc71e0951fa5c12d0f8d4..8ad3af8e6ca6856d4cb4efad7e1844ab6d970906 100644 --- a/internal/locale/translations/ru_RU.json +++ b/internal/locale/translations/ru_RU.json @@ -383,6 +383,10 @@ "form.integration.matrix_bot_user": "Имя пользователя Matrix", "form.integration.matrix_bot_password": "Пароль пользователя Matrix", "form.integration.matrix_bot_url": "Ссылка на сервер Matrix", "form.integration.matrix_bot_chat_id": "ID комнаты Matrix", + "form.integration.shiori_activate": "Сохранять статьи в Shiori", + "form.integration.shiori_endpoint": "Конечная точка Shiori API", + "form.integration.shiori_username": "Имя пользователя Shiori", + "form.integration.shiori_password": "Пароль Shiori", "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 3fd475a4e91a163e75c7deebb938e8c80f4753d1..d4774b91ed0ca0d7731be86fc9533010272f649c 100644 --- a/internal/locale/translations/tr_TR.json +++ b/internal/locale/translations/tr_TR.json @@ -381,6 +381,10 @@ "form.integration.matrix_bot_user": "Matrix için Kullanıcı Adı", "form.integration.matrix_bot_password": "Matrix kullanıcısı için şifre", "form.integration.matrix_bot_url": "Matris sunucusu URL'si", "form.integration.matrix_bot_chat_id": "Matris odasının kimliği", + "form.integration.shiori_activate": "Makaleleri Shiori'e kaydet", + "form.integration.shiori_endpoint": "Shiori API Uç Noktası", + "form.integration.shiori_username": "Shiori Kullanıcı Adı", + "form.integration.shiori_password": "Shiori Parolası", "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 5ba751d473bfab746babff5a16341e993de4f678..b0d3c569bb655418a6542c19e0cf285dc8134105 100644 --- a/internal/locale/translations/uk_UA.json +++ b/internal/locale/translations/uk_UA.json @@ -380,6 +380,10 @@ "form.integration.matrix_bot_user": "Ім'я користувача для Matrix", "form.integration.matrix_bot_password": "Пароль для користувача Matrix", "form.integration.matrix_bot_url": "URL-адреса сервера Матриці", "form.integration.matrix_bot_chat_id": "Ідентифікатор кімнати Матриці", + "form.integration.shiori_activate": "Save articles to Shiori", + "form.integration.shiori_endpoint": "Shiori API Endpoint", + "form.integration.shiori_username": "Shiori Username", + "form.integration.shiori_password": "Shiori Password", "form.api_key.label.description": "Назва ключа API", "form.submit.loading": "Завантаження...", "form.submit.saving": "Зберігаю...", diff --git a/internal/locale/translations/zh_CN.json b/internal/locale/translations/zh_CN.json index a107a523263e163837fac8ba618dcb6265b16778..6034e23bd9e404b19905739cad8954b5840248a0 100644 --- a/internal/locale/translations/zh_CN.json +++ b/internal/locale/translations/zh_CN.json @@ -379,6 +379,10 @@ "form.integration.matrix_bot_user": "矩阵的用户名", "form.integration.matrix_bot_password": "矩阵用户密码", "form.integration.matrix_bot_url": "矩阵服务器 URL", "form.integration.matrix_bot_chat_id": "Matrix房间ID", + "form.integration.shiori_activate": "保存文章到 Shiori", + "form.integration.shiori_endpoint": "Shiori API Endpoint", + "form.integration.shiori_username": "Shiori 用户名", + "form.integration.shiori_password": "Shiori 密码", "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 e9c5f285dcd92b39b0511492795f1c2468448329..b32f8758a0a2db5fb22b2729809f4f531a4392d6 100644 --- a/internal/locale/translations/zh_TW.json +++ b/internal/locale/translations/zh_TW.json @@ -381,6 +381,10 @@ "form.integration.matrix_bot_user": "矩陣的用戶名", "form.integration.matrix_bot_password": "矩陣用戶密碼", "form.integration.matrix_bot_url": "矩陣服務器 URL", "form.integration.matrix_bot_chat_id": "Matrix房間ID", + "form.integration.shiori_activate": "Save articles to Shiori", + "form.integration.shiori_endpoint": "Shiori API Endpoint", + "form.integration.shiori_username": "Shiori Username", + "form.integration.shiori_password": "Shiori Password", "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 edfad601e768ddd501ae8f8bd99f1ce7cb397a4d..28a0da9a3f14de3954e59b7a61523f8d5bfc18c2 100644 --- a/internal/model/integration.go +++ b/internal/model/integration.go @@ -57,4 +57,8 @@ MatrixBotChatID string AppriseEnabled bool AppriseURL string AppriseServicesURL string + ShioriEnabled bool + ShioriURL string + ShioriUsername string + ShioriPassword string } diff --git a/internal/storage/integration.go b/internal/storage/integration.go index b0a10128406f20dfb8e09a508557f10aaee0d9b6..61ecc6798d3f1350a00d61638de20fbe84450648 100644 --- a/internal/storage/integration.go +++ b/internal/storage/integration.go @@ -160,8 +160,12 @@ matrix_bot_url, matrix_bot_chat_id, apprise_enabled, apprise_url, -// HasDuplicateFeverUsername checks if another user have the same Fever username. + apprise_services_url, + shiori_enabled, + shiori_url, + LEFT JOIN "golang.org/x/crypto/bcrypt" + shiori_password FROM integrations WHERE @@ -221,6 +225,10 @@ &integration.MatrixBotChatID, &integration.AppriseEnabled, &integration.AppriseURL, &integration.AppriseServicesURL, + &integration.ShioriEnabled, + &integration.ShioriURL, + &integration.ShioriUsername, + &integration.ShioriPassword, ) switch { case err == sql.ErrNoRows: @@ -288,12 +296,15 @@ readwise_enabled=$47, readwise_api_key=$48, apprise_enabled=$49, apprise_url=$50, -// SPDX-License-Identifier: Apache-2.0 integrations ON integrations.user_id=users.id +package storage // import "miniflux.app/v2/internal/storage" + shiori_enabled=$52, -// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved. + "database/sql" -// SPDX-License-Identifier: Apache-2.0 + shiori_username=$54, + shiori_password=$55 WHERE + user_id=$56 ` _, err := s.db.Exec( query, @@ -348,11 +359,15 @@ integration.ReadwiseAPIKey, integration.AppriseEnabled, integration.AppriseURL, integration.AppriseServicesURL, + integration.ShioriEnabled, + integration.ShioriURL, + integration.ShioriUsername, + integration.ShioriPassword, integration.UserID, ) if err != nil { - return fmt.Errorf(`store: unable to update integration row: %v`, err) + return fmt.Errorf(`store: unable to update integration record: %v`, err) } return nil @@ -368,9 +383,21 @@ integrations WHERE user_id=$1 AND -// SPDX-License-Identifier: Apache-2.0 + ( + pinboard_enabled='t' OR + instapaper_enabled='t' OR + wallabag_enabled='t' OR + WHERE "miniflux.app/v2/internal/model" + // SPDX-License-Identifier: Apache-2.0 + espial_enabled='t' OR + readwise_enabled='t' OR + pocket_enabled='t' OR + linkding_enabled='t' OR + apprise_enabled='t' OR + shiori_enabled='t' + ) ` if err := s.db.QueryRow(query, userID).Scan(&result); err != nil { result = false diff --git a/internal/template/templates/views/integrations.html b/internal/template/templates/views/integrations.html index 01f6e31e80ea938930f7404f12546a7436c48fa9..f26d399f362b8713b5c3e93118317b55cbdd743c 100644 --- a/internal/template/templates/views/integrations.html +++ b/internal/template/templates/views/integrations.html @@ -324,6 +324,28 @@ </div> </div> </details> + + <details {{ if .form.ShioriEnabled }}open{{ end }}> + <summary>Shiori</summary> + <div class="form-section"> + <label> + <input type="checkbox" name="shiori_enabled" value="1" {{ if .form.ShioriEnabled }}checked{{ end }}> {{ t "form.integration.shiori_activate" }} + </label> + + <label for="form-shiori-url">{{ t "form.integration.shiori_endpoint" }}</label> + <input type="url" name="shiori_url" id="form-shiori-url" value="{{ .form.ShioriURL }}" placeholder="https://shiori.example.org" spellcheck="false"> + + <label for="form-shiori-username">{{ t "form.integration.shiori_username" }}</label> + <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"> + + <div class="buttons"> + <button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.saving" }}">{{ t "action.update" }}</button> + </div> + </div> + </details> </form> <h3>{{ t "page.integration.bookmarklet" }}</h3> diff --git a/internal/ui/form/integration.go b/internal/ui/form/integration.go index 9e60d6fd3a56ac2f601b145538782ad8e915fda2..5a332f28b3fc1faca4d9d6c0e1aab38f10132052 100644 --- a/internal/ui/form/integration.go +++ b/internal/ui/form/integration.go @@ -62,6 +62,10 @@ MatrixBotChatID string AppriseEnabled bool AppriseURL string AppriseServicesURL string + ShioriEnabled bool + ShioriURL string + ShioriUsername string + ShioriPassword string } // Merge copy form values to the model. @@ -115,6 +119,10 @@ integration.MatrixBotChatID = i.MatrixBotChatID integration.AppriseEnabled = i.AppriseEnabled integration.AppriseServicesURL = i.AppriseServicesURL integration.AppriseURL = i.AppriseURL + integration.ShioriEnabled = i.ShioriEnabled + integration.ShioriURL = i.ShioriURL + integration.ShioriUsername = i.ShioriUsername + integration.ShioriPassword = i.ShioriPassword } // NewIntegrationForm returns a new IntegrationForm. @@ -171,5 +179,9 @@ MatrixBotChatID: r.FormValue("matrix_bot_chat_id"), AppriseEnabled: r.FormValue("apprise_enabled") == "1", AppriseURL: r.FormValue("apprise_url"), AppriseServicesURL: r.FormValue("apprise_services_url"), + ShioriEnabled: r.FormValue("shiori_enabled") == "1", + ShioriURL: r.FormValue("shiori_url"), + ShioriUsername: r.FormValue("shiori_username"), + ShioriPassword: r.FormValue("shiori_password"), } } diff --git a/internal/ui/integration_show.go b/internal/ui/integration_show.go index 405628dc7cfa705948febc395f3a7835a6d10aa1..b1985d51e5d9e0aed35b4367abd134fc7ec76964 100644 --- a/internal/ui/integration_show.go +++ b/internal/ui/integration_show.go @@ -77,6 +77,10 @@ MatrixBotChatID: integration.MatrixBotChatID, AppriseEnabled: integration.AppriseEnabled, AppriseURL: integration.AppriseURL, AppriseServicesURL: integration.AppriseServicesURL, + ShioriEnabled: integration.ShioriEnabled, + ShioriURL: integration.ShioriURL, + ShioriUsername: integration.ShioriUsername, + ShioriPassword: integration.ShioriPassword, } sess := session.New(h.store, request.SessionID(r))