import {NachklangFeedbackDB} from '../Feedback.db.js'; import {QuestionType} from '../feedback.interface.js'; import {AdminQuestion} from './admin.interface.js'; const mapRow = (row: any): AdminQuestion => ({ questionId: row.question_id, label: row.label, helpText: row.help_text, questionType: row.question_type, isArchived: !!row.is_archived }); export const listQuestions = async (includeArchived: boolean): Promise => { let conn = await NachklangFeedbackDB.getConnection(); try { const query = includeArchived ? 'SELECT * FROM questions ORDER BY created_at DESC' : 'SELECT * FROM questions WHERE is_archived = 0 ORDER BY created_at DESC'; const rows = await conn.query(query); return rows.map(mapRow); } finally { await conn.end(); } }; export const createQuestion = async (label: string, helpText: string | null, questionType: QuestionType): Promise => { let conn = await NachklangFeedbackDB.getConnection(); try { await conn.beginTransaction(); const res = await conn.query( 'INSERT INTO questions (label, help_text, question_type) VALUES (?,?,?) RETURNING question_id', [label, helpText, questionType] ); await conn.commit(); return res[0].question_id; } catch (err) { await conn.rollback(); throw err; } finally { await conn.end(); } }; /** * Edits label/help text only. question_type is immutable after creation - * changing it would invalidate existing answers' question_type_snapshot * semantics. The admin UI offers "archive and create new" instead. */ export const updateQuestion = async (questionId: number, label: string, helpText: string | null): Promise => { let conn = await NachklangFeedbackDB.getConnection(); try { await conn.beginTransaction(); const res = await conn.query('UPDATE questions SET label = ?, help_text = ? WHERE question_id = ?', [label, helpText, questionId]); await conn.commit(); return res.affectedRows > 0; } catch (err) { await conn.rollback(); throw err; } finally { await conn.end(); } }; export type RemoveQuestionResult = 'ARCHIVED' | 'DELETED' | 'NOT_FOUND'; /** * Archives (soft delete) a question. Hard-deletes it instead if it has * never been assigned to any event, so an admin's typo doesn't have to * live forever in the library. */ export const removeQuestion = async (questionId: number): Promise => { let conn = await NachklangFeedbackDB.getConnection(); try { await conn.beginTransaction(); const existsRows = await conn.query('SELECT 1 FROM questions WHERE question_id = ?', [questionId]); if (existsRows.length === 0) { await conn.rollback(); return 'NOT_FOUND'; } const usageRows = await conn.query('SELECT 1 FROM event_questions WHERE question_id = ? LIMIT 1', [questionId]); if (usageRows.length === 0) { await conn.query('DELETE FROM questions WHERE question_id = ?', [questionId]); await conn.commit(); return 'DELETED'; } await conn.query('UPDATE questions SET is_archived = 1 WHERE question_id = ?', [questionId]); await conn.commit(); return 'ARCHIVED'; } catch (err) { await conn.rollback(); throw err; } finally { await conn.end(); } };