From 00231e7ade040b9dfae32c8d995083cec0eacc43 Mon Sep 17 00:00:00 2001 From: Dream Hunter Date: Mon, 15 Apr 2024 23:19:05 +0800 Subject: [PATCH] feat: allow user delete mail && notify when send access changed (#132) --- frontend/src/views/MailBox.vue | 27 +++++++++++++++++-- frontend/src/views/admin/MailsUnknow.vue | 3 +++ frontend/src/views/admin/SenderAccess.vue | 1 + vitepress-docs/docs/en/index.md | 2 +- vitepress-docs/docs/index.md | 2 +- worker/src/admin_api.js | 7 ++++- worker/src/router.js | 11 ++++++++ worker/src/utils.js | 32 +++++++++++++++++++++++ 8 files changed, 80 insertions(+), 5 deletions(-) diff --git a/frontend/src/views/MailBox.vue b/frontend/src/views/MailBox.vue index 47b297e4..b2ba5b5e 100644 --- a/frontend/src/views/MailBox.vue +++ b/frontend/src/views/MailBox.vue @@ -32,14 +32,18 @@ const { t } = useI18n({ refresh: 'Refresh', attachments: 'Show Attachments', downloadMail: 'Download Mail', - pleaseSelectMail: "Please select a mail to view." + pleaseSelectMail: "Please select a mail to view.", + delete: 'Delete', + deleteMailTip: 'Are you sure you want to delete this mail?' }, zh: { autoRefresh: '自动刷新', refresh: '刷新', downloadMail: '下载邮件', attachments: '查看附件', - pleaseSelectMail: "请选择一封邮件查看。" + pleaseSelectMail: "请选择一封邮件查看。", + delete: '删除', + deleteMailTip: '确定要删除这封邮件吗?' } } }); @@ -100,6 +104,19 @@ const mailItemClass = (row) => { return curMail.value && row.id == curMail.value.id ? (themeSwitch.value ? 'overlay overlay-dark-backgroud' : 'overlay overlay-light-backgroud') : ''; }; +const deleteMail = async () => { + try { + await api.fetch(`/api/mails/${curMail.value.id}`, { + method: 'DELETE' + }); + message.success(t("success")); + curMail.value = null; + await refresh(); + } catch (error) { + message.error(error.message || "error"); + } +}; + onMounted(async () => { await refresh(); }); @@ -158,6 +175,12 @@ onMounted(async () => { FROM: {{ curMail.source }} + + + {{ t('deleteMailTip') }} + {{ t('attachments') }} diff --git a/frontend/src/views/admin/MailsUnknow.vue b/frontend/src/views/admin/MailsUnknow.vue index 11f6c8fc..ff628ed7 100644 --- a/frontend/src/views/admin/MailsUnknow.vue +++ b/frontend/src/views/admin/MailsUnknow.vue @@ -86,6 +86,9 @@ onMounted(async () => { ID: {{ row.id }} + + TO: {{ row.address }} +
diff --git a/frontend/src/views/admin/SenderAccess.vue b/frontend/src/views/admin/SenderAccess.vue index 71e359c7..a88d876d 100644 --- a/frontend/src/views/admin/SenderAccess.vue +++ b/frontend/src/views/admin/SenderAccess.vue @@ -57,6 +57,7 @@ const updateData = async () => { await api.fetch(`/admin/address_sender`, { method: 'POST', body: JSON.stringify({ + address: curRow.value.address, address_id: curRow.value.id, balance: senderBalance.value, enabled: senderEnabled.value ? 1 : 0 diff --git a/vitepress-docs/docs/en/index.md b/vitepress-docs/docs/en/index.md index 76dcde17..b9763491 100644 --- a/vitepress-docs/docs/en/index.md +++ b/vitepress-docs/docs/en/index.md @@ -20,5 +20,5 @@ features: - title: Use rust wasm to parse emails details: Use rust wasm to parse emails, support various RFC standards for emails, support attachments, extremely fast - title: Support sending emails - details: Support sending txt or html emails through domain name mailboxes + details: Support sending txt or html emails through domain name mailboxes,Support DKIM signature --- diff --git a/vitepress-docs/docs/index.md b/vitepress-docs/docs/index.md index a577cfdc..4613bfe5 100644 --- a/vitepress-docs/docs/index.md +++ b/vitepress-docs/docs/index.md @@ -24,5 +24,5 @@ features: - title: 使用 rust wasm 解析邮件 details: 使用 rust wasm 解析邮件,支持邮件各种RFC标准,支持附件, 速度极快 - title: 支持发送邮件 - details: 支持通过域名邮箱发送 txt 或者 html 邮件 + details: 支持通过域名邮箱发送 txt 或者 html 邮件,支持 DKIM 签名 --- diff --git a/worker/src/admin_api.js b/worker/src/admin_api.js index 42ddd543..5c3ff190 100644 --- a/worker/src/admin_api.js +++ b/worker/src/admin_api.js @@ -1,6 +1,7 @@ import { Hono } from 'hono' import { Jwt } from 'hono/utils/jwt' import { getSendbox } from './send_mail_api' +import { sendAdminInternalMail } from './utils' const api = new Hono() @@ -164,7 +165,7 @@ api.get('/admin/address_sender', async (c) => { }) api.post('/admin/address_sender', async (c) => { - let { address_id, balance, enabled } = await c.req.json(); + let { address, address_id, balance, enabled } = await c.req.json(); if (!address_id) { return c.text("Invalid address_id", 400) } @@ -175,6 +176,10 @@ api.post('/admin/address_sender', async (c) => { if (!success) { return c.text("Failed to update address sender", 500) } + await sendAdminInternalMail( + c, address, "Account Send Access Updated", + `You send access has been ${enabled ? "enabled" : "disabled"}, balance: ${balance}` + ); return c.json({ success: success }) diff --git a/worker/src/router.js b/worker/src/router.js index c310ce82..77a435f1 100644 --- a/worker/src/router.js +++ b/worker/src/router.js @@ -33,6 +33,17 @@ api.get('/api/mails', async (c) => { }) }) +api.delete('/api/mails/:id', async (c) => { + const { address } = c.get("jwtPayload") + const { id } = c.req.param(); + const { success } = await c.env.DB.prepare( + `DELETE FROM raw_mails WHERE address = ? and id = ?` + ).bind(address, id).run(); + return c.json({ + success: success + }) +}) + api.get('/api/settings', async (c) => { const { address, address_id } = c.get("jwtPayload") if (address_id && address_id > 0) { diff --git a/worker/src/utils.js b/worker/src/utils.js index 624e9502..87e28153 100644 --- a/worker/src/utils.js +++ b/worker/src/utils.js @@ -1,3 +1,5 @@ +import { createMimeMessage } from "mimetext"; + export const getDomains = (c) => { if (!c.env.DOMAINS) { return []; @@ -45,3 +47,33 @@ export const getAdminPasswords = (c) => { } return c.env.ADMIN_PASSWORDS; } + +export const sendAdminInternalMail = async (c, toMail, subject, text) => { + try { + + const msg = createMimeMessage(); + msg.setSender({ + name: "Admin", + addr: "admin@internal" + }); + msg.setRecipient(toMail); + msg.setSubject(subject); + msg.addMessage({ + contentType: 'text/plain', + data: text + }); + const message_id = Math.random().toString(36).substring(2, 15); + const { success } = await c.env.DB.prepare( + `INSERT INTO raw_mails (source, address, raw, message_id) VALUES (?, ?, ?, ?)` + ).bind( + "admin@internal", toMail, msg.asRaw(), message_id + ).run(); + if (!success) { + console.log(`Failed save message from admin@internal to ${toMail}`); + } + return success; + } catch (error) { + console.log("sendAdminInternalMail error", error); + return false; + } +};