v1.2.2: Fix Nominatim CSP, Tenant Admin kann eigene Symbole hochladen
This commit is contained in:
@@ -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'",
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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"
|
||||
/>
|
||||
<Select value={symbolCatFilter} onValueChange={setSymbolCatFilter}>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
@@ -909,9 +910,13 @@ export default function AdminPage() {
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<span className="text-sm text-muted-foreground ml-auto">
|
||||
<span className="text-sm text-muted-foreground mr-auto">
|
||||
{tenantSymbols.filter(s => s.isActive).length} aktiv / {tenantSymbols.length} gesamt
|
||||
</span>
|
||||
<Button onClick={() => setIsUploadDialogOpen(true)}>
|
||||
<Upload className="w-4 h-4 mr-2" />
|
||||
Eigene Symbole hochladen
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Bulk category action */}
|
||||
@@ -1050,7 +1055,7 @@ export default function AdminPage() {
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</>
|
||||
)}
|
||||
</TabsContent>
|
||||
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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' },
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user