fix featured

This commit is contained in:
Devin Zuczek
2026-07-08 09:53:33 -04:00
parent a029d0ed67
commit 1bb8389bcc
3 changed files with 81 additions and 0 deletions
+54
View File
@@ -533,6 +533,60 @@ export async function getRecommendedRooms(
.slice(skip, skip + take)
}
/** Compact room projection carried by a featured-room group. */
export interface FeaturedRoom {
RoomId: number
RoomName: string
ImageName: string
IsRecRoomApproved: boolean
ExcludeFromLists: boolean
ExcludeFromSearch: boolean
}
/** A time-boxed group of featured rooms, as returned by `/featuredrooms/current`. */
export interface FeaturedRoomGroup {
FeaturedRoomGroupId: number
name: string
StartAt: string
EndAt: string
Rooms: FeaturedRoom[]
}
/**
* Featured rooms group: public, non-dorm rooms not excluded from lists, in random
* order. There's no editorial curation behind this yet, so "featured" is just a
* random shuffle of the eligible rooms wrapped in a single always-active group.
* Small dataset, so done in memory.
*/
export async function getFeaturedRooms(db: D1Database): Promise<FeaturedRoomGroup> {
const { results } = await db.prepare('SELECT data FROM rooms').all<RoomRow>()
const rooms = parseAll(results).filter(
(r) => r.IsDorm !== true && r.Accessibility === 1 && r.ExcludeFromLists !== true
)
// FisherYates shuffle so the feed varies between requests.
for (let i = rooms.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1))
;[rooms[i], rooms[j]] = [rooms[j], rooms[i]]
}
const str = (v: unknown): string => (typeof v === 'string' ? v : '')
const num = (v: unknown): number => (typeof v === 'number' ? v : 0)
return {
FeaturedRoomGroupId: 1,
name: 'Featured Rooms',
StartAt: '2025-12-01T11:01:00Z',
EndAt: '9999-12-08T11:00:00Z',
Rooms: rooms.map((r) => ({
RoomId: num(r.RoomId),
RoomName: str(r.Name),
ImageName: str(r.ImageName),
IsRecRoomApproved: r.IsRecRoomApproved === true,
ExcludeFromLists: r.ExcludeFromLists === true,
ExcludeFromSearch: r.ExcludeFromSearch === true,
})),
}
}
/**
* Rooms similar to a target room: public, non-dorm rooms (excluding the target)
* that share at least one tag with it, ranked by shared-tag count then
+8
View File
@@ -10,6 +10,7 @@ import {
findSubRoom,
getBaseRooms,
getFavoritedRooms,
getFeaturedRooms,
getHotRooms,
getInteraction,
getPublicRoomsByCreator,
@@ -292,6 +293,13 @@ const app = new Hono<App>()
return c.json(await getRecommendedRooms(c.env.DB, skip, take))
})
// Featured rooms — a single always-active group whose `Rooms` are a randomly
// ordered set of public, non-dorm rooms. No real curation yet, so `current`
// just returns a shuffled list of eligible rooms in the featured-group shape.
.get('/featuredrooms/current', async (c) => {
return c.json(await getFeaturedRooms(c.env.DB))
})
// Bulk room lookup by `id` or `name` — returns an array of matched rooms (the
// client calls this bare on the rooms host). Rooms not in D1 are simply absent
// from the result; the client treats an empty result as NoSuchRoom.
@@ -340,6 +340,25 @@ describe('rooms endpoints', () => {
expect(body.length).toBeLessThanOrEqual(3)
})
it('GET /featuredrooms/current returns a featured-room group of public rooms', async () => {
const res = await SELF.fetch(`${ORIGIN}/featuredrooms/current`)
expect(res.status).toBe(200)
const body = (await res.json()) as {
FeaturedRoomGroupId: number
name: string
StartAt: string
EndAt: string
Rooms: Array<{ RoomId: number; RoomName: string; ImageName: string }>
}
expect(body.FeaturedRoomGroupId).toBe(1)
expect(body.name).toBe('Featured Rooms')
expect(body.Rooms.length).toBeGreaterThan(0)
// Compact projection carries name + image, not the full room blob.
expect(body.Rooms.every((r) => typeof r.RoomName === 'string')).toBe(true)
// The dorm (RoomId 1) is non-public, so it's never featured.
expect(body.Rooms.some((r) => r.RoomId === 1)).toBe(false)
})
it('GET /rooms/:id/similar returns { Results, TotalResults } of tag-sharing rooms (excluding self)', async () => {
const res = await SELF.fetch(`${ORIGIN}/rooms/2/similar`)
expect(res.status).toBe(200)