Add search to the admin guest book endpoint

At scale (many submissions after a concert), paging through the guest book 20 entries at a time with no way to find a specific person is impractical. Add an optional ?search= query param that filters entries whose name or message contains the term (case-insensitive), with LIKE wildcards escaped so a literal % or _ in a search term can't be misinterpreted as a pattern.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-13 21:32:32 +02:00
parent 07d757e9af
commit 2988a70d8f
2 changed files with 27 additions and 5 deletions
@@ -166,13 +166,29 @@ export interface GuestBookEntry {
message: string | null;
}
export const getGuestBookEntries = async (eventId: number, page: number, pageSize: number): Promise<{entries: GuestBookEntry[]; total: number}> => {
// Escapes LIKE wildcards (% and _) so a search term is matched literally,
// not interpreted as a pattern - a search for "50%" must not match everything.
const escapeLikeTerm = (term: string) => term.replace(/[\\%_]/g, (c) => `\\${c}`);
export const getGuestBookEntries = async (
eventId: number,
page: number,
pageSize: number,
search?: string
): Promise<{entries: GuestBookEntry[]; total: number}> => {
let conn = await NachklangFeedbackDB.getConnection();
try {
const totalRows = await conn.query('SELECT COUNT(*) as cnt FROM guest_book_entries WHERE event_id = ?', [eventId]);
const trimmedSearch = search?.trim();
const whereClause = trimmedSearch
? 'WHERE event_id = ? AND (display_name LIKE ? ESCAPE \'\\\\\' OR message LIKE ? ESCAPE \'\\\\\')'
: 'WHERE event_id = ?';
const likeParam = trimmedSearch ? `%${escapeLikeTerm(trimmedSearch)}%` : undefined;
const whereParams = trimmedSearch ? [eventId, likeParam, likeParam] : [eventId];
const totalRows = await conn.query(`SELECT COUNT(*) as cnt FROM guest_book_entries ${whereClause}`, whereParams);
const rows = await conn.query(
'SELECT entry_id, submission_id, created_at, display_name, message FROM guest_book_entries WHERE event_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ?',
[eventId, pageSize, (page - 1) * pageSize]
`SELECT entry_id, submission_id, created_at, display_name, message FROM guest_book_entries ${whereClause} ORDER BY created_at DESC LIMIT ? OFFSET ?`,
[...whereParams, pageSize, (page - 1) * pageSize]
);
return {
total: Number(totalRows[0].cnt),