import { z } from "zod" export const roleSchema = z.enum(["owner", "support", "admin", "editor", "manager"]) export const permissionScopeSchema = z.enum(["own", "team", "global"]) export const permissionSchema = z.enum([ "dashboard:read", "roadmap:read", "pages:read", "pages:write", "pages:publish", "navigation:read", "navigation:write", "media:read", "media:write", "media:refine", "users:read", "users:write", "users:manage_roles", "commissions:read", "commissions:write", "commissions:transition", "banner:read", "banner:write", "news:read", "news:write", "news:publish", ]) export type Role = z.infer export type Permission = z.infer export type PermissionScope = z.infer export type PermissionGrant = { permission: Permission scopes: PermissionScope[] } const allPermissions = permissionSchema.options const allGlobalGrants: PermissionGrant[] = allPermissions.map((permission) => ({ permission, scopes: ["global"], })) export const permissionMatrix: Record = { owner: allGlobalGrants, support: allGlobalGrants, admin: allGlobalGrants, manager: [ { permission: "dashboard:read", scopes: ["global"] }, { permission: "roadmap:read", scopes: ["global"] }, { permission: "pages:read", scopes: ["global"] }, { permission: "pages:write", scopes: ["global"] }, { permission: "pages:publish", scopes: ["global"] }, { permission: "navigation:read", scopes: ["global"] }, { permission: "navigation:write", scopes: ["global"] }, { permission: "media:read", scopes: ["global"] }, { permission: "media:write", scopes: ["global"] }, { permission: "media:refine", scopes: ["global"] }, { permission: "users:read", scopes: ["global"] }, { permission: "users:write", scopes: ["team"] }, { permission: "commissions:read", scopes: ["global"] }, { permission: "commissions:write", scopes: ["global"] }, { permission: "commissions:transition", scopes: ["global"] }, { permission: "banner:read", scopes: ["global"] }, { permission: "banner:write", scopes: ["global"] }, { permission: "news:read", scopes: ["global"] }, { permission: "news:write", scopes: ["global"] }, { permission: "news:publish", scopes: ["global"] }, ], editor: [ { permission: "dashboard:read", scopes: ["global"] }, { permission: "pages:read", scopes: ["team"] }, { permission: "pages:write", scopes: ["team"] }, { permission: "pages:publish", scopes: ["own"] }, { permission: "navigation:read", scopes: ["team"] }, { permission: "navigation:write", scopes: ["team"] }, { permission: "media:read", scopes: ["team"] }, { permission: "media:write", scopes: ["team"] }, { permission: "media:refine", scopes: ["team"] }, { permission: "users:read", scopes: ["own"] }, { permission: "commissions:read", scopes: ["own"] }, { permission: "commissions:write", scopes: ["own"] }, { permission: "commissions:transition", scopes: ["own"] }, { permission: "banner:read", scopes: ["global"] }, { permission: "news:read", scopes: ["team"] }, { permission: "news:write", scopes: ["team"] }, { permission: "news:publish", scopes: ["own"] }, ], } const scopeWeight: Record = { own: 1, team: 2, global: 3, } export function normalizeRole(input: string | null | undefined): Role | null { if (!input) { return null } const parsed = roleSchema.safeParse(input.toLowerCase()) if (!parsed.success) { return null } return parsed.data } export function hasPermission( role: Role, permission: Permission, scope: PermissionScope = "global", ): boolean { const grants = permissionMatrix[role] const grant = grants.find((item) => item.permission === permission) if (!grant) { return false } return grant.scopes.some((grantedScope) => scopeWeight[grantedScope] >= scopeWeight[scope]) }