Rechtemanagement erweitert
This commit is contained in:
parent
85f07108c1
commit
673e33aaf7
27
app.js
27
app.js
|
@ -45,9 +45,30 @@ const memberRoutes = require("./routes/member");
|
|||
const trainingRoutes = require("./routes/training");
|
||||
const anwesendRoutes = require("./routes/anwesend");
|
||||
|
||||
app.use("/user", userRoutes);
|
||||
app.use("/spiele", spieleRoutes);
|
||||
app.use("/feature", featureRoutes);
|
||||
app.use(
|
||||
"/:abteilung?/user",
|
||||
(req, res, next) => {
|
||||
req.abteilung = req.params.abteilung; // `abteilung` in req speichern
|
||||
next();
|
||||
},
|
||||
userRoutes
|
||||
);
|
||||
app.use(
|
||||
"/:abteilung?/spiele",
|
||||
(req, res, next) => {
|
||||
req.abteilung = req.params.abteilung; // `abteilung` in req speichern
|
||||
next();
|
||||
},
|
||||
spieleRoutes
|
||||
);
|
||||
app.use(
|
||||
"/:abteilung?/feature",
|
||||
(req, res, next) => {
|
||||
req.abteilung = req.params.abteilung; // `abteilung` in req speichern
|
||||
next();
|
||||
},
|
||||
featureRoutes
|
||||
);
|
||||
app.use(
|
||||
"/:abteilung?/member",
|
||||
(req, res, next) => {
|
||||
|
|
|
@ -20,6 +20,36 @@ const requireAuth = (req, res, next) => {
|
|||
}
|
||||
};
|
||||
|
||||
function requireRole(minRole) {
|
||||
return (req, res, next) => {
|
||||
const user = req.user; // Aus decoded JWT
|
||||
const abteilung = req.abteilung;
|
||||
|
||||
if (!user || !user.roles || !abteilung) {
|
||||
return res
|
||||
.status(403)
|
||||
.json({ error: "Keine Berechtigung (keine Abteilung gesetzt)" });
|
||||
}
|
||||
|
||||
const role = user.roles[abteilung];
|
||||
|
||||
if (!role) {
|
||||
return res
|
||||
.status(403)
|
||||
.json({ error: "Keine Rechte für diese Abteilung" });
|
||||
}
|
||||
console.log(role);
|
||||
console.log(minRole);
|
||||
console.log(role <= minRole);
|
||||
if (role > minRole) {
|
||||
// z.B. 1: Admin, 2: ÜL, etc.
|
||||
return res.status(403).json({ error: "Nicht genügend Rechte" });
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
}
|
||||
|
||||
const requireAdmin = async (req, res, next) => {
|
||||
try {
|
||||
const result = await pool.query("SELECT role FROM users WHERE id = $1", [
|
||||
|
@ -37,4 +67,4 @@ const requireAdmin = async (req, res, next) => {
|
|||
}
|
||||
};
|
||||
|
||||
module.exports = { requireAuth, requireAdmin };
|
||||
module.exports = { requireAuth, requireRole, requireAdmin };
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
const express = require("express");
|
||||
const pool = require("../db"); // PostgreSQL-Datenbankverbindung
|
||||
const { requireAuth, requireAdmin } = require("../middleware/auth"); // Auth-Middleware
|
||||
const {
|
||||
requireAuth,
|
||||
requireRole,
|
||||
requireAdmin,
|
||||
} = require("../middleware/auth"); // Auth-Middleware
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// **1. Alle Anwesenheiten eines Trainings abrufen**
|
||||
router.get("/:id", requireAuth, async (req, res) => {
|
||||
router.get("/:id", requireAuth, requireRole(3), async (req, res) => {
|
||||
const { id } = req.params; // Training-ID
|
||||
const abteilung = req.abteilung; // Abteilung aus Middleware
|
||||
|
||||
|
@ -34,7 +38,7 @@ router.get("/:id", requireAuth, async (req, res) => {
|
|||
});
|
||||
|
||||
// **2. Anwesenheit für ein Training setzen**
|
||||
router.post("/:id", requireAuth, async (req, res) => {
|
||||
router.post("/:id", requireAuth, requireRole(3), async (req, res) => {
|
||||
const { id } = req.params; // Training-ID
|
||||
const { inriege, anw } = req.body; // Arrays mit IDs
|
||||
|
||||
|
|
|
@ -1,20 +1,25 @@
|
|||
const express = require("express");
|
||||
const pool = require("../db"); // PostgreSQL-Datenbankverbindung
|
||||
const { requireAuth, requireAdmin } = require("../middleware/auth"); // Auth-Middleware
|
||||
const {
|
||||
requireAuth,
|
||||
requireRole,
|
||||
requireAdmin,
|
||||
} = require("../middleware/auth"); // Auth-Middleware
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get("/:id?", requireAuth, async (req, res) => {
|
||||
router.get("/:id?", requireAuth, requireRole(3), async (req, res) => {
|
||||
const { id } = req.params; // Mitglieds-ID (optional)
|
||||
const abteilung = req.abteilung; // Abteilung aus Middleware
|
||||
|
||||
console.log(abteilung);
|
||||
try {
|
||||
let query;
|
||||
let values = [];
|
||||
|
||||
if (id) {
|
||||
if (abteilung) {
|
||||
// **Einzelnes Mitglied mit aktueller Riege abrufen**
|
||||
console.log("**Einzelnes Mitglied mit aktueller Riege abrufen**");
|
||||
query = `
|
||||
SELECT
|
||||
m.*,
|
||||
|
@ -32,12 +37,12 @@ router.get("/:id?", requireAuth, async (req, res) => {
|
|||
`;
|
||||
values = [id, abteilung];
|
||||
} else {
|
||||
// **Einzelnes Mitglied ohne Riege abrufen**
|
||||
console.log(" **Einzelnes Mitglied ohne Riege abrufen**");
|
||||
query = `SELECT * FROM members WHERE id = $1`;
|
||||
values = [id];
|
||||
}
|
||||
} else if (abteilung) {
|
||||
// **Alle Mitglieder einer Abteilung abrufen**
|
||||
console.log("**Alle Mitglieder einer Abteilung abrufen**");
|
||||
query = `
|
||||
SELECT
|
||||
m.*,
|
||||
|
@ -51,11 +56,11 @@ router.get("/:id?", requireAuth, async (req, res) => {
|
|||
AND riegenzuordnung.bis IS NULL
|
||||
LEFT JOIN riegen r
|
||||
ON riegenzuordnung.fid_riege = r.id
|
||||
WHERE r.fid_abteilung = $1 OR r.fid_abteilung IS NULL
|
||||
WHERE r.fid_abteilung = $1
|
||||
`;
|
||||
values = [abteilung];
|
||||
} else {
|
||||
// **Alle Mitglieder abrufen**
|
||||
console.log("**Alle Mitglieder abrufen**");
|
||||
query = `SELECT * FROM mitglieder`;
|
||||
}
|
||||
|
||||
|
@ -73,7 +78,7 @@ router.get("/:id?", requireAuth, async (req, res) => {
|
|||
});
|
||||
|
||||
// **2. Mitglied anlegen oder aktualisieren (Nur für Admins)**
|
||||
router.put("/:id?", requireAuth, requireAdmin, async (req, res) => {
|
||||
router.put("/:id?", requireAuth, requireRole(3), async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const {
|
||||
vorname,
|
||||
|
@ -174,7 +179,7 @@ router.put("/:id?", requireAuth, requireAdmin, async (req, res) => {
|
|||
});
|
||||
|
||||
// **3. Mitglied löschen (Nur für Admins)**
|
||||
router.delete("/:id", requireAuth, requireAdmin, async (req, res) => {
|
||||
router.delete("/:id", requireAuth, requireRole(2), async (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
|
@ -197,7 +202,7 @@ router.delete("/:id", requireAuth, requireAdmin, async (req, res) => {
|
|||
});
|
||||
|
||||
// **1. notfallnummern abrufen (Falls ID gegeben: Nur die Nummern eines Mitglieds)**
|
||||
router.get("/phone/:id", requireAuth, async (req, res) => {
|
||||
router.get("/phone/:id", requireAuth, requireRole(3), async (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
|
@ -220,7 +225,7 @@ router.get("/phone/:id", requireAuth, async (req, res) => {
|
|||
});
|
||||
|
||||
// **2. Telefonnummer anlegen oder aktualisieren (Nur für Admins)**
|
||||
router.put("/phone/:id?", requireAuth, requireAdmin, async (req, res) => {
|
||||
router.put("/phone/:id?", requireAuth, requireRole(3), async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { fid_teilnehmer, name, nummer, verbindung, stand } = req.body;
|
||||
|
||||
|
@ -285,7 +290,7 @@ router.put("/phone/:id?", requireAuth, requireAdmin, async (req, res) => {
|
|||
});
|
||||
|
||||
// **3. Telefonnummer löschen (Nur für Admins)**
|
||||
router.delete("/phone/:id", requireAuth, requireAdmin, async (req, res) => {
|
||||
router.delete("/phone/:id", requireAuth, requireRole(2), async (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
|
@ -307,7 +312,7 @@ router.delete("/phone/:id", requireAuth, requireAdmin, async (req, res) => {
|
|||
}
|
||||
});
|
||||
|
||||
router.post("/riege/:id", requireAuth, requireAdmin, async (req, res) => {
|
||||
router.post("/riege/:id", requireAuth, requireRole(2), async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const abteilung = req.abteilung;
|
||||
const { neue_riege } = req.body;
|
||||
|
|
|
@ -61,7 +61,7 @@ router.delete("/:id", requireAuth, requireAdmin, async (req, res) => {
|
|||
}
|
||||
});
|
||||
|
||||
router.put("/:id?", requireAuth, requireAdmin, async (req, res) => {
|
||||
router.put("/:id?", requireAuth, async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { name, material, regeln, variationen, dauer, type } = req.body;
|
||||
|
||||
|
@ -115,5 +115,4 @@ router.put("/:id?", requireAuth, requireAdmin, async (req, res) => {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const express = require("express");
|
||||
const pool = require("../db"); // PostgreSQL-Datenbankverbindung
|
||||
const { requireAuth, requireAdmin } = require("../middleware/auth"); // Auth-Middleware
|
||||
const { requireAuth, requireRole } = require("../middleware/auth"); // Auth-Middleware
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
@ -55,7 +55,7 @@ router.get("/:year?/:kw?", requireAuth, async (req, res) => {
|
|||
}
|
||||
});
|
||||
|
||||
router.post("/leiten/:id", requireAuth, async (req, res) => {
|
||||
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
|
||||
|
@ -122,7 +122,7 @@ router.post("/leiten/:id", requireAuth, async (req, res) => {
|
|||
}
|
||||
});
|
||||
|
||||
router.post("/new/:jahr/:kw", requireAuth, requireAdmin, async (req, res) => {
|
||||
router.post("/new/:jahr/:kw", requireAuth, requireRole(2), async (req, res) => {
|
||||
const { jahr, kw } = req.params;
|
||||
const abteilung = req.abteilung; // Abteilung aus Middleware
|
||||
|
||||
|
|
109
routes/user.js
109
routes/user.js
|
@ -4,7 +4,11 @@ const bcrypt = require("bcryptjs");
|
|||
const jwt = require("jsonwebtoken");
|
||||
const crypto = require("crypto");
|
||||
const nodemailer = require("nodemailer");
|
||||
const { requireAuth, requireAdmin } = require("../middleware/auth"); // Falls Middleware in einer extra Datei liegt
|
||||
const {
|
||||
requireAuth,
|
||||
requireRole,
|
||||
requireAdmin,
|
||||
} = require("../middleware/auth"); // Falls Middleware in einer extra Datei liegt
|
||||
const { transporter, sendActivationEmail } = require("../middleware/mail");
|
||||
|
||||
const router = express.Router();
|
||||
|
@ -47,7 +51,7 @@ router.post("/login", async (req, res) => {
|
|||
|
||||
try {
|
||||
const userResult = await pool.query(
|
||||
"SELECT *, CASE WHEN admin_temp IS NOT NULL AND (now() - admin_temp) > interval '22 hours' THEN 'expired' ELSE 'valid' END AS admin_status FROM users WHERE username = $1",
|
||||
"SELECT * FROM users WHERE username = $1",
|
||||
[username]
|
||||
);
|
||||
if (userResult.rows.length > 0) {
|
||||
|
@ -56,20 +60,24 @@ router.post("/login", async (req, res) => {
|
|||
const match = await bcrypt.compare(password, user.password);
|
||||
if (match) {
|
||||
if (user.is_active) {
|
||||
const rightsResult = await pool.query(
|
||||
`SELECT fid_abteilung, fid_role FROM userrights WHERE fid_user = $1`,
|
||||
[user.id]
|
||||
);
|
||||
|
||||
// Rollen-Map erstellen:
|
||||
const roles = {};
|
||||
rightsResult.rows.forEach((row) => {
|
||||
roles[row.fid_abteilung] = row.fid_role;
|
||||
});
|
||||
const token = jwt.sign(
|
||||
{ id: user.id, username: user.username, role: user.role },
|
||||
{ id: user.id, username: user.username, roles },
|
||||
process.env.JWT_SECRET,
|
||||
{
|
||||
expiresIn: "24h",
|
||||
expiresIn: "24d",
|
||||
}
|
||||
);
|
||||
if (user.admin_status === "expired") {
|
||||
await pool.query(
|
||||
"UPDATE users SET role = $1, admin_temp = NULL WHERE id = $2",
|
||||
["user", user.id]
|
||||
);
|
||||
}
|
||||
res.json({ token });
|
||||
res.json({ token, roles });
|
||||
} else {
|
||||
return res.status(401).json({ error: "Auf Freischlatung warten" });
|
||||
}
|
||||
|
@ -209,10 +217,40 @@ router.post("/update", requireAuth, async (req, res) => {
|
|||
// Liste der User mit Rollen und is_active
|
||||
router.get("/admin", requireAuth, requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
"SELECT id, username, email, role, is_active FROM users ORDER BY is_active ASC, role DESC"
|
||||
// 1️⃣ Alle Benutzer abfragen:
|
||||
const usersResult = await pool.query(
|
||||
"SELECT id, username, email, is_active FROM users ORDER BY is_active ASC"
|
||||
);
|
||||
res.json(result.rows);
|
||||
|
||||
const users = usersResult.rows;
|
||||
|
||||
// 2️⃣ Alle Rollen pro User abfragen:
|
||||
const rolesResult = await pool.query(
|
||||
`SELECT ur.fid_user, ur.fid_abteilung, ur.fid_role, r.role
|
||||
FROM userrights ur
|
||||
JOIN userroles r ON ur.fid_role = r.id`
|
||||
);
|
||||
|
||||
// 3️⃣ Rollen für Benutzer gruppieren:
|
||||
const userRolesMap = {};
|
||||
rolesResult.rows.forEach((row) => {
|
||||
if (!userRolesMap[row.fid_user]) {
|
||||
userRolesMap[row.fid_user] = [];
|
||||
}
|
||||
userRolesMap[row.fid_user].push({
|
||||
abteilung: row.fid_abteilung,
|
||||
role_id: row.fid_role,
|
||||
role_name: row.role,
|
||||
});
|
||||
});
|
||||
|
||||
// 4️⃣ Benutzer + Rollen zusammenführen:
|
||||
const enrichedUsers = users.map((user) => ({
|
||||
...user,
|
||||
roles: userRolesMap[user.id] || [],
|
||||
}));
|
||||
|
||||
res.json(enrichedUsers);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: "Interner Serverfehler" });
|
||||
|
@ -258,6 +296,49 @@ router.put("/activate/:id", requireAuth, requireAdmin, async (req, res) => {
|
|||
}
|
||||
});
|
||||
|
||||
router.put(
|
||||
"/rights/:userId/:role",
|
||||
requireAuth,
|
||||
requireRole(2),
|
||||
async (req, res) => {
|
||||
const { userId, role } = req.params;
|
||||
const abteilung = req.abteilung; // Abteilung aus Middleware
|
||||
|
||||
if (!abteilung || !role) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: "Abteilung und Rolle müssen angegeben werden" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Prüfen, ob bereits ein Recht für User & Abteilung existiert
|
||||
const existing = await pool.query(
|
||||
`SELECT id FROM userrights WHERE fid_user = $1 AND fid_abteilung = $2`,
|
||||
[userId, abteilung]
|
||||
);
|
||||
|
||||
if (existing.rows.length > 0) {
|
||||
// Eintrag existiert → UPDATE
|
||||
await pool.query(`UPDATE userrights SET fid_role = $1 WHERE id = $2`, [
|
||||
role,
|
||||
existing.rows[0].id,
|
||||
]);
|
||||
} else {
|
||||
// Kein Eintrag → INSERT
|
||||
await pool.query(
|
||||
`INSERT INTO userrights (fid_user, fid_abteilung, fid_role) VALUES ($1, $2, $3)`,
|
||||
[userId, abteilung, role]
|
||||
);
|
||||
}
|
||||
|
||||
res.json({ message: "Rolle erfolgreich vergeben/geändert" });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: "Interner Serverfehler" });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
router.delete("/:id", requireAuth, requireAdmin, async (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
|
|
Loading…
Reference in New Issue