const router = require('express').Router(); const { query } = require('../db'); const STATUSES = ['pending', 'generating', 'done', 'failed']; // GET /api/picture-jobs router.get('/', async (req, res, next) => { try { const { status, limit = 50, offset = 0 } = req.query; const params = [Math.min(parseInt(limit), 500), parseInt(offset)]; const conditions = []; if (status) { conditions.push(`pj.status = $${params.length + 1}`); params.push(status); } const where = conditions.length ? `WHERE ${conditions.join(' AND ')}` : ''; const result = await query( `SELECT pj.*, COALESCE(json_agg(DISTINCT pjw.word_id) FILTER (WHERE pjw.word_id IS NOT NULL), '[]') AS word_ids FROM picture_jobs pj LEFT JOIN picture_job_words pjw ON pjw.picture_job_id = pj.id ${where} GROUP BY pj.id ORDER BY pj.created_at DESC LIMIT $1 OFFSET $2`, params ); res.json(result.rows); } catch (err) { next(err); } }); // GET /api/picture-jobs/:id router.get('/:id', async (req, res, next) => { try { const result = await query( `SELECT pj.*, COALESCE(json_agg(DISTINCT pjw.word_id) FILTER (WHERE pjw.word_id IS NOT NULL), '[]') AS word_ids FROM picture_jobs pj LEFT JOIN picture_job_words pjw ON pjw.picture_job_id = pj.id WHERE pj.id = $1 GROUP BY pj.id`, [req.params.id] ); if (!result.rows.length) return res.status(404).json({ error: 'Not found' }); res.json(result.rows[0]); } catch (err) { next(err); } }); // GET /api/picture-jobs/:id/words router.get('/:id/words', async (req, res, next) => { try { const result = await query( `SELECT w.* FROM words w JOIN picture_job_words pjw ON pjw.word_id = w.id WHERE pjw.picture_job_id = $1`, [req.params.id] ); res.json(result.rows); } catch (err) { next(err); } }); // POST /api/picture-jobs router.post('/', async (req, res, next) => { try { const { kategorie_id, prompt_fix, prompt_atmosphere, prompt_setting, prompt_final, word_ids } = req.body; const result = await query( `INSERT INTO picture_jobs (kategorie_id, prompt_fix, prompt_atmosphere, prompt_setting, prompt_final) VALUES ($1, $2, $3, $4, $5) RETURNING *`, [kategorie_id || null, prompt_fix || null, prompt_atmosphere || null, prompt_setting || null, prompt_final || null] ); const job = result.rows[0]; if (Array.isArray(word_ids) && word_ids.length) { for (const wid of word_ids) { await query( `INSERT INTO picture_job_words (picture_job_id, word_id) VALUES ($1, $2) ON CONFLICT DO NOTHING`, [job.id, wid] ).catch(() => {}); } } res.status(201).json({ ...job, word_ids: word_ids || [] }); } catch (err) { next(err); } }); // PATCH /api/picture-jobs/:id router.patch('/:id', async (req, res, next) => { try { const allowed = ['kategorie_id', 'prompt_fix', 'prompt_atmosphere', 'prompt_setting', 'prompt_final', 'status', 'picture_id']; const fields = Object.keys(req.body).filter(k => allowed.includes(k)); if (!fields.length) return res.status(400).json({ error: 'No valid fields provided' }); if (req.body.status && !STATUSES.includes(req.body.status)) return res.status(400).json({ error: `status must be one of: ${STATUSES.join(', ')}` }); const setClauses = fields.map((f, i) => `${f} = $${i + 1}`).join(', '); const result = await query( `UPDATE picture_jobs SET ${setClauses} WHERE id = $${fields.length + 1} RETURNING *`, [...fields.map(f => req.body[f]), req.params.id] ); if (!result.rows.length) return res.status(404).json({ error: 'Not found' }); res.json(result.rows[0]); } catch (err) { next(err); } }); // PUT /api/picture-jobs/:id/words/:wordId router.put('/:id/words/:wordId', async (req, res, next) => { try { await query( `INSERT INTO picture_job_words (picture_job_id, word_id) VALUES ($1, $2) ON CONFLICT DO NOTHING`, [req.params.id, req.params.wordId] ); res.status(204).end(); } catch (err) { next(err); } }); // DELETE /api/picture-jobs/:id/words/:wordId router.delete('/:id/words/:wordId', async (req, res, next) => { try { await query( `DELETE FROM picture_job_words WHERE picture_job_id = $1 AND word_id = $2`, [req.params.id, req.params.wordId] ); res.status(204).end(); } catch (err) { next(err); } }); // DELETE /api/picture-jobs/:id router.delete('/:id', async (req, res, next) => { try { const result = await query('DELETE FROM picture_jobs WHERE id = $1 RETURNING id', [req.params.id]); if (!result.rows.length) return res.status(404).json({ error: 'Not found' }); res.status(204).end(); } catch (err) { next(err); } }); module.exports = router;