You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

118 lines
3.2 KiB

import { parseAdminAuth } from "@/lib/api/admin-auth-context";
import { fail, ok } from "@/lib/response";
import { writeAudit } from "@/modules/audit/service";
import { AuthError } from "@/modules/auth/errors";
import {
hasCustomerProviderCredential,
isProviderCredentialProvider,
listCustomerProviderCredentialsForAdmin,
upsertCustomerProviderCredential,
} from "@/modules/customer/provider-credentials";
type RouteContext = {
params: Promise<{ customer_id: string }>;
};
export async function GET(request: Request, context: RouteContext) {
let auth;
try {
auth = parseAdminAuth(request);
} catch (error) {
if (error instanceof AuthError) {
return fail(error.code, error.message, error.httpStatus);
}
throw error;
}
const { customer_id: customerId } = await context.params;
const list = await listCustomerProviderCredentialsForAdmin(customerId);
await writeAudit(
"customer:provider_credential_view",
auth.userId,
customerId,
{ providers: list.filter((x) => x.has_password).map((x) => x.provider) },
);
return ok({ customer_id: customerId, list });
}
export async function PUT(request: Request, context: RouteContext) {
let auth;
try {
auth = parseAdminAuth(request);
} catch (error) {
if (error instanceof AuthError) {
return fail(error.code, error.message, error.httpStatus);
}
throw error;
}
const { customer_id: customerId } = await context.params;
let body: unknown;
try {
body = await request.json();
} catch {
return fail("VALIDATION_FAILED", "请求体格式无效", 400);
}
const payload = body as {
provider?: unknown;
email?: unknown;
password?: unknown;
clear?: unknown;
};
if (!isProviderCredentialProvider(payload.provider)) {
return fail("VALIDATION_FAILED", "provider 须为 mothership 或 flock", 400);
}
// 产品约束:查价网站账密仅支持新建客户时首次写入,禁止事后修改/清除
if (payload.clear === true) {
return fail(
"VALIDATION_FAILED",
"不支持清除查价网站账密;如需更换请新建客户并重新绑定",
400,
);
}
if (typeof payload.email !== "string") {
return fail("VALIDATION_FAILED", "登录邮箱无效", 400);
}
const password =
typeof payload.password === "string" ? payload.password : undefined;
try {
if (await hasCustomerProviderCredential(customerId, payload.provider)) {
return fail(
"VALIDATION_FAILED",
"该承运商账密已绑定,不支持修改;仅可在管理端查看",
400,
);
}
const saved = await upsertCustomerProviderCredential(
customerId,
payload.provider,
{
email: payload.email,
password,
updatedBy: auth.userId,
},
);
await writeAudit(
"customer:provider_credential_upsert",
auth.userId,
customerId,
{
provider: payload.provider,
email: saved.email,
password_updated: Boolean(password?.trim()),
},
);
return ok(saved);
} catch (error) {
const message = error instanceof Error ? error.message : "保存失败";
return fail("VALIDATION_FAILED", message, 400);
}
}