tkd-api/routes/training.js

245 lines
7.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const express = require("express");
const pool = require("../db"); // PostgreSQL-Datenbankverbindung
const { requireAuth, requireRole } = require("../middleware/auth"); // Auth-Middleware
const router = express.Router();
// **Trainings abrufen (mit Geräten & Leitern)**
router.get("/:year?/:kw?", requireAuth, async (req, res) => {
const { year, kw } = req.params;
const abteilung = req.abteilung; // Abteilung aus Middleware
if (!abteilung) {
return res.status(400).json({ error: "Abteilung ist erforderlich" });
}
try {
let query;
let values = [abteilung];
if (year && kw) {
// **Trainings einer bestimmten Woche abrufen**
query = `
SELECT * FROM trainings
WHERE abteilung = $1 AND year = $2 AND kw = $3
ORDER BY year DESC, kw DESC
`;
values.push(year, kw);
} else if (year) {
// **Alle Trainings eines yeares abrufen**
query = `
SELECT * FROM trainings
WHERE abteilung = $1 AND year = $2
ORDER BY kw ASC
`;
values.push(year);
} else {
// **Alle Trainings der Abteilung abrufen**
query = `
SELECT * FROM trainings
WHERE abteilung = $1
ORDER BY year DESC, kw DESC
`;
}
const result = await pool.query(query, values);
if (result.rows.length === 0) {
return res.status(404).json({ error: "Keine Trainings gefunden" });
}
return res.json(result.rows);
} catch (err) {
console.error(err);
res.status(500).json({ error: "Interner Serverfehler" });
}
});
router.post("/leiten/:id", requireAuth, requireRole(3), async (req, res) => {
const { id } = req.params; // Trainings-ID
const abteilung = req.abteilung; // Abteilung aus Middleware
const { fid_helfer, fid_spiel, typ, action } = req.body; // Daten aus POST-Body
if (!action || !["new", "update"].includes(action)) {
return res.status(400).json({
error: 'Es muss "new" oder "update" als action angegeben werden',
});
}
if (!fid_helfer || !typ) {
return res
.status(400)
.json({ error: "fid_helfer und typ sind erforderlich" });
}
if (typ !== "a" && typ !== "s") {
return res
.status(400)
.json({ error: 'Typ muss "a" (Aufwärmen) oder "s" (Spiel) sein' });
}
try {
if (action === "new") {
// **Neuen Eintrag erstellen**
const result = await pool.query(
`INSERT INTO leiten (fid_training, fid_helfer, fid_spiel, typ)
VALUES ($1, $2, $3, $4)
RETURNING *`,
[id, fid_helfer, fid_spiel || null, typ]
);
return res.status(201).json({
message: "Leiten erfolgreich hinzugefügt",
leiten: result.rows[0],
});
} else {
// **Vorhandenen Eintrag aktualisieren**
const checkLeiten = await pool.query(
`SELECT * FROM leiten WHERE fid_training = $1 AND fid_helfer = $2 AND typ = $3`,
[id, fid_helfer, typ]
);
if (checkLeiten.rows.length === 0) {
return res
.status(404)
.json({ error: "Kein passender Leiten-Eintrag gefunden" });
}
const updateResult = await pool.query(
`UPDATE leiten
SET fid_spiel = $1
WHERE fid_training = $2 AND fid_helfer = $3 AND typ = $4
RETURNING *`,
[fid_spiel || null, id, fid_helfer, typ]
);
return res.json({
message: "Leiten erfolgreich aktualisiert",
leiten: updateResult.rows[0],
});
}
} catch (err) {
console.error(err);
res.status(500).json({ error: "Interner Serverfehler" });
}
});
router.post("/new/:jahr/:kw", requireAuth, requireRole(2), async (req, res) => {
const { jahr, kw } = req.params;
const abteilung = req.abteilung; // Abteilung aus Middleware
if (!abteilung) {
return res.status(400).json({ error: "Abteilung ist erforderlich" });
}
try {
await pool.query("BEGIN"); // Transaktion starten
// **1. Prüfen, ob bereits ein Training in dieser Woche existiert**
const existingTraining = await pool.query(
`SELECT id FROM trainings WHERE year = $1 AND kw = $2 AND abteilung = $3`,
[jahr, kw, abteilung]
);
if (existingTraining.rows.length > 0) {
await pool.query("ROLLBACK");
return res
.status(400)
.json({ error: "Training für diese Woche existiert bereits" });
}
// **2. Prüfen, ob die Abteilung Riegen hat**
const abteilungResult = await pool.query(
`SELECT riegen, geraete FROM abteilungen WHERE id = $1`,
[abteilung]
);
if (abteilungResult.rows.length === 0) {
return res.status(404).json({ error: "Abteilung nicht gefunden" });
}
const { riegen, geraete } = abteilungResult.rows[0]; // `riegen = true/false`, `geraete` = int[]
// **3. Neues Training anlegen**
const trainingResult = await pool.query(
`INSERT INTO trainings (year, kw, abteilung) VALUES ($1, $2, $3) RETURNING id`,
[jahr, kw, abteilung]
);
const trainingId = trainingResult.rows[0].id;
let geraeteplan = [];
if (riegen) {
// **4. Die letzten zwei Trainings abrufen**
const lastTrainings = await pool.query(
`SELECT g.geraete
FROM trainings t
JOIN geraeteplan g ON t.id = g.fid_training
WHERE t.abteilung = $1
ORDER BY t.year DESC, t.kw DESC
LIMIT 2`,
[abteilung]
);
let lastUsed1 =
lastTrainings.rows.length > 0 ? lastTrainings.rows[0].geraete : [];
let lastUsed2 =
lastTrainings.rows.length > 1 ? lastTrainings.rows[1].geraete : [];
// **5. Falls eines der letzten beiden Trainings Geräte 1113 enthielt → Letztes gültiges Training nehmen**
if (lastUsed1.some((g) => g >= 11 && g <= 13)) {
lastUsed1 = [];
}
if (lastUsed2.some((g) => g >= 11 && g <= 13)) {
lastUsed2 = [];
}
// **6. Bestimmen, ob hochgezählt werden soll**
let nextGeraete = [];
if (
lastUsed1.length > 0 &&
JSON.stringify(lastUsed1) === JSON.stringify(lastUsed2)
) {
// Hochzählen, weil die letzten beiden Trainings identisch waren
let lastDeviceIndex = geraete.findIndex((g) => g === lastUsed1[0]);
// Falls letztes Gerät 10 war, dann zurück auf 1
let nextDevice = geraete[(lastDeviceIndex + 1) % geraete.length];
if (lastUsed1[0] === 10) {
nextDevice = 1;
}
nextGeraete = [nextDevice, ...lastUsed1.slice(0, 4)];
} else if (lastUsed1.length > 0) {
// Letztes Training wiederholen
nextGeraete = lastUsed1;
} else {
// Erstes Training → Starte mit den ersten fünf Geräten
nextGeraete = geraete.slice(0, 5);
}
// **7. Geräteplan speichern als int[]**
await pool.query(
`INSERT INTO geraeteplan (fid_training, geraete) VALUES ($1, $2)`,
[trainingId, nextGeraete]
);
geraeteplan = nextGeraete;
}
await pool.query("COMMIT"); // Transaktion abschließen
res.status(201).json({
message: "Training erfolgreich erstellt",
training: { id: trainingId, year: jahr, kw, abteilung },
geraeteplan,
});
} catch (err) {
await pool.query("ROLLBACK"); // Falls Fehler, Transaktion rückgängig machen
console.error(err);
res.status(500).json({ error: "Interner Serverfehler" });
}
});
module.exports = router;