Skip to content

Commit

Permalink
feat: telegram bot TelegramSettings && webhook (#244)
Browse files Browse the repository at this point in the history
* feat: telegram bot TelegramSettings

* feat: webhook
  • Loading branch information
dreamhunter2333 authored May 18, 2024
1 parent 53a06fc commit ca00a87
Show file tree
Hide file tree
Showing 32 changed files with 776 additions and 111 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# CHANGE LOG

## main branch

- `telegram bot` 白名单配置
- `ENABLE_WEBHOOK` 添加 webhook
- admin 页面使用双层 tab

## v0.4.2

- 修复 smtp imap proxy sever 的一些 bug
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
- [x] `admin` 后台创建无前缀邮箱
- [x] 添加 `SMTP proxy server`,支持 `SMTP` 发送邮件, `IMAP` 查看邮件
- [x] 添加完整的用户注册登录功能,可绑定邮箱地址,绑定后可自动获取邮箱JWT凭证切换不同邮箱
- [x] `Telegram Bot` 使用,以及 `Telegram` 推送

## Reference

Expand Down
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cloudflare_temp_email",
"version": "0.4.2",
"version": "0.4.3",
"private": true,
"type": "module",
"scripts": {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ const getOpenSettings = async (message) => {
enableIndexAbout: res["enableIndexAbout"] || false,
copyright: res["copyright"] || openSettings.value.copyright,
cfTurnstileSiteKey: res["cfTurnstileSiteKey"] || "",
enableWebhook: res["enableWebhook"] || false,
});
if (openSettings.value.needAuth) {
showAuth.value = true;
Expand Down
58 changes: 39 additions & 19 deletions frontend/src/views/Admin.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import About from './common/About.vue';
import Maintenance from './admin/Maintenance.vue';
import Appearance from './common/Appearance.vue';
import Telegram from './admin/Telegram.vue';
import Webhook from './admin/Webhook.vue';
const {
localeCache, adminAuth, showAdminAuth, adminTab, loading, globalTabplacement
Expand All @@ -42,12 +43,14 @@ const { t } = useI18n({
account: 'Account',
account_create: 'Create Account',
account_settings: 'Account Settings',
user: 'User',
user_management: 'User Management',
user_settings: 'User Settings',
unknow: 'Mails with unknow receiver',
senderAccess: 'Sender Access Control',
sendBox: 'Send Box',
telegram: 'Telegram Bot',
webhook: 'Webhook',
statistics: 'Statistics',
maintenance: 'Maintenance',
appearance: 'Appearance',
Expand All @@ -61,12 +64,14 @@ const { t } = useI18n({
account: '账号',
account_create: '创建账号',
account_settings: '账号设置',
user: '用户',
user_management: '用户管理',
user_settings: '用户设置',
unknow: '无收件人邮件',
senderAccess: '发件权限控制',
sendBox: '发件箱',
telegram: '电报机器人',
webhook: 'Webhook',
statistics: '统计',
maintenance: '维护',
appearance: '外观',
Expand Down Expand Up @@ -98,28 +103,43 @@ onMounted(async () => {
</n-modal>
<n-tabs type="card" v-model:value="adminTab" :placement="globalTabplacement">
<n-tab-pane name="account" :tab="t('account')">
<Account />
<n-tabs type="bar" animated>
<n-tab-pane name="account" :tab="t('account')">
<Account />
</n-tab-pane>
<n-tab-pane name="account_create" :tab="t('account_create')">
<CreateAccount />
</n-tab-pane>
<n-tab-pane name="account_settings" :tab="t('account_settings')">
<AccountSettings />
</n-tab-pane>
<n-tab-pane name="senderAccess" :tab="t('senderAccess')">
<SenderAccess />
</n-tab-pane>
<n-tab-pane name="webhook" :tab="t('webhook')">
<Webhook />
</n-tab-pane>
</n-tabs>
</n-tab-pane>
<n-tab-pane name="account_create" :tab="t('account_create')">
<CreateAccount />
</n-tab-pane>
<n-tab-pane name="account_settings" :tab="t('account_settings')">
<AccountSettings />
</n-tab-pane>
<n-tab-pane name="user_management" :tab="t('user_management')">
<UserManagement />
</n-tab-pane>
<n-tab-pane name="user_settings" :tab="t('user_settings')">
<UserSettings />
<n-tab-pane name="user" :tab="t('user')">
<n-tabs type="bar" animated>
<n-tab-pane name="user_management" :tab="t('user_management')">
<UserManagement />
</n-tab-pane>
<n-tab-pane name="user_settings" :tab="t('user_settings')">
<UserSettings />
</n-tab-pane>
</n-tabs>
</n-tab-pane>
<n-tab-pane name="mails" :tab="t('mails')">
<Mails />
</n-tab-pane>
<n-tab-pane name="unknow" :tab="t('unknow')">
<MailsUnknow />
</n-tab-pane>
<n-tab-pane name="senderAccess" :tab="t('senderAccess')">
<SenderAccess />
<n-tabs type="bar" animated>
<n-tab-pane name="mails" :tab="t('mails')">
<Mails />
</n-tab-pane>
<n-tab-pane name="unknow" :tab="t('unknow')">
<MailsUnknow />
</n-tab-pane>
</n-tabs>
</n-tab-pane>
<n-tab-pane name="sendBox" :tab="t('sendBox')">
<SendBox />
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/views/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import AutoReply from './index/AutoReply.vue';
import SendBox from './index/SendBox.vue';
import SendMail from './index/SendMail.vue';
import AccountSettings from './index/AccountSettings.vue';
import WenHook from './index/Webhook.vue';
import About from './common/About.vue';
const { localeCache, settings, openSettings, indexTab, globalTabplacement } = useGlobalState()
Expand Down Expand Up @@ -65,6 +66,9 @@ const deleteMail = async (curMailId) => {
<n-tab-pane v-if="openSettings.enableAutoReply" name="auto_reply" :tab="t('auto_reply')">
<AutoReply />
</n-tab-pane>
<n-tab-pane v-if="openSettings.enableWebhook" name="webhook" :tab="t('webhook')">
<WenHook />
</n-tab-pane>
<n-tab-pane v-if="openSettings.enableIndexAbout" name="about" :tab="t('about')">
<About />
</n-tab-pane>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/admin/Account.vue
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ onMounted(async () => {
</script>

<template>
<div>
<div style="margin-top: 10px;">
<n-modal v-model:show="showEmailCredential" preset="dialog" title="Dialog">
<template #header>
<div>{{ t("addressCredential") }}</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/admin/Mails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ onMounted(async () => {
</script>

<template>
<div>
<div style="margin-top: 10px;">
<n-input-group>
<n-input v-model:value="adminMailTabAddress" :placeholder="t('addressQueryTip')" />
<n-input v-model:value="mailKeyword" :placeholder="t('keywordQueryTip')" />
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/admin/MailsUnknow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ onMounted(async () => {
</script>

<template>
<div v-if="adminAuth">
<div v-if="adminAuth" style="margin-top: 10px;">
<MailBox :enableUserDeleteEmail="false" :fetchMailData="fetchMailUnknowData" />
</div>
</template>
77 changes: 70 additions & 7 deletions frontend/src/views/admin/Telegram.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
<script setup>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
// @ts-ignore
import { useGlobalState } from '../../store'
// @ts-ignore
import { api } from '../../api'
const { localeCache } = useGlobalState()
// @ts-ignore
const message = useMessage()
const { t } = useI18n({
Expand All @@ -14,11 +18,19 @@ const { t } = useI18n({
init: 'Init',
successTip: 'Success',
status: 'Check Status',
enableTelegramAllowList: 'Enable Telegram Allow List(Manually input user ID)',
enable: 'Enable',
telegramAllowList: 'Telegram Allow List',
save: 'Save',
},
zh: {
init: '初始化',
successTip: '成功',
status: '查看状态',
enableTelegramAllowList: '启用 Telegram 白名单(手动输入用户 ID)',
enable: '启用',
telegramAllowList: 'Telegram 白名单',
save: '保存',
}
}
});
Expand All @@ -27,35 +39,86 @@ const status = ref({
fetched: false,
})
const fetchData = async () => {
const fetchStatus = async () => {
try {
const res = await api.fetch(`/admin/telegram/status`)
Object.assign(status.value, res)
status.value.fetched = true
} catch (error) {
message.error(error.message || "error");
message.error((error as Error).message || "error");
}
}
const save = async () => {
const init = async () => {
try {
await api.fetch(`/admin/telegram/init`, {
method: 'POST',
})
message.success(t('successTip'))
} catch (error) {
message.error(error.message || "error");
message.error((error as Error).message || "error");
}
}
class TelegramSettings {
enableAllowList: boolean;
allowList: string[];
constructor(enableAllowList: boolean, allowList: string[]) {
this.enableAllowList = enableAllowList;
this.allowList = allowList;
}
}
const settings = ref(new TelegramSettings(false, []))
const getSettings = async () => {
try {
const res = await api.fetch(`/admin/telegram/settings`)
Object.assign(settings.value, res)
} catch (error) {
message.error((error as Error).message || "error");
}
}
const saveSettings = async () => {
try {
await api.fetch(`/admin/telegram/settings`, {
method: 'POST',
body: JSON.stringify(settings.value),
})
message.success(t('successTip'))
} catch (error) {
message.error((error as Error).message || "error");
}
}
onMounted(async () => {
await getSettings();
})
</script>

<template>
<div class="center">
<n-card style="max-width: 800px; overflow: auto;">
<n-button @click="save" type="primary" block>
<n-card>
<n-form-item-row :label="t('enableTelegramAllowList')">
<n-input-group>
<n-checkbox v-model:checked="settings.enableAllowList" style="width: 20%;">
{{ t('enable') }}
</n-checkbox>
<n-select v-model:value="settings.allowList" filterable multiple tag style="width: 80%;"
:placeholder="t('telegramAllowList')" />
</n-input-group>
</n-form-item-row>
<n-button @click="saveSettings" type="primary" block>
{{ t('save') }}
</n-button>
</n-card>
<n-button @click="init" type="primary" block>
{{ t('init') }}
</n-button>
<n-button @click="fetchData" secondary block>
<n-button @click="fetchStatus" secondary block>
{{ t('status') }}
</n-button>
<pre v-if="status.fetched">{{ JSON.stringify(status, null, 2) }}</pre>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/admin/UserManagement.vue
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ onMounted(async () => {
</script>

<template>
<div>
<div style="margin-top: 10px;">
<n-modal v-model:show="showCreateUser" preset="dialog" :title="t('createUser')">
<n-form>
<n-form-item-row :label="t('email')" required>
Expand Down
Loading

0 comments on commit ca00a87

Please sign in to comment.