Initial commit: Lageplan v1.0 - Next.js 15.5, React 19

This commit is contained in:
Pepe Ziberi
2026-02-21 11:57:44 +01:00
commit adf3dc8c1d
167 changed files with 34265 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/db'
import { uploadFile } from '@/lib/minio'
import { getSession, isAdmin } from '@/lib/auth'
import { v4 as uuidv4 } from 'uuid'
const ALLOWED_TYPES = ['image/png', 'image/svg+xml', 'image/jpeg', 'image/webp']
const MAX_SIZE = 5 * 1024 * 1024 // 5MB
export async function POST(req: NextRequest) {
try {
const user = await getSession()
if (!user || !isAdmin(user.role)) {
return NextResponse.json({ error: 'Nicht autorisiert' }, { status: 403 })
}
const formData = await req.formData()
const file = formData.get('file') as File | null
const categoryId = formData.get('categoryId') as string
const iconType = (formData.get('iconType') as string) || 'STANDARD'
const name = formData.get('name') as string
if (!file || !categoryId || !name) {
return NextResponse.json(
{ error: 'Datei, Kategorie und Name sind erforderlich' },
{ status: 400 }
)
}
if (!ALLOWED_TYPES.includes(file.type)) {
return NextResponse.json(
{ error: 'Nur PNG, SVG, JPEG und WebP Dateien erlaubt' },
{ status: 400 }
)
}
if (file.size > MAX_SIZE) {
return NextResponse.json(
{ error: 'Datei zu groß (max. 5MB)' },
{ status: 400 }
)
}
// Check category exists
const category = await (prisma as any).iconCategory.findUnique({
where: { id: categoryId },
})
if (!category) {
return NextResponse.json(
{ error: 'Kategorie nicht gefunden' },
{ status: 404 }
)
}
// Generate safe filename
const ext = file.name.split('.').pop()?.toLowerCase() || 'png'
const safeFileName = `${uuidv4()}.${ext}`
const fileKey = `icons/${safeFileName}`
// Upload to MinIO
const buffer = Buffer.from(await file.arrayBuffer())
await uploadFile(fileKey, buffer, file.type)
// TENANT_ADMIN: icons get tenantId. SERVER_ADMIN: global icons (tenantId=null)
const tenantId = user.role === 'SERVER_ADMIN' ? null : user.tenantId || null
// Create database entry
const icon = await (prisma as any).iconAsset.create({
data: {
name: name.trim(),
fileKey,
mimeType: file.type,
categoryId,
iconType: iconType as any,
isSystem: false,
isActive: true,
tenantId,
ownerId: user.id,
},
include: {
category: true,
},
})
return NextResponse.json({ icon }, { status: 201 })
} catch (error) {
console.error('Error uploading icon:', error)
return NextResponse.json({ error: 'Upload fehlgeschlagen' }, { status: 500 })
}
}