Files
miaojingAI/src/app/api/admin/system-apis/route.ts

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();
}
}