feat(api): admin account governance endpoints
P4a Task 6: GET /admin/users 双模式收口(无 accountPrefix 进入管理列表 模式:全量用户、query/status 过滤、createdAt+ID 倒序键集游标、仅 admin; 前缀模式 P1b 语义保留)+ PATCH / reset-password / activate / deactivate 治理端点(sourceStatus 只读拒绝、自我保护、会话撤销、审计、生成初始 密码)。附带修复 full-chain e2e 的 job-done 断言竞态(轮询条件补齐 photo_jobs 终态)。api e2e 214 → 227 全绿。 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -10,8 +10,8 @@
|
||||
// 'carol' → 空、'Carol' → 命中;
|
||||
// ④ LIKE 通配符转义(ESCAPE 子句):前缀中的 _ / % 按字面匹配,不作单字符/
|
||||
// 任意串通配(esc_ 仅命中字面下划线账号;al% 空);
|
||||
// ⑤ 参数边界:accountPrefix 缺失(过渡期实现仍 400,Task 6 起进入管理列表
|
||||
// 模式)/1 字符/65 字符 → 400;2 与 64 字符合法;limit 缺省 20(P1b 时
|
||||
// ⑤ 参数边界:accountPrefix 缺失 → 管理列表模式分流(staff 403 / admin
|
||||
// 200,Task 6 双模式收口后语义)/1 字符/65 字符 → 400;2 与 64 字符合法;limit 缺省 20(P1b 时
|
||||
// 为 10,P4a 统一分页 bounds)、1..100 界内、0/101/非整数 → 400;
|
||||
// ⑥ 访问策略(P1b 决策,契约描述):未认证 401;任何已认证工作人员(含非
|
||||
// admin 的 staff)200;admin 200。
|
||||
@@ -197,13 +197,30 @@ describe('账号查询 GET /admin/users (e2e)', () => {
|
||||
expect(percent.body.items).toEqual([]);
|
||||
});
|
||||
|
||||
it('accountPrefix 边界:过渡期缺失/空串仍 400;1 字符/65 字符 → 400;64 字符 → 200 空', async () => {
|
||||
// Task 6 起缺失 accountPrefix 进入管理列表模式(仅 admin);当前实现仅
|
||||
// 前缀模式,缺失/空串仍 400(控制器文件头登记的过渡期边界)。
|
||||
const missing = await lookup(staffToken, {});
|
||||
expect(missing.status).toBe(400);
|
||||
expect(missing.body.code).toBe(ErrorCodes.VALIDATION_FAILED);
|
||||
it('accountPrefix 边界:缺失 → 双模式分流(staff 403 / admin 200 管理列表);1/65 字符 → 400;64 → 200 空', async () => {
|
||||
// Task 6 起缺失 accountPrefix 进入管理列表模式(仅 admin):staff 无前缀
|
||||
// → 403 AUTH_FORBIDDEN;admin → 200 管理列表(全量用户,含非激活态——
|
||||
// 深度断言由 admin-users.e2e-spec 守护,此处只断言模式分流与响应形状)。
|
||||
const staffMissing = await lookup(staffToken, {});
|
||||
expect(staffMissing.status).toBe(403);
|
||||
expect(staffMissing.body.code).toBe(ErrorCodes.AUTH_FORBIDDEN);
|
||||
|
||||
const adminMissing = await lookup(adminToken, {});
|
||||
expect(adminMissing.status).toBe(200);
|
||||
expect(Object.keys(adminMissing.body).sort()).toEqual([
|
||||
'hasMore',
|
||||
'items',
|
||||
'nextCursor',
|
||||
]);
|
||||
// 管理列表包含前缀模式排除的非激活用户(本 spec 的排除组)。
|
||||
const adminAccounts = (
|
||||
adminMissing.body.items as { account: string }[]
|
||||
).map((item) => item.account);
|
||||
expect(adminAccounts).toContain('aldis');
|
||||
expect(adminAccounts).toContain('alpend');
|
||||
expect(adminAccounts).toContain('allock');
|
||||
|
||||
// 显式空串是「提供了非法值」而非「未提供」→ 仍 400。
|
||||
const empty = await lookup(staffToken, { accountPrefix: '' });
|
||||
expect(empty.status).toBe(400);
|
||||
expect(empty.body.code).toBe(ErrorCodes.VALIDATION_FAILED);
|
||||
|
||||
Reference in New Issue
Block a user