Allow dev CORS from LAN IPs; add submission deletion
The dev-only CORS bypass in app.ts only ever matched http://localhost:<port>, never the LAN IP a phone actually connects through over WiFi - so testing the feedback form from a real device against a local dev API had its submissions silently rejected by CORS. Extended the bypass to also allow private LAN ranges (192.168.x.x, 10.x.x.x, 172.16-31.x.x), dev-only as before. Also adds DELETE /feedback/admin/submissions/:submissionId (cascades to the submission's answers, guest book entry, and newsletter signup in explicit dependency order, single-path by submission_id) so an admin can remove an individual abusive/inappropriate entry - decided in IMPLEMENTATION_PLAN.md §7 item 8. getGuestBookEntries now also returns submissionId so the admin UI can target the delete call. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -160,6 +160,7 @@ export const getReport = async (eventId: number): Promise<EventReport | null> =>
|
||||
|
||||
export interface GuestBookEntry {
|
||||
entryId: number;
|
||||
submissionId: number;
|
||||
submittedAt: string;
|
||||
displayName: string | null;
|
||||
message: string | null;
|
||||
@@ -170,12 +171,18 @@ export const getGuestBookEntries = async (eventId: number, page: number, pageSiz
|
||||
try {
|
||||
const totalRows = await conn.query('SELECT COUNT(*) as cnt FROM guest_book_entries WHERE event_id = ?', [eventId]);
|
||||
const rows = await conn.query(
|
||||
'SELECT entry_id, created_at, display_name, message FROM guest_book_entries WHERE event_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ?',
|
||||
'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]
|
||||
);
|
||||
return {
|
||||
total: Number(totalRows[0].cnt),
|
||||
entries: rows.map((r: any) => ({entryId: r.entry_id, submittedAt: r.created_at, displayName: r.display_name, message: r.message}))
|
||||
entries: rows.map((r: any) => ({
|
||||
entryId: r.entry_id,
|
||||
submissionId: r.submission_id,
|
||||
submittedAt: r.created_at,
|
||||
displayName: r.display_name,
|
||||
message: r.message
|
||||
}))
|
||||
};
|
||||
} finally {
|
||||
await conn.end();
|
||||
@@ -192,6 +199,39 @@ export interface NewsletterSignupRow {
|
||||
lastError: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes one submission and everything under it (its answers, guest book
|
||||
* entry, newsletter signup). Single-path deletes by submission_id - unlike
|
||||
* deleteEvent's multi-path cascade issue, there's only one way to reach each
|
||||
* child table here, so explicit ordering is for consistency with that
|
||||
* function's style, not to work around an ambiguous-cascade error.
|
||||
*/
|
||||
export const deleteSubmission = async (submissionId: number): Promise<boolean> => {
|
||||
let conn = await NachklangFeedbackDB.getConnection();
|
||||
try {
|
||||
await conn.beginTransaction();
|
||||
|
||||
const rows = await conn.query('SELECT submission_id FROM submissions WHERE submission_id = ?', [submissionId]);
|
||||
if (rows.length === 0) {
|
||||
await conn.rollback();
|
||||
return false;
|
||||
}
|
||||
|
||||
await conn.query('DELETE FROM guest_book_entries WHERE submission_id = ?', [submissionId]);
|
||||
await conn.query('DELETE FROM newsletter_signups WHERE submission_id = ?', [submissionId]);
|
||||
await conn.query('DELETE FROM submission_answers WHERE submission_id = ?', [submissionId]);
|
||||
await conn.query('DELETE FROM submissions WHERE submission_id = ?', [submissionId]);
|
||||
|
||||
await conn.commit();
|
||||
return true;
|
||||
} catch (err) {
|
||||
await conn.rollback();
|
||||
throw err;
|
||||
} finally {
|
||||
await conn.end();
|
||||
}
|
||||
};
|
||||
|
||||
export const getNewsletterSignups = async (eventId: number): Promise<NewsletterSignupRow[]> => {
|
||||
let conn = await NachklangFeedbackDB.getConnection();
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user