Praxissofttware/controllers/admin.controller.js

344 lines
8.4 KiB
JavaScript

const db = require("../db");
const bcrypt = require("bcrypt");
const {
createUser,
getAllUsers,
updateUserById,
} = require("../services/admin.service");
async function listUsers(req, res) {
const { q } = req.query;
try {
let users;
if (q) {
users = await getAllUsers(db, q);
} else {
users = await getAllUsers(db);
}
res.render("admin_users", {
title: "Benutzer",
sidebarPartial: "partials/admin-sidebar",
active: "users",
user: req.session.user,
lang: req.session.lang || "de",
users,
currentUser: req.session.user,
query: { q },
});
} catch (err) {
console.error(err);
res.send("Datenbankfehler");
}
}
function showCreateUser(req, res) {
res.render("admin_create_user", {
error: null,
user: req.session.user,
});
}
async function postCreateUser(req, res) {
let {
title,
first_name,
last_name,
username,
password,
role,
fachrichtung,
arztnummer,
} = req.body;
title = title?.trim();
first_name = first_name?.trim();
last_name = last_name?.trim();
username = username?.trim();
fachrichtung = fachrichtung?.trim();
arztnummer = arztnummer?.trim();
// 🔴 Grundvalidierung
if (!first_name || !last_name || !username || !password || !role) {
return res.render("admin_create_user", {
error: "Alle Pflichtfelder müssen ausgefüllt sein",
user: req.session.user,
});
}
// 🔴 Arzt-spezifische Validierung
if (role === "arzt") {
if (!fachrichtung || !arztnummer) {
return res.render("admin_create_user", {
error: "Für Ärzte sind Fachrichtung und Arztnummer Pflicht",
user: req.session.user,
});
}
} else {
// Sicherheit: Mitarbeiter dürfen keine Arzt-Daten haben
fachrichtung = null;
arztnummer = null;
title = null;
}
try {
await createUser(
db,
title,
first_name,
last_name,
username,
password,
role,
fachrichtung,
arztnummer,
);
req.session.flash = {
type: "success",
message: "Benutzer erfolgreich angelegt",
};
res.redirect("/admin/users");
} catch (error) {
res.render("admin_create_user", {
error,
user: req.session.user,
});
}
}
async function changeUserRole(req, res) {
const userId = req.params.id;
const { role } = req.body;
if (!["arzt", "mitarbeiter"].includes(role)) {
req.session.flash = { type: "danger", message: "Ungültige Rolle" };
return res.redirect("/admin/users");
}
db.query("UPDATE users SET role = ? WHERE id = ?", [role, userId], (err) => {
if (err) {
console.error(err);
req.session.flash = {
type: "danger",
message: "Fehler beim Ändern der Rolle",
};
} else {
req.session.flash = {
type: "success",
message: "Rolle erfolgreich geändert",
};
}
res.redirect("/admin/users");
});
}
async function resetUserPassword(req, res) {
const userId = req.params.id;
const { password } = req.body;
if (!password || password.length < 4) {
req.session.flash = { type: "warning", message: "Passwort zu kurz" };
return res.redirect("/admin/users");
}
const hash = await bcrypt.hash(password, 10);
db.query(
"UPDATE users SET password = ? WHERE id = ?",
[hash, userId],
(err) => {
if (err) {
console.error(err);
req.session.flash = {
type: "danger",
message: "Fehler beim Zurücksetzen",
};
} else {
req.session.flash = {
type: "success",
message: "Passwort zurückgesetzt",
};
}
res.redirect("/admin/users");
},
);
}
function activateUser(req, res) {
const userId = req.params.id;
db.query("UPDATE users SET active = 1 WHERE id = ?", [userId], (err) => {
if (err) {
console.error(err);
req.session.flash = {
type: "danger",
message: "Benutzer konnte nicht aktiviert werden",
};
} else {
req.session.flash = {
type: "success",
message: "Benutzer wurde aktiviert",
};
}
res.redirect("/admin/users");
});
}
function deactivateUser(req, res) {
const userId = req.params.id;
db.query("UPDATE users SET active = 0 WHERE id = ?", [userId], (err) => {
if (err) {
console.error(err);
req.session.flash = {
type: "danger",
message: "Benutzer konnte nicht deaktiviert werden",
};
} else {
req.session.flash = {
type: "success",
message: "Benutzer wurde deaktiviert",
};
}
res.redirect("/admin/users");
});
}
async function showInvoiceOverview(req, res) {
const search = req.query.q || "";
const view = req.query.view || "year";
const currentYear = new Date().getFullYear();
const fromYear = req.query.fromYear || currentYear;
const toYear = req.query.toYear || currentYear;
try {
const [yearly] = await db.promise().query(`
SELECT
YEAR(invoice_date) AS year,
SUM(total_amount) AS total
FROM invoices
WHERE status IN ('paid','open')
GROUP BY YEAR(invoice_date)
ORDER BY year DESC
`);
const [quarterly] = await db.promise().query(`
SELECT
YEAR(invoice_date) AS year,
QUARTER(invoice_date) AS quarter,
SUM(total_amount) AS total
FROM invoices
WHERE status IN ('paid','open')
GROUP BY YEAR(invoice_date), QUARTER(invoice_date)
ORDER BY year DESC, quarter DESC
`);
const [monthly] = await db.promise().query(`
SELECT
DATE_FORMAT(invoice_date, '%Y-%m') AS month,
SUM(total_amount) AS total
FROM invoices
WHERE status IN ('paid','open')
GROUP BY month
ORDER BY month DESC
`);
const [patients] = await db.promise().query(
`
SELECT
CONCAT(p.firstname, ' ', p.lastname) AS patient,
SUM(i.total_amount) AS total
FROM invoices i
JOIN patients p ON p.id = i.patient_id
WHERE i.status IN ('paid','open')
AND CONCAT(p.firstname, ' ', p.lastname) LIKE ?
GROUP BY p.id
ORDER BY total DESC
`,
[`%${search}%`],
);
res.render("admin/admin_invoice_overview", {
title: "Rechnungsübersicht",
sidebarPartial: "partials/admin-sidebar", // ✅ keine Sidebar
active: "invoices",
user: req.session.user,
lang: req.session.lang || "de",
yearly,
quarterly,
monthly,
patients,
search,
fromYear,
toYear,
});
} catch (err) {
console.error(err);
res.status(500).send("Fehler beim Laden der Rechnungsübersicht");
}
}
async function updateUser(req, res) {
const userId = req.params.id;
let { title, first_name, last_name, username, role } = req.body;
title = title?.trim() || null;
first_name = first_name?.trim();
last_name = last_name?.trim();
username = username?.trim();
role = role?.trim();
try {
// ✅ Fehlende Felder aus DB holen (weil disabled inputs nicht gesendet werden)
const [rows] = await db
.promise()
.query("SELECT * FROM users WHERE id = ?", [userId]);
if (!rows.length) {
req.session.flash = { type: "danger", message: "User nicht gefunden" };
return res.redirect("/admin/users");
}
const current = rows[0];
// ✅ Fallback: wenn Felder nicht gesendet wurden -> alte Werte behalten
const updatedData = {
title: title ?? current.title,
first_name: first_name ?? current.first_name,
last_name: last_name ?? current.last_name,
username: username ?? current.username,
role: role ?? current.role,
};
await updateUserById(db, userId, updatedData);
req.session.flash = { type: "success", message: "User aktualisiert ✅" };
return res.redirect("/admin/users");
} catch (err) {
console.error(err);
req.session.flash = { type: "danger", message: "Fehler beim Speichern" };
return res.redirect("/admin/users");
}
}
module.exports = {
listUsers,
showCreateUser,
postCreateUser,
changeUserRole,
resetUserPassword,
activateUser,
deactivateUser,
showInvoiceOverview,
updateUser,
};