344 lines
8.4 KiB
JavaScript
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/sidebar-empty", // ✅ keine Sidebar
|
|
active: "",
|
|
|
|
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,
|
|
};
|