Fixed creation of users + better frontend handling of permissions

This commit is contained in:
cdricms
2025-03-06 17:34:52 +01:00
parent 3c6038bce1
commit 7cb633b4c6
46 changed files with 1511 additions and 909 deletions

View File

@@ -1,2 +1,3 @@
export const API_URL = process.env.NEXT_PUBLIC_API_URL ?? "";
export const SITE_NAME = "Latosa® Escrima";
export const BASE_URL = process.env.SERVER_NAME ?? "latosa.cems.dev";

View File

@@ -1,25 +1,43 @@
import { Role } from "@/types/types";
export default function hasPermissions(
roles: Role[],
permissions: { [key: string]: string[] },
) {
type PermissionResult<T extends Record<string, readonly string[]>> = {
[K in keyof T]: {
[A in T[K][number]]: boolean;
} & { all: boolean }; // Per-resource 'all'
} & { all: boolean }; // Global 'all'
// hasPermissions function with 'all' flags
export default function hasPermissions<
T extends Record<string, readonly string[]>,
>(roles: Role[], permissions: T): PermissionResult<T> {
// Build permissions set
const permissionsSet: Map<string, null> = new Map();
for (const role of roles) {
if (!role.permissions) continue;
for (const perm of role?.permissions) {
const key = perm.resource + ":" + perm.action;
for (const perm of role.permissions) {
const key = `${perm.resource}:${perm.action}`;
permissionsSet.set(key, null);
}
}
for (const [perm, actions] of Object.entries(permissions)) {
// Build result
const result = { all: true } as PermissionResult<T>; // Initialize global 'all' as true
let globalAll = true; // Track global state
for (const resource in permissions) {
const actions = permissions[resource];
let resourceAll = true; // Track per-resource state
result[resource] = { all: true } as any; // Initialize resource object
for (const action of actions) {
if (!permissionsSet.has(perm + ":" + action)) {
return false;
}
const hasPerm = permissionsSet.has(`${resource}:${action}`);
(result[resource] as Record<string, boolean>)[action] = hasPerm;
resourceAll = resourceAll && hasPerm; // Update resource 'all'
}
result[resource].all = resourceAll; // Set resource 'all'
globalAll = globalAll && resourceAll; // Update global 'all'
}
return true;
result.all = globalAll; // Set global 'all'
return result as PermissionResult<T>;
}

View File

@@ -8,3 +8,33 @@ export function cn(...inputs: ClassValue[]) {
export function toTitleCase(str: string) {
return str.replace(/\b\w/g, (char) => char.toUpperCase());
}
namespace DiffUtils {
export function getDifferences<T extends object>(
obj1: T,
obj2: T,
): Partial<T> {
return Object.entries(obj2).reduce((diff, [key, value]) => {
if (
JSON.stringify(obj1[key as keyof T]) !==
JSON.stringify(obj2[key as keyof T])
) {
diff[key as keyof T] = value as T[keyof T];
}
return diff;
}, {} as Partial<T>);
}
export function isEmpty<T extends object>(obj: T) {
return Object.keys(obj).length === 0;
}
}
// Make it globally available
if (typeof window !== "undefined") {
(window as any).DiffUtils = DiffUtils;
} else {
(global as any).DiffUtils = DiffUtils;
}
export default DiffUtils;