584 lines
14 KiB
JavaScript
584 lines
14 KiB
JavaScript
const path = require("path");
|
|
const express = require("express");
|
|
const session = require("express-session");
|
|
const bcrypt = require("bcryptjs");
|
|
const multer = require("multer");
|
|
const { lireJson, ecrireJson, genererId } = require("./lib/donnees");
|
|
|
|
const app = express();
|
|
const port = process.env.PORT || 3000;
|
|
|
|
/* ---------- Configuration ---------- */
|
|
|
|
app.use(express.json());
|
|
app.use(express.urlencoded({ extended: true }));
|
|
app.use(express.static(path.join(__dirname, "public")));
|
|
app.use("/uploads", express.static(path.join(__dirname, "uploads")));
|
|
|
|
app.use(session({
|
|
secret: "mon-poulailler-secret-local",
|
|
resave: false,
|
|
saveUninitialized: false,
|
|
cookie: { maxAge: 24 * 60 * 60 * 1000 }
|
|
}));
|
|
|
|
/* Stockage des photos uploadées */
|
|
const stockage = multer.diskStorage({
|
|
destination: function (req, file, callback)
|
|
{
|
|
callback(null, path.join(__dirname, "uploads"));
|
|
},
|
|
filename: function (req, file, callback)
|
|
{
|
|
const extension = path.extname(file.originalname);
|
|
callback(null, genererId() + extension);
|
|
}
|
|
});
|
|
|
|
const upload = multer({
|
|
storage: stockage,
|
|
limits: { fileSize: 5 * 1024 * 1024 },
|
|
fileFilter: function (req, file, callback)
|
|
{
|
|
if (file.mimetype.startsWith("image/"))
|
|
{
|
|
callback(null, true);
|
|
}
|
|
else
|
|
{
|
|
callback(new Error("Seules les images sont acceptées"));
|
|
}
|
|
}
|
|
});
|
|
|
|
/* ---------- Middlewares d'accès ---------- */
|
|
|
|
function exigerConnexion(req, res, next)
|
|
{
|
|
if (!req.session.utilisateur)
|
|
{
|
|
return res.status(401).json({ erreur: "Vous devez être connecté" });
|
|
}
|
|
|
|
next();
|
|
}
|
|
|
|
function exigerAdmin(req, res, next)
|
|
{
|
|
if (!req.session.utilisateur || req.session.utilisateur.profil !== "admin")
|
|
{
|
|
return res.status(403).json({ erreur: "Réservé à l'administrateur" });
|
|
}
|
|
|
|
next();
|
|
}
|
|
|
|
/* ---------- Authentification ---------- */
|
|
|
|
app.get("/api/session", function (req, res)
|
|
{
|
|
if (req.session.utilisateur)
|
|
{
|
|
return res.json({ connecte: true, utilisateur: req.session.utilisateur });
|
|
}
|
|
|
|
res.json({ connecte: false });
|
|
});
|
|
|
|
app.post("/api/connexion", function (req, res)
|
|
{
|
|
const login = req.body.login;
|
|
const motDePasse = req.body.motDePasse;
|
|
const utilisateurs = lireJson("utilisateurs.json", []);
|
|
|
|
const utilisateur = utilisateurs.find(function (u)
|
|
{
|
|
return u.login === login;
|
|
});
|
|
|
|
if (!utilisateur)
|
|
{
|
|
return res.status(401).json({ erreur: "Identifiant ou mot de passe incorrect" });
|
|
}
|
|
|
|
const motDePasseOk = bcrypt.compareSync(motDePasse, utilisateur.motDePasseHash);
|
|
|
|
if (!motDePasseOk)
|
|
{
|
|
return res.status(401).json({ erreur: "Identifiant ou mot de passe incorrect" });
|
|
}
|
|
|
|
req.session.utilisateur = {
|
|
id: utilisateur.id,
|
|
login: utilisateur.login,
|
|
profil: utilisateur.profil
|
|
};
|
|
|
|
res.json({ message: "Connexion réussie", utilisateur: req.session.utilisateur });
|
|
});
|
|
|
|
app.post("/api/deconnexion", function (req, res)
|
|
{
|
|
req.session.destroy(function ()
|
|
{
|
|
res.json({ message: "Déconnexion réussie" });
|
|
});
|
|
});
|
|
|
|
app.post("/api/utilisateurs", exigerConnexion, exigerAdmin, function (req, res)
|
|
{
|
|
const login = req.body.login;
|
|
const motDePasse = req.body.motDePasse;
|
|
const profil = req.body.profil || "utilisateur";
|
|
|
|
if (!login || !motDePasse)
|
|
{
|
|
return res.status(400).json({ erreur: "Login et mot de passe obligatoires" });
|
|
}
|
|
|
|
if (profil !== "admin" && profil !== "utilisateur")
|
|
{
|
|
return res.status(400).json({ erreur: "Profil invalide" });
|
|
}
|
|
|
|
const utilisateurs = lireJson("utilisateurs.json", []);
|
|
const existeDeja = utilisateurs.some(function (u)
|
|
{
|
|
return u.login === login;
|
|
});
|
|
|
|
if (existeDeja)
|
|
{
|
|
return res.status(400).json({ erreur: "Ce login existe déjà" });
|
|
}
|
|
|
|
const nouvelUtilisateur = {
|
|
id: genererId(),
|
|
login: login,
|
|
motDePasseHash: bcrypt.hashSync(motDePasse, 10),
|
|
profil: profil
|
|
};
|
|
|
|
utilisateurs.push(nouvelUtilisateur);
|
|
ecrireJson("utilisateurs.json", utilisateurs);
|
|
|
|
res.status(201).json({
|
|
message: "Compte créé",
|
|
utilisateur: {
|
|
id: nouvelUtilisateur.id,
|
|
login: nouvelUtilisateur.login,
|
|
profil: nouvelUtilisateur.profil
|
|
}
|
|
});
|
|
});
|
|
|
|
app.get("/api/utilisateurs", exigerConnexion, exigerAdmin, function (req, res)
|
|
{
|
|
const utilisateurs = lireJson("utilisateurs.json", []);
|
|
const liste = utilisateurs.map(function (u)
|
|
{
|
|
return { id: u.id, login: u.login, profil: u.profil };
|
|
});
|
|
|
|
res.json(liste);
|
|
});
|
|
|
|
/* ---------- Animaux ---------- */
|
|
|
|
app.get("/api/animaux", exigerConnexion, function (req, res)
|
|
{
|
|
const actifsSeulement = req.query.actifs === "oui";
|
|
const archivesSeulement = req.query.archives === "oui";
|
|
let animaux = lireJson("animaux.json", []);
|
|
|
|
if (actifsSeulement)
|
|
{
|
|
animaux = animaux.filter(function (a)
|
|
{
|
|
return a.actif === true;
|
|
});
|
|
}
|
|
|
|
if (archivesSeulement)
|
|
{
|
|
animaux = animaux.filter(function (a)
|
|
{
|
|
return a.actif === false;
|
|
});
|
|
}
|
|
|
|
res.json(animaux);
|
|
});
|
|
|
|
app.get("/api/animaux/:id", exigerConnexion, function (req, res)
|
|
{
|
|
const animaux = lireJson("animaux.json", []);
|
|
const animal = animaux.find(function (a)
|
|
{
|
|
return a.id === req.params.id;
|
|
});
|
|
|
|
if (!animal)
|
|
{
|
|
return res.status(404).json({ erreur: "Animal introuvable" });
|
|
}
|
|
|
|
const periodesPonte = lireJson("periodesPonte.json", []).filter(function (p)
|
|
{
|
|
return p.idAnimal === animal.id;
|
|
});
|
|
|
|
const periodesCouvage = lireJson("periodesCouvage.json", []).filter(function (p)
|
|
{
|
|
return p.idAnimal === animal.id;
|
|
});
|
|
|
|
res.json({
|
|
animal: animal,
|
|
periodesPonte: periodesPonte,
|
|
periodesCouvage: periodesCouvage
|
|
});
|
|
});
|
|
|
|
app.post("/api/animaux", exigerConnexion, upload.single("photo"), function (req, res)
|
|
{
|
|
const type = req.body.type;
|
|
const couleurBague = req.body.couleurBague || "";
|
|
const numeroBague = req.body.numeroBague || "";
|
|
const dateNaissance = req.body.dateNaissance || "";
|
|
const etatSante = req.body.etatSante || "bon";
|
|
|
|
if (type !== "poule" && type !== "coq")
|
|
{
|
|
return res.status(400).json({ erreur: "Le type doit être poule ou coq" });
|
|
}
|
|
|
|
const animaux = lireJson("animaux.json", []);
|
|
|
|
const nouvelAnimal = {
|
|
id: genererId(),
|
|
type: type,
|
|
photo: req.file ? "/uploads/" + req.file.filename : "",
|
|
couleurBague: couleurBague,
|
|
numeroBague: numeroBague,
|
|
dateNaissance: dateNaissance,
|
|
etatSante: etatSante,
|
|
dateFinDeVie: null,
|
|
actif: true
|
|
};
|
|
|
|
animaux.push(nouvelAnimal);
|
|
ecrireJson("animaux.json", animaux);
|
|
|
|
res.status(201).json(nouvelAnimal);
|
|
});
|
|
|
|
app.put("/api/animaux/:id", exigerConnexion, upload.single("photo"), function (req, res)
|
|
{
|
|
const animaux = lireJson("animaux.json", []);
|
|
const index = animaux.findIndex(function (a)
|
|
{
|
|
return a.id === req.params.id;
|
|
});
|
|
|
|
if (index === -1)
|
|
{
|
|
return res.status(404).json({ erreur: "Animal introuvable" });
|
|
}
|
|
|
|
const animal = animaux[index];
|
|
|
|
if (req.body.type === "poule" || req.body.type === "coq")
|
|
{
|
|
animal.type = req.body.type;
|
|
}
|
|
|
|
if (req.body.couleurBague !== undefined)
|
|
{
|
|
animal.couleurBague = req.body.couleurBague;
|
|
}
|
|
|
|
if (req.body.numeroBague !== undefined)
|
|
{
|
|
animal.numeroBague = req.body.numeroBague;
|
|
}
|
|
|
|
if (req.body.dateNaissance !== undefined)
|
|
{
|
|
animal.dateNaissance = req.body.dateNaissance;
|
|
}
|
|
|
|
if (req.body.etatSante !== undefined)
|
|
{
|
|
animal.etatSante = req.body.etatSante;
|
|
}
|
|
|
|
if (req.file)
|
|
{
|
|
animal.photo = "/uploads/" + req.file.filename;
|
|
}
|
|
|
|
animaux[index] = animal;
|
|
ecrireJson("animaux.json", animaux);
|
|
|
|
res.json(animal);
|
|
});
|
|
|
|
app.post("/api/animaux/:id/deces", exigerConnexion, function (req, res)
|
|
{
|
|
const animaux = lireJson("animaux.json", []);
|
|
const index = animaux.findIndex(function (a)
|
|
{
|
|
return a.id === req.params.id;
|
|
});
|
|
|
|
if (index === -1)
|
|
{
|
|
return res.status(404).json({ erreur: "Animal introuvable" });
|
|
}
|
|
|
|
const animal = animaux[index];
|
|
animal.actif = false;
|
|
animal.dateFinDeVie = req.body.dateFinDeVie || new Date().toISOString().slice(0, 10);
|
|
|
|
/* Clôturer les périodes en cours */
|
|
const periodesPonte = lireJson("periodesPonte.json", []);
|
|
periodesPonte.forEach(function (periode)
|
|
{
|
|
if (periode.idAnimal === animal.id && !periode.dateFin)
|
|
{
|
|
periode.dateFin = animal.dateFinDeVie;
|
|
}
|
|
});
|
|
ecrireJson("periodesPonte.json", periodesPonte);
|
|
|
|
const periodesCouvage = lireJson("periodesCouvage.json", []);
|
|
periodesCouvage.forEach(function (periode)
|
|
{
|
|
if (periode.idAnimal === animal.id && !periode.dateFin)
|
|
{
|
|
periode.dateFin = animal.dateFinDeVie;
|
|
}
|
|
});
|
|
ecrireJson("periodesCouvage.json", periodesCouvage);
|
|
|
|
animaux[index] = animal;
|
|
ecrireJson("animaux.json", animaux);
|
|
|
|
res.json(animal);
|
|
});
|
|
|
|
/* ---------- Périodes de ponte ---------- */
|
|
|
|
app.post("/api/periodes-ponte", exigerConnexion, function (req, res)
|
|
{
|
|
const idAnimal = req.body.idAnimal;
|
|
const dateDebut = req.body.dateDebut;
|
|
const dateFin = req.body.dateFin || null;
|
|
const remarque = req.body.remarque || "";
|
|
|
|
if (!idAnimal || !dateDebut)
|
|
{
|
|
return res.status(400).json({ erreur: "idAnimal et dateDebut sont obligatoires" });
|
|
}
|
|
|
|
const animaux = lireJson("animaux.json", []);
|
|
const animal = animaux.find(function (a)
|
|
{
|
|
return a.id === idAnimal;
|
|
});
|
|
|
|
if (!animal)
|
|
{
|
|
return res.status(404).json({ erreur: "Animal introuvable" });
|
|
}
|
|
|
|
if (animal.type !== "poule")
|
|
{
|
|
return res.status(400).json({ erreur: "La ponte concerne uniquement les poules" });
|
|
}
|
|
|
|
const periodes = lireJson("periodesPonte.json", []);
|
|
const nouvellePeriode = {
|
|
id: genererId(),
|
|
idAnimal: idAnimal,
|
|
dateDebut: dateDebut,
|
|
dateFin: dateFin,
|
|
remarque: remarque
|
|
};
|
|
|
|
periodes.push(nouvellePeriode);
|
|
ecrireJson("periodesPonte.json", periodes);
|
|
|
|
res.status(201).json(nouvellePeriode);
|
|
});
|
|
|
|
app.put("/api/periodes-ponte/:id", exigerConnexion, function (req, res)
|
|
{
|
|
const periodes = lireJson("periodesPonte.json", []);
|
|
const index = periodes.findIndex(function (p)
|
|
{
|
|
return p.id === req.params.id;
|
|
});
|
|
|
|
if (index === -1)
|
|
{
|
|
return res.status(404).json({ erreur: "Période introuvable" });
|
|
}
|
|
|
|
if (req.body.dateDebut !== undefined)
|
|
{
|
|
periodes[index].dateDebut = req.body.dateDebut;
|
|
}
|
|
|
|
if (req.body.dateFin !== undefined)
|
|
{
|
|
periodes[index].dateFin = req.body.dateFin || null;
|
|
}
|
|
|
|
if (req.body.remarque !== undefined)
|
|
{
|
|
periodes[index].remarque = req.body.remarque;
|
|
}
|
|
|
|
ecrireJson("periodesPonte.json", periodes);
|
|
res.json(periodes[index]);
|
|
});
|
|
|
|
/* ---------- Périodes de couvage ---------- */
|
|
|
|
app.post("/api/periodes-couvage", exigerConnexion, function (req, res)
|
|
{
|
|
const idAnimal = req.body.idAnimal;
|
|
const dateDebut = req.body.dateDebut;
|
|
const dateFin = req.body.dateFin || null;
|
|
const remarque = req.body.remarque || "";
|
|
|
|
if (!idAnimal || !dateDebut)
|
|
{
|
|
return res.status(400).json({ erreur: "idAnimal et dateDebut sont obligatoires" });
|
|
}
|
|
|
|
const animaux = lireJson("animaux.json", []);
|
|
const animal = animaux.find(function (a)
|
|
{
|
|
return a.id === idAnimal;
|
|
});
|
|
|
|
if (!animal)
|
|
{
|
|
return res.status(404).json({ erreur: "Animal introuvable" });
|
|
}
|
|
|
|
if (animal.type !== "poule")
|
|
{
|
|
return res.status(400).json({ erreur: "Le couvage concerne uniquement les poules" });
|
|
}
|
|
|
|
const periodes = lireJson("periodesCouvage.json", []);
|
|
const nouvellePeriode = {
|
|
id: genererId(),
|
|
idAnimal: idAnimal,
|
|
dateDebut: dateDebut,
|
|
dateFin: dateFin,
|
|
remarque: remarque
|
|
};
|
|
|
|
periodes.push(nouvellePeriode);
|
|
ecrireJson("periodesCouvage.json", periodes);
|
|
|
|
res.status(201).json(nouvellePeriode);
|
|
});
|
|
|
|
app.put("/api/periodes-couvage/:id", exigerConnexion, function (req, res)
|
|
{
|
|
const periodes = lireJson("periodesCouvage.json", []);
|
|
const index = periodes.findIndex(function (p)
|
|
{
|
|
return p.id === req.params.id;
|
|
});
|
|
|
|
if (index === -1)
|
|
{
|
|
return res.status(404).json({ erreur: "Période introuvable" });
|
|
}
|
|
|
|
if (req.body.dateDebut !== undefined)
|
|
{
|
|
periodes[index].dateDebut = req.body.dateDebut;
|
|
}
|
|
|
|
if (req.body.dateFin !== undefined)
|
|
{
|
|
periodes[index].dateFin = req.body.dateFin || null;
|
|
}
|
|
|
|
if (req.body.remarque !== undefined)
|
|
{
|
|
periodes[index].remarque = req.body.remarque;
|
|
}
|
|
|
|
ecrireJson("periodesCouvage.json", periodes);
|
|
res.json(periodes[index]);
|
|
});
|
|
|
|
/* ---------- Statistiques ---------- */
|
|
|
|
app.get("/api/statistiques", exigerConnexion, function (req, res)
|
|
{
|
|
const animaux = lireJson("animaux.json", []);
|
|
const actifs = animaux.filter(function (a)
|
|
{
|
|
return a.actif === true;
|
|
});
|
|
|
|
const poulesActives = actifs.filter(function (a)
|
|
{
|
|
return a.type === "poule";
|
|
});
|
|
|
|
const coqsActifs = actifs.filter(function (a)
|
|
{
|
|
return a.type === "coq";
|
|
});
|
|
|
|
const periodesPonte = lireJson("periodesPonte.json", []);
|
|
const periodesCouvage = lireJson("periodesCouvage.json", []);
|
|
|
|
const idsPoules = poulesActives.map(function (p)
|
|
{
|
|
return p.id;
|
|
});
|
|
|
|
const enPonte = idsPoules.filter(function (id)
|
|
{
|
|
return periodesPonte.some(function (periode)
|
|
{
|
|
return periode.idAnimal === id && !periode.dateFin;
|
|
});
|
|
});
|
|
|
|
const enCouvage = idsPoules.filter(function (id)
|
|
{
|
|
return periodesCouvage.some(function (periode)
|
|
{
|
|
return periode.idAnimal === id && !periode.dateFin;
|
|
});
|
|
});
|
|
|
|
res.json({
|
|
nombrePoulesActives: poulesActives.length,
|
|
nombreCoqsActifs: coqsActifs.length,
|
|
nombreTotalActifs: actifs.length,
|
|
nombreEnCouvage: enCouvage.length,
|
|
nombreEnPonte: enPonte.length
|
|
});
|
|
});
|
|
|
|
/* ---------- Démarrage ---------- */
|
|
|
|
app.listen(port, function ()
|
|
{
|
|
console.log("Mon Poulailler écoute sur http://localhost:" + port);
|
|
});
|