From db433e5c2e5d3afdcea88a2b03084a3fb0fcf098 Mon Sep 17 00:00:00 2001 From: sysops Date: Tue, 17 Mar 2026 21:23:24 +0100 Subject: [PATCH] fix: Rollenhierarchie domain_admin/superadmin in Frontend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - useAuth: neue Rollen domain_admin/superadmin + hasRole() helper - Admin-Page: useAuth(domain_admin), isSuperAdmin-Flag - Tabs LDAP/Security/Mandanten/Module nur für superadmin - Navbar: Admin-Link für domain_admin + superadmin sichtbar - User-Anlage: domain_admin-Rolle wählbar, superadmin nur für superadmin Co-Authored-By: Claude Sonnet 4.6 --- src/app/admin/page.tsx | 14 ++++++++------ src/app/admin/upload/page.tsx | 2 +- src/components/navbar.tsx | 2 +- src/hooks/useAuth.ts | 27 ++++++++++++++++----------- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 5ab56a2..9640518 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -89,7 +89,8 @@ function formatBytes(bytes: number): string { } export default function AdminPage() { - const { user, loading: authLoading } = useAuth("admin"); + const { user, loading: authLoading } = useAuth("domain_admin"); + const isSuperAdmin = user?.role === "superadmin"; // Dashboard state const [smtpStatus, setSmtpStatus] = useState(null); @@ -620,10 +621,10 @@ export default function AdminPage() { Benutzer Audit-Log Import - LDAP - Security - Mandanten - Module + {isSuperAdmin && LDAP} + {isSuperAdmin && Security} + {isSuperAdmin && Mandanten} + {isSuperAdmin && Module} {/* ── Dashboard ── */} @@ -1166,7 +1167,8 @@ export default function AdminPage() { User Auditor - Admin + Domain Admin + {isSuperAdmin && Superadmin} diff --git a/src/app/admin/upload/page.tsx b/src/app/admin/upload/page.tsx index dd21045..abd062d 100644 --- a/src/app/admin/upload/page.tsx +++ b/src/app/admin/upload/page.tsx @@ -17,7 +17,7 @@ function formatBytes(bytes: number): string { } export default function UploadPage() { - const { user, loading: authLoading } = useAuth("admin"); + const { user, loading: authLoading } = useAuth("domain_admin"); const [dragOver, setDragOver] = useState(false); const [selectedFiles, setSelectedFiles] = useState([]); diff --git a/src/components/navbar.tsx b/src/components/navbar.tsx index e1e72c2..9f602d8 100644 --- a/src/components/navbar.tsx +++ b/src/components/navbar.tsx @@ -54,7 +54,7 @@ export function Navbar({ username, role }: NavbarProps) { > POP3 Import - {role === "admin" && ( + {(role === "admin" || role === "domain_admin" || role === "superadmin") && ( domain_admin(4) > admin(3) > auditor(2) > user(1) +const roleLevels: Record = { + user: 1, + auditor: 2, + admin: 3, + domain_admin: 4, + superadmin: 5, +}; + +export function hasRole(userRole: string, required: string): boolean { + return (roleLevels[userRole] ?? 0) >= (roleLevels[required] ?? 0); +} + +export function useAuth(requireRole?: "admin" | "domain_admin" | "superadmin" | "auditor") { const router = useRouter(); const cached = getCachedUser(); const [user, setUser] = useState(cached); @@ -16,11 +29,7 @@ export function useAuth(requireRole?: "admin" | "auditor") { const checkAuth = useCallback(async () => { const cached = getCachedUser(); if (cached !== null) { - if (requireRole === "admin" && cached.role !== "admin") { - router.replace("/search"); - return; - } - if (requireRole === "auditor" && cached.role !== "auditor" && cached.role !== "admin") { + if (requireRole && !hasRole(cached.role, requireRole)) { router.replace("/search"); return; } @@ -32,11 +41,7 @@ export function useAuth(requireRole?: "admin" | "auditor") { try { const me = await getMe(); setCachedUser(me); - if (requireRole === "admin" && me.role !== "admin") { - router.replace("/search"); - return; - } - if (requireRole === "auditor" && me.role !== "auditor" && me.role !== "admin") { + if (requireRole && !hasRole(me.role, requireRole)) { router.replace("/search"); return; }