Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Telegram bot config UI #1747

Merged
merged 12 commits into from
May 26, 2023
10 changes: 10 additions & 0 deletions api/system_setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package api
import (
"encoding/json"
"fmt"
"strings"

"golang.org/x/exp/slices"
)
Expand Down Expand Up @@ -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")
}
Expand Down
15 changes: 10 additions & 5 deletions api/user_setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package api
import (
"encoding/json"
"fmt"
"strconv"

"golang.org/x/exp/slices"
)
Expand Down Expand Up @@ -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")
Expand Down
2 changes: 2 additions & 0 deletions plugin/telegram/robot.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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
}

Expand Down
8 changes: 7 additions & 1 deletion server/telegram.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package server

import (
"context"
"encoding/json"
"fmt"
"path"
"strconv"
Expand Down Expand Up @@ -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
}
}
Expand Down
55 changes: 54 additions & 1 deletion web/src/components/Settings/PreferencesSection.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -13,13 +16,29 @@ const PreferencesSection = () => {
const userStore = useUserStore();
const { appearance, locale } = globalStore.state;
const { setting, localSetting } = userStore.state.user as User;
const [telegramUserId, setTelegramUserId] = useState<string>("");
const visibilitySelectorItems = VISIBILITY_SELECTOR_ITEMS.map((item) => {
return {
value: item.value,
text: t(`memo.visibility.${item.text.toLowerCase()}`),
};
});

useEffect(() => {
getMyselfUser().then(
CorrectRoadH marked this conversation as resolved.
Show resolved Hide resolved
({
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) => {
Expand Down Expand Up @@ -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 (
<div className="section-container preferences-section-container">
<p className="title-text">{t("common.basic")}</p>
Expand Down Expand Up @@ -118,6 +152,25 @@ const PreferencesSection = () => {
<span className="normal-text">{t("setting.preference-section.auto-collapse")}</span>
<Switch className="ml-2" checked={localSetting.enableAutoCollapse} onChange={handleAutoCollapseChanged} />
</label>

<Divider className="!mt-3 !my-4" />

<div className="form-label">
<div className="flex flex-row items-center">
<span className="text-sm mr-1">{t("setting.preference-section.telegram-user-id")}</span>
</div>
<Button onClick={handleSaveTelegramUserId}>{t("common.save")}</Button>
</div>
<Input
className="w-full"
sx={{
fontFamily: "monospace",
fontSize: "14px",
}}
value={telegramUserId}
onChange={(event) => handleTelegramUserIdChanged(event.target.value)}
placeholder={t("setting.preference-section.telegram-user-id-placeholder")}
/>
</div>
);
};
Expand Down
45 changes: 45 additions & 0 deletions web/src/components/Settings/SystemSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const SystemSection = () => {
disablePublicMemos: systemStatus.disablePublicMemos,
maxUploadSizeMiB: systemStatus.maxUploadSizeMiB,
});
const [telegramRobotToken, setTelegramRobotToken] = useState<string>("");
const [openAIConfig, setOpenAIConfig] = useState<OpenAIConfig>({
key: "",
host: "",
Expand All @@ -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);
}
});
}, []);

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -246,6 +270,27 @@ const SystemSection = () => {
/>
</div>
<Divider className="!mt-3 !my-4" />
<div className="form-label">
<div className="flex flex-row items-center">
<span className="text-sm mr-1">{t("setting.system-section.telegram-robot-token")}</span>
<HelpButton
hint={t("setting.system-section.telegram-robot-token-description")}
url="https://core.telegram.org/bots#how-do-i-create-a-bot"
/>
</div>
<Button onClick={handleSaveTelegramRobotToken}>{t("common.save")}</Button>
</div>
<Input
className="w-full"
sx={{
fontFamily: "monospace",
fontSize: "14px",
}}
placeholder={t("setting.system-section.telegram-robot-token-placeholder")}
value={telegramRobotToken}
onChange={(event) => handleTelegramRobotTokenChanged(event.target.value)}
/>
boojack marked this conversation as resolved.
Show resolved Hide resolved
<Divider className="!mt-3 !my-4" />
<div className="form-label">
<div className="flex flex-row items-center">
<span className="text-sm mr-1">{t("setting.system-section.openai-api-key")}</span>
Expand Down
5 changes: 5 additions & 0 deletions web/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
5 changes: 5 additions & 0 deletions web/src/locales/zh-Hans.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "更新时间"
},
Expand Down Expand Up @@ -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 密钥",
Expand Down