1
0
Fork 0
mirror of https://github.com/miniflux/v2.git synced 2025-06-27 16:36:00 +00:00

feat(integration): add cubox integration

Signed-off-by: Shaolong Chen <shaolong.chen@outlook.it>
This commit is contained in:
Shaolong Chen 2024-10-18 13:18:17 +08:00 committed by Frédéric Guillot
parent 3b654fefa7
commit 366928b35d
26 changed files with 173 additions and 4 deletions

View file

@ -952,4 +952,12 @@ 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 cubox_enabled bool default 'f';
ALTER TABLE integrations ADD COLUMN cubox_api_link text default '';
`
_, err = tx.Exec(sql)
return err
},
}

View file

@ -0,0 +1,70 @@
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
// Cubox API documentation: https://help.cubox.cc/save/api/
package cubox // import "miniflux.app/v2/internal/integration/cubox"
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"time"
"miniflux.app/v2/internal/version"
)
const defaultClientTimeout = 10 * time.Second
type Client struct {
apiLink string
}
func NewClient(apiLink string) *Client {
return &Client{apiLink: apiLink}
}
func (c *Client) SaveLink(entryURL string) error {
if c.apiLink == "" {
return errors.New("cubox: missing API link")
}
requestBody, err := json.Marshal(&card{
Type: "url",
Content: entryURL,
})
if err != nil {
return fmt.Errorf("cubox: unable to encode request body: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), defaultClientTimeout)
defer cancel()
request, err := http.NewRequestWithContext(ctx, http.MethodPost, c.apiLink, bytes.NewReader(requestBody))
if err != nil {
return fmt.Errorf("cubox: unable to create request: %w", err)
}
request.Header.Set("Content-Type", "application/json")
request.Header.Set("User-Agent", "Miniflux/"+version.Version)
response, err := http.DefaultClient.Do(request)
if err != nil {
return fmt.Errorf("cubox: unable to send request: %w", err)
}
defer response.Body.Close()
if response.StatusCode != 200 {
return fmt.Errorf("cubox: unable to save link: status=%d", response.StatusCode)
}
return nil
}
type card struct {
Type string `json:"type"`
Content string `json:"content"`
}

View file

@ -9,6 +9,7 @@ import (
"miniflux.app/v2/internal/config"
"miniflux.app/v2/internal/integration/apprise"
"miniflux.app/v2/internal/integration/betula"
"miniflux.app/v2/internal/integration/cubox"
"miniflux.app/v2/internal/integration/espial"
"miniflux.app/v2/internal/integration/instapaper"
"miniflux.app/v2/internal/integration/linkace"
@ -322,6 +323,25 @@ func SendEntry(entry *model.Entry, userIntegrations *model.Integration) {
}
}
if userIntegrations.CuboxEnabled {
slog.Debug("Sending entry to Cubox",
slog.Int64("user_id", userIntegrations.UserID),
slog.Int64("entry_id", entry.ID),
slog.String("entry_url", entry.URL),
)
client := cubox.NewClient(userIntegrations.CuboxAPILink)
if err := client.SaveLink(entry.URL); err != nil {
slog.Error("Unable to send entry to Cubox",
slog.Int64("user_id", userIntegrations.UserID),
slog.Int64("entry_id", entry.ID),
slog.String("entry_url", entry.URL),
slog.Any("error", err),
)
}
}
if userIntegrations.ShioriEnabled {
slog.Debug("Sending entry to Shiori",
slog.Int64("user_id", userIntegrations.UserID),

View file

@ -355,6 +355,8 @@
"form.feed.label.ntfy_default_priority": "Ntfy default priority",
"form.feed.label.ntfy_low_priority": "Ntfy low priority",
"form.feed.label.ntfy_min_priority": "Ntfy min priority",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.feed.fieldset.general": "Allgemein",
"form.feed.fieldset.rules": "Regeln",
"form.feed.fieldset.network_settings": "Netzwerkeinstellungen",

View file

@ -359,6 +359,8 @@
"form.feed.label.ntfy_default_priority": "Ntfy default priority",
"form.feed.label.ntfy_low_priority": "Ntfy low priority",
"form.feed.label.ntfy_min_priority": "Ntfy min priority",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.category.label.title": "Τίτλος",
"form.category.hide_globally": "Απόκρυψη καταχωρήσεων σε γενική λίστα μη αναγνωσμένων",
"form.user.label.username": "Χρήστης",

View file

@ -510,6 +510,8 @@
"form.integration.ntfy_username": "Ntfy Username (optional)",
"form.integration.ntfy_password": "Ntfy Password (optional)",
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.api_key.label.description": "API Key Label",
"form.submit.loading": "Loading…",
"form.submit.saving": "Saving…",

View file

@ -355,6 +355,8 @@
"form.feed.label.ntfy_default_priority": "Prioridad predeterminada a Ntfy",
"form.feed.label.ntfy_low_priority": "Prioridad baja a Ntfy",
"form.feed.label.ntfy_min_priority": "Prioridad mínima a Ntfy",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.feed.fieldset.general": "General",
"form.feed.fieldset.rules": "Reglas",
"form.feed.fieldset.network_settings": "Ajustes de red",

View file

@ -355,6 +355,8 @@
"form.feed.label.ntfy_default_priority": "Ntfy default priority",
"form.feed.label.ntfy_low_priority": "Ntfy low priority",
"form.feed.label.ntfy_min_priority": "Ntfy min priority",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.feed.fieldset.general": "General",
"form.feed.fieldset.rules": "Rules",
"form.feed.fieldset.network_settings": "Network Settings",

View file

@ -355,6 +355,8 @@
"form.feed.label.ntfy_default_priority": "Priorité par défaut de notification",
"form.feed.label.ntfy_low_priority": "Priorité basse de notification",
"form.feed.label.ntfy_min_priority": "Priorité minimale de notification",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.feed.fieldset.general": "Général",
"form.feed.fieldset.rules": "Règles",
"form.feed.fieldset.network_settings": "Paramètres réseau",

View file

@ -355,6 +355,8 @@
"form.feed.label.ntfy_default_priority": "Ntfy default priority",
"form.feed.label.ntfy_low_priority": "Ntfy low priority",
"form.feed.label.ntfy_min_priority": "Ntfy min priority",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.feed.fieldset.general": "General",
"form.feed.fieldset.rules": "Rules",
"form.feed.fieldset.network_settings": "Network Settings",

View file

@ -345,6 +345,8 @@
"form.feed.label.ntfy_default_priority": "Ntfy default priority",
"form.feed.label.ntfy_low_priority": "Ntfy low priority",
"form.feed.label.ntfy_min_priority": "Ntfy min priority",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.feed.fieldset.general": "General",
"form.feed.fieldset.rules": "Rules",
"form.feed.fieldset.network_settings": "Network Settings",

View file

@ -355,6 +355,8 @@
"form.feed.label.ntfy_default_priority": "Ntfy default priority",
"form.feed.label.ntfy_low_priority": "Ntfy low priority",
"form.feed.label.ntfy_min_priority": "Ntfy min priority",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.feed.fieldset.general": "General",
"form.feed.fieldset.rules": "Rules",
"form.feed.fieldset.network_settings": "Network Settings",

View file

@ -345,6 +345,8 @@
"form.feed.label.ntfy_default_priority": "Ntfy default priority",
"form.feed.label.ntfy_low_priority": "Ntfy low priority",
"form.feed.label.ntfy_min_priority": "Ntfy min priority",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.feed.fieldset.general": "General",
"form.feed.fieldset.rules": "Rules",
"form.feed.fieldset.network_settings": "Network Settings",

View file

@ -355,6 +355,8 @@
"form.feed.label.ntfy_default_priority": "Ntfy standaard prioriteit",
"form.feed.label.ntfy_low_priority": "Ntfy lage prioriteit",
"form.feed.label.ntfy_min_priority": "Ntfy minimale prioriteit",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.feed.fieldset.general": "Algemeen",
"form.feed.fieldset.rules": "Regels",
"form.feed.fieldset.network_settings": "Netwerk Instellingen",

View file

@ -365,6 +365,8 @@
"form.feed.label.ntfy_default_priority": "Domyślny priorytet ntfy",
"form.feed.label.ntfy_low_priority": "Niski priorytet ntfy",
"form.feed.label.ntfy_min_priority": "Minimalny priorytet ntfy",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.feed.fieldset.general": "Ogólne",
"form.feed.fieldset.rules": "Reguły",
"form.feed.fieldset.network_settings": "Ustawienia sieci",

View file

@ -355,6 +355,8 @@
"form.feed.label.ntfy_default_priority": "Ntfy default priority",
"form.feed.label.ntfy_low_priority": "Ntfy low priority",
"form.feed.label.ntfy_min_priority": "Ntfy min priority",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.feed.fieldset.general": "General",
"form.feed.fieldset.rules": "Rules",
"form.feed.fieldset.network_settings": "Network Settings",

View file

@ -365,6 +365,8 @@
"form.feed.label.ntfy_default_priority": "Ntfy default priority",
"form.feed.label.ntfy_low_priority": "Ntfy low priority",
"form.feed.label.ntfy_min_priority": "Ntfy min priority",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.feed.fieldset.general": "General",
"form.feed.fieldset.rules": "Rules",
"form.feed.fieldset.network_settings": "Network Settings",

View file

@ -286,6 +286,8 @@
"form.feed.label.ntfy_default_priority": "Ntfy default priority",
"form.feed.label.ntfy_low_priority": "Ntfy low priority",
"form.feed.label.ntfy_min_priority": "Ntfy min priority",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.prefs.fieldset.application_settings": "Uygulama Ayarları",
"form.prefs.fieldset.authentication_settings": "Kimlik Doğrulama Ayarları",
"form.prefs.fieldset.reader_settings": "Okuyucu Ayarları",

View file

@ -365,6 +365,8 @@
"form.feed.label.ntfy_default_priority": "Ntfy default priority",
"form.feed.label.ntfy_low_priority": "Ntfy low priority",
"form.feed.label.ntfy_min_priority": "Ntfy min priority",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.category.label.title": "Назва",
"form.category.hide_globally": "Приховати записи в глобальному списку непрочитаного",
"form.feed.fieldset.general": "General",

View file

@ -345,6 +345,8 @@
"form.feed.label.ntfy_default_priority": "Ntfy默认优先级",
"form.feed.label.ntfy_low_priority": "Ntfy低优先级",
"form.feed.label.ntfy_min_priority": "Ntfy最低优先级",
"form.integration.cubox_activate": "保存文章到 Cubox",
"form.integration.cubox_api_link": "Cubox API 链接",
"form.feed.fieldset.general": "通用",
"form.feed.fieldset.rules": "规则",
"form.feed.fieldset.network_settings": "网络设置",

View file

@ -345,6 +345,8 @@
"form.feed.label.ntfy_default_priority": "Ntfy default priority",
"form.feed.label.ntfy_low_priority": "Ntfy low priority",
"form.feed.label.ntfy_min_priority": "Ntfy min priority",
"form.integration.cubox_activate": "Save entries to Cubox",
"form.integration.cubox_api_link": "Cubox API link",
"form.feed.fieldset.general": "通用",
"form.feed.fieldset.rules": "規則",
"form.feed.fieldset.network_settings": "網路設定",

View file

@ -104,4 +104,6 @@ type Integration struct {
NtfyUsername string
NtfyPassword string
NtfyIconURL string
CuboxEnabled bool
CuboxAPILink string
}

View file

@ -207,7 +207,9 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) {
ntfy_api_token,
ntfy_username,
ntfy_password,
ntfy_icon_url
ntfy_icon_url,
cubox_enabled,
cubox_api_link
FROM
integrations
WHERE
@ -314,6 +316,8 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) {
&integration.NtfyUsername,
&integration.NtfyPassword,
&integration.NtfyIconURL,
&integration.CuboxEnabled,
&integration.CuboxAPILink,
)
switch {
case err == sql.ErrNoRows:
@ -428,9 +432,11 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error {
ntfy_api_token=$95,
ntfy_username=$96,
ntfy_password=$97,
ntfy_icon_url=$98
ntfy_icon_url=$98,
cubox_enabled=$99,
cubox_api_link=$100
WHERE
user_id=$99
user_id=$101
`
_, err := s.db.Exec(
query,
@ -532,6 +538,8 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error {
integration.NtfyUsername,
integration.NtfyPassword,
integration.NtfyIconURL,
integration.CuboxEnabled,
integration.CuboxAPILink,
integration.UserID,
)
@ -571,7 +579,8 @@ func (s *Storage) HasSaveEntry(userID int64) (result bool) {
webhook_enabled='t' OR
omnivore_enabled='t' OR
raindrop_enabled='t' OR
betula_enabled='t'
betula_enabled='t' OR
cubox_enabled='t'
)
`
if err := s.db.QueryRow(query, userID).Scan(&result); err != nil {

View file

@ -57,6 +57,22 @@
</div>
</details>
<details {{ if .form.CuboxEnabled }}open{{ end }}>
<summary>Cubox</summary>
<div class="form-section">
<label>
<input type="checkbox" name="cubox_enabled" value="1" {{ if .form.CuboxEnabled }}checked{{ end }}> {{ t "form.integration.cubox_activate" }}
</label>
<label for="form-cubox-api-link">{{ t "form.integration.cubox_api_link" }}</label>
<input type="url" name="cubox_api_link" id="form-cubox-api-link" value="{{ .form.CuboxAPILink }}" placeholder="https://cubox.pro/c/api/save/xxx" 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>
<details {{ if .form.EspialEnabled }}open{{ end }}>
<summary>Espial</summary>
<div class="form-section">

View file

@ -110,6 +110,8 @@ type IntegrationForm struct {
NtfyUsername string
NtfyPassword string
NtfyIconURL string
CuboxEnabled bool
CuboxAPILink string
}
// Merge copy form values to the model.
@ -209,6 +211,8 @@ func (i IntegrationForm) Merge(integration *model.Integration) {
integration.NtfyUsername = i.NtfyUsername
integration.NtfyPassword = i.NtfyPassword
integration.NtfyIconURL = i.NtfyIconURL
integration.CuboxEnabled = i.CuboxEnabled
integration.CuboxAPILink = i.CuboxAPILink
}
// NewIntegrationForm returns a new IntegrationForm.
@ -311,6 +315,8 @@ func NewIntegrationForm(r *http.Request) *IntegrationForm {
NtfyUsername: r.FormValue("ntfy_username"),
NtfyPassword: r.FormValue("ntfy_password"),
NtfyIconURL: r.FormValue("ntfy_icon_url"),
CuboxEnabled: r.FormValue("cubox_enabled") == "1",
CuboxAPILink: r.FormValue("cubox_api_link"),
}
}

View file

@ -124,6 +124,8 @@ func (h *handler) showIntegrationPage(w http.ResponseWriter, r *http.Request) {
NtfyUsername: integration.NtfyUsername,
NtfyPassword: integration.NtfyPassword,
NtfyIconURL: integration.NtfyIconURL,
CuboxEnabled: integration.CuboxEnabled,
CuboxAPILink: integration.CuboxAPILink,
}
sess := session.New(h.store, request.SessionID(r))