fix(audit): UI — L18 (decorative emoji -> Lucide icons), L19 (gated NotesList timer + create-from-url ref-in-effect)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
import type { Metadata, Viewport } from 'next';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { notFound, redirect } from 'next/navigation';
|
||||
import { headers } from 'next/headers';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
|
||||
import { auth } from '@/lib/auth';
|
||||
import { db } from '@/lib/db';
|
||||
import { ports as portsTable } from '@/lib/db/schema/ports';
|
||||
import { userPortRoles, userProfiles } from '@/lib/db/schema/users';
|
||||
import { QueryProvider } from '@/providers/query-provider';
|
||||
import { PortProvider } from '@/providers/port-provider';
|
||||
|
||||
@@ -60,7 +61,22 @@ export default async function ScannerLayout({
|
||||
const port = await db.query.ports.findFirst({
|
||||
where: eq(portsTable.slug, portSlug),
|
||||
});
|
||||
if (!port) redirect('/login');
|
||||
if (!port) notFound();
|
||||
|
||||
// Membership gate (mirrors the dashboard layout): super admins reach
|
||||
// every port; everyone else needs an explicit user_port_roles row for
|
||||
// THIS port. Without this the scanner resolved the port by slug alone,
|
||||
// so any authenticated user could scan receipts into a port they have
|
||||
// no role on.
|
||||
const profile = await db.query.userProfiles.findFirst({
|
||||
where: eq(userProfiles.userId, session.user.id),
|
||||
});
|
||||
if (!profile?.isSuperAdmin) {
|
||||
const membership = await db.query.userPortRoles.findFirst({
|
||||
where: and(eq(userPortRoles.userId, session.user.id), eq(userPortRoles.portId, port.id)),
|
||||
});
|
||||
if (!membership) notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<QueryProvider>
|
||||
|
||||
Reference in New Issue
Block a user