Public: anyone can read this; the crew can change it.
A visitor is told to put someone on a crew that is not theirs #517
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/231-a-visitor-is-told-to-put-someone-on-a-cr → main 1 commit fork
2 files
changed +42
−2
src/web/studio/now.ts +5 −2
| @@ -291,9 +291,12 @@ export async function nowCard( | ||
| 291 | 291 | return row({ |
| 292 | 292 | lead: avatar("crew"), |
| 293 | 293 | title: html`<a href="${tellHref(base, i.number)}">${i.title}</a>`, |
| 294 | // The invitation is a writer's (the shelf's rule, `ownerFacts`); the | |
| 295 | // fact — nobody has taken it — stays for everyone. | |
| 294 | 296 | meta: html`told ${time(i.createdAt)} · |
| 295 | <span class="muted">nobody on the crew to take it —</span> | |
| 296 | <a href="${base}/settings">add someone</a>`, | |
| 297 | <span class="muted">nobody on the crew to take it</span>${ownerFacts | |
| 298 | ? html` — <a href="${base}/settings">add someone</a>` | |
| 299 | : null}`, | |
| 297 | 300 | trail: wordBadge("told"), |
| 298 | 301 | }); |
| 299 | 302 | }), |
test/studio.test.ts +37
| @@ -4592,6 +4592,43 @@ describe('a tell nobody on the crew can take is not "quiet"', () => { | ||
| 4592 | 4592 | expect(shelfRow).not.toContain("quiet — tell the crew something"); |
| 4593 | 4593 | expect(shelfRow).toContain("nobody on the crew to take it"); |
| 4594 | 4594 | }); |
| 4595 | ||
| 4596 | test("a reader of the public app sees the fact, not the owner's invitation or a link to settings", async () => { | |
| 4597 | app.db.run("UPDATE repo SET visibility = 'public' WHERE id = ?", [ | |
| 4598 | repo.id, | |
| 4599 | ]); | |
| 4600 | const b = await createUser(app.db, { | |
| 4601 | username: "bob", | |
| 4602 | email: "[email protected]", | |
| 4603 | password: "a-good-passphrase", | |
| 4604 | }); | |
| 4605 | if (!b.ok) throw new Error(b.error); | |
| 4606 | const bobCookie = ( | |
| 4607 | ( | |
| 4608 | await fetch(`${base}/signin`, { | |
| 4609 | method: "POST", | |
| 4610 | body: new URLSearchParams({ | |
| 4611 | username: "bob", | |
| 4612 | password: "a-good-passphrase", | |
| 4613 | }), | |
| 4614 | redirect: "manual", | |
| 4615 | }) | |
| 4616 | ).headers.get("set-cookie") ?? "" | |
| 4617 | ).split(";")[0]!; | |
| 4618 | const read = await ( | |
| 4619 | await fetch(`${base}/alice/pad`, { | |
| 4620 | headers: { cookie: `${bobCookie}; forge_mode=studio` }, | |
| 4621 | }) | |
| 4622 | ).text(); | |
| 4623 | expect(read).toContain("Add a dark mode toggle."); | |
| 4624 | expect(read).toContain("nobody on the crew to take it"); | |
| 4625 | expect(read).not.toContain("add someone"); | |
| 4626 | expect(read).not.toContain(`href="/alice/pad/settings"`); | |
| 4627 | // The writer still gets the invitation, link included. | |
| 4628 | const write = await (await get("/alice/pad")).text(); | |
| 4629 | expect(write).toContain("add someone"); | |
| 4630 | expect(write).toContain(`href="/alice/pad/settings"`); | |
| 4631 | }); | |
| 4595 | 4632 | }); |
| 4596 | 4633 | |
| 4597 | 4634 | /** |
new above
offline