fix(icons): /api/icons auf Raw-SQL umgestellt – zeigt jetzt alle Tenant-Kategorien in der App
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 11m39s

This commit is contained in:
Pepe Ziberi
2026-05-21 15:00:47 +02:00
parent 93d5519e58
commit 9cba24aad8

View File

@@ -2,6 +2,38 @@ import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/db'
import { getSession } from '@/lib/auth'
async function ensureTables() {
await prisma.$executeRawUnsafe(`
CREATE TABLE IF NOT EXISTS tenant_symbols (
id TEXT PRIMARY KEY DEFAULT gen_random_uuid(),
"isActive" BOOLEAN NOT NULL DEFAULT true,
"tenantId" TEXT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
"iconId" TEXT REFERENCES icon_assets(id) ON DELETE SET NULL,
"name" TEXT,
"svgPath" TEXT,
"isUploaded" BOOLEAN NOT NULL DEFAULT false,
"categoryId" TEXT,
"migratedFromIconId" TEXT,
"customName" TEXT,
"sortOrder" INTEGER,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
)
`)
await prisma.$executeRawUnsafe(`
CREATE TABLE IF NOT EXISTS tenant_categories (
id TEXT PRIMARY KEY DEFAULT gen_random_uuid(),
"name" TEXT NOT NULL,
"description" TEXT,
"sortOrder" INTEGER NOT NULL DEFAULT 0,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"tenantId" TEXT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE
)
`)
}
export async function GET() {
/* ─── 1. Global library (legacy IconAsset) ─── */
let categoriesWithUrls: any[] = []
@@ -9,41 +41,38 @@ export async function GET() {
const user = await getSession()
const tenantId = user?.tenantId
const categoryWhere: any = tenantId
? { OR: [{ tenantId: null }, { tenantId }] }
: {}
const categories = await (prisma as any).iconCategory.findMany({
where: categoryWhere,
orderBy: { sortOrder: 'asc' },
include: {
icons: {
where: tenantId
? { isActive: true, OR: [{ tenantId: null }, { tenantId }] }
: { isActive: true, tenantId: null },
orderBy: { name: 'asc' },
},
},
})
const categories = await prisma.$queryRawUnsafe(
`SELECT * FROM icon_categories WHERE "tenantId" IS NULL OR "tenantId" = $1 ORDER BY "sortOrder" ASC`,
tenantId || null
) as any[]
let hiddenIconIds: string[] = []
if (tenantId) {
const tenant = await (prisma as any).tenant.findUnique({
where: { id: tenantId },
select: { hiddenIconIds: true },
})
hiddenIconIds = tenant?.hiddenIconIds || []
const tenant = await prisma.$queryRawUnsafe(
`SELECT "hiddenIconIds" FROM tenants WHERE id = $1 LIMIT 1`,
tenantId
) as any[]
hiddenIconIds = tenant[0]?.hiddenIconIds || []
}
categoriesWithUrls = categories.map((cat: any) => ({
...cat,
icons: cat.icons
for (const cat of categories) {
const icons = await prisma.$queryRawUnsafe(
`SELECT * FROM icon_assets WHERE "categoryId" = $1 AND "isActive" = true AND ("tenantId" IS NULL OR "tenantId" = $2) ORDER BY name ASC`,
cat.id, tenantId || null
) as any[]
const filteredIcons = icons
.filter((icon: any) => !hiddenIconIds.includes(icon.id))
.map((icon: any) => ({
...icon,
url: `/api/icons/${icon.id}/image`,
})),
}))
if (filteredIcons.length > 0) {
categoriesWithUrls.push({
...cat,
icons: filteredIcons,
})
}
}
} catch (err) {
console.error('Error fetching legacy icon categories:', err)
categoriesWithUrls = []
@@ -58,18 +87,23 @@ export async function GET() {
const tenantId = user?.tenantId
if (tenantId) {
const tenantSymbols = await (prisma as any).tenantSymbol.findMany({
where: { tenantId },
include: { category: true },
orderBy: [{ category: { sortOrder: 'asc' } }, { sortOrder: 'asc' }],
})
await ensureTables()
const tenantSymbols = await prisma.$queryRawUnsafe(
`SELECT ts.*, tc.id as "catId", tc.name as "catName"
FROM tenant_symbols ts
LEFT JOIN tenant_categories tc ON ts."categoryId" = tc.id
WHERE ts."tenantId" = $1 AND ts."isActive" = true
ORDER BY COALESCE(tc."sortOrder", 9999) ASC, COALESCE(ts."sortOrder", 9999) ASC`,
tenantId
) as any[]
flatTenantSymbols = tenantSymbols.map((ts: any) => ({
id: ts.id,
name: ts.customName || ts.name,
customName: ts.customName,
categoryId: ts.categoryId,
categoryName: ts.category?.name || null,
categoryName: ts.catName || null,
isUploaded: ts.isUploaded,
migratedFromIconId: ts.migratedFromIconId,
imageUrl: ts.isUploaded
@@ -87,12 +121,13 @@ export async function GET() {
}
const catIds = Array.from(groups.keys()).filter(Boolean) as string[]
const tenantCategories = catIds.length
? await (prisma as any).tenantCategory.findMany({
where: { id: { in: catIds }, tenantId },
orderBy: { sortOrder: 'asc' },
})
: []
let tenantCategories: any[] = []
if (catIds.length > 0) {
tenantCategories = await prisma.$queryRawUnsafe(
`SELECT * FROM tenant_categories WHERE id = ANY($1) AND "tenantId" = $2 ORDER BY "sortOrder" ASC`,
catIds, tenantId
) as any[]
}
const catMap = new Map(tenantCategories.map((c: any) => [c.id, c]))
@@ -100,8 +135,8 @@ export async function GET() {
const cat = catId ? catMap.get(catId) : null
return {
categoryId: catId,
categoryName: cat ? (cat as any).name || 'Kategorie' : 'Ohne Kategorie',
sortOrder: cat ? (cat as any).sortOrder ?? 999 : 999,
categoryName: cat ? cat.name || 'Kategorie' : 'Ohne Kategorie',
sortOrder: cat ? cat.sortOrder ?? 999 : 999,
symbols,
}
})
@@ -120,19 +155,22 @@ export async function GET() {
const tenantId = user?.tenantId
if (tenantId) {
const legacy = await (prisma as any).tenantSymbol.findMany({
where: { tenantId, iconId: { not: null } },
include: { icon: { select: { id: true, name: true, mimeType: true, iconType: true } } },
orderBy: { sortOrder: 'asc' },
})
const legacy = await prisma.$queryRawUnsafe(
`SELECT ts.*, ia.id as "iconId", ia.name as "iconName", ia."mimeType", ia."iconType"
FROM tenant_symbols ts
JOIN icon_assets ia ON ts."iconId" = ia.id
WHERE ts."tenantId" = $1 AND ts."iconId" IS NOT NULL
ORDER BY COALESCE(ts."sortOrder", 9999) ASC`,
tenantId
) as any[]
mySymbolsLegacy = legacy.map((ts: any) => ({
id: ts.icon.id,
id: ts.iconId,
tenantSymbolId: ts.id,
name: ts.customName || ts.icon.name,
name: ts.customName || ts.iconName,
customName: ts.customName,
mimeType: ts.icon.mimeType,
iconType: ts.icon.iconType,
url: `/api/icons/${ts.icon.id}/image`,
mimeType: ts.mimeType,
iconType: ts.iconType,
url: `/api/icons/${ts.iconId}/image`,
}))
}
} catch (err) {