style: format code with prettier
Local Build and Deploy / deploy (push) Successful in 49s

This commit is contained in:
openhands committed 2026-07-12 21:07:34 +02:00
1 parent e85e4d74ea
commit 2e4ed76121
378 files changed
+22404 -20686

No files matched your search

+91 -70
View File
@@ -1,23 +1,23 @@
import { unstable_cache } from 'next/cache'
import { redirect } from 'next/navigation'
import { cache } from 'react'
import { auth } from './auth'
import { sessionUserId } from './auth/session-user'
import { prisma } from './prisma'
import { logAuthorizationEvent } from './admin/authorization-events'
import { isDynamicSuperAdmin } from './admin/authorization-policy'
import { resolveAuthorizationState } from './admin/rank-authority'
import { unstable_cache } from "next/cache";
import { redirect } from "next/navigation";
import { cache } from "react";
import { auth } from "./auth";
import { sessionUserId } from "./auth/session-user";
import { prisma } from "./prisma";
import { logAuthorizationEvent } from "./admin/authorization-events";
import { isDynamicSuperAdmin } from "./admin/authorization-policy";
import { resolveAuthorizationState } from "./admin/rank-authority";
// Re-export PERMS from the standalone file (safe for client components)
export { PERMS } from './permission-slugs'
export { PERMS } from "./permission-slugs";
import { PERMS } from './permission-slugs'
import { PERMS } from "./permission-slugs";
// ── Permission Set ──────────────────────────────────────────────────
export type { PermissionSet } from '@/types/admin'
export type { PermissionSet } from "@/types/admin";
import type { PermissionSet } from '@/types/admin'
import type { PermissionSet } from "@/types/admin";
function createEmptySet(): PermissionSet {
return {
@@ -25,7 +25,7 @@ function createEmptySet(): PermissionSet {
hasAny: () => false,
hasAll: () => false,
isSuperAdmin: false,
}
};
}
/**
@@ -48,12 +48,12 @@ const getCachedPermissionSlugs = unstable_cache(
FROM acl_roles ar
WHERE ar.slug = ${`rank_${rank}`}
)
`
return rows.map((r) => r.slug)
`;
return rows.map((r) => r.slug);
},
['user-permissions'],
{ revalidate: 60, tags: ['permissions'] },
)
["user-permissions"],
{ revalidate: 60, tags: ["permissions"] },
);
/**
* Load permission slugs for a database-refreshed user rank. The dynamically
@@ -73,25 +73,32 @@ export const loadUserPermissions = cache(async function loadUserPermissions(
hasAny: () => true,
hasAll: () => true,
isSuperAdmin: true,
}
};
}
const slugArray = await getCachedPermissionSlugs(userId, rank)
if (slugArray.length === 0) return createEmptySet()
const slugArray = await getCachedPermissionSlugs(userId, rank);
if (slugArray.length === 0) return createEmptySet();
const slugs = new Set(slugArray)
const slugs = new Set(slugArray);
return {
has: (perm: string) => slugs.has(perm),
hasAny: (...perms: string[]) => perms.some((p) => slugs.has(p)),
hasAll: (...perms: string[]) => perms.every((p) => slugs.has(p)),
isSuperAdmin: false,
}
};
} catch (error) {
await logAuthorizationEvent({ kind: 'permission.load_error', userId, rank, source: 'loadUserPermissions', reason: 'ACL query failed', error })
await logAuthorizationEvent({
kind: "permission.load_error",
userId,
rank,
source: "loadUserPermissions",
reason: "ACL query failed",
error,
});
// Fail-closed: return empty set on any error
return createEmptySet()
return createEmptySet();
}
})
});
const getCurrentAuthorizationState = cache(async (userId: number) =>
resolveAuthorizationState(userId, {
@@ -99,11 +106,11 @@ const getCurrentAuthorizationState = cache(async (userId: number) =>
highestRank: async () => {
const rows = await prisma.$queryRaw<{ highest_rank: number | bigint | null }[]>`
SELECT MAX(id) AS highest_rank FROM permission_ranks
`
return rows[0]?.highest_rank == null ? null : Number(rows[0].highest_rank)
`;
return rows[0]?.highest_rank == null ? null : Number(rows[0].highest_rank);
},
}),
)
);
// ── Context Helpers ─────────────────────────────────────────────────
@@ -112,17 +119,23 @@ const getCurrentAuthorizationState = cache(async (userId: number) =>
* Redirects to login if not authenticated.
*/
export async function getAdminContext() {
const session = await auth()
const session = await auth();
if (!session?.user) {
redirect('/login')
redirect("/login");
}
const userId = sessionUserId(session.user.id)
if (!userId) redirect('/login')
const state = await getCurrentAuthorizationState(userId)
if (!state) redirect('/login')
const permissions = await loadUserPermissions(userId, state.actor.rank, state.highestRank)
return { session: { ...session, user: { ...session.user, id: userId, username: state.actor.username, rank: state.actor.rank } }, permissions }
const userId = sessionUserId(session.user.id);
if (!userId) redirect("/login");
const state = await getCurrentAuthorizationState(userId);
if (!state) redirect("/login");
const permissions = await loadUserPermissions(userId, state.actor.rank, state.highestRank);
return {
session: {
...session,
user: { ...session.user, id: userId, username: state.actor.username, rank: state.actor.rank },
},
permissions,
};
}
/**
@@ -130,15 +143,21 @@ export async function getAdminContext() {
* Returns null if not authenticated (caller handles 401).
*/
export async function getApiAdminContext() {
const session = await auth()
if (!session?.user) return null
const session = await auth();
if (!session?.user) return null;
const userId = sessionUserId(session.user.id)
if (!userId) return null
const state = await getCurrentAuthorizationState(userId)
if (!state) return null
const permissions = await loadUserPermissions(userId, state.actor.rank, state.highestRank)
return { session: { ...session, user: { ...session.user, id: userId, username: state.actor.username, rank: state.actor.rank } }, permissions }
const userId = sessionUserId(session.user.id);
if (!userId) return null;
const state = await getCurrentAuthorizationState(userId);
if (!state) return null;
const permissions = await loadUserPermissions(userId, state.actor.rank, state.highestRank);
return {
session: {
...session,
user: { ...session.user, id: userId, username: state.actor.username, rank: state.actor.rank },
},
permissions,
};
}
/**
@@ -146,7 +165,7 @@ export async function getApiAdminContext() {
* All fallbacks are represented as ACL role permissions by migration 0011.
*/
export function canAccess(permissions: PermissionSet, slug: string, _rank?: number): boolean {
return permissions.has(slug)
return permissions.has(slug);
}
/**
@@ -154,32 +173,34 @@ export function canAccess(permissions: PermissionSet, slug: string, _rank?: numb
* Redirects to login if unauthenticated and to / without moderator ACL access.
*/
export async function getModContext() {
const session = await auth()
const session = await auth();
if (!session?.user) {
redirect('/login')
redirect("/login");
}
const userId = sessionUserId(session.user.id)
if (!userId) redirect('/login')
const state = await getCurrentAuthorizationState(userId)
if (!state) redirect('/')
const permissions = await loadUserPermissions(userId, state.actor.rank, state.highestRank)
if (!canAccess(permissions, PERMS.MOD_DASHBOARD)) redirect('/')
return { session: { ...session, user: { ...session.user, id: userId, username: state.actor.username, rank: state.actor.rank } }, permissions }
const userId = sessionUserId(session.user.id);
if (!userId) redirect("/login");
const state = await getCurrentAuthorizationState(userId);
if (!state) redirect("/");
const permissions = await loadUserPermissions(userId, state.actor.rank, state.highestRank);
if (!canAccess(permissions, PERMS.MOD_DASHBOARD)) redirect("/");
return {
session: {
...session,
user: { ...session.user, id: userId, username: state.actor.username, rank: state.actor.rank },
},
permissions,
};
}
// ── Legacy single-check functions (kept for backward compatibility) ──
/** Check if a user has a CMS permission using their current database rank. */
export async function checkPermission(
userId: number,
_rank: number,
permission: string,
): Promise<boolean> {
const state = await getCurrentAuthorizationState(userId)
if (!state) return false
const perms = await loadUserPermissions(userId, state.actor.rank, state.highestRank)
return perms.has(permission)
export async function checkPermission(userId: number, _rank: number, permission: string): Promise<boolean> {
const state = await getCurrentAuthorizationState(userId);
if (!state) return false;
const perms = await loadUserPermissions(userId, state.actor.rank, state.highestRank);
return perms.has(permission);
}
/** Check multiple permissions (user needs ALL of them) */
@@ -188,13 +209,13 @@ export async function checkAllPermissions(
_rank: number,
permissions: string[],
): Promise<boolean> {
const state = await getCurrentAuthorizationState(userId)
if (!state) return false
const perms = await loadUserPermissions(userId, state.actor.rank, state.highestRank)
return perms.hasAll(...permissions)
const state = await getCurrentAuthorizationState(userId);
if (!state) return false;
const perms = await loadUserPermissions(userId, state.actor.rank, state.highestRank);
return perms.hasAll(...permissions);
}
/** Check if user has admin access */
export async function hasAdminAccess(userId: number, rank: number): Promise<boolean> {
return checkPermission(userId, rank, PERMS.ADMIN_DASHBOARD)
return checkPermission(userId, rank, PERMS.ADMIN_DASHBOARD);
}