mirror of
https://github.com/miniflux/v2.git
synced 2025-06-27 16:36:00 +00:00
feat(integration): add Discord integration
This commit is contained in:
parent
f116f7dd6a
commit
9b25ea4ed6
26 changed files with 209 additions and 4 deletions
|
@ -969,4 +969,12 @@ var migrations = []func(tx *sql.Tx, driver string) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
|
sql := `
|
||||||
|
ALTER TABLE integrations ADD COLUMN discord_enabled bool default 'f';
|
||||||
|
ALTER TABLE integrations ADD COLUMN discord_webhook_link text default '';
|
||||||
|
`
|
||||||
|
_, err = tx.Exec(sql)
|
||||||
|
return err
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
109
internal/integration/discord/discord.go
Normal file
109
internal/integration/discord/discord.go
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Discord Webhooks documentation: https://discord.com/developers/docs/resources/webhook
|
||||||
|
|
||||||
|
package discord // import "miniflux.app/v2/internal/integration/discord"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"miniflux.app/v2/internal/model"
|
||||||
|
"miniflux.app/v2/internal/urllib"
|
||||||
|
"miniflux.app/v2/internal/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultClientTimeout = 10 * time.Second
|
||||||
|
const discordMsgColor = 5793266
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
webhookURL string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(webhookURL string) *Client {
|
||||||
|
return &Client{webhookURL: webhookURL}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) SendDiscordMsg(feed *model.Feed, entries model.Entries) error {
|
||||||
|
for _, entry := range entries {
|
||||||
|
requestBody, err := json.Marshal(&discordMessage{
|
||||||
|
Embeds: []discordEmbed{
|
||||||
|
{
|
||||||
|
Title: "RSS feed update from Miniflux",
|
||||||
|
Color: discordMsgColor,
|
||||||
|
Fields: []discordFields{
|
||||||
|
{
|
||||||
|
Name: "Updated feed",
|
||||||
|
Value: feed.Title,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Article link",
|
||||||
|
Value: "[" + entry.Title + "]" + "(" + entry.URL + ")",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Author",
|
||||||
|
Value: entry.Author,
|
||||||
|
Inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Source website",
|
||||||
|
Value: urllib.RootURL(feed.SiteURL),
|
||||||
|
Inline: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("discord: unable to encode request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
request, err := http.NewRequest(http.MethodPost, c.webhookURL, bytes.NewReader(requestBody))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("discord: unable to create request: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
request.Header.Set("Content-Type", "application/json")
|
||||||
|
request.Header.Set("User-Agent", "Miniflux/"+version.Version)
|
||||||
|
|
||||||
|
slog.Debug("Sending Discord notification",
|
||||||
|
slog.String("webhookURL", c.webhookURL),
|
||||||
|
slog.String("title", feed.Title),
|
||||||
|
slog.String("entry_url", entry.URL),
|
||||||
|
)
|
||||||
|
|
||||||
|
httpClient := &http.Client{Timeout: defaultClientTimeout}
|
||||||
|
response, err := httpClient.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("discord: unable to send request: %v", err)
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
if response.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("discord: unable to send a notification: url=%s status=%d", c.webhookURL, response.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type discordFields struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
Inline bool `json:"inline,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type discordEmbed struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
Color int `json:"color"`
|
||||||
|
Fields []discordFields `json:"fields"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type discordMessage struct {
|
||||||
|
Embeds []discordEmbed `json:"embeds"`
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"miniflux.app/v2/internal/integration/apprise"
|
"miniflux.app/v2/internal/integration/apprise"
|
||||||
"miniflux.app/v2/internal/integration/betula"
|
"miniflux.app/v2/internal/integration/betula"
|
||||||
"miniflux.app/v2/internal/integration/cubox"
|
"miniflux.app/v2/internal/integration/cubox"
|
||||||
|
"miniflux.app/v2/internal/integration/discord"
|
||||||
"miniflux.app/v2/internal/integration/espial"
|
"miniflux.app/v2/internal/integration/espial"
|
||||||
"miniflux.app/v2/internal/integration/instapaper"
|
"miniflux.app/v2/internal/integration/instapaper"
|
||||||
"miniflux.app/v2/internal/integration/linkace"
|
"miniflux.app/v2/internal/integration/linkace"
|
||||||
|
@ -535,6 +536,22 @@ func PushEntries(feed *model.Feed, entries model.Entries, userIntegrations *mode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if userIntegrations.DiscordEnabled {
|
||||||
|
slog.Debug("Sending new entries to Discord",
|
||||||
|
slog.Int64("user_id", userIntegrations.UserID),
|
||||||
|
slog.Int("nb_entries", len(entries)),
|
||||||
|
slog.Int64("feed_id", feed.ID),
|
||||||
|
)
|
||||||
|
|
||||||
|
client := discord.NewClient(
|
||||||
|
userIntegrations.DiscordWebhookLink,
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := client.SendDiscordMsg(feed, entries); err != nil {
|
||||||
|
slog.Warn("Unable to send new entries to Discord", slog.Any("error", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Integrations that only support sending individual entries
|
// Integrations that only support sending individual entries
|
||||||
if userIntegrations.TelegramBotEnabled {
|
if userIntegrations.TelegramBotEnabled {
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
|
|
|
@ -513,6 +513,8 @@
|
||||||
"form.integration.ntfy_username": "Ntfy-Benutzername (optional)",
|
"form.integration.ntfy_username": "Ntfy-Benutzername (optional)",
|
||||||
"form.integration.ntfy_password": "Ntfy-Passwort (optional)",
|
"form.integration.ntfy_password": "Ntfy-Passwort (optional)",
|
||||||
"form.integration.ntfy_icon_url": "Ntfy-Symbol-URL (optional)",
|
"form.integration.ntfy_icon_url": "Ntfy-Symbol-URL (optional)",
|
||||||
|
"form.integration.discord_activate": "Einträge zu Discord pushen",
|
||||||
|
"form.integration.discord_webhook_link": "Discord-Webhook-URL",
|
||||||
"form.api_key.label.description": "API-Schlüsselbezeichnung",
|
"form.api_key.label.description": "API-Schlüsselbezeichnung",
|
||||||
"form.submit.loading": "Lade...",
|
"form.submit.loading": "Lade...",
|
||||||
"form.submit.saving": "Speichern...",
|
"form.submit.saving": "Speichern...",
|
||||||
|
|
|
@ -513,6 +513,8 @@
|
||||||
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
||||||
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
||||||
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
||||||
|
"form.integration.discord_activate": "Push entries to Discord",
|
||||||
|
"form.integration.discord_webhook_link": "Discord Webhook link",
|
||||||
"form.api_key.label.description": "Ετικέτα κλειδιού API",
|
"form.api_key.label.description": "Ετικέτα κλειδιού API",
|
||||||
"form.submit.loading": "Φόρτωση...",
|
"form.submit.loading": "Φόρτωση...",
|
||||||
"form.submit.saving": "Αποθήκευση...",
|
"form.submit.saving": "Αποθήκευση...",
|
||||||
|
|
|
@ -513,6 +513,8 @@
|
||||||
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
||||||
"form.integration.cubox_activate": "Save entries to Cubox",
|
"form.integration.cubox_activate": "Save entries to Cubox",
|
||||||
"form.integration.cubox_api_link": "Cubox API link",
|
"form.integration.cubox_api_link": "Cubox API link",
|
||||||
|
"form.integration.discord_activate": "Push entries to Discord",
|
||||||
|
"form.integration.discord_webhook_link": "Discord Webhook link",
|
||||||
"form.api_key.label.description": "API Key Label",
|
"form.api_key.label.description": "API Key Label",
|
||||||
"form.submit.loading": "Loading…",
|
"form.submit.loading": "Loading…",
|
||||||
"form.submit.saving": "Saving…",
|
"form.submit.saving": "Saving…",
|
||||||
|
|
|
@ -513,6 +513,8 @@
|
||||||
"form.integration.ntfy_username": "Nombre de usuario de Ntfy (opcional)",
|
"form.integration.ntfy_username": "Nombre de usuario de Ntfy (opcional)",
|
||||||
"form.integration.ntfy_password": "Contraseña de Ntfy (opcional)",
|
"form.integration.ntfy_password": "Contraseña de Ntfy (opcional)",
|
||||||
"form.integration.ntfy_icon_url": "URL del icono de Ntfy (opcional)",
|
"form.integration.ntfy_icon_url": "URL del icono de Ntfy (opcional)",
|
||||||
|
"form.integration.discord_activate": "Enviar artículos a Discord",
|
||||||
|
"form.integration.discord_webhook_link": "URL de la Webhook de Discord",
|
||||||
"form.api_key.label.description": "Etiqueta de clave API",
|
"form.api_key.label.description": "Etiqueta de clave API",
|
||||||
"form.submit.loading": "Cargando...",
|
"form.submit.loading": "Cargando...",
|
||||||
"form.submit.saving": "Guardando...",
|
"form.submit.saving": "Guardando...",
|
||||||
|
|
|
@ -513,6 +513,8 @@
|
||||||
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
||||||
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
||||||
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
||||||
|
"form.integration.discord_activate": "Push entries to Discord",
|
||||||
|
"form.integration.discord_webhook_link": "Discord Webhook link",
|
||||||
"form.api_key.label.description": "API Key Label",
|
"form.api_key.label.description": "API Key Label",
|
||||||
"form.submit.loading": "Ladataan...",
|
"form.submit.loading": "Ladataan...",
|
||||||
"form.submit.saving": "Tallennetaan...",
|
"form.submit.saving": "Tallennetaan...",
|
||||||
|
|
|
@ -513,6 +513,8 @@
|
||||||
"form.integration.ntfy_username": "Nom d'utilisateur Ntfy (optionnel)",
|
"form.integration.ntfy_username": "Nom d'utilisateur Ntfy (optionnel)",
|
||||||
"form.integration.ntfy_password": "Mot de passe Ntfy (facultatif)",
|
"form.integration.ntfy_password": "Mot de passe Ntfy (facultatif)",
|
||||||
"form.integration.ntfy_icon_url": "URL de l'icône Ntfy (facultatif)",
|
"form.integration.ntfy_icon_url": "URL de l'icône Ntfy (facultatif)",
|
||||||
|
"form.integration.discord_activate": "Envoyer les articles vers Discord",
|
||||||
|
"form.integration.discord_webhook_link": "URL du Webhook Discord",
|
||||||
"form.api_key.label.description": "Libellé de la clé d'API",
|
"form.api_key.label.description": "Libellé de la clé d'API",
|
||||||
"form.submit.loading": "Chargement...",
|
"form.submit.loading": "Chargement...",
|
||||||
"form.submit.saving": "Sauvegarde en cours...",
|
"form.submit.saving": "Sauvegarde en cours...",
|
||||||
|
|
|
@ -513,6 +513,8 @@
|
||||||
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
||||||
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
||||||
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
||||||
|
"form.integration.discord_activate": "Push entries to Discord",
|
||||||
|
"form.integration.discord_webhook_link": "Discord Webhook link",
|
||||||
"form.api_key.label.description": "एपीआई कुंजी लेबल",
|
"form.api_key.label.description": "एपीआई कुंजी लेबल",
|
||||||
"form.submit.loading": "लोड हो रहा है...",
|
"form.submit.loading": "लोड हो रहा है...",
|
||||||
"form.submit.saving": "सहेजा जा रहा है...",
|
"form.submit.saving": "सहेजा जा रहा है...",
|
||||||
|
|
|
@ -503,6 +503,8 @@
|
||||||
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
||||||
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
||||||
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
||||||
|
"form.integration.discord_activate": "Push entries to Discord",
|
||||||
|
"form.integration.discord_webhook_link": "Discord Webhook link",
|
||||||
"form.api_key.label.description": "Label Kunci API",
|
"form.api_key.label.description": "Label Kunci API",
|
||||||
"form.submit.loading": "Memuat...",
|
"form.submit.loading": "Memuat...",
|
||||||
"form.submit.saving": "Menyimpan...",
|
"form.submit.saving": "Menyimpan...",
|
||||||
|
|
|
@ -514,6 +514,8 @@
|
||||||
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
||||||
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
||||||
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
||||||
|
"form.integration.discord_activate": "Push entries to Discord",
|
||||||
|
"form.integration.discord_webhook_link": "Discord Webhook link",
|
||||||
"form.submit.loading": "Caricamento in corso...",
|
"form.submit.loading": "Caricamento in corso...",
|
||||||
"form.submit.saving": "Salvataggio in corso...",
|
"form.submit.saving": "Salvataggio in corso...",
|
||||||
"time_elapsed.not_yet": "non ancora",
|
"time_elapsed.not_yet": "non ancora",
|
||||||
|
|
|
@ -503,6 +503,8 @@
|
||||||
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
||||||
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
||||||
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
||||||
|
"form.integration.discord_activate": "Push entries to Discord",
|
||||||
|
"form.integration.discord_webhook_link": "Discord Webhook link",
|
||||||
"form.api_key.label.description": "API キーラベル",
|
"form.api_key.label.description": "API キーラベル",
|
||||||
"form.submit.loading": "読み込み中…",
|
"form.submit.loading": "読み込み中…",
|
||||||
"form.submit.saving": "保存中…",
|
"form.submit.saving": "保存中…",
|
||||||
|
|
|
@ -513,6 +513,8 @@
|
||||||
"form.integration.ntfy_username": "Ntfy gebruikersnaam (optioneel)",
|
"form.integration.ntfy_username": "Ntfy gebruikersnaam (optioneel)",
|
||||||
"form.integration.ntfy_password": "Ntfy wachtwoord (optioneel)",
|
"form.integration.ntfy_password": "Ntfy wachtwoord (optioneel)",
|
||||||
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optioneel)",
|
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optioneel)",
|
||||||
|
"form.integration.discord_activate": "Artikelen opslaan in Discord",
|
||||||
|
"form.integration.discord_webhook_link": "Discord Webhook link",
|
||||||
"form.api_key.label.description": "API-sleutel omschrijving",
|
"form.api_key.label.description": "API-sleutel omschrijving",
|
||||||
"form.submit.loading": "Laden...",
|
"form.submit.loading": "Laden...",
|
||||||
"form.submit.saving": "Opslaan...",
|
"form.submit.saving": "Opslaan...",
|
||||||
|
|
|
@ -523,6 +523,8 @@
|
||||||
"form.integration.ntfy_username": "Login do ntfy (opcjonalny)",
|
"form.integration.ntfy_username": "Login do ntfy (opcjonalny)",
|
||||||
"form.integration.ntfy_password": "Hasło do ntfy (opcjonalne)",
|
"form.integration.ntfy_password": "Hasło do ntfy (opcjonalne)",
|
||||||
"form.integration.ntfy_icon_url": "Adres URL ikony ntfy (opcjonalny)",
|
"form.integration.ntfy_icon_url": "Adres URL ikony ntfy (opcjonalny)",
|
||||||
|
"form.integration.discord_activate": "Przesyłaj wpisy do Discord",
|
||||||
|
"form.integration.discord_webhook_link": "Adres URL Webhook Discord",
|
||||||
"form.api_key.label.description": "Etykieta klucza API",
|
"form.api_key.label.description": "Etykieta klucza API",
|
||||||
"form.submit.loading": "Ładowanie…",
|
"form.submit.loading": "Ładowanie…",
|
||||||
"form.submit.saving": "Zapisywanie…",
|
"form.submit.saving": "Zapisywanie…",
|
||||||
|
|
|
@ -513,6 +513,8 @@
|
||||||
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
||||||
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
||||||
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
||||||
|
"form.integration.discord_activate": "Push entries to Discord",
|
||||||
|
"form.integration.discord_webhook_link": "Discord Webhook link",
|
||||||
"form.api_key.label.description": "Etiqueta da chave de API",
|
"form.api_key.label.description": "Etiqueta da chave de API",
|
||||||
"form.submit.loading": "Carregando...",
|
"form.submit.loading": "Carregando...",
|
||||||
"form.submit.saving": "Salvando...",
|
"form.submit.saving": "Salvando...",
|
||||||
|
|
|
@ -523,6 +523,8 @@
|
||||||
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
||||||
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
||||||
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
||||||
|
"form.integration.discord_activate": "Отправить статьи в Discord",
|
||||||
|
"form.integration.discord_webhook_link": "Ссылка на Discord Webhook",
|
||||||
"form.api_key.label.description": "Описание API-ключа",
|
"form.api_key.label.description": "Описание API-ключа",
|
||||||
"form.submit.loading": "Загрузка…",
|
"form.submit.loading": "Загрузка…",
|
||||||
"form.submit.saving": "Сохранение…",
|
"form.submit.saving": "Сохранение…",
|
||||||
|
|
|
@ -288,6 +288,8 @@
|
||||||
"form.feed.label.ntfy_min_priority": "Ntfy min priority",
|
"form.feed.label.ntfy_min_priority": "Ntfy min priority",
|
||||||
"form.integration.cubox_activate": "Save entries to Cubox",
|
"form.integration.cubox_activate": "Save entries to Cubox",
|
||||||
"form.integration.cubox_api_link": "Cubox API link",
|
"form.integration.cubox_api_link": "Cubox API link",
|
||||||
|
"form.integration.discord_activate": "Makaleleri Discord'a gönder",
|
||||||
|
"form.integration.discord_webhook_link": "Discord hizmet Webhook'lerinin virgülle ayrılmış listesi",
|
||||||
"form.prefs.fieldset.application_settings": "Uygulama Ayarları",
|
"form.prefs.fieldset.application_settings": "Uygulama Ayarları",
|
||||||
"form.prefs.fieldset.authentication_settings": "Kimlik Doğrulama Ayarları",
|
"form.prefs.fieldset.authentication_settings": "Kimlik Doğrulama Ayarları",
|
||||||
"form.prefs.fieldset.reader_settings": "Okuyucu Ayarları",
|
"form.prefs.fieldset.reader_settings": "Okuyucu Ayarları",
|
||||||
|
|
|
@ -523,6 +523,8 @@
|
||||||
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
||||||
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
||||||
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
||||||
|
"form.integration.discord_activate": "Push entries to Discord",
|
||||||
|
"form.integration.discord_webhook_link": "Discord Webhook link",
|
||||||
"form.api_key.label.description": "Назва ключа API",
|
"form.api_key.label.description": "Назва ключа API",
|
||||||
"form.submit.loading": "Завантаження...",
|
"form.submit.loading": "Завантаження...",
|
||||||
"form.submit.saving": "Зберігаю...",
|
"form.submit.saving": "Зберігаю...",
|
||||||
|
|
|
@ -503,6 +503,8 @@
|
||||||
"form.integration.ntfy_username": "Ntfy用户名(可选)",
|
"form.integration.ntfy_username": "Ntfy用户名(可选)",
|
||||||
"form.integration.ntfy_password": "Ntfy密码(可选)",
|
"form.integration.ntfy_password": "Ntfy密码(可选)",
|
||||||
"form.integration.ntfy_icon_url": "Ntfy图标URL(可选)",
|
"form.integration.ntfy_icon_url": "Ntfy图标URL(可选)",
|
||||||
|
"form.integration.discord_activate": "将新文章推送到 Discord",
|
||||||
|
"form.integration.discord_webhook_link": "Discord Webhook link",
|
||||||
"form.api_key.label.description": "API密钥标签",
|
"form.api_key.label.description": "API密钥标签",
|
||||||
"form.submit.loading": "载入中…",
|
"form.submit.loading": "载入中…",
|
||||||
"form.submit.saving": "保存中…",
|
"form.submit.saving": "保存中…",
|
||||||
|
|
|
@ -503,6 +503,8 @@
|
||||||
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
"form.integration.ntfy_username": "Ntfy Username (optional)",
|
||||||
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
"form.integration.ntfy_password": "Ntfy Password (optional)",
|
||||||
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
"form.integration.ntfy_icon_url": "Ntfy Icon URL (optional)",
|
||||||
|
"form.integration.discord_activate": "推送文章到 Discord",
|
||||||
|
"form.integration.discord_webhook_link": "Discord Webhook link",
|
||||||
"form.api_key.label.description": "API金鑰標籤",
|
"form.api_key.label.description": "API金鑰標籤",
|
||||||
"form.submit.loading": "載入中…",
|
"form.submit.loading": "載入中…",
|
||||||
"form.submit.saving": "儲存中…",
|
"form.submit.saving": "儲存中…",
|
||||||
|
|
|
@ -106,4 +106,6 @@ type Integration struct {
|
||||||
NtfyIconURL string
|
NtfyIconURL string
|
||||||
CuboxEnabled bool
|
CuboxEnabled bool
|
||||||
CuboxAPILink string
|
CuboxAPILink string
|
||||||
|
DiscordEnabled bool
|
||||||
|
DiscordWebhookLink string
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,7 +209,9 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) {
|
||||||
ntfy_password,
|
ntfy_password,
|
||||||
ntfy_icon_url,
|
ntfy_icon_url,
|
||||||
cubox_enabled,
|
cubox_enabled,
|
||||||
cubox_api_link
|
cubox_api_link,
|
||||||
|
discord_enabled,
|
||||||
|
discord_webhook_link
|
||||||
FROM
|
FROM
|
||||||
integrations
|
integrations
|
||||||
WHERE
|
WHERE
|
||||||
|
@ -318,6 +320,8 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) {
|
||||||
&integration.NtfyIconURL,
|
&integration.NtfyIconURL,
|
||||||
&integration.CuboxEnabled,
|
&integration.CuboxEnabled,
|
||||||
&integration.CuboxAPILink,
|
&integration.CuboxAPILink,
|
||||||
|
&integration.DiscordEnabled,
|
||||||
|
&integration.DiscordWebhookLink,
|
||||||
)
|
)
|
||||||
switch {
|
switch {
|
||||||
case err == sql.ErrNoRows:
|
case err == sql.ErrNoRows:
|
||||||
|
@ -434,9 +438,11 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error {
|
||||||
ntfy_password=$97,
|
ntfy_password=$97,
|
||||||
ntfy_icon_url=$98,
|
ntfy_icon_url=$98,
|
||||||
cubox_enabled=$99,
|
cubox_enabled=$99,
|
||||||
cubox_api_link=$100
|
cubox_api_link=$100,
|
||||||
|
discord_enabled=$101,
|
||||||
|
discord_webhook_link=$102
|
||||||
WHERE
|
WHERE
|
||||||
user_id=$101
|
user_id=$103
|
||||||
`
|
`
|
||||||
_, err := s.db.Exec(
|
_, err := s.db.Exec(
|
||||||
query,
|
query,
|
||||||
|
@ -540,6 +546,8 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error {
|
||||||
integration.NtfyIconURL,
|
integration.NtfyIconURL,
|
||||||
integration.CuboxEnabled,
|
integration.CuboxEnabled,
|
||||||
integration.CuboxAPILink,
|
integration.CuboxAPILink,
|
||||||
|
integration.DiscordEnabled,
|
||||||
|
integration.DiscordWebhookLink,
|
||||||
integration.UserID,
|
integration.UserID,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -580,7 +588,8 @@ func (s *Storage) HasSaveEntry(userID int64) (result bool) {
|
||||||
omnivore_enabled='t' OR
|
omnivore_enabled='t' OR
|
||||||
raindrop_enabled='t' OR
|
raindrop_enabled='t' OR
|
||||||
betula_enabled='t' OR
|
betula_enabled='t' OR
|
||||||
cubox_enabled='t'
|
cubox_enabled='t' OR
|
||||||
|
discord_enabled='t'
|
||||||
)
|
)
|
||||||
`
|
`
|
||||||
if err := s.db.QueryRow(query, userID).Scan(&result); err != nil {
|
if err := s.db.QueryRow(query, userID).Scan(&result); err != nil {
|
||||||
|
|
|
@ -73,6 +73,22 @@
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
<details {{ if .form.DiscordEnabled }}open{{ end }}>
|
||||||
|
<summary>Discord</summary>
|
||||||
|
<div class="form-section">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="discord_enabled" value="1" {{ if .form.DiscordEnabled }}checked{{ end }}> {{ t "form.integration.discord_activate" }}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="form-discord-webhook-link">{{ t "form.integration.discord_webhook_link" }}</label>
|
||||||
|
<input type="url" name="discord_webhook_link" id="form-discord-webhook-link" value="{{ .form.DiscordWebhookLink }}" placeholder="https://discord.com/api/webhooks/xxx/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 }}>
|
<details {{ if .form.EspialEnabled }}open{{ end }}>
|
||||||
<summary>Espial</summary>
|
<summary>Espial</summary>
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
|
|
|
@ -112,6 +112,8 @@ type IntegrationForm struct {
|
||||||
NtfyIconURL string
|
NtfyIconURL string
|
||||||
CuboxEnabled bool
|
CuboxEnabled bool
|
||||||
CuboxAPILink string
|
CuboxAPILink string
|
||||||
|
DiscordEnabled bool
|
||||||
|
DiscordWebhookLink string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge copy form values to the model.
|
// Merge copy form values to the model.
|
||||||
|
@ -213,6 +215,8 @@ func (i IntegrationForm) Merge(integration *model.Integration) {
|
||||||
integration.NtfyIconURL = i.NtfyIconURL
|
integration.NtfyIconURL = i.NtfyIconURL
|
||||||
integration.CuboxEnabled = i.CuboxEnabled
|
integration.CuboxEnabled = i.CuboxEnabled
|
||||||
integration.CuboxAPILink = i.CuboxAPILink
|
integration.CuboxAPILink = i.CuboxAPILink
|
||||||
|
integration.DiscordEnabled = i.DiscordEnabled
|
||||||
|
integration.DiscordWebhookLink = i.DiscordWebhookLink
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIntegrationForm returns a new IntegrationForm.
|
// NewIntegrationForm returns a new IntegrationForm.
|
||||||
|
@ -317,6 +321,8 @@ func NewIntegrationForm(r *http.Request) *IntegrationForm {
|
||||||
NtfyIconURL: r.FormValue("ntfy_icon_url"),
|
NtfyIconURL: r.FormValue("ntfy_icon_url"),
|
||||||
CuboxEnabled: r.FormValue("cubox_enabled") == "1",
|
CuboxEnabled: r.FormValue("cubox_enabled") == "1",
|
||||||
CuboxAPILink: r.FormValue("cubox_api_link"),
|
CuboxAPILink: r.FormValue("cubox_api_link"),
|
||||||
|
DiscordEnabled: r.FormValue("discord_enabled") == "1",
|
||||||
|
DiscordWebhookLink: r.FormValue("discord_webhook_link"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,6 +126,8 @@ func (h *handler) showIntegrationPage(w http.ResponseWriter, r *http.Request) {
|
||||||
NtfyIconURL: integration.NtfyIconURL,
|
NtfyIconURL: integration.NtfyIconURL,
|
||||||
CuboxEnabled: integration.CuboxEnabled,
|
CuboxEnabled: integration.CuboxEnabled,
|
||||||
CuboxAPILink: integration.CuboxAPILink,
|
CuboxAPILink: integration.CuboxAPILink,
|
||||||
|
DiscordEnabled: integration.DiscordEnabled,
|
||||||
|
DiscordWebhookLink: integration.DiscordWebhookLink,
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := session.New(h.store, request.SessionID(r))
|
sess := session.New(h.store, request.SessionID(r))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue