mirror of
https://github.com/djdevin/recflare.git
synced 2026-09-08 14:41:28 -07:00
fix featured
This commit is contained in:
@@ -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
|
||||
)
|
||||
// Fisher–Yates 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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user