143 lines
4.9 KiB
TypeScript
143 lines
4.9 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
|
import { requireAdmin } from '@/lib/admin-auth';
|
|
import { getDbClient } from '@/storage/database/local-db';
|
|
import {
|
|
encryptApiKeyForStorage,
|
|
ensureSystemApiSchema,
|
|
isUuid,
|
|
listSystemApis,
|
|
toSafeSystemApi,
|
|
} from '@/lib/server-api-config';
|
|
|
|
async function readBody(request: NextRequest) {
|
|
return request.json().catch(() => ({}));
|
|
}
|
|
|
|
function normalizeType(value: unknown): 'image' | 'video' | 'text' {
|
|
return value === 'video' || value === 'text' ? value : 'image';
|
|
}
|
|
|
|
export async function GET(request: NextRequest) {
|
|
const authError = await requireAdmin(request);
|
|
if (authError) return authError;
|
|
const includeInactive = request.nextUrl.searchParams.get('includeInactive') !== 'false';
|
|
return NextResponse.json({ apis: await listSystemApis(includeInactive) });
|
|
}
|
|
|
|
export async function POST(request: NextRequest) {
|
|
const authError = await requireAdmin(request);
|
|
if (authError) return authError;
|
|
|
|
const body = await readBody(request);
|
|
if (!body.name?.trim() || !body.modelName?.trim()) {
|
|
return NextResponse.json({ error: '请填写显示名称和模型名称' }, { status: 400 });
|
|
}
|
|
|
|
const secret = encryptApiKeyForStorage(String(body.apiKey || ''));
|
|
const client = await getDbClient();
|
|
try {
|
|
await ensureSystemApiSchema(client);
|
|
const result = await client.query(
|
|
`INSERT INTO system_api_configs (
|
|
provider, name, api_url, model_name, note, api_key_encrypted,
|
|
api_key_preview, type, credits_per_use, is_active, sort_order
|
|
)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,
|
|
COALESCE((SELECT MAX(sort_order) + 1 FROM system_api_configs), 0))
|
|
RETURNING id, provider, name, api_url, model_name, note, api_key_preview,
|
|
type, credits_per_use, is_active, sort_order, created_at, updated_at`,
|
|
[
|
|
String(body.provider || '').trim(),
|
|
String(body.name).trim(),
|
|
String(body.apiUrl || '').trim(),
|
|
String(body.modelName).trim(),
|
|
String(body.note || '').trim(),
|
|
secret.encrypted,
|
|
secret.preview,
|
|
normalizeType(body.type),
|
|
Number(body.creditsPerUse || 10),
|
|
body.isActive !== false,
|
|
],
|
|
);
|
|
return NextResponse.json({ api: toSafeSystemApi(result.rows[0]) });
|
|
} finally {
|
|
client.release();
|
|
}
|
|
}
|
|
|
|
export async function PUT(request: NextRequest) {
|
|
const authError = await requireAdmin(request);
|
|
if (authError) return authError;
|
|
|
|
const body = await readBody(request);
|
|
if (!isUuid(body.id) || !body.name?.trim() || !body.modelName?.trim()) {
|
|
return NextResponse.json({ error: '缺少 API ID、显示名称或模型名称' }, { status: 400 });
|
|
}
|
|
|
|
const updates: string[] = [];
|
|
const params: unknown[] = [];
|
|
let idx = 1;
|
|
const add = (column: string, value: unknown) => {
|
|
updates.push(`${column} = $${idx++}`);
|
|
params.push(value);
|
|
};
|
|
|
|
add('provider', String(body.provider || '').trim());
|
|
add('name', String(body.name).trim());
|
|
add('api_url', String(body.apiUrl || '').trim());
|
|
add('model_name', String(body.modelName).trim());
|
|
add('note', String(body.note || '').trim());
|
|
add('type', normalizeType(body.type));
|
|
add('credits_per_use', Number(body.creditsPerUse || 10));
|
|
add('is_active', body.isActive !== false);
|
|
if (body.sortOrder !== undefined) add('sort_order', Number(body.sortOrder || 0));
|
|
|
|
if (typeof body.apiKey === 'string' && body.apiKey.trim() && body.apiKey !== '********') {
|
|
const secret = encryptApiKeyForStorage(body.apiKey);
|
|
add('api_key_encrypted', secret.encrypted);
|
|
add('api_key_preview', secret.preview);
|
|
}
|
|
if (body.clearApiKey === true) {
|
|
add('api_key_encrypted', '');
|
|
add('api_key_preview', '');
|
|
}
|
|
updates.push('updated_at = NOW()');
|
|
params.push(body.id);
|
|
|
|
const client = await getDbClient();
|
|
try {
|
|
await ensureSystemApiSchema(client);
|
|
const result = await client.query(
|
|
`UPDATE system_api_configs
|
|
SET ${updates.join(', ')}
|
|
WHERE id = $${idx}
|
|
RETURNING id, provider, name, api_url, model_name, note, api_key_preview,
|
|
type, credits_per_use, is_active, sort_order, created_at, updated_at`,
|
|
params,
|
|
);
|
|
if (result.rows.length === 0) {
|
|
return NextResponse.json({ error: '系统 API 不存在' }, { status: 404 });
|
|
}
|
|
return NextResponse.json({ api: toSafeSystemApi(result.rows[0]) });
|
|
} finally {
|
|
client.release();
|
|
}
|
|
}
|
|
|
|
export async function DELETE(request: NextRequest) {
|
|
const authError = await requireAdmin(request);
|
|
if (authError) return authError;
|
|
const body = await readBody(request);
|
|
const id = body.id || request.nextUrl.searchParams.get('id');
|
|
if (!isUuid(id)) return NextResponse.json({ error: '缺少 API ID' }, { status: 400 });
|
|
|
|
const client = await getDbClient();
|
|
try {
|
|
await ensureSystemApiSchema(client);
|
|
await client.query('DELETE FROM system_api_configs WHERE id = $1', [id]);
|
|
return NextResponse.json({ success: true });
|
|
} finally {
|
|
client.release();
|
|
}
|
|
}
|