From 8e0fe29bec2d830036d7f98aab4c1347ef5f77e5 Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Thu, 8 Jan 2026 20:10:21 +1300 Subject: [PATCH] Web accessibility --- src/web/pug/guild_not_linked.pug | 2 +- src/web/pug/includes/template.pug | 6 +- src/web/routes/guild.test.js | 102 ++++++++++++++++++++++++++---- 3 files changed, 95 insertions(+), 15 deletions(-) diff --git a/src/web/pug/guild_not_linked.pug b/src/web/pug/guild_not_linked.pug index 59de2fb..61c57e9 100644 --- a/src/web/pug/guild_not_linked.pug +++ b/src/web/pug/guild_not_linked.pug @@ -4,7 +4,7 @@ mixin space(space) .s-user-card.flex__1 span.s-avatar.s-avatar__32.s-user-card--avatar if space.avatar - img.s-avatar--image(src=mUtils.getPublicUrlForMxc(space.avatar)) + img.s-avatar--image(src=mUtils.getPublicUrlForMxc(space.avatar) alt="") else .s-avatar--letter.bg-silver-400.bar-md(aria-hidden="true")= space.name[0] .s-user-card--info.ai-start diff --git a/src/web/pug/includes/template.pug b/src/web/pug/includes/template.pug index d9f1c30..93aaefc 100644 --- a/src/web/pug/includes/template.pug +++ b/src/web/pug/includes/template.pug @@ -1,7 +1,7 @@ mixin guild(guild) span.s-avatar.s-avatar__32.s-user-card--avatar if guild.icon - img.s-avatar--image(src=`https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.png?size=32`) + img.s-avatar--image(src=`https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.png?size=32` alt="") else .s-avatar--letter.bg-silver-400.bar-md(aria-hidden="true")= guild.name[0] .s-user-card--info.ai-start @@ -82,10 +82,10 @@ html(lang="en") +define-themed-button("matrix", "black") body.themed.theme-system header.s-topbar - .s-topbar--skip-link(href="#content") Skip to main content + a.s-topbar--skip-link(href="#content") Skip to main content .s-topbar--container.wmx9 a.s-topbar--logo(href=rel("/")) - img.s-avatar.s-avatar__32(src=rel("/icon.png")) + img.s-avatar.s-avatar__32(src=rel("/icon.png") alt="") nav.s-topbar--navigation ul.s-topbar--content li.ps-relative.g8 diff --git a/src/web/routes/guild.test.js b/src/web/routes/guild.test.js index ea59173..bb77c12 100644 --- a/src/web/routes/guild.test.js +++ b/src/web/routes/guild.test.js @@ -89,7 +89,7 @@ test("web guild: unbridged self-service guild shows available spaces", async t = }) t.has(html, `Data Horde`) t.has(html, `
  • here is the space topic
  • `) - t.has(html, ``) + t.has(html, ``) t.notMatch(html, /some room<\/strong>/) t.notMatch(html, /somebody else's space<\/strong>/) }) @@ -190,21 +190,66 @@ test("api invite: can invite with valid nonce", async t => { api: { async getStateEvent(roomID, type, key) { called++ - return {membership: "leave"} + if (type === "m.room.member" && key === "@cadence:cadence.moe") { + return {membership: "leave"} + } else if (type === "m.room.power_levels" && key === "") { + return {} + } else { + t.fail(`unexpected getStateEvent call. roomID: ${roomID}, type: ${type}, key: ${key}`) + } + }, + async getStateEventOuter(roomID, type, key) { + called++ + return { + type: "m.room.create", + state_key: "", + sender: "@_ooye_bot:cadence.moe", + event_id: "$create", + origin_server_ts: 0, + room_id: roomID, + content: { + room_version: "11" + } + } }, async inviteToRoom(roomID, mxidToInvite, mxid) { + called++ t.equal(roomID, "!jjmvBegULiLucuWEHU:cadence.moe") - called++ }, - async setUserPowerCascade(roomID, mxid, power) { - t.equal(power, 50) // moderator + async *generateFullHierarchy(spaceID) { called++ + yield { + room_id: "!hierarchy", + children_state: [], + guest_can_join: false, + num_joined_members: 2, + } + }, + async sendState(roomID, type, key, content) { + called++ + t.ok(["!hierarchy", "!jjmvBegULiLucuWEHU:cadence.moe"].includes(roomID), `expected room ID to be in hierarchy, but was ${roomID}`) + t.equal(type, "m.room.power_levels") + t.equal(key, "") + t.deepEqual(content, { + users: {"@cadence:cadence.moe": 50} + }) + return "$updated" } } }) ) t.notOk(error) - t.equal(called, 3) + /* + 1. get membership + 2. invite to room + set power: + 3. generate hierarchy + 4-5. calculate powers + 6. send state + 7-8. calculate powers + 9. send state + */ + t.equal(called, 9) // get membership + }) test("api invite: access denied when nonce has been used", async t => { @@ -235,21 +280,56 @@ test("api invite: can invite to a moderated guild", async t => { api: { async getStateEvent(roomID, type, key) { called++ - throw new MatrixServerError({errcode: "M_NOT_FOUND", error: "Event not found or something"}) + if (type === "m.room.member" && key === "@cadence:cadence.moe") { + return {membership: "leave"} + } else if (type === "m.room.power_levels" && key === "") { + return {} + } else { + t.fail(`unexpected getStateEvent call. roomID: ${roomID}, type: ${type}, key: ${key}`) + } + }, + async getStateEventOuter(roomID, type, key) { + called++ + return { + type: "m.room.create", + state_key: "", + sender: "@_ooye_bot:cadence.moe", + event_id: "$create", + origin_server_ts: 0, + room_id: roomID, + content: { + room_version: "11" + } + } }, async inviteToRoom(roomID, mxidToInvite, mxid) { + called++ t.equal(roomID, "!jjmvBegULiLucuWEHU:cadence.moe") - called++ }, - async setUserPowerCascade(roomID, mxid, power) { - t.equal(power, 100) // moderator + async *generateFullHierarchy(spaceID) { called++ + yield { + room_id: "!hierarchy", + children_state: [], + guest_can_join: false, + num_joined_members: 2, + } + }, + async sendState(roomID, type, key, content) { + called++ + t.ok(["!hierarchy", "!jjmvBegULiLucuWEHU:cadence.moe"].includes(roomID), `expected room ID to be in hierarchy, but was ${roomID}`) + t.equal(type, "m.room.power_levels") + t.equal(key, "") + t.deepEqual(content, { + users: {"@cadence:cadence.moe": 100} + }) + return "$updated" } } }) ) t.notOk(error) - t.equal(called, 3) + t.equal(called, 9) }) test("api invite: does not reinvite joined users", async t => {