|
@ -1,7 +1,11 @@ |
|
|
import type { ClientType } from '#db/repositories/client/types'; |
|
|
import type { ClientType } from '#db/repositories/client/types'; |
|
|
import type { UserType } from '#db/repositories/user/types'; |
|
|
import type { UserType } from '#db/repositories/user/types'; |
|
|
|
|
|
|
|
|
export type Role = number & { readonly __role: unique symbol }; |
|
|
type BrandedRole = { |
|
|
|
|
|
readonly __role: unique symbol; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
export type Role = number & BrandedRole; |
|
|
|
|
|
|
|
|
export const roles = { |
|
|
export const roles = { |
|
|
ADMIN: 1 as Role, |
|
|
ADMIN: 1 as Role, |
|
@ -26,9 +30,24 @@ function roleToKey(role: Role) { |
|
|
return roleKey as Roles; |
|
|
return roleKey as Roles; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// TODO: https://github.com/nitrojs/nitro/issues/2758#issuecomment-2650531472
|
|
|
|
|
|
|
|
|
|
|
|
type BrandedNumber = { |
|
|
|
|
|
toString: unknown; |
|
|
|
|
|
toFixed: unknown; |
|
|
|
|
|
toExponential: unknown; |
|
|
|
|
|
toPrecision: unknown; |
|
|
|
|
|
valueOf: unknown; |
|
|
|
|
|
toLocaleString: unknown; |
|
|
|
|
|
} & BrandedRole; |
|
|
|
|
|
|
|
|
|
|
|
type SharedUserType = |
|
|
|
|
|
| Pick<UserType, 'id' | 'role'> |
|
|
|
|
|
| (Pick<UserType, 'id'> & { role: BrandedNumber }); |
|
|
|
|
|
|
|
|
type PermissionCheck<Key extends keyof Permissions> = |
|
|
type PermissionCheck<Key extends keyof Permissions> = |
|
|
| boolean |
|
|
| boolean |
|
|
| ((user: UserType, data: Permissions[Key]['dataType']) => boolean); |
|
|
| ((user: SharedUserType, data: Permissions[Key]['dataType']) => boolean); |
|
|
|
|
|
|
|
|
type RolesWithPermissions = { |
|
|
type RolesWithPermissions = { |
|
|
[R in Roles]: { |
|
|
[R in Roles]: { |
|
@ -87,14 +106,15 @@ export const ROLES = { |
|
|
} as const satisfies RolesWithPermissions; |
|
|
} as const satisfies RolesWithPermissions; |
|
|
|
|
|
|
|
|
export function hasPermissions<Resource extends keyof Permissions>( |
|
|
export function hasPermissions<Resource extends keyof Permissions>( |
|
|
user: UserType, |
|
|
user: SharedUserType, |
|
|
resource: Resource, |
|
|
resource: Resource, |
|
|
action: Permissions[Resource]['action'], |
|
|
action: Permissions[Resource]['action'], |
|
|
data?: Permissions[Resource]['dataType'] |
|
|
data?: Permissions[Resource]['dataType'] |
|
|
) { |
|
|
) { |
|
|
const permission = (ROLES as RolesWithPermissions)[roleToKey(user.role)][ |
|
|
const permission = (ROLES as RolesWithPermissions)[ |
|
|
resource |
|
|
// TODO: remove typecast
|
|
|
][action]; |
|
|
roleToKey(user.role as Role) |
|
|
|
|
|
][resource][action]; |
|
|
|
|
|
|
|
|
if (typeof permission === 'boolean') { |
|
|
if (typeof permission === 'boolean') { |
|
|
return permission; |
|
|
return permission; |
|
|