feat: Unbekannte und nicht erlaubte Seiten leiten zum Dashboard um
- src/app/not-found.tsx: jede nicht existierende Route landet auf /dashboard statt der Next.js-Standard-404-Seite (der bestehende Auth-Guard in (app)/layout.tsx schickt nicht angemeldete User von dort automatisch weiter zu /login). - settings/layout.tsx: fehlt die Berechtigung fuer den Einstellungen-Bereich, wird jetzt zu /dashboard umgeleitet statt nur einen Hinweistext anzuzeigen (gleiches Redirect-Muster wie der bestehende Login-Guard). Login-nach-Anmeldung-Redirect zu /dashboard und der Auth-Gate in (app)/layout.tsx bestanden bereits.
This commit is contained in:
1 parent
9de123ab32
commit
b3157484c4
3 files changed
+61
-8
No files matched your search
@@ -0,0 +1,46 @@
|
|||||||
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import { render, screen } from "@testing-library/react";
|
||||||
|
import SettingsLayout from "./layout";
|
||||||
|
|
||||||
|
const replaceMock = vi.fn();
|
||||||
|
vi.mock("next/navigation", () => ({
|
||||||
|
useRouter: () => ({ replace: replaceMock }),
|
||||||
|
}));
|
||||||
|
|
||||||
|
let mockUser: { permissions: string[] } | null = null;
|
||||||
|
vi.mock("@/lib/auth/auth-context", () => ({
|
||||||
|
useAuth: () => ({ user: mockUser }),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("SettingsLayout", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
replaceMock.mockReset();
|
||||||
|
mockUser = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders children when the user has a settings-area permission", () => {
|
||||||
|
mockUser = { permissions: ["users:read"] };
|
||||||
|
|
||||||
|
render(
|
||||||
|
<SettingsLayout>
|
||||||
|
<p>Einstellungen-Inhalt</p>
|
||||||
|
</SettingsLayout>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText("Einstellungen-Inhalt")).toBeInTheDocument();
|
||||||
|
expect(replaceMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("redirects to the dashboard when the user lacks every settings-area permission", () => {
|
||||||
|
mockUser = { permissions: ["colonies:read"] };
|
||||||
|
|
||||||
|
render(
|
||||||
|
<SettingsLayout>
|
||||||
|
<p>Einstellungen-Inhalt</p>
|
||||||
|
</SettingsLayout>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.queryByText("Einstellungen-Inhalt")).not.toBeInTheDocument();
|
||||||
|
expect(replaceMock).toHaveBeenCalledWith("/dashboard");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { ReactNode } from "react";
|
import { ReactNode, useEffect } from "react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
import { useAuth } from "@/lib/auth/auth-context";
|
import { useAuth } from "@/lib/auth/auth-context";
|
||||||
|
|
||||||
const SETTINGS_AREA_PERMISSIONS = [
|
const SETTINGS_AREA_PERMISSIONS = [
|
||||||
@@ -14,19 +15,20 @@ const SETTINGS_AREA_PERMISSIONS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export default function SettingsLayout({ children }: { children: ReactNode }) {
|
export default function SettingsLayout({ children }: { children: ReactNode }) {
|
||||||
|
const router = useRouter();
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const hasSettingsAccess = SETTINGS_AREA_PERMISSIONS.some((permission) =>
|
const hasSettingsAccess = SETTINGS_AREA_PERMISSIONS.some((permission) =>
|
||||||
user?.permissions.includes(permission),
|
user?.permissions.includes(permission),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!hasSettingsAccess) {
|
||||||
|
router.replace("/dashboard");
|
||||||
|
}
|
||||||
|
}, [hasSettingsAccess, router]);
|
||||||
|
|
||||||
if (!hasSettingsAccess) {
|
if (!hasSettingsAccess) {
|
||||||
return (
|
return null;
|
||||||
<main className="p-6">
|
|
||||||
<p className="text-sm text-muted-foreground">
|
|
||||||
Diese Seite ist nur für Administratoren verfügbar.
|
|
||||||
</p>
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
|
export default function NotFound() {
|
||||||
|
redirect("/dashboard");
|
||||||
|
}
|
||||||
Reference in new issue
Block a user