Initial commit

This commit is contained in:
Olivier CROGUENNEC
2026-06-13 14:57:15 +02:00
commit 48ed7fe65e
209 changed files with 49979 additions and 0 deletions
+135
View File
@@ -0,0 +1,135 @@
import { Router } from 'express';
import db from '../db/index.js';
import { HttpError } from '../middleware/errorHandler.js';
const router = Router();
const TYPES_VALIDES = ['etoiles', 'lettres', 'score', 'custom'];
/** Valide et normalise un critère entrant */
function parseBody(body) {
const { plateforme_id, nom, type = 'etoiles', valeurs, min_val, max_val, description, ordre } = body;
if (!plateforme_id) throw new HttpError(400, 'plateforme_id est requis');
if (!nom?.trim()) throw new HttpError(400, 'nom est requis');
if (!TYPES_VALIDES.includes(type)) throw new HttpError(400, `type invalide — attendu : ${TYPES_VALIDES.join(', ')}`);
// Validation selon le type
if (type === 'score') {
if (min_val === undefined || max_val === undefined) throw new HttpError(400, 'min_val et max_val requis pour le type score');
if (Number(min_val) >= Number(max_val)) throw new HttpError(400, 'min_val doit être inférieur à max_val');
}
if ((type === 'lettres' || type === 'custom') && (!valeurs || !valeurs.length)) {
throw new HttpError(400, `valeurs est requis pour le type ${type}`);
}
return {
plateforme_id: Number(plateforme_id),
nom: nom.trim(),
type,
valeurs: (type === 'lettres' || type === 'custom')
? JSON.stringify(Array.isArray(valeurs) ? valeurs : valeurs.split(',').map(v => v.trim()).filter(Boolean))
: null,
min_val: type === 'score' ? Number(min_val) : null,
max_val: type === 'score' ? Number(max_val) : null,
description: description?.trim() || null,
ordre: Number(ordre ?? 0),
};
}
/** Enrichit les lignes DB (parse valeurs JSON) */
function enrich(row) {
return {
...row,
valeurs: row.valeurs ? JSON.parse(row.valeurs) : null,
};
}
/* ── GET /api/notation?plateforme_id=X ───────────────────────── */
router.get('/', (req, res) => {
const { plateforme_id } = req.query;
if (plateforme_id) {
const rows = db.prepare(`
SELECT nc.* FROM notation_criteres nc
JOIN plateformes p ON p.id = nc.plateforme_id
WHERE nc.plateforme_id = ? AND p.user_id = ?
ORDER BY nc.ordre, nc.id
`).all(Number(plateforme_id), req.user.id);
return res.json(rows.map(enrich));
}
// Tous les critères de l'utilisateur (toutes plateformes)
const rows = db.prepare(`
SELECT nc.*, p.nom AS plateforme_nom FROM notation_criteres nc
JOIN plateformes p ON p.id = nc.plateforme_id
WHERE p.user_id = ?
ORDER BY p.nom, nc.ordre, nc.id
`).all(req.user.id);
res.json(rows.map(enrich));
});
/* ── POST /api/notation ──────────────────────────────────────── */
router.post('/', (req, res, next) => {
try {
const data = parseBody(req.body);
// Vérifie que la plateforme appartient à l'utilisateur
const plat = db.prepare('SELECT id FROM plateformes WHERE id = ? AND user_id = ?')
.get(data.plateforme_id, req.user.id);
if (!plat) throw new HttpError(404, 'Plateforme introuvable');
const r = db.prepare(`
INSERT INTO notation_criteres (plateforme_id, nom, type, valeurs, min_val, max_val, description, ordre)
VALUES (?,?,?,?,?,?,?,?)
`).run(data.plateforme_id, data.nom, data.type, data.valeurs, data.min_val, data.max_val, data.description, data.ordre);
const created = enrich(db.prepare('SELECT * FROM notation_criteres WHERE id = ?').get(r.lastInsertRowid));
res.status(201).json(created);
} catch (e) { next(e); }
});
/* ── PUT /api/notation/:id ───────────────────────────────────── */
router.put('/:id', (req, res, next) => {
try {
const existing = db.prepare(`
SELECT nc.* FROM notation_criteres nc
JOIN plateformes p ON p.id = nc.plateforme_id
WHERE nc.id = ? AND p.user_id = ?
`).get(req.params.id, req.user.id);
if (!existing) throw new HttpError(404, 'Critère introuvable');
const data = parseBody({ ...req.body, plateforme_id: existing.plateforme_id });
db.prepare(`
UPDATE notation_criteres
SET nom=?, type=?, valeurs=?, min_val=?, max_val=?, description=?, ordre=?
WHERE id=?
`).run(data.nom, data.type, data.valeurs, data.min_val, data.max_val, data.description, data.ordre, req.params.id);
res.json(enrich(db.prepare('SELECT * FROM notation_criteres WHERE id = ?').get(req.params.id)));
} catch (e) { next(e); }
});
/* ── DELETE /api/notation/:id ────────────────────────────────── */
router.delete('/:id', (req, res, next) => {
try {
const existing = db.prepare(`
SELECT nc.id FROM notation_criteres nc
JOIN plateformes p ON p.id = nc.plateforme_id
WHERE nc.id = ? AND p.user_id = ?
`).get(req.params.id, req.user.id);
if (!existing) throw new HttpError(404, 'Critère introuvable');
db.prepare('DELETE FROM notation_criteres WHERE id = ?').run(req.params.id);
res.json({ deleted: true });
} catch (e) { next(e); }
});
/* ── PUT /api/notation/reorder ───────────────────────────────── */
router.put('/reorder', (req, res, next) => {
try {
const { ids } = req.body; // tableau d'ids dans le nouvel ordre
if (!Array.isArray(ids)) throw new HttpError(400, 'ids[] requis');
const upd = db.prepare('UPDATE notation_criteres SET ordre = ? WHERE id = ?');
const tx = db.transaction(() => ids.forEach((id, i) => upd.run(i, id)));
tx();
res.json({ reordered: true });
} catch (e) { next(e); }
});
export default router;