mirror of
https://github.com/djdevin/recflare.git
synced 2026-09-08 14:41:28 -07:00
[rooms] fix bulk loading issue
This commit is contained in:
+27
-10
@@ -167,6 +167,14 @@ function tooManyIds(c: Context<App>) {
|
|||||||
return c.json(`At most ${MAX_BULK_ROOM_IDS} room ids may be looked up at once`, 400)
|
return c.json(`At most ${MAX_BULK_ROOM_IDS} room ids may be looked up at once`, 400)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether a bulk lookup asked for the public-only filter. The client sends the C# spelling
|
||||||
|
* (`True`/`False`) and absent means False, so anything but a case-insensitive `true` is off.
|
||||||
|
*/
|
||||||
|
function excludePrivateRooms(value: string | undefined): boolean {
|
||||||
|
return (value ?? '').toLowerCase() === 'true'
|
||||||
|
}
|
||||||
|
|
||||||
function allIds(idParam: string): number[] {
|
function allIds(idParam: string): number[] {
|
||||||
return idParam
|
return idParam
|
||||||
.split(',')
|
.split(',')
|
||||||
@@ -939,13 +947,15 @@ const app = new Hono<App>()
|
|||||||
tags: ['Rooms'],
|
tags: ['Rooms'],
|
||||||
summary: 'Look up several rooms at once',
|
summary: 'Look up several rooms at once',
|
||||||
description: [
|
description: [
|
||||||
'Rooms by a comma-separated `id` list, or a single `name`. Ids that aren’t in D1 are',
|
'Rooms by `id` — repeated `id` params, a comma-separated list, or both — or a single',
|
||||||
'simply absent from the result rather than an error — the client reads an empty result',
|
'`name`. Ids that aren’t in D1 are simply absent from the result rather than an error —',
|
||||||
'as NoSuchRoom.',
|
'the client reads an empty result as NoSuchRoom. `excludePrivateRooms=True` drops rooms',
|
||||||
|
'that are not publicly visible, as on the POST.',
|
||||||
].join(' '),
|
].join(' '),
|
||||||
parameters: [
|
parameters: [
|
||||||
stringQuery('id', 'Comma-separated room ids'),
|
stringQuery('id', 'Room ids — repeated `id` fields, comma-separated, or both'),
|
||||||
stringQuery('name', 'A single room name. Ignored when `id` is given'),
|
stringQuery('name', 'A single room name. Ignored when `id` is given'),
|
||||||
|
stringQuery('excludePrivateRooms', 'True drops rooms that are not publicly visible'),
|
||||||
],
|
],
|
||||||
responses: {
|
responses: {
|
||||||
200: json(RoomDto.array(), 'The rooms that matched (missing ids are omitted)'),
|
200: json(RoomDto.array(), 'The rooms that matched (missing ids are omitted)'),
|
||||||
@@ -956,15 +966,22 @@ const app = new Hono<App>()
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
const idParam = c.req.query('id')
|
// `id` repeats (`?id=641&id=657`) as often as it is comma-separated, and the client
|
||||||
|
// spells it both ways — read every occurrence, then split each on commas.
|
||||||
|
const idParams = c.req.queries('id') ?? []
|
||||||
const nameParam = c.req.query('name')
|
const nameParam = c.req.query('name')
|
||||||
if (!idParam && !nameParam) {
|
if (idParams.length === 0 && !nameParam) {
|
||||||
return c.json("Either 'id' or 'name' query parameter is required", 400)
|
return c.json("Either 'id' or 'name' query parameter is required", 400)
|
||||||
}
|
}
|
||||||
if (idParam) {
|
if (idParams.length > 0) {
|
||||||
const ids = allIds(idParam)
|
const ids = idParams.flatMap(allIds)
|
||||||
if (ids.length > MAX_BULK_ROOM_IDS) return tooManyIds(c)
|
if (ids.length > MAX_BULK_ROOM_IDS) return tooManyIds(c)
|
||||||
return c.json(await getRoomsByIds(c.env.DB, ids))
|
const rooms = await getRoomsByIds(c.env.DB, ids)
|
||||||
|
return c.json(
|
||||||
|
excludePrivateRooms(c.req.query('excludePrivateRooms'))
|
||||||
|
? rooms.filter((r) => r.Accessibility === 1)
|
||||||
|
: rooms
|
||||||
|
)
|
||||||
}
|
}
|
||||||
const room = await getRoomByName(c.env.DB, nameParam ?? '')
|
const room = await getRoomByName(c.env.DB, nameParam ?? '')
|
||||||
return c.json(room ? [room] : [])
|
return c.json(room ? [room] : [])
|
||||||
@@ -1018,7 +1035,7 @@ const app = new Hono<App>()
|
|||||||
if (ids.length > MAX_BULK_ROOM_IDS) return tooManyIds(c)
|
if (ids.length > MAX_BULK_ROOM_IDS) return tooManyIds(c)
|
||||||
const rooms = await getRoomsByIds(c.env.DB, ids)
|
const rooms = await getRoomsByIds(c.env.DB, ids)
|
||||||
|
|
||||||
const excludePrivate = (field('excludePrivateRooms')[0] ?? '').toLowerCase() === 'true'
|
const excludePrivate = excludePrivateRooms(field('excludePrivateRooms')[0])
|
||||||
return c.json(excludePrivate ? rooms.filter((r) => r.Accessibility === 1) : rooms)
|
return c.json(excludePrivate ? rooms.filter((r) => r.Accessibility === 1) : rooms)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -219,6 +219,17 @@ describe('rooms endpoints', () => {
|
|||||||
expect(body.map((r) => r.Name).sort()).toEqual(['DormRoom', 'RecCenter'])
|
expect(body.map((r) => r.Name).sort()).toEqual(['DormRoom', 'RecCenter'])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('GET /rooms/bulk takes repeated id params, like the POST form', async () => {
|
||||||
|
// The client spells the GET's id list the same way it spells the POST body's — one
|
||||||
|
// `id` per room. Reading only the first left it rendering a single room.
|
||||||
|
const res = await SELF.fetch(
|
||||||
|
`${ORIGIN}/rooms/bulk?id=1&id=2&id=999999&excludePrivateRooms=False`
|
||||||
|
)
|
||||||
|
expect(res.status).toBe(200)
|
||||||
|
const body = (await res.json()) as Array<{ Name: string }>
|
||||||
|
expect(body.map((r) => r.Name).sort()).toEqual(['DormRoom', 'RecCenter'])
|
||||||
|
})
|
||||||
|
|
||||||
it('GET /rooms/bulk?name=RecCenter returns [RecCenter]', async () => {
|
it('GET /rooms/bulk?name=RecCenter returns [RecCenter]', async () => {
|
||||||
const res = await SELF.fetch(`${ORIGIN}/rooms/bulk?name=RecCenter`)
|
const res = await SELF.fetch(`${ORIGIN}/rooms/bulk?name=RecCenter`)
|
||||||
const body = (await res.json()) as Array<{ Name: string }>
|
const body = (await res.json()) as Array<{ Name: string }>
|
||||||
|
|||||||
Reference in New Issue
Block a user