diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 959705b..424a1b7 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -50,6 +50,13 @@ "when": 1776451200000, "tag": "0006_seed_system_skills_fix", "breakpoints": true + }, + { + "idx": 7, + "version": "7", + "when": 1776537600000, + "tag": "0004_add_openrouter_provider", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/app/api/settings/api-keys/route.ts b/src/app/api/settings/api-keys/route.ts index 3688093..dce9c7e 100644 --- a/src/app/api/settings/api-keys/route.ts +++ b/src/app/api/settings/api-keys/route.ts @@ -3,7 +3,7 @@ import { db } from '@/lib/db'; import { tenantApiKeys } from '@/lib/db/schema'; -import { eq, and } from 'drizzle-orm'; +import { eq, and, isNull } from 'drizzle-orm'; import { requirePermission } from '@/lib/auth/rbac'; import { encrypt, keyHint } from '@/lib/crypto'; import { logAuditEvent } from '@/lib/auth/audit'; @@ -53,7 +53,7 @@ export async function POST(request: Request) { return Response.json({ error: 'API-Schlüssel ist erforderlich (mindestens 8 Zeichen).' }, { status: 400 }); } - // Check for duplicate provider+label + // Check for duplicate provider+label (null labels must use IS NULL, not equality) const existing = await db .select({ id: tenantApiKeys.id }) .from(tenantApiKeys) @@ -61,7 +61,7 @@ export async function POST(request: Request) { and( eq(tenantApiKeys.tenantId, ctx.tenantId), eq(tenantApiKeys.provider, provider as AIProvider), - label ? eq(tenantApiKeys.label, label) : undefined, + label ? eq(tenantApiKeys.label, label) : isNull(tenantApiKeys.label), ), ) .limit(1); @@ -84,24 +84,30 @@ export async function POST(request: Request) { } const hint = keyHint(apiKey); - const [created] = await db - .insert(tenantApiKeys) - .values({ - tenantId: ctx.tenantId, - provider: provider as AIProvider, - encryptedKey, - keyHint: hint, - label: label || null, - createdByUserId: ctx.userId, - }) - .returning({ - id: tenantApiKeys.id, - provider: tenantApiKeys.provider, - keyHint: tenantApiKeys.keyHint, - label: tenantApiKeys.label, - isActive: tenantApiKeys.isActive, - createdAt: tenantApiKeys.createdAt, - }); + let created: { id: string; provider: string; keyHint: string; label: string | null; isActive: boolean; createdAt: Date }; + try { + [created] = await db + .insert(tenantApiKeys) + .values({ + tenantId: ctx.tenantId, + provider: provider as AIProvider, + encryptedKey, + keyHint: hint, + label: label || null, + createdByUserId: ctx.userId, + }) + .returning({ + id: tenantApiKeys.id, + provider: tenantApiKeys.provider, + keyHint: tenantApiKeys.keyHint, + label: tenantApiKeys.label, + isActive: tenantApiKeys.isActive, + createdAt: tenantApiKeys.createdAt, + }); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + return Response.json({ error: `Datenbankfehler beim Speichern: ${msg}` }, { status: 500 }); + } const ip = request.headers.get('x-forwarded-for')?.split(',')[0]?.trim(); await logAuditEvent(ctx, 'create', 'tenant_api_key', created.id, { provider, label: label || null }, ip);