mirror of
https://github.com/djdevin/recflare.git
synced 2026-10-25 23:18:51 -07:00
[rooms] obey excludefromlists
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
-- The flag SEARCH filters on, as an indexed column — the search-side twin of
|
||||
-- `exclude_from_lists` (0014).
|
||||
--
|
||||
-- Generated from packages/domain/src/rooms-db.ts (ROOM_SCHEMA_DDL) — keep in sync.
|
||||
--
|
||||
-- `ExcludeFromLists` keeps a room out of the browse and discovery feeds; `ExcludeFromSearch`
|
||||
-- keeps it out of `/rooms/search` and the search box's suggestions. They are independent:
|
||||
-- a room may opt out of the feeds and still be findable by name, or the other way round.
|
||||
-- Until now nothing read `ExcludeFromSearch` at all, so an opted-out room was served by
|
||||
-- every search that matched it.
|
||||
--
|
||||
-- VIRTUAL like `exclude_from_lists`, so the blob stays the only copy and no backfill is
|
||||
-- needed. It is not added to `idx_room_public`: that partial index already narrows a search
|
||||
-- to the public, non-dorm rooms, and this term is then checked against the handful of rows
|
||||
-- it fetched — see SEARCHABLE_WHERE.
|
||||
ALTER TABLE room ADD COLUMN exclude_from_search INTEGER GENERATED ALWAYS AS (json_extract(data, '$.ExcludeFromSearch')) VIRTUAL;
|
||||
@@ -1179,8 +1179,9 @@ const app = new Hono<App>()
|
||||
)
|
||||
|
||||
// Room search: `query` is space/`+`-separated terms — `#tag` matches room tags,
|
||||
// plain terms match the name. Public, non-dorm rooms only. Paginated via
|
||||
// skip/take. Returns `{ Results, TotalResults }`.
|
||||
// plain terms match the name. Public, non-dorm rooms not opted out of search
|
||||
// (`ExcludeFromSearch`) only — `ExcludeFromLists` is the feeds' flag and does not hide
|
||||
// a room here. Paginated via skip/take. Returns `{ Results, TotalResults }`.
|
||||
//
|
||||
// `#community` is the one tag term that isn't a tag lookup: it is the browse chip's
|
||||
// pseudo-tag reaching search, and means rooms a PLAYER made rather than the seeded
|
||||
@@ -1192,7 +1193,9 @@ const app = new Hono<App>()
|
||||
summary: 'Search rooms',
|
||||
description: [
|
||||
'Full room search. `query` is space- or `+`-separated terms: a `#tag` term matches the',
|
||||
'room’s tags, a plain term matches its name. Public, non-dorm rooms only.',
|
||||
'room’s tags, a plain term matches its name. Public, non-dorm rooms only, and never one',
|
||||
'whose `ExcludeFromSearch` is set; `ExcludeFromLists` hides a room from the feeds, not',
|
||||
'from here.',
|
||||
'`#community` is a pseudo-tag no room carries — it narrows to rooms a player made',
|
||||
'(anything the system Coach account didn’t create), like `/rooms/hot?tag=community`.',
|
||||
].join(' '),
|
||||
@@ -1218,8 +1221,9 @@ const app = new Hono<App>()
|
||||
//
|
||||
// Every suggestion is something `/rooms/search` will actually find, so submitting one
|
||||
// can't come back empty: they're drawn from room names (what a plain search term
|
||||
// matches) and room tags (what a `#tag` term matches), over the same public, non-dorm
|
||||
// rooms search considers. Tags come back with their `#` for that reason.
|
||||
// matches) and room tags (what a `#tag` term matches), over the same public, non-dorm,
|
||||
// searchable rooms search considers — a room opted out of search is not suggested
|
||||
// either. Tags come back with their `#` for that reason.
|
||||
//
|
||||
// `searchSessionId` is the client's own correlation id for a typing session — it ties
|
||||
// the keystrokes and the eventual search together in the reference's analytics. Nothing
|
||||
@@ -1231,8 +1235,9 @@ const app = new Hono<App>()
|
||||
summary: 'Search suggestions for the search box',
|
||||
description: [
|
||||
'Type-ahead suggestions as a bare array of strings — not rooms, not an envelope.',
|
||||
'Drawn from room names and room tags over the public, non-dorm rooms `/rooms/search`',
|
||||
'searches, so every suggestion is one that finds something when submitted; a tag',
|
||||
'Drawn from room names and room tags over the public, non-dorm, searchable rooms',
|
||||
'`/rooms/search` searches, so every suggestion is one that finds something when',
|
||||
'submitted and a room opted out of search is never suggested; a tag',
|
||||
'suggestion carries its `#` so it searches by tag. A `query` starting with `#`',
|
||||
'suggests tags only. Matches that START with the query come first, then ones that',
|
||||
'merely contain it, alphabetically within each — the same query always suggests the',
|
||||
|
||||
@@ -1204,7 +1204,7 @@ describe('rooms endpoints', () => {
|
||||
IsDorm: false,
|
||||
SubRooms: [],
|
||||
})
|
||||
// Same room, opted out.
|
||||
// Same room, opted out of the feeds.
|
||||
await seed({
|
||||
RoomId: 30802,
|
||||
Name: 'OptedOut',
|
||||
@@ -1214,6 +1214,16 @@ describe('rooms endpoints', () => {
|
||||
ExcludeFromLists: true,
|
||||
SubRooms: [],
|
||||
})
|
||||
// And one opted out of SEARCH instead — the other flag, which the feeds ignore.
|
||||
await seed({
|
||||
RoomId: 30803,
|
||||
Name: 'Unsearchable',
|
||||
CreatorAccountId: 830,
|
||||
Accessibility: 1,
|
||||
IsDorm: false,
|
||||
ExcludeFromSearch: true,
|
||||
SubRooms: [],
|
||||
})
|
||||
|
||||
const namesIn = async (path: string) => {
|
||||
const body = (await (await SELF.fetch(`${ORIGIN}${path}`)).json()) as
|
||||
@@ -1224,13 +1234,22 @@ describe('rooms endpoints', () => {
|
||||
for (const feed of ['/rooms/hot?take=200', '/rooms/recommendations?take=200']) {
|
||||
expect(await namesIn(feed)).toContain('NoExcludeKey')
|
||||
expect(await namesIn(feed)).not.toContain('OptedOut')
|
||||
// `ExcludeFromSearch` is search's flag, not the feeds': the room still lists.
|
||||
expect(await namesIn(feed)).toContain('Unsearchable')
|
||||
}
|
||||
|
||||
// SEARCH is the wider filter (PUBLIC_WHERE): a room can opt out of the browse feeds
|
||||
// and still be findable by name, so this must not have narrowed with the feeds.
|
||||
// SEARCH is its own filter (SEARCHABLE_WHERE): a room can opt out of the browse feeds
|
||||
// and still be findable by name, so this must not have narrowed with the feeds…
|
||||
expect(await namesIn('/rooms/search?query=optedout')).toContain('OptedOut')
|
||||
// …while a room opted out of SEARCH is not found, by name or by the missing key's
|
||||
// opposite — and the suggestion box, which draws from the same rooms, never offers it.
|
||||
expect(await namesIn('/rooms/search?query=unsearchable')).toEqual([])
|
||||
expect(await namesIn('/rooms/search?query=noexcludekey')).toContain('NoExcludeKey')
|
||||
expect(
|
||||
await (await SELF.fetch(`${ORIGIN}/rooms/autocomplete_search?query=unsearch&take=10`)).json()
|
||||
).toEqual([])
|
||||
|
||||
await env.DB.prepare('DELETE FROM room WHERE room_id IN (30801, 30802)').run()
|
||||
await env.DB.prepare('DELETE FROM room WHERE room_id IN (30801, 30802, 30803)').run()
|
||||
})
|
||||
|
||||
// Served only to the client builds that render it — the 2023 client's other room
|
||||
|
||||
Reference in New Issue
Block a user