Add Feedback domain module: public submission flow, admin CRUD, reporting (#7)
Jenkins Production Deployment

Co-authored-by: Patrick Müller <mail@pmueller.me>
Reviewed-on: #7
Co-authored-by: Patrick Mueller <patrick@mueller-patrick.tech>
Co-committed-by: Patrick Mueller <patrick@mueller-patrick.tech>
This commit was merged in pull request #7.
This commit is contained in:
2026-08-23 09:39:02 +00:00
committed by Patrick Müller
parent e7621b8290
commit b05f6b9da0
38 changed files with 4115 additions and 2 deletions
@@ -0,0 +1,56 @@
import {NachklangFeedbackDB} from '../Feedback.db';
export const addSong = async (eventId: number, title: string, composer: string | null): Promise<number> => {
let conn = await NachklangFeedbackDB.getConnection();
try {
await conn.beginTransaction();
const posRows = await conn.query('SELECT COALESCE(MAX(position), -1) + 1 as next_position FROM songs WHERE event_id = ?', [eventId]);
const position = posRows[0].next_position;
const res = await conn.query(
'INSERT INTO songs (event_id, title, composer, position) VALUES (?,?,?,?) RETURNING song_id',
[eventId, title, composer, position]
);
await conn.commit();
return res[0].song_id;
} catch (err) {
await conn.rollback();
throw err;
} finally {
await conn.end();
}
};
export const updateSong = async (songId: number, title: string, composer: string | null): Promise<boolean> => {
let conn = await NachklangFeedbackDB.getConnection();
try {
await conn.beginTransaction();
const res = await conn.query('UPDATE songs SET title = ?, composer = ? WHERE song_id = ?', [title, composer, songId]);
await conn.commit();
return res.affectedRows > 0;
} catch (err) {
await conn.rollback();
throw err;
} finally {
await conn.end();
}
};
/**
* Removes a song. submission_answers rows referencing it keep their
* song_title_snapshot (song_id is set to NULL via ON DELETE SET NULL) -
* past answers still say what song was rated, even after the song is gone.
*/
export const deleteSong = async (songId: number): Promise<boolean> => {
let conn = await NachklangFeedbackDB.getConnection();
try {
await conn.beginTransaction();
const res = await conn.query('DELETE FROM songs WHERE song_id = ?', [songId]);
await conn.commit();
return res.affectedRows > 0;
} catch (err) {
await conn.rollback();
throw err;
} finally {
await conn.end();
}
};