diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f016f2a..7d2756c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ ### Bug Fixes +- fix: |Admin| 管理后台删除邮箱地址时,先删除该地址的邮件、发件记录、自动回复等关联数据,最后再删除地址本身;此前地址行先被删除导致按地址名匹配的子查询查不到数据,邮件等记录被遗留在数据库中 - fix: |AI 提取| 强化提示词,要求 AI 保持邮件原始链接域名,避免小模型改写验证链接域名导致错误跳转(issue #1072) - fix: |AI 提取| HTML-only 邮件在发送给 Workers AI 前会先压缩为可读文本,避免样式模板过长导致验证码位于 4000 字截断之后而无法识别 - fix: |Frontend| 移动端 Header 增加页头内边距,避免标题、菜单按钮与屏幕边缘过近 diff --git a/CHANGELOG_EN.md b/CHANGELOG_EN.md index cffca048..397d8a5a 100644 --- a/CHANGELOG_EN.md +++ b/CHANGELOG_EN.md @@ -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 diff --git a/worker/src/admin_api/address_api.ts b/worker/src/admin_api/address_api.ts index f8d5e9fb..ba29deeb 100644 --- a/worker/src/admin_api/address_api.ts +++ b/worker/src/admin_api/address_api.ts @@ -70,29 +70,38 @@ const createNewAddress = async (c: Context) => { const deleteAddress = async (c: Context) => { 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) => {