From 657964cda4fb7a0cea0b1b5d01fbd568c1d491b2 Mon Sep 17 00:00:00 2001 From: Leon Date: Fri, 1 Nov 2024 11:35:09 +0800 Subject: [PATCH] feat: add Bark notification channel and related settings --- internal/domain/notify.go | 11 +- internal/notify/notify.go | 14 +- ui/src/components/notify/Bark.tsx | 246 +++++++++++++++++++++++ ui/src/domain/settings.ts | 10 +- ui/src/i18n/locales/en/nls.common.json | 3 +- ui/src/i18n/locales/en/nls.settings.json | 3 +- ui/src/i18n/locales/zh/nls.common.json | 4 +- ui/src/i18n/locales/zh/nls.settings.json | 3 +- ui/src/pages/setting/Notify.tsx | 9 + 9 files changed, 291 insertions(+), 12 deletions(-) create mode 100644 ui/src/components/notify/Bark.tsx diff --git a/internal/domain/notify.go b/internal/domain/notify.go index 534d8b02..440bbef7 100644 --- a/internal/domain/notify.go +++ b/internal/domain/notify.go @@ -1,12 +1,13 @@ package domain const ( - NotifyChannelDingtalk = "dingtalk" - NotifyChannelWebhook = "webhook" - NotifyChannelTelegram = "telegram" - NotifyChannelLark = "lark" + NotifyChannelDingtalk = "dingtalk" + NotifyChannelWebhook = "webhook" + NotifyChannelTelegram = "telegram" + NotifyChannelLark = "lark" NotifyChannelServerChan = "serverchan" - NotifyChannelMail = "mail" + NotifyChannelMail = "mail" + NotifyChannelBark = "bark" ) type NotifyTestPushReq struct { diff --git a/internal/notify/notify.go b/internal/notify/notify.go index 4b91cdbd..a7fdcd8b 100644 --- a/internal/notify/notify.go +++ b/internal/notify/notify.go @@ -11,6 +11,7 @@ import ( "github.com/usual2970/certimate/internal/utils/app" notifyPackage "github.com/nikoksr/notify" + "github.com/nikoksr/notify/service/bark" "github.com/nikoksr/notify/service/dingding" "github.com/nikoksr/notify/service/http" "github.com/nikoksr/notify/service/lark" @@ -108,6 +109,8 @@ func getNotifier(channel string, conf map[string]any) (notifyPackage.Notifier, e return getServerChanNotifier(conf), nil case domain.NotifyChannelMail: return getMailNotifier(conf), nil + case domain.NotifyChannelBark: + return getBarkNotifier(conf), nil } return nil, fmt.Errorf("notifier not found") @@ -157,6 +160,15 @@ func getServerChanNotifier(conf map[string]any) notifyPackage.Notifier { return rs } +func getBarkNotifier(conf map[string]any) notifyPackage.Notifier { + deviceKey := getString(conf, "deviceKey") + serverURL := getString(conf, "serverUrl") + if serverURL == "" { + return bark.New(deviceKey) + } + return bark.NewWithServers(deviceKey, serverURL) +} + func getDingTalkNotifier(conf map[string]any) notifyPackage.Notifier { return dingding.New(&dingding.Config{ Token: getString(conf, "accessToken"), @@ -169,7 +181,7 @@ func getLarkNotifier(conf map[string]any) notifyPackage.Notifier { } func getMailNotifier(conf map[string]any) notifyPackage.Notifier { - rs := NewMail(getString(conf, "senderAddress"),getString(conf,"receiverAddress"), getString(conf, "smtpHostAddr"), getString(conf, "smtpHostPort")) + rs := NewMail(getString(conf, "senderAddress"), getString(conf, "receiverAddress"), getString(conf, "smtpHostAddr"), getString(conf, "smtpHostPort")) rs.SetAuth(getString(conf, "username"), getString(conf, "password")) diff --git a/ui/src/components/notify/Bark.tsx b/ui/src/components/notify/Bark.tsx new file mode 100644 index 00000000..8eaf8042 --- /dev/null +++ b/ui/src/components/notify/Bark.tsx @@ -0,0 +1,246 @@ +import { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; + +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Switch } from "@/components/ui/switch"; +import { useToast } from "@/components/ui/use-toast"; +import { getErrMessage } from "@/lib/error"; +import { NotifyChannels, NotifyChannelBark } from "@/domain/settings"; +import { update } from "@/repository/settings"; +import { useNotifyContext } from "@/providers/notify"; +import { notifyTest } from "@/api/notify"; +import Show from "@/components/Show"; + +type BarkSetting = { + id: string; + name: string; + data: NotifyChannelBark; +}; + +const Bark = () => { + const { config, setChannels } = useNotifyContext(); + const { t } = useTranslation(); + + const [changed, setChanged] = useState(false); + + const [bark, setBark] = useState({ + id: config.id ?? "", + name: "notifyChannels", + data: { + serverUrl: "", + deviceKey: "", + enabled: false, + }, + }); + + const [originBark, setOriginBark] = useState({ + id: config.id ?? "", + name: "notifyChannels", + data: { + serverUrl: "", + deviceKey: "", + enabled: false, + }, + }); + + useEffect(() => { + setChanged(false); + }, [config]); + + useEffect(() => { + const data = getDetailBark(); + setOriginBark({ + id: config.id ?? "", + name: "common.provider.bark", + data, + }); + }, [config]); + + useEffect(() => { + const data = getDetailBark(); + setBark({ + id: config.id ?? "", + name: "common.provider.bark", + data, + }); + }, [config]); + + const { toast } = useToast(); + + const checkChanged = (data: NotifyChannelBark) => { + if (data.serverUrl !== originBark.data.serverUrl || data.deviceKey !== originBark.data.deviceKey) { + setChanged(true); + } else { + setChanged(false); + } + }; + + const getDetailBark = () => { + const df: NotifyChannelBark = { + serverUrl: "", + deviceKey: "", + enabled: false, + }; + if (!config.content) { + return df; + } + const chanels = config.content as NotifyChannels; + if (!chanels.bark) { + return df; + } + + return chanels.bark as NotifyChannelBark; + }; + + const handleSaveClick = async () => { + try { + const resp = await update({ + ...config, + name: "notifyChannels", + content: { + ...config.content, + bark: { + ...bark.data, + }, + }, + }); + + setChannels(resp); + toast({ + title: t("common.save.succeeded.message"), + description: t("settings.notification.config.saved.message"), + }); + } catch (e) { + const msg = getErrMessage(e); + + toast({ + title: t("common.save.failed.message"), + description: `${t("settings.notification.config.failed.message")}: ${msg}`, + variant: "destructive", + }); + } + }; + + const handlePushTestClick = async () => { + try { + await notifyTest("bark"); + + toast({ + title: t("settings.notification.config.push.test.message.success.message"), + description: t("settings.notification.config.push.test.message.success.message"), + }); + } catch (e) { + const msg = getErrMessage(e); + + toast({ + title: t("settings.notification.config.push.test.message.failed.message"), + description: `${t("settings.notification.config.push.test.message.failed.message")}: ${msg}`, + variant: "destructive", + }); + } + }; + + const handleSwitchChange = async () => { + const newData = { + ...bark, + data: { + ...bark.data, + enabled: !bark.data.enabled, + }, + }; + setBark(newData); + + try { + const resp = await update({ + ...config, + name: "notifyChannels", + content: { + ...config.content, + bark: { + ...newData.data, + }, + }, + }); + + setChannels(resp); + } catch (e) { + const msg = getErrMessage(e); + + toast({ + title: t("common.save.failed.message"), + description: `${t("settings.notification.config.failed.message")}: ${msg}`, + variant: "destructive", + }); + } + }; + + return ( +
+ { + const newData = { + ...bark, + data: { + ...bark.data, + serverUrl: e.target.value, + }, + }; + + checkChanged(newData.data); + setBark(newData); + }} + /> + + { + const newData = { + ...bark, + data: { + ...bark.data, + deviceKey: e.target.value, + }, + }; + + checkChanged(newData.data); + setBark(newData); + }} + /> + +
+ + +
+ +
+ + + + + + + +
+
+ ); +}; + +export default Bark; diff --git a/ui/src/domain/settings.ts b/ui/src/domain/settings.ts index 114fc8ac..7962ef7a 100644 --- a/ui/src/domain/settings.ts +++ b/ui/src/domain/settings.ts @@ -24,6 +24,7 @@ export type NotifyChannels = { webhook?: NotifyChannel; serverchan?: NotifyChannel; mail?: NotifyChannelMail; + bark?: NotifyChannelBark; }; export type NotifyChannel = @@ -32,7 +33,8 @@ export type NotifyChannel = | NotifyChannelTelegram | NotifyChannelWebhook | NotifyChannelServerChan - | NotifyChannelMail; + | NotifyChannelMail + | NotifyChannelBark; export type NotifyChannelDingTalk = { accessToken: string; @@ -71,6 +73,12 @@ export type NotifyChannelMail = { enabled: boolean; }; +export type NotifyChannelBark = { + deviceKey: string; + serverUrl: string; + enabled: boolean; +}; + export const defaultNotifyTemplate: NotifyTemplate = { title: "您有 {COUNT} 张证书即将过期", content: "有 {COUNT} 张证书即将过期,域名分别为 {DOMAINS},请保持关注!", diff --git a/ui/src/i18n/locales/en/nls.common.json b/ui/src/i18n/locales/en/nls.common.json index 6870c616..a704e08f 100644 --- a/ui/src/i18n/locales/en/nls.common.json +++ b/ui/src/i18n/locales/en/nls.common.json @@ -86,5 +86,6 @@ "common.provider.dingtalk": "DingTalk", "common.provider.telegram": "Telegram", "common.provider.lark": "Lark", - "common.provider.mail": "Mail" + "common.provider.mail": "Mail", + "common.provider.bark": "Bark" } diff --git a/ui/src/i18n/locales/en/nls.settings.json b/ui/src/i18n/locales/en/nls.settings.json index fd84b888..a7d2f857 100644 --- a/ui/src/i18n/locales/en/nls.settings.json +++ b/ui/src/i18n/locales/en/nls.settings.json @@ -42,6 +42,8 @@ "settings.notification.mail.smtp_port.placeholder": "SMTP server port, if not set, default is 25", "settings.notification.mail.username.placeholder": "username", "settings.notification.mail.password.placeholder": "password", + "settings.notification.bark.serverUrl.placeholder": "Server URL, e.g. https://your-bark-server.com, leave it blank to use the bark default server", + "settings.notification.bark.deviceKey.placeholder": "Device Key,e.g. XXXXXXXXXXXXXXXXXXXX", "settings.ca.tab": "Certificate Authority", "settings.ca.provider.errmsg.empty": "Please select a Certificate Authority", @@ -49,4 +51,3 @@ "settings.ca.eab_hmac_key.errmsg.empty": "Please enter EAB_HMAC_KEY.", "settings.ca.eab_kid_hmac_key.errmsg.empty": "Please enter EAB_KID and EAB_HMAC_KEY" } - diff --git a/ui/src/i18n/locales/zh/nls.common.json b/ui/src/i18n/locales/zh/nls.common.json index 12fcd58a..2b59430e 100644 --- a/ui/src/i18n/locales/zh/nls.common.json +++ b/ui/src/i18n/locales/zh/nls.common.json @@ -86,6 +86,6 @@ "common.provider.dingtalk": "钉钉", "common.provider.telegram": "Telegram", "common.provider.lark": "飞书", - "common.provider.mail": "电子邮件" + "common.provider.mail": "电子邮件", + "common.provider.bark": "Bark" } - diff --git a/ui/src/i18n/locales/zh/nls.settings.json b/ui/src/i18n/locales/zh/nls.settings.json index 2c0a807f..23185807 100644 --- a/ui/src/i18n/locales/zh/nls.settings.json +++ b/ui/src/i18n/locales/zh/nls.settings.json @@ -42,6 +42,8 @@ "settings.notification.mail.smtp_port.placeholder": "SMTP服务器端口, 如果未设置, 默认为25", "settings.notification.mail.username.placeholder": "用于登录到邮件服务器的用户名", "settings.notification.mail.password.placeholder": "用于登录到邮件服务器的密码", + "settings.notification.bark.serverUrl.placeholder": "服务器URL,形如: https://your-bark-server.com, 留空则使用 Bark 默认服务器", + "settings.notification.bark.deviceKey.placeholder": "设备密钥,形如: XXXXXXXXXXXXXXXXXXXX", "settings.ca.tab": "证书颁发机构(CA)", "settings.ca.provider.errmsg.empty": "请选择证书分发机构", @@ -49,4 +51,3 @@ "settings.ca.eab_hmac_key.errmsg.empty": "请输入EAB_HMAC_KEY", "settings.ca.eab_kid_hmac_key.errmsg.empty": "请输入EAB_KID和EAB_HMAC_KEY" } - diff --git a/ui/src/pages/setting/Notify.tsx b/ui/src/pages/setting/Notify.tsx index 350e4b8b..c29d0405 100644 --- a/ui/src/pages/setting/Notify.tsx +++ b/ui/src/pages/setting/Notify.tsx @@ -8,6 +8,7 @@ import Telegram from "@/components/notify/Telegram"; import Webhook from "@/components/notify/Webhook"; import ServerChan from "@/components/notify/ServerChan"; import Mail from "@/components/notify/Mail"; +import Bark from "@/components/notify/Bark"; import { NotifyProvider } from "@/providers/notify"; const Notify = () => { @@ -62,12 +63,20 @@ const Notify = () => { + {t("common.provider.mail")} + + + {t("common.provider.bark")} + + + +