| 1 | import { test } from "node:test"; |
| 2 | import assert from "node:assert/strict"; |
| 3 | |
| 4 | import type { User } from "@g1t/contracts"; |
| 5 | |
| 6 | import { MAX_REQUEST_NOTE, mayAdmit, mayInviteGuests, mayJoin, mayRead, mayVisit, requestNote, visibilityOf } from "./access.ts"; |
| 7 | |
| 8 | const person = (over: Partial<User> = {}): User => ({ id: "usr_1", username: "ana", verified: true, ...over }); |
| 9 | |
| 10 | test("a channel is private, kept to the workspace, or public; a direct message is always private", () => { |
| 11 | assert.equal(visibilityOf({ kind: "channel", private: 1, public: 0 }), "private"); |
| 12 | assert.equal(visibilityOf({ kind: "channel", private: 0, public: 0 }), "workspace"); |
| 13 | assert.equal(visibilityOf({ kind: "channel", private: 0, public: 1 }), "public"); |
| 14 | // Private wins: a private channel is never open to anyone. |
| 15 | assert.equal(visibilityOf({ kind: "channel", private: 1, public: 1 }), "private"); |
| 16 | assert.equal(visibilityOf({ kind: "dm", private: 1, public: 1 }), "private"); |
| 17 | }); |
| 18 | |
| 19 | test("who may read: anyone in it; members for a workspace channel; anyone for a public one", () => { |
| 20 | for (const role of ["owner", "member", null] as const) { |
| 21 | assert.equal(mayRead("private", role, true), true); |
| 22 | assert.equal(mayRead("private", role, false), false); |
| 23 | assert.equal(mayRead("public", role, false), true); |
| 24 | } |
| 25 | assert.equal(mayRead("workspace", "member", false), true); |
| 26 | assert.equal(mayRead("workspace", null, false), false); |
| 27 | // A guest asked into a workspace channel reads it. |
| 28 | assert.equal(mayRead("workspace", null, true), true); |
| 29 | }); |
| 30 | |
| 31 | test("someone outside the workspace taken out of a public channel can't join it again on their own", () => { |
| 32 | assert.equal(mayJoin("public", null, false, false), true); |
| 33 | assert.equal(mayJoin("public", null, true, false), false); |
| 34 | // Members are never kept out this way; leaving or being taken out is not a ban for them. |
| 35 | assert.equal(mayJoin("public", "member", true, false), true); |
| 36 | assert.equal(mayJoin("workspace", null, false, false), false); |
| 37 | assert.equal(mayJoin("private", "owner", false, false), false); |
| 38 | assert.equal(mayJoin("workspace", "member", false, true), false); |
| 39 | }); |
| 40 | |
| 41 | test("owners always invite guests; members while the workspace lets them", () => { |
| 42 | const owner = person({ workspaces: [{ slug: "flagon-io", role: "owner" }] }); |
| 43 | assert.equal(mayInviteGuests(owner, "Flagon-IO"), true); |
| 44 | const member = (allowed?: boolean) => |
| 45 | person({ |
| 46 | workspaces: [ |
| 47 | { |
| 48 | slug: "flagon-io", |
| 49 | role: "member", |
| 50 | ...(allowed === undefined ? {} : { privileges: { members_can_invite_outside_collaborators: allowed } as never }), |
| 51 | }, |
| 52 | ], |
| 53 | }); |
| 54 | assert.equal(mayInviteGuests(member(), "flagon-io"), true); |
| 55 | assert.equal(mayInviteGuests(member(true), "flagon-io"), true); |
| 56 | assert.equal(mayInviteGuests(member(false), "flagon-io"), false); |
| 57 | assert.equal(mayInviteGuests(person(), "flagon-io"), false); |
| 58 | assert.equal(mayInviteGuests(null, "flagon-io"), false); |
| 59 | }); |
| 60 | |
| 61 | test("only signed-in people with a confirmed address come in as guests", () => { |
| 62 | assert.equal(mayVisit(person()), null); |
| 63 | assert.match(mayVisit(null) ?? "", /Sign in/); |
| 64 | assert.match(mayVisit(person({ verified: false })) ?? "", /Confirm your email/); |
| 65 | assert.match(mayVisit(person({ kind: "workspace" })) ?? "", /Only people/); |
| 66 | }); |
| 67 | |
| 68 | test("letting someone in: anyone in the channel for a member; those who invite guests for anyone else", () => { |
| 69 | assert.equal(mayAdmit(true, true, false), true); |
| 70 | assert.equal(mayAdmit(false, true, false), false); |
| 71 | assert.equal(mayAdmit(false, true, true), true); |
| 72 | assert.equal(mayAdmit(true, false, true), false); |
| 73 | }); |
| 74 | |
| 75 | test("a request's note is trimmed, cut to length, and null when empty", () => { |
| 76 | assert.equal(requestNote(" hi "), "hi"); |
| 77 | assert.equal(requestNote(" "), null); |
| 78 | assert.equal(requestNote(42), null); |
| 79 | assert.equal(requestNote("x".repeat(MAX_REQUEST_NOTE + 10))?.length, MAX_REQUEST_NOTE); |
| 80 | }); |