| 1 | /** |
| 2 | * Who may do what to a work item: lib/work-items.ts has the rest of how |
| 3 | * the site shows them. |
| 4 | */ |
| 5 | import { type Abilities, CAPABILITIES, type Capability, type RepoRole, type User, allows, granted, maxRole, permission } from "@g1t/contracts"; |
| 6 | |
| 7 | /** |
| 8 | * The viewer's role on a work item of `workspace`, as |
| 9 | * `crates/contracts/src/access.rs` `item_role` reads it: the better of |
| 10 | * what their membership of the workspace gives (at least Read, since every |
| 11 | * member sees its work) and their role on its origin repository. Null |
| 12 | * when they may not see it. |
| 13 | */ |
| 14 | export function itemRole( |
| 15 | viewer: User | null | undefined, |
| 16 | workspace: string, |
| 17 | origin: { id: string; namespace: string; isPrivate: boolean } | null, |
| 18 | ): RepoRole | null { |
| 19 | const slug = workspace.toLowerCase(); |
| 20 | const member = viewer?.workspaces?.some((m) => m.slug.toLowerCase() === slug) |
| 21 | ? maxRole(granted(viewer, { id: "", namespace: slug, isPrivate: true }), "read") |
| 22 | : null; |
| 23 | return maxRole(member, origin ? permission(viewer, origin) : null); |
| 24 | } |
| 25 | |
| 26 | /** Whether the viewer may do `capability` on a work item, by the same table as a repository's. */ |
| 27 | export function canItem( |
| 28 | viewer: User | null | undefined, |
| 29 | workspace: string, |
| 30 | origin: { id: string; namespace: string; isPrivate: boolean } | null, |
| 31 | capability: Capability, |
| 32 | ): boolean { |
| 33 | return allows(itemRole(viewer, workspace, origin), capability); |
| 34 | } |
| 35 | |
| 36 | /** Every capability, true or false, for one viewer on a work item: what its page passes to its parts. */ |
| 37 | export function itemAbilities( |
| 38 | viewer: User | null | undefined, |
| 39 | workspace: string, |
| 40 | origin: { id: string; namespace: string; isPrivate: boolean } | null, |
| 41 | ): Abilities { |
| 42 | const role = itemRole(viewer, workspace, origin); |
| 43 | return Object.fromEntries(CAPABILITIES.map((row) => [row.capability, allows(role, row.capability)])) as Abilities; |
| 44 | } |