From a45d01f9fd2874543b7d80fadcb9683ac38acade Mon Sep 17 00:00:00 2001 From: Dream Hunter Date: Thu, 26 Mar 2026 00:18:15 +0800 Subject: [PATCH] feat: return address_id in /admin/new_address response (#913) * feat: return address_id in /admin/new_address response - Add address_id field to newAddress function return type - Update CHANGELOG.md and CHANGELOG_EN.md Fixes #912 Co-Authored-By: Claude Opus 4.6 * test: verify address_id in new_address response * fix: add address_id validation and improve test coverage - Add null check for address_id after DB query - Change address_id to required field in return type - Add dedicated test for /admin/new_address endpoint - Update e2e helper return type to non-optional --------- Co-authored-by: Claude Opus 4.6 --- CHANGELOG.md | 1 + CHANGELOG_EN.md | 1 + e2e/fixtures/test-helpers.ts | 4 ++-- e2e/tests/api/address-lifecycle.spec.ts | 3 ++- e2e/tests/api/admin-new-address.spec.ts | 19 +++++++++++++++++++ worker/src/common.ts | 7 ++++++- 6 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 e2e/tests/api/admin-new-address.spec.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e107df0..e24c7275 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ### Features +- feat: |Admin API| `/admin/new_address` 接口返回值新增 `address_id` 字段,避免创建后需再次查询地址 ID(#912) - feat: |自动回复| 发件人过滤支持正则表达式匹配,使用 `/pattern/` 语法(如 `/@example\.com$/`),同时保持前缀匹配的向后兼容 - feat: |Turnstile| 新增全局登录表单 Turnstile 人机验证,通过 `ENABLE_GLOBAL_TURNSTILE_CHECK` 环境变量控制(#767) - feat: |Telegram| Telegram 推送支持发送邮件附件(单文件限制 50MB),多附件通过 `sendMediaGroup` 批量发送,通过 `ENABLE_TG_PUSH_ATTACHMENT` 环境变量开启(#894) diff --git a/CHANGELOG_EN.md b/CHANGELOG_EN.md index 38e0ca7f..e19298b6 100644 --- a/CHANGELOG_EN.md +++ b/CHANGELOG_EN.md @@ -10,6 +10,7 @@ ### Features +- feat: |Admin API| `/admin/new_address` endpoint now returns `address_id` field, avoiding additional query after address creation (#912) - feat: |Auto Reply| Add regex matching support for sender filter using `/pattern/` syntax (e.g. `/@example\.com$/`), backward compatible with prefix matching - feat: |Turnstile| Add global Turnstile CAPTCHA for all login forms via `ENABLE_GLOBAL_TURNSTILE_CHECK` env var (#767) - feat: |Telegram| Support sending email attachments in Telegram push (50MB per file limit), multiple attachments sent via `sendMediaGroup`, controlled by `ENABLE_TG_PUSH_ATTACHMENT` env var (#894) diff --git a/e2e/fixtures/test-helpers.ts b/e2e/fixtures/test-helpers.ts index ff05c3c8..2720e0ec 100644 --- a/e2e/fixtures/test-helpers.ts +++ b/e2e/fixtures/test-helpers.ts @@ -16,7 +16,7 @@ export async function createTestAddress( ctx: APIRequestContext, name: string, domain: string = TEST_DOMAIN -): Promise<{ jwt: string; address: string }> { +): Promise<{ jwt: string; address: string; address_id: number }> { const uniqueName = `${name}${Date.now()}`; const res = await ctx.post(`${WORKER_URL}/api/new_address`, { data: { name: uniqueName, domain }, @@ -25,7 +25,7 @@ export async function createTestAddress( throw new Error(`Failed to create address: ${res.status()} ${await res.text()}`); } const body = await res.json(); - return { jwt: body.jwt, address: body.address }; + return { jwt: body.jwt, address: body.address, address_id: body.address_id }; } /** diff --git a/e2e/tests/api/address-lifecycle.spec.ts b/e2e/tests/api/address-lifecycle.spec.ts index cc0f5c7f..31bfdd8a 100644 --- a/e2e/tests/api/address-lifecycle.spec.ts +++ b/e2e/tests/api/address-lifecycle.spec.ts @@ -4,9 +4,10 @@ import { WORKER_URL, TEST_DOMAIN, createTestAddress, deleteAddress, requestSendA test.describe('Address Lifecycle', () => { test('create address, request send access, fetch settings, then delete', async ({ request }) => { // Create address - const { jwt, address } = await createTestAddress(request, 'lifecycle-test'); + const { jwt, address, address_id } = await createTestAddress(request, 'lifecycle-test'); expect(address).toContain('@' + TEST_DOMAIN); expect(jwt).toBeTruthy(); + expect(address_id).toBeGreaterThan(0); // Request send access (creates address_sender row with DEFAULT_SEND_BALANCE) await requestSendAccess(request, jwt); diff --git a/e2e/tests/api/admin-new-address.spec.ts b/e2e/tests/api/admin-new-address.spec.ts new file mode 100644 index 00000000..37e9c19a --- /dev/null +++ b/e2e/tests/api/admin-new-address.spec.ts @@ -0,0 +1,19 @@ +import { test, expect } from '@playwright/test'; +import { WORKER_URL, TEST_DOMAIN } from '../../fixtures/test-helpers'; + +test.describe('Admin New Address', () => { + test('should return address_id in response', async ({ request }) => { + const uniqueName = `admin-test${Date.now()}`; + const res = await request.post(`${WORKER_URL}/admin/new_address`, { + data: { name: uniqueName, domain: TEST_DOMAIN }, + }); + + expect(res.ok()).toBe(true); + const body = await res.json(); + + expect(body.address).toContain('@' + TEST_DOMAIN); + expect(body.jwt).toBeTruthy(); + expect(body.address_id).toBeGreaterThan(0); + expect(typeof body.address_id).toBe('number'); + }); +}); diff --git a/worker/src/common.ts b/worker/src/common.ts index 9b758f0f..4021714f 100644 --- a/worker/src/common.ts +++ b/worker/src/common.ts @@ -168,7 +168,7 @@ export const newAddress = async ( enableCheckNameRegex?: boolean, sourceMeta?: string | undefined | null, } -): Promise<{ address: string, jwt: string, password?: string | null }> => { +): Promise<{ address: string, jwt: string, password?: string | null, address_id: number }> => { const msgs = i18n.getMessagesbyContext(c); // trim whitespace and remove special characters name = name.trim().replace(getNameRegex(c), '') @@ -247,6 +247,10 @@ export const newAddress = async ( `SELECT id FROM address where name = ?` ).bind(name).first("id"); + if (!address_id) { + throw new Error(msgs.FailedCreateAddressMsg); + } + // 如果启用地址密码功能,自动生成密码 const generatedPassword = await generatePasswordForAddress(c, name); @@ -259,6 +263,7 @@ export const newAddress = async ( jwt: jwt, address: name, password: generatedPassword, + address_id: address_id, } }