From 5345bd051775722659787a1aa37d10a83b7ea4ba Mon Sep 17 00:00:00 2001 From: Devin Zuczek Date: Wed, 15 Jul 2026 16:20:57 -0400 Subject: [PATCH] fix room publish --- apps/rooms/src/rooms.app.ts | 27 +++++++++++++++++++++ apps/rooms/src/test/integration/api.test.ts | 25 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/apps/rooms/src/rooms.app.ts b/apps/rooms/src/rooms.app.ts index 376a57c..abb880c 100644 --- a/apps/rooms/src/rooms.app.ts +++ b/apps/rooms/src/rooms.app.ts @@ -725,6 +725,33 @@ const app = new Hono() return roomEnvelope(c, updated) }) + // Set a room's top-level `Accessibility` (the visibility the public-room/search + // filters key on — see the RoomAccessibility enum). Auth-gated (401) and + // owner/co-owner-only (403). Body is the `accessibility` form field (an integer). + // Returns the updated room in the `{ success, error, value }` envelope. + .put('/rooms/:roomId{[0-9]+}/accessibility', async (c) => { + const accountId = await authedAccountId(c) + if (accountId === null) return unauthorized(c) + + const roomId = Number.parseInt(c.req.param('roomId'), 10) + const room = await getRoomById(c.env.DB, roomId) + if (!room) return roomEnvelope(c, null, 'This room does not exist!') + // A valid token but not the room's owner/co-owner → 403 (the auth gate above + // already returned 401 for a missing/invalid token). + if (!canManageRoom(room, accountId)) return c.body(null, 403) + + const body = (await c.req.parseBody().catch(() => ({}))) as Record + const accessibility = + typeof body.accessibility === 'string' ? Number.parseInt(body.accessibility, 10) : Number.NaN + if (Number.isNaN(accessibility)) { + return roomEnvelope(c, null, 'You must provide a valid accessibility!') + } + + const updated = await updateRoomFields(c.env.DB, roomId, room, { Accessibility: accessibility }) + await pushRoomUpdate(c, accountId, updated) + return roomEnvelope(c, updated) + }) + // A subroom's data descriptor (the SubRoom object from the room's SubRooms // array). Public — the client fetches it while loading the room. 404 when the // room or subroom is unknown. diff --git a/apps/rooms/src/test/integration/api.test.ts b/apps/rooms/src/test/integration/api.test.ts index 69e4714..7db17ba 100644 --- a/apps/rooms/src/test/integration/api.test.ts +++ b/apps/rooms/src/test/integration/api.test.ts @@ -794,6 +794,31 @@ describe('rooms endpoints', () => { expect(await screensOf()).toContainEqual({ ImageName: 'second.jpg', Title: '', Subtitle: '' }) }) + it('PUT /rooms/:id/accessibility sets the room-level Accessibility (auth-gated, owner/co-owner-only)', async () => { + // No token → 401; a valid token with no role → 403. + expect((await putForm('/rooms/2/accessibility', { accessibility: '1' })).status).toBe(401) + expect((await putForm('/rooms/2/accessibility', { accessibility: '1' }, '999')).status).toBe(403) + // Unknown room → failure envelope. + expect( + await envOf(await putForm('/rooms/99999/accessibility', { accessibility: '1' }, '1')) + ).toMatchObject({ success: false, error: 'This room does not exist!' }) + // Non-numeric → failure envelope. + expect( + await envOf(await putForm('/rooms/2/accessibility', { accessibility: 'x' }, '1')) + ).toMatchObject({ success: false }) + + // Owner sets it (0 = Private); the success envelope carries the updated room. + const priv = await envOf(await putForm('/rooms/2/accessibility', { accessibility: '0' }, '1')) + expect(priv).toMatchObject({ success: true, error: '' }) + expect(priv.value?.Accessibility).toBe(0) + const room = (await (await SELF.fetch(`${ORIGIN}/rooms/2`)).json()) as { Accessibility: number } + expect(room.Accessibility).toBe(0) + + // The co-owner (account 2) may set it back to public (1). + const pub = await envOf(await putForm('/rooms/2/accessibility', { accessibility: '1' }, '2')) + expect(pub.value?.Accessibility).toBe(1) + }) + it('GET /rooms/:id/subrooms/:sid/data returns the subroom descriptor (404 when unknown)', async () => { // Room 2 has SubRoomId 2 in the seed. const res = await SELF.fetch(`${ORIGIN}/rooms/2/subrooms/2/data`)