/bewerbung: Tabs Unterlagen/E-Mail + Admin-Nutzerdetailseite
- Bewerbungsdetail: Toggle zwischen Bewerbungsunterlagen und E-Mail-Korrespondenz (hash-basiert), weniger Scroll auf der Seite. - Admin: Klick auf einen Nutzer öffnet neue Verwaltungsseite /admin/users/:id (Passwort, Anmelden als, Jobsuche, Admin-Status, Löschen). - Admin-Tabelle: Löschen und Jobsuche aus den Aktionen entfernt (jetzt auf der Nutzerdetailseite). Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -4284,6 +4284,53 @@ initializeDatabase().then(async () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Einzelnen Benutzer verwalten (Detailansicht von „Bestehende Benutzer").
|
||||
app.get('/admin/users/:id', requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const id = Number(req.params.id);
|
||||
const user = await dbGet('SELECT id, username, is_admin, created_at FROM users WHERE id = ?', [id]);
|
||||
if (!user) return res.status(404).send('Benutzer nicht gefunden.');
|
||||
const anzahl = await dbGet('SELECT COUNT(*) AS c FROM bewerbungen WHERE user_id = ?', [id]);
|
||||
const bewerbungen = await dbAll(
|
||||
'SELECT id, firma, stelle, status, datum FROM bewerbungen WHERE user_id = ? ORDER BY date(datum) DESC, created_at DESC LIMIT 10',
|
||||
[id]
|
||||
);
|
||||
const adminCount = await dbGet('SELECT COUNT(*) AS c FROM users WHERE is_admin = 1');
|
||||
res.render('admin-user', {
|
||||
user,
|
||||
currentUserId: req.user.id,
|
||||
anzahlBewerbungen: anzahl ? anzahl.c : 0,
|
||||
bewerbungen: bewerbungen || [],
|
||||
adminCount: adminCount ? adminCount.c : 0,
|
||||
hideSettings: false,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Admin user detail error:', error);
|
||||
res.status(500).send('Serverfehler');
|
||||
}
|
||||
});
|
||||
|
||||
// Admin-Status eines Benutzers umschalten. Der letzte Admin darf nicht
|
||||
// abgesetzt werden (sonst sperrt man sich aus).
|
||||
app.post('/admin/users/:id/toggle-admin', requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const id = Number(req.params.id);
|
||||
const target = await dbGet('SELECT id, is_admin FROM users WHERE id = ?', [id]);
|
||||
if (!target) return res.status(404).send('Benutzer nicht gefunden.');
|
||||
if (target.is_admin) {
|
||||
const adminCount = await dbGet('SELECT COUNT(*) AS c FROM users WHERE is_admin = 1');
|
||||
if (adminCount && adminCount.c <= 1) return res.status(400).send('Der letzte Admin darf nicht abgesetzt werden.');
|
||||
}
|
||||
const neu = target.is_admin ? 0 : 1;
|
||||
await dbRun('UPDATE users SET is_admin = ? WHERE id = ?', [neu, id]);
|
||||
await auditLog(req.user.id, id, `admin_toggle → ${neu ? 'admin' : 'user'}`);
|
||||
res.redirect('/admin/users/' + id);
|
||||
} catch (error) {
|
||||
console.error('Admin toggle-admin error:', error);
|
||||
res.status(500).send('Serverfehler');
|
||||
}
|
||||
});
|
||||
|
||||
// --- Impersonation: admin "logs in as" a user --------------------------
|
||||
// Best practice (Django/Flask-impersonate style): the admin's own session
|
||||
// keeps its cookie token, but its user_id switches to the target and the
|
||||
|
||||
Reference in New Issue
Block a user