feat: v2.3.0 设置内配置 Cloudflare OAuth 客户端 + 全列表批量删除

- 设置新增「Cloudflare 接入」tab:Client ID / Client Secret(Secret AES-GCM 加密入库,
  只回显末 4 位),并展示可复制的授权回调地址;settings 优先、env 变量兜底,
  保存后立即生效无需重新部署;DELETE /api/settings/cf-oauth 清除
- 四个资源列表(账号/域名/邮箱/收件箱)加复选框批量选择与批量删除
- 新增 POST /api/{accounts,domains,mailboxes,emails}/batch-delete:
  账号软删+撤销凭据;域名/邮箱级联删除其下邮件;邮件连 R2 原文与附件一并清理
- 抽出 deleteEmailById / deleteEmailsByMailbox / revokeAccount 供单条与批量共用
- 点击复选框不再触发行点击(避免误开详情抽屉)
- 新增 tests/batch.test.ts(6 例)与 settings OAuth 凭据用例(2 例);ui-smoke 扩到 17 步
This commit is contained in:
bigcode
2026-09-30 15:53:18 +08:00
parent e2c3c353cf
commit 3be6e483b4
19 changed files with 1001 additions and 79 deletions
+44 -2
View File
@@ -266,21 +266,63 @@ export const getEmail = (id: string) => api<EmailDetail>(`/api/emails/${id}`);
export const deleteEmail = (id: string) => api(`/api/emails/${id}`, "DELETE");
/* ---- 批量删除(列表复选框) ---- */
/** # 成员变量: 批量删除结果 **/
export interface BatchDeleteResult {
ok: boolean;
/** 成功删除的主记录数 **/
deleted: number;
/** 级联删除的邮箱数(域名批量删除时有值) **/
mailboxes?: number;
/** 级联删除的邮件数(域名/邮箱批量删除时有值) **/
emails?: number;
/** 删除失败的 id 及原因(不存在/已删除) **/
failed: { id: string; reason: string }[];
}
export const batchDeleteAccounts = (ids: string[]) =>
api<BatchDeleteResult>("/api/accounts/batch-delete", "POST", { ids });
export const batchDeleteDomains = (ids: string[]) =>
api<BatchDeleteResult>("/api/domains/batch-delete", "POST", { ids });
export const batchDeleteMailboxes = (ids: string[]) =>
api<BatchDeleteResult>("/api/mailboxes/batch-delete", "POST", { ids });
export const batchDeleteEmails = (ids: string[]) =>
api<BatchDeleteResult>("/api/emails/batch-delete", "POST", { ids });
/* ---- 设置 ---- */
export interface SettingsInfo {
username: string;
webhook: { url: string; headers: Record<string, string>; has_key: boolean; key_last4: string };
api_key: { has_key: boolean; key_last4: string; created_at: string | null };
/** Cloudflare OAuth 客户端凭据元信息(不含明文 secret) */
cf_oauth: {
client_id: string;
has_secret: boolean;
secret_last4: string;
/** settings = 后台设置;env = 部署变量兜底;none = 未配置 */
source: "settings" | "env" | "none";
};
/** 需要在 Cloudflare Dashboard 登记的授权回调地址 */
redirect_uri: string;
}
export const getSettings = () => api<SettingsInfo>("/api/settings");
/** 保存设置;webhook.key:undefined 保留原值、空串清除、非空设置新 key */
/** 保存设置
* webhook.key / cf_oauth.secret 语义一致:undefined 保留原值、空串清除、非空设置新值 */
export const putSettings = (body: {
webhook?: { url: string; headers?: Record<string, string>; key?: string };
webhook?: { url: string; headers: Record<string, string>; key?: string };
cf_oauth?: { client_id: string; secret?: string };
}) => api("/api/settings", "PUT", body);
/** 清除后台保存的 Cloudflare OAuth 客户端凭据(env 兜底不受影响) */
export const deleteCfOAuth = () => api("/api/settings/cf-oauth", "DELETE");
export const changePassword = (old_password: string, new_password: string) =>
api("/api/settings/password", "PUT", { old_password, new_password });