98 lines
4.4 KiB
JavaScript
98 lines
4.4 KiB
JavaScript
import { Router } from 'express';
|
|
import { z } from 'zod';
|
|
import db from '../db/index.js';
|
|
import { HttpError } from '../middleware/errorHandler.js';
|
|
|
|
const router = Router();
|
|
// Toutes ces routes sont montées sous requireAdmin dans server.js
|
|
|
|
/* GET /api/ref-categories — liste complète */
|
|
router.get('/', (_req, res) => {
|
|
const rows = db.prepare(`
|
|
SELECT c.id, c.nom,
|
|
COUNT(rc.referentiel_id) AS nb_utilises
|
|
FROM categories_inv c
|
|
LEFT JOIN referentiel_categories_inv rc ON rc.categorie_id = c.id
|
|
GROUP BY c.id
|
|
ORDER BY c.nom
|
|
`).all();
|
|
res.json(rows);
|
|
});
|
|
|
|
/* POST /api/ref-categories — créer */
|
|
router.post('/', (req, res, next) => {
|
|
try {
|
|
const { nom } = z.object({ nom: z.string().min(1).max(200) }).parse(req.body);
|
|
const exists = db.prepare('SELECT id FROM categories_inv WHERE nom = ?').get(nom.trim());
|
|
if (exists) throw new HttpError(409, `La catégorie "${nom.trim()}" existe déjà.`);
|
|
const r = db.prepare('INSERT INTO categories_inv (nom) VALUES (?)').run(nom.trim());
|
|
res.status(201).json({ id: r.lastInsertRowid, nom: nom.trim(), nb_utilises: 0 });
|
|
} catch (e) { next(e); }
|
|
});
|
|
|
|
/* PUT /api/ref-categories/:id — renommer (propage automatiquement) */
|
|
router.put('/:id', (req, res, next) => {
|
|
try {
|
|
const { nom } = z.object({ nom: z.string().min(1).max(200) }).parse(req.body);
|
|
const row = db.prepare('SELECT id, nom FROM categories_inv WHERE id = ?').get(req.params.id);
|
|
if (!row) throw new HttpError(404, 'Catégorie introuvable');
|
|
const dup = db.prepare('SELECT id FROM categories_inv WHERE nom = ? AND id != ?').get(nom.trim(), row.id);
|
|
if (dup) throw new HttpError(409, `La catégorie "${nom.trim()}" existe déjà.`);
|
|
db.prepare('UPDATE categories_inv SET nom = ? WHERE id = ?').run(nom.trim(), row.id);
|
|
const nb = db.prepare('SELECT COUNT(*) AS n FROM referentiel_categories_inv WHERE categorie_id = ?').get(row.id).n;
|
|
res.json({ id: row.id, nom: nom.trim(), nb_utilises: nb });
|
|
} catch (e) { next(e); }
|
|
});
|
|
|
|
/* DELETE /api/ref-categories/:id — supprimer si non utilisée */
|
|
router.delete('/:id', (req, res, next) => {
|
|
try {
|
|
const row = db.prepare('SELECT id FROM categories_inv WHERE id = ?').get(req.params.id);
|
|
if (!row) throw new HttpError(404, 'Catégorie introuvable');
|
|
const nb = db.prepare('SELECT COUNT(*) AS n FROM referentiel_categories_inv WHERE categorie_id = ?').get(row.id).n;
|
|
if (nb > 0) throw new HttpError(409, `Catégorie utilisée par ${nb} référentiel(s) — retirez-la d'abord.`);
|
|
db.prepare('DELETE FROM categories_inv WHERE id = ?').run(row.id);
|
|
res.status(204).end();
|
|
} catch (e) { next(e); }
|
|
});
|
|
|
|
/* POST /api/ref-categories/:id/merge — fusionner dans une autre catégorie */
|
|
router.post('/:id/merge', (req, res, next) => {
|
|
try {
|
|
const { target_id } = z.object({ target_id: z.number().int() }).parse(req.body);
|
|
const source = db.prepare('SELECT id, nom FROM categories_inv WHERE id = ?').get(req.params.id);
|
|
if (!source) throw new HttpError(404, 'Catégorie source introuvable');
|
|
const target = db.prepare('SELECT id, nom FROM categories_inv WHERE id = ?').get(target_id);
|
|
if (!target) throw new HttpError(404, 'Catégorie cible introuvable');
|
|
if (source.id === target.id) throw new HttpError(400, 'Source et cible identiques');
|
|
|
|
const result = db.transaction(() => {
|
|
const refs = db.prepare(
|
|
'SELECT referentiel_id FROM referentiel_categories_inv WHERE categorie_id = ?'
|
|
).all(source.id);
|
|
let added = 0, skipped = 0;
|
|
for (const { referentiel_id } of refs) {
|
|
const exists = db.prepare(
|
|
'SELECT 1 FROM referentiel_categories_inv WHERE referentiel_id = ? AND categorie_id = ?'
|
|
).get(referentiel_id, target.id);
|
|
if (!exists) {
|
|
db.prepare(
|
|
'INSERT INTO referentiel_categories_inv (referentiel_id, categorie_id) VALUES (?, ?)'
|
|
).run(referentiel_id, target.id);
|
|
added++;
|
|
} else {
|
|
skipped++;
|
|
}
|
|
}
|
|
db.prepare('DELETE FROM referentiel_categories_inv WHERE categorie_id = ?').run(source.id);
|
|
db.prepare('DELETE FROM categories_inv WHERE id = ?').run(source.id);
|
|
return { added, skipped, total: refs.length };
|
|
})();
|
|
|
|
res.json({ ok: true, ...result,
|
|
message: `Fusion terminée : ${result.added} lien(s) ajouté(s), ${result.skipped} déjà présent(s). "${source.nom}" supprimée.` });
|
|
} catch (e) { next(e); }
|
|
});
|
|
|
|
export default router;
|