From a9bb8785bacb98530da6a5c3083cb74d2470bca5 Mon Sep 17 00:00:00 2001 From: Dream Hunter Date: Sun, 22 Dec 2024 15:40:26 +0800 Subject: [PATCH] feat: support send mail from admin portal(no balance limit) (#524) --- CHANGELOG.md | 4 +- frontend/src/views/Admin.vue | 6 + frontend/src/views/admin/SendMail.vue | 199 ++++++++++++++++++++++++++ worker/src/admin_api/index.ts | 4 + worker/src/admin_api/send_mail.ts | 22 +++ worker/src/mails_api/send_mail_api.ts | 7 +- worker/src/user_api/oauth2.ts | 4 +- worker/src/user_api/passkey.ts | 4 +- worker/src/user_api/user.ts | 4 +- 9 files changed, 245 insertions(+), 9 deletions(-) create mode 100644 frontend/src/views/admin/SendMail.vue create mode 100644 worker/src/admin_api/send_mail.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 90edaf76..ab4fc5c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ # main(v0.8.2) -- feat: |Doc| 修复文档中的一些错误 +- fix: |Doc| 修复文档中的一些错误 +- fix: |Github Action| 修复 frontend 部署分支错误的问题 +- fix: admin 发送邮件功能 # v0.8.2 diff --git a/frontend/src/views/Admin.vue b/frontend/src/views/Admin.vue index 0b14af7f..e97c61cb 100644 --- a/frontend/src/views/Admin.vue +++ b/frontend/src/views/Admin.vue @@ -23,6 +23,7 @@ import Telegram from './admin/Telegram.vue'; import Webhook from './admin/Webhook.vue'; import MailWebhook from './admin/MailWebhook.vue'; import WorkerConfig from './admin/WorkerConfig.vue'; +import SendMail from './admin/SendMail.vue'; const { adminAuth, showAdminAuth, adminTab, loading, @@ -45,6 +46,7 @@ const { t } = useI18n({ accessHeader: 'Admin Password', accessTip: 'Please enter the admin password', mails: 'Emails', + sendMail: 'Send Mail', qucickSetup: 'Quick Setup', account: 'Account', account_create: 'Create Account', @@ -70,6 +72,7 @@ const { t } = useI18n({ accessHeader: 'Admin 密码', accessTip: '请输入 Admin 密码', mails: '邮件', + sendMail: '发送邮件', qucickSetup: '快速设置', account: '账号', account_create: '创建账号', @@ -172,6 +175,9 @@ onMounted(async () => { + + + diff --git a/frontend/src/views/admin/SendMail.vue b/frontend/src/views/admin/SendMail.vue new file mode 100644 index 00000000..d9c59ca9 --- /dev/null +++ b/frontend/src/views/admin/SendMail.vue @@ -0,0 +1,199 @@ + + + + + diff --git a/worker/src/admin_api/index.ts b/worker/src/admin_api/index.ts index efaa16da..1ee7f952 100644 --- a/worker/src/admin_api/index.ts +++ b/worker/src/admin_api/index.ts @@ -11,6 +11,7 @@ import webhook_settings from './webhook_settings' import mail_webhook_settings from './mail_webhook_settings' import oauth2_settings from './oauth2_settings' import worker_config from './worker_config' +import { sendMailbyAdmin } from './send_mail' export const api = new Hono() @@ -330,3 +331,6 @@ api.post("/admin/mail_webhook/test", mail_webhook_settings.testWebhookSettings); // worker config api.get("/admin/worker/configs", worker_config.getConfig); + +// send mail by admin +api.post("/admin/send_mail", sendMailbyAdmin); diff --git a/worker/src/admin_api/send_mail.ts b/worker/src/admin_api/send_mail.ts new file mode 100644 index 00000000..d430361d --- /dev/null +++ b/worker/src/admin_api/send_mail.ts @@ -0,0 +1,22 @@ +import { Context } from "hono"; +import { HonoCustomType } from "../types"; +import { sendMail } from "../mails_api/send_mail_api"; + +export const sendMailbyAdmin = async (c: Context) => { + const { + from_name, from_mail, + to_mail, to_name, + subject, content, is_html + } = await c.req.json(); + await sendMail(c, from_mail, { + from_name: from_name, + to_name: to_name, + to_mail: to_mail, + subject: subject, + content: content, + is_html: is_html, + }, { + isAdmin: true + }) + return c.json({ status: "ok" }); +} diff --git a/worker/src/mails_api/send_mail_api.ts b/worker/src/mails_api/send_mail_api.ts index 9ba2bf64..463a0f3f 100644 --- a/worker/src/mails_api/send_mail_api.ts +++ b/worker/src/mails_api/send_mail_api.ts @@ -94,6 +94,9 @@ export const sendMail = async ( reqJson: { from_name: string, to_mail: string, to_name: string, subject: string, content: string, is_html: boolean + }, + options?: { + isAdmin?: boolean } ): Promise => { if (!address) { @@ -107,7 +110,7 @@ export const sendMail = async ( } const user_role = c.get("userRolePayload"); const is_no_limit_send_balance = user_role && user_role === getStringValue(c.env.NO_LIMIT_SEND_ROLE); - if (!is_no_limit_send_balance) { + if (!is_no_limit_send_balance && !options?.isAdmin) { // check permission const balance = await c.env.DB.prepare( `SELECT balance FROM address_sender @@ -158,7 +161,7 @@ export const sendMail = async ( throw new Error("Please enable resend or verified address list") } // update balance - if (!sendByVerifiedAddressList && !is_no_limit_send_balance) { + if (!sendByVerifiedAddressList && !is_no_limit_send_balance && !options?.isAdmin) { try { const { success } = await c.env.DB.prepare( `UPDATE address_sender SET balance = balance - 1 where address = ?` diff --git a/worker/src/user_api/oauth2.ts b/worker/src/user_api/oauth2.ts index d0b0705a..7ff1c779 100644 --- a/worker/src/user_api/oauth2.ts +++ b/worker/src/user_api/oauth2.ts @@ -94,8 +94,8 @@ export default { const jwt = await Jwt.sign({ user_email: email, user_id: user_id, - // 30 days expire in seconds - exp: Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60, + // 90 days expire in seconds + exp: Math.floor(Date.now() / 1000) + 90 * 24 * 60 * 60, iat: Math.floor(Date.now() / 1000), }, c.env.JWT_SECRET, "HS256") return c.json({ diff --git a/worker/src/user_api/passkey.ts b/worker/src/user_api/passkey.ts index fad6d79f..dd9b81b4 100644 --- a/worker/src/user_api/passkey.ts +++ b/worker/src/user_api/passkey.ts @@ -193,8 +193,8 @@ export default { const jwt = await Jwt.sign({ user_email: user_email, user_id: user_id, - // 30 days expire in seconds - exp: Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60, + // 90 days expire in seconds + exp: Math.floor(Date.now() / 1000) + 90 * 24 * 60 * 60, iat: Math.floor(Date.now() / 1000), }, c.env.JWT_SECRET, "HS256") return c.json({ diff --git a/worker/src/user_api/user.ts b/worker/src/user_api/user.ts index cf27df32..39df68b6 100644 --- a/worker/src/user_api/user.ts +++ b/worker/src/user_api/user.ts @@ -165,8 +165,8 @@ export default { const jwt = await Jwt.sign({ user_email: email, user_id: user_id, - // 30 days expire in seconds - exp: Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60, + // 90 days expire in seconds + exp: Math.floor(Date.now() / 1000) + 90 * 24 * 60 * 60, iat: Math.floor(Date.now() / 1000), }, c.env.JWT_SECRET, "HS256") return c.json({