fix: clean up related mails before deleting address in admin API (#1081)

* fix: clean up related mails before deleting address in admin API

* fix: run admin address deletion in a single D1 batch
This commit is contained in:
Maxim Lapan
2026-07-11 14:06:14 +08:00
committed by GitHub
parent 565bb839db
commit 99b332345b
3 changed files with 31 additions and 20 deletions

View File

@@ -15,6 +15,7 @@
### Bug Fixes
- fix: |Admin| 管理后台删除邮箱地址时,先删除该地址的邮件、发件记录、自动回复等关联数据,最后再删除地址本身;此前地址行先被删除导致按地址名匹配的子查询查不到数据,邮件等记录被遗留在数据库中
- fix: |AI 提取| 强化提示词,要求 AI 保持邮件原始链接域名避免小模型改写验证链接域名导致错误跳转issue #1072
- fix: |AI 提取| HTML-only 邮件在发送给 Workers AI 前会先压缩为可读文本,避免样式模板过长导致验证码位于 4000 字截断之后而无法识别
- fix: |Frontend| 移动端 Header 增加页头内边距,避免标题、菜单按钮与屏幕边缘过近

View File

@@ -15,6 +15,7 @@
### Bug Fixes
- fix: |Admin| When deleting an address from the admin panel, delete its mails, sender records, sendbox and auto-reply entries before removing the address row itself; previously the address row was deleted first, so the name-based subqueries matched nothing and the mails were left orphaned in the database
- fix: |AI Extract| Strengthen the prompt to keep original link domains from the email, preventing small models from rewriting verification-link domains (issue #1072)
- fix: |AI Extract| Convert HTML-only mail bodies into compact readable text before sending them to Workers AI, preventing long templates from pushing verification codes past the 4000-character truncation window
- fix: |Frontend| Add mobile Header page padding so the title and menu button no longer sit too close to the screen edge

View File

@@ -70,29 +70,38 @@ const createNewAddress = async (c: Context<HonoCustomType>) => {
const deleteAddress = async (c: Context<HonoCustomType>) => {
const msgs = i18n.getMessagesbyContext(c);
const { id } = c.req.param();
const { success } = await c.env.DB.prepare(
`DELETE FROM address WHERE id = ? `
).bind(id).run();
// single batch runs as one transaction: rows keyed by address name are
// deleted first and the address row last, so the name subqueries still
// resolve and a failed statement rolls back the whole deletion
const results = await c.env.DB.batch([
c.env.DB.prepare(
`DELETE FROM raw_mails WHERE address IN`
+ ` (select name from address where id = ?) `
).bind(id),
c.env.DB.prepare(
`DELETE FROM address_sender WHERE address IN`
+ ` (select name from address where id = ?) `
).bind(id),
c.env.DB.prepare(
`DELETE FROM sendbox WHERE address IN`
+ ` (select name from address where id = ?) `
).bind(id),
c.env.DB.prepare(
`DELETE FROM auto_reply_mails WHERE address IN`
+ ` (select name from address where id = ?) `
).bind(id),
c.env.DB.prepare(
`DELETE FROM users_address WHERE address_id = ?`
).bind(id),
c.env.DB.prepare(
`DELETE FROM address WHERE id = ? `
).bind(id),
]);
const success = results.every((result) => result.success);
if (!success) {
return c.text(msgs.OperationFailedMsg, 500)
}
const { success: mailSuccess } = await c.env.DB.prepare(
`DELETE FROM raw_mails WHERE address IN`
+ ` (select name from address where id = ?) `
).bind(id).run();
if (!mailSuccess) {
return c.text(msgs.OperationFailedMsg, 500)
}
const { success: sendAccess } = await c.env.DB.prepare(
`DELETE FROM address_sender WHERE address IN`
+ ` (select name from address where id = ?) `
).bind(id).run();
const { success: usersAddressSuccess } = await c.env.DB.prepare(
`DELETE FROM users_address WHERE address_id = ?`
).bind(id).run();
return c.json({
success: success && mailSuccess && sendAccess && usersAddressSuccess
})
return c.json({ success })
};
const clearInbox = async (c: Context<HonoCustomType>) => {