v1.5 - history and timeline as well as many datastructure updates added, polished, fixes
This commit is contained in:
parent
1f0aa3078f
commit
1d84400aef
63 changed files with 7927 additions and 208 deletions
57
src/lib/roles.ts
Normal file
57
src/lib/roles.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/* ═══════════════════════════════════════════════════════════════
|
||||
ROLES — src/lib/roles.ts
|
||||
|
||||
The same ladder as server/src/auth.js, and it has to stay the
|
||||
same ladder. This copy exists to decide what to draw; the
|
||||
server's copy decides what's allowed. If they ever disagree the
|
||||
worst case is a button that 403s, which is the right way round
|
||||
for them to fail.
|
||||
|
||||
Components should ask canDelete(user), not
|
||||
user.role === "admin". The second form is what silently locked
|
||||
superadmins out of saving when the third role went in: an
|
||||
equality check against a ladder is a bug waiting for the next
|
||||
role to be added, and there's now a fourth.
|
||||
═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
export const ROLES = ["viewer", "editor", "admin", "superadmin"] as const;
|
||||
|
||||
export type Role = (typeof ROLES)[number];
|
||||
|
||||
export const ROLE_RANK: Record<Role, number> = {
|
||||
viewer: 1,
|
||||
editor: 2,
|
||||
admin: 3,
|
||||
superadmin: 4,
|
||||
};
|
||||
|
||||
export const ROLE_LABELS: Record<Role, string> = {
|
||||
viewer: "Viewer",
|
||||
editor: "Editor",
|
||||
admin: "Admin",
|
||||
superadmin: "Superadmin",
|
||||
};
|
||||
|
||||
/* Each line is what that role adds to the one above it in the
|
||||
list. Read top to bottom, they describe the whole ladder. */
|
||||
export const ROLE_NOTES: Record<Role, string> = {
|
||||
viewer: "Can read everything in the CMS and change nothing.",
|
||||
editor: "Can create and update records. Can't delete anything.",
|
||||
admin: "Can delete records, including feedback.",
|
||||
superadmin: "Can manage accounts, roles and sessions.",
|
||||
};
|
||||
|
||||
type MaybeUser = { role?: string | null } | null | undefined;
|
||||
|
||||
/* Minimum, not equality: a superadmin passes atLeast(user, "editor"). */
|
||||
export function atLeast(user: MaybeUser, role: Role): boolean {
|
||||
const have = ROLE_RANK[(user?.role ?? "") as Role] ?? 0;
|
||||
return have >= ROLE_RANK[role];
|
||||
}
|
||||
|
||||
/* Named for the capability rather than the rank, so call sites
|
||||
read as intent and a future reshuffle of the ladder is one edit
|
||||
here rather than a search for every comparison. */
|
||||
export const canWrite = (user: MaybeUser) => atLeast(user, "editor");
|
||||
export const canDelete = (user: MaybeUser) => atLeast(user, "admin");
|
||||
export const isSuper = (user: MaybeUser) => atLeast(user, "superadmin");
|
||||
Loading…
Add table
Add a link
Reference in a new issue