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' },
},
},