diff --git a/api/system_setting.go b/api/system_setting.go index 3cdc9867..522fda8e 100644 --- a/api/system_setting.go +++ b/api/system_setting.go @@ -3,6 +3,7 @@ package api import ( "encoding/json" "fmt" + "strings" "golang.org/x/exp/slices" ) @@ -186,6 +187,15 @@ func (upsert SystemSettingUpsert) Validate() error { return fmt.Errorf(systemSettingUnmarshalError, settingName) } + case SystemSettingTelegramRobotTokenName: + if upsert.Value == "" { + return nil + } + fragments := strings.Split(upsert.Value, ":") + if len(fragments) != 2 { + return fmt.Errorf(systemSettingUnmarshalError, settingName) + } + default: return fmt.Errorf("invalid system setting name") } diff --git a/api/user_setting.go b/api/user_setting.go index c5e95a21..288a26ca 100644 --- a/api/user_setting.go +++ b/api/user_setting.go @@ -3,6 +3,7 @@ package api import ( "encoding/json" "fmt" + "strconv" "golang.org/x/exp/slices" ) @@ -101,13 +102,17 @@ func (upsert UserSettingUpsert) Validate() error { return fmt.Errorf("invalid user setting memo visibility value") } } else if upsert.Key == UserSettingTelegramUserIDKey { - telegramUserID := 0 - err := json.Unmarshal([]byte(upsert.Value), &telegramUserID) + var s string + err := json.Unmarshal([]byte(upsert.Value), &s) if err != nil { - return fmt.Errorf("failed to unmarshal user setting telegram userid value") + return fmt.Errorf("invalid user setting telegram user id value") } - if telegramUserID <= 0 { - return fmt.Errorf("invalid user setting telegram userid value") + + if s == "" { + return nil + } + if _, err := strconv.Atoi(s); err != nil { + return fmt.Errorf("invalid user setting telegram user id value") } } else { return fmt.Errorf("invalid user setting key") diff --git a/plugin/telegram/robot.go b/plugin/telegram/robot.go index 48bc1354..aa114cda 100644 --- a/plugin/telegram/robot.go +++ b/plugin/telegram/robot.go @@ -24,6 +24,7 @@ func NewRobotWithHandler(h Handler) *Robot { } const noTokenWait = 30 * time.Second +const errRetryWait = 10 * time.Second // Start start an infinity call of getUpdates from Telegram, call r.MessageHandle while get new message updates. func (r *Robot) Start(ctx context.Context) { @@ -37,6 +38,7 @@ func (r *Robot) Start(ctx context.Context) { } if err != nil { log.Warn("fail to telegram.GetUpdates", zap.Error(err)) + time.Sleep(errRetryWait) continue } diff --git a/server/telegram.go b/server/telegram.go index db051366..8fd14036 100644 --- a/server/telegram.go +++ b/server/telegram.go @@ -2,6 +2,7 @@ package server import ( "context" + "encoding/json" "fmt" "path" "strconv" @@ -33,7 +34,12 @@ func (t *telegramHandler) MessageHandle(ctx context.Context, message telegram.Me return fmt.Errorf("Fail to find memo user: %s", err) } for _, userSetting := range userSettingList { - if userSetting.Value == strconv.Itoa(message.From.ID) { + var value string + if err := json.Unmarshal([]byte(userSetting.Value), &value); err != nil { + continue + } + + if value == strconv.Itoa(message.From.ID) { creatorID = userSetting.UserID } } diff --git a/web/src/components/Settings/PreferencesSection.tsx b/web/src/components/Settings/PreferencesSection.tsx index e2229647..68dad14e 100644 --- a/web/src/components/Settings/PreferencesSection.tsx +++ b/web/src/components/Settings/PreferencesSection.tsx @@ -1,4 +1,7 @@ -import { Switch, Option, Select } from "@mui/joy"; +import { Input, Button, Divider, Switch, Option, Select } from "@mui/joy"; +import { useEffect, useState } from "react"; +import { toast } from "react-hot-toast"; +import { getMyselfUser } from "@/helpers/api"; import React from "react"; import { useTranslation } from "react-i18next"; import { useGlobalStore, useUserStore } from "@/store/module"; @@ -13,6 +16,7 @@ const PreferencesSection = () => { const userStore = useUserStore(); const { appearance, locale } = globalStore.state; const { setting, localSetting } = userStore.state.user as User; + const [telegramUserId, setTelegramUserId] = useState(""); const visibilitySelectorItems = VISIBILITY_SELECTOR_ITEMS.map((item) => { return { value: item.value, @@ -20,6 +24,21 @@ const PreferencesSection = () => { }; }); + useEffect(() => { + getMyselfUser().then( + ({ + data: { + data: { userSettingList: userSettingList }, + }, + }) => { + const telegramUserIdSetting = userSettingList.find((setting: any) => setting.key === "telegram-user-id"); + if (telegramUserIdSetting) { + setTelegramUserId(JSON.parse(telegramUserIdSetting.value)); + } + } + ); + }, []); + const dailyReviewTimeOffsetOptions: number[] = [...Array(24).keys()]; const handleLocaleSelectChange = async (locale: Locale) => { @@ -49,6 +68,21 @@ const PreferencesSection = () => { userStore.upsertLocalSetting({ ...localSetting, enableAutoCollapse: event.target.checked }); }; + const handleSaveTelegramUserId = async () => { + try { + await userStore.upsertUserSetting("telegram-user-id", telegramUserId); + toast.success(t("common.dialog.success")); + } catch (error: any) { + console.error(error); + toast.error(error.response.data.message); + return; + } + }; + + const handleTelegramUserIdChanged = async (value: string) => { + setTelegramUserId(value); + }; + return (

{t("common.basic")}

@@ -118,6 +152,25 @@ const PreferencesSection = () => { {t("setting.preference-section.auto-collapse")} + + + +
+
+ {t("setting.preference-section.telegram-user-id")} +
+ +
+ handleTelegramUserIdChanged(event.target.value)} + placeholder={t("setting.preference-section.telegram-user-id-placeholder")} + />
); }; diff --git a/web/src/components/Settings/SystemSection.tsx b/web/src/components/Settings/SystemSection.tsx index e1200aa6..421d0ab1 100644 --- a/web/src/components/Settings/SystemSection.tsx +++ b/web/src/components/Settings/SystemSection.tsx @@ -32,6 +32,7 @@ const SystemSection = () => { disablePublicMemos: systemStatus.disablePublicMemos, maxUploadSizeMiB: systemStatus.maxUploadSizeMiB, }); + const [telegramRobotToken, setTelegramRobotToken] = useState(""); const [openAIConfig, setOpenAIConfig] = useState({ key: "", host: "", @@ -47,6 +48,11 @@ const SystemSection = () => { if (openAIConfigSetting) { setOpenAIConfig(JSON.parse(openAIConfigSetting.value)); } + + const telegramRobotSetting = systemSettings.find((setting) => setting.name === "telegram-robot-token"); + if (telegramRobotSetting) { + setTelegramRobotToken(telegramRobotSetting.value); + } }); }, []); @@ -126,6 +132,24 @@ const SystemSection = () => { toast.success("OpenAI Config updated"); }; + const handleTelegramRobotTokenChanged = (value: string) => { + setTelegramRobotToken(value); + }; + + const handleSaveTelegramRobotToken = async () => { + try { + await api.upsertSystemSetting({ + name: "telegram-robot-token", + value: telegramRobotToken, + }); + } catch (error: any) { + console.error(error); + toast.error(error.response.data.message); + return; + } + toast.success("OpenAI Config updated"); + }; + const handleAdditionalStyleChanged = (value: string) => { setState({ ...state, @@ -246,6 +270,27 @@ const SystemSection = () => { /> +
+
+ {t("setting.system-section.telegram-robot-token")} + +
+ +
+ handleTelegramRobotTokenChanged(event.target.value)} + /> +
{t("setting.system-section.openai-api-key")} diff --git a/web/src/locales/en.json b/web/src/locales/en.json index e88732a2..70656869 100644 --- a/web/src/locales/en.json +++ b/web/src/locales/en.json @@ -192,6 +192,8 @@ "editor-font-style": "Editor font style", "mobile-editor-style": "Mobile editor style", "default-memo-sort-option": "Memo display time", + "telegram-user-id": "Telegram UserID", + "telegram-user-id-placeholder": "Send any words to Your Telegram Robot to get", "created_ts": "Created Time", "updated_ts": "Updated Time", "daily-review-time-offset": "Daily Review Time Offset", @@ -256,6 +258,9 @@ "additional-script": "Additional script", "additional-style-placeholder": "Additional CSS code", "additional-script-placeholder": "Additional JavaScript code", + "telegram-robot-token": "Telegram Robot Token", + "telegram-robot-token-description": "Get from @BotFather of Telegram", + "telegram-robot-token-placeholder": "Your Telegram Robot token", "openai-api-key": "OpenAI: API Key", "openai-api-key-description": "Get API key", "openai-api-key-placeholder": "Your OpenAI API Key", diff --git a/web/src/locales/zh-Hans.json b/web/src/locales/zh-Hans.json index 115cca57..ffab21d9 100644 --- a/web/src/locales/zh-Hans.json +++ b/web/src/locales/zh-Hans.json @@ -328,6 +328,8 @@ "enable-double-click": "开启双击编辑", "enable-folding-memo": "开启折叠备忘录", "mobile-editor-style": "移动端编辑器样式", + "telegram-user-id": "Telegram UserID", + "telegram-user-id-placeholder": "向Telegram机器人发送任意消息以获取", "theme": "主题", "updated_ts": "更新时间" }, @@ -404,6 +406,9 @@ "database-file-size": "数据库文件大小", "disable-public-memos": "禁用公共备忘录", "ignore-version-upgrade": "忽略版本升级", + "telegram-robot-token": "Telegram 机器人 Token", + "telegram-robot-token-description": "从 Telegram 的 @BotFather 处获取", + "telegram-robot-token-placeholder": "Telegram 的机器人 Token", "openai-api-host": "OpenAI:API Host", "openai-api-host-placeholder": "默认:https://api.openai.com/", "openai-api-key": "OpenAI:API 密钥",