haixunMaster/app/api/accounts/[id]/route.ts

114 lines
3.9 KiB
TypeScript

import { NextResponse } from "next/server";
import { prisma } from "@/lib/db";
import { setActiveAccountForUser } from "@/lib/account-context";
import { assertAccountOwnedByUser } from "@/lib/auth/accounts";
import { authErrorResponse } from "@/lib/auth/api";
import { requireSessionUser } from "@/lib/auth/session";
import { deleteAccountWithRelations } from "@/lib/services/delete-account";
function trimOrNull(value: string | null | undefined): string | null {
if (value == null) return null;
const trimmed = value.trim();
return trimmed || null;
}
function trimUsername(value: string | null | undefined): string | null {
if (value == null) return null;
const trimmed = value.replace(/^@/, "").trim();
return trimmed || null;
}
export async function PATCH(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const user = await requireSessionUser();
const { id } = await params;
await assertAccountOwnedByUser(user.id, id);
const body = (await request.json()) as {
displayName?: string | null;
username?: string | null;
persona?: string | null;
styleProfile?: string | null;
styleBenchmark?: string | null;
brief?: string | null;
productBrief?: string | null;
targetAudience?: string | null;
goals?: string | null;
};
const account = await prisma.account.update({
where: { id },
data: {
...(body.displayName !== undefined && { displayName: trimOrNull(body.displayName) }),
...(body.username !== undefined && { username: trimUsername(body.username) }),
...(body.persona !== undefined && { persona: trimOrNull(body.persona) }),
...(body.styleProfile !== undefined && { styleProfile: trimOrNull(body.styleProfile) }),
...(body.styleBenchmark !== undefined && {
styleBenchmark: trimUsername(body.styleBenchmark),
}),
...(body.brief !== undefined && { brief: trimOrNull(body.brief) }),
...(body.productBrief !== undefined && { productBrief: trimOrNull(body.productBrief) }),
...(body.targetAudience !== undefined && {
targetAudience: trimOrNull(body.targetAudience),
}),
...(body.goals !== undefined && { goals: trimOrNull(body.goals) }),
},
});
return NextResponse.json({ account });
} catch (error) {
const authRes = authErrorResponse(error);
if (authRes) return authRes;
const message = error instanceof Error ? error.message : "更新帳號失敗";
console.error("[accounts] PATCH failed:", error);
return NextResponse.json({ error: message }, { status: 500 });
}
}
export async function DELETE(
_request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const user = await requireSessionUser();
const { id } = await params;
await assertAccountOwnedByUser(user.id, id);
const isActive = user.activeAccountId === id;
let nextActiveId: string | null = user.activeAccountId ?? null;
if (isActive) {
const next = await prisma.account.findFirst({
where: { userId: user.id, id: { not: id } },
orderBy: { updatedAt: "desc" },
select: { id: true },
});
nextActiveId = next?.id ?? null;
}
await deleteAccountWithRelations(id);
if (isActive) {
if (nextActiveId) {
await setActiveAccountForUser(user.id, nextActiveId);
} else {
await prisma.user.update({
where: { id: user.id },
data: { activeAccountId: null },
});
}
}
return NextResponse.json({ deleted: true, activeAccountId: nextActiveId });
} catch (error) {
const authRes = authErrorResponse(error);
if (authRes) return authRes;
const message = error instanceof Error ? error.message : "刪除帳號失敗";
console.error("[accounts] DELETE failed:", error);
return NextResponse.json({ error: message }, { status: 500 });
}
}