haixunMaster/app/api/settings/route.ts

95 lines
3.5 KiB
TypeScript

import { NextResponse } from "next/server";
import { prisma } from "@/lib/db";
import { apiRouteErrorResponse } from "@/lib/auth/api";
import { requireSessionUser } from "@/lib/auth/session";
import { getOrCreateSettingsForUser } from "@/lib/user-settings";
import {
getApiKeyStatus,
getMaskedProviderApiKeys,
mergeProviderApiKeys,
parseProviderApiKeys,
serializeProviderApiKeys,
type ProviderApiKeys,
} from "@/lib/ai/keys";
import { getAppBaseUrl } from "@/lib/threads-api";
import type { Setting } from "@prisma/client";
function toPublicSettings(settings: Setting, request?: Request) {
const apiKeys = parseProviderApiKeys(settings.providerApiKeys);
return {
id: settings.id,
persona: settings.persona,
aiProvider: settings.aiProvider,
aiModel: settings.aiModel,
researchAiProvider: settings.researchAiProvider,
researchAiModel: settings.researchAiModel,
draftsPerScan: settings.draftsPerScan,
matrixRows: settings.matrixRows,
scanCron: settings.scanCron,
appUrl: settings.appUrl,
threadsOAuthRedirectUri: request
? `${getAppBaseUrl(request, settings.appUrl)}/api/threads/oauth/callback`
: null,
apiKeys: getMaskedProviderApiKeys(apiKeys),
apiKeysConfigured: getApiKeyStatus(apiKeys),
};
}
export async function GET(request: Request) {
try {
const user = await requireSessionUser();
const settings = await getOrCreateSettingsForUser(user.id);
return NextResponse.json(toPublicSettings(settings, request));
} catch (error) {
return apiRouteErrorResponse(error, "settings");
}
}
export async function PATCH(request: Request) {
try {
const user = await requireSessionUser();
const body = await request.json();
const current = await getOrCreateSettingsForUser(user.id);
const existingKeys = parseProviderApiKeys(current.providerApiKeys);
let providerApiKeys = existingKeys;
if (body.apiKeys && typeof body.apiKeys === "object") {
providerApiKeys = mergeProviderApiKeys(existingKeys, body.apiKeys as ProviderApiKeys);
}
const settings = await prisma.setting.update({
where: { userId: user.id },
data: {
...(body.persona !== undefined && { persona: body.persona }),
...(body.aiProvider !== undefined && { aiProvider: body.aiProvider }),
...(body.aiModel !== undefined && { aiModel: body.aiModel }),
...(body.researchAiProvider !== undefined && { researchAiProvider: body.researchAiProvider }),
...(body.researchAiModel !== undefined && { researchAiModel: body.researchAiModel }),
...(body.draftsPerScan !== undefined && { draftsPerScan: body.draftsPerScan }),
...(body.matrixRows !== undefined && { matrixRows: body.matrixRows }),
...(body.scanCron !== undefined && { scanCron: body.scanCron }),
...(body.appUrl !== undefined && {
appUrl: (() => {
const trimmed = body.appUrl?.trim();
if (!trimmed) return null;
try {
const url = new URL(trimmed);
if (!["http:", "https:"].includes(url.protocol)) return null;
return `${url.protocol}//${url.host}`;
} catch {
return null;
}
})(),
}),
...(body.apiKeys !== undefined && {
providerApiKeys: serializeProviderApiKeys(providerApiKeys),
}),
},
});
return NextResponse.json(toPublicSettings(settings, request));
} catch (error) {
return apiRouteErrorResponse(error, "settings/update");
}
}