diff --git a/next.config.js b/next.config.js index c7c6037..29da266 100644 --- a/next.config.js +++ b/next.config.js @@ -51,7 +51,7 @@ const nextConfig = { "style-src 'self' 'unsafe-inline'", "img-src 'self' data: blob: https://*.tile.openstreetmap.org https://api.maptiler.com https://server.arcgisonline.com https://*.geo.admin.ch http://localhost:9000 http://minio:9000", "font-src 'self' data:", - "connect-src 'self' ws: wss: https://api.maptiler.com https://*.tile.openstreetmap.org https://api.open-meteo.com https://server.arcgisonline.com https://*.geo.admin.ch", + "connect-src 'self' ws: wss: https://api.maptiler.com https://*.tile.openstreetmap.org https://nominatim.openstreetmap.org https://api.open-meteo.com https://server.arcgisonline.com https://*.geo.admin.ch", "frame-ancestors 'self'", "base-uri 'self'", "form-action 'self'", diff --git a/package.json b/package.json index abd6011..fa6c274 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lageplan", - "version": "1.2.1", + "version": "1.2.2", "description": "Feuerwehr Lageplan - Krokier-App für Einsatzdokumentation", "private": true, "scripts": { diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index ec42e9a..26e227b 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -552,7 +552,8 @@ export default function AdminPage() { setUploadFiles(null) setUploadCategory('') setUploadIconName('') - fetchData() + if (user?.role === 'TENANT_ADMIN') fetchTenantSymbols() + else fetchData() } catch (error) { toast({ title: 'Upload-Fehler', description: error instanceof Error ? error.message : 'Fehler', variant: 'destructive' }) } finally { setIsUploading(false) } @@ -896,7 +897,7 @@ export default function AdminPage() { placeholder="Symbole suchen..." value={symbolSearch} onChange={e => setSymbolSearch(e.target.value)} - className="w-48" + className="w-full sm:w-64" /> - + {tenantSymbols.filter(s => s.isActive).length} aktiv / {tenantSymbols.length} gesamt + {/* Bulk category action */} @@ -1050,7 +1055,7 @@ export default function AdminPage() { ))} )} - + )} diff --git a/src/app/api/admin/icons/upload/route.ts b/src/app/api/admin/icons/upload/route.ts index 014c152..c917822 100644 --- a/src/app/api/admin/icons/upload/route.ts +++ b/src/app/api/admin/icons/upload/route.ts @@ -10,7 +10,7 @@ const MAX_SIZE = 5 * 1024 * 1024 // 5MB export async function POST(req: NextRequest) { try { const user = await getSession() - if (!user || !isAdmin(user.role)) { + if (!user || (user.role !== 'SERVER_ADMIN' && user.role !== 'TENANT_ADMIN')) { return NextResponse.json({ error: 'Nicht autorisiert' }, { status: 403 }) } @@ -55,27 +55,25 @@ export async function POST(req: NextRequest) { // Generate safe filename const ext = file.name.split('.').pop()?.toLowerCase() || 'png' + const isTenantAdmin = user.role === 'TENANT_ADMIN' + const prefix = isTenantAdmin ? `tenant-${user.tenantId}/icons` : 'icons' const safeFileName = `${uuidv4()}.${ext}` - const fileKey = `icons/${safeFileName}` + const fileKey = `${prefix}/${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 + // Save to DB 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, + fileKey, + mimeType: file.type, + isSystem: !isTenantAdmin, // true für Server Admin, false für Tenant Admin + tenantId: isTenantAdmin ? user.tenantId : null, ownerId: user.id, }, include: { diff --git a/src/app/api/icons/route.ts b/src/app/api/icons/route.ts index f7ee392..bc8fc45 100644 --- a/src/app/api/icons/route.ts +++ b/src/app/api/icons/route.ts @@ -32,7 +32,7 @@ export async function GET() { icons: { where: user?.tenantId ? { isActive: true, OR: [{ tenantId: null }, { tenantId: user.tenantId }] } - : { isActive: true }, + : { isActive: true, tenantId: null }, orderBy: { name: 'asc' }, }, },