Upload via GUI (360 Dateien)

This commit is contained in:
2026-10-30 21:50:10 +00:00
parent fa7cb047a9
commit 2ee9be11c0
2 changed files with 486 additions and 431 deletions
+1
View File
@@ -108,6 +108,7 @@ if ('serviceWorker' in navigator) {
<?php if ($staff['role'] === 'admin'): ?><a href="/staff/languages.php" class="<?= $activePage==='languages'?'active':'' ?>">Sprachen</a><?php endif; ?>
<?php if ($staff['role'] === 'admin'): ?><a href="/staff/ticket_templates.php" class="<?= $activePage==='ticket_templates'?'active':'' ?>">Ticket-Vorlagen</a><a href="/staff/status_page.php" class="<?= $activePage==='status_page'?'active':'' ?>">Statusseite</a><a href="/staff/problems.php" class="<?= $activePage==='problems'?'active':'' ?>">Problemmanagement</a><?php endif; ?>
<?php if ($staff['role'] === 'admin'): ?><a href="/staff/mail_queue.php" class="<?= $activePage==='mail_queue'?'active':'' ?>">Mail-Warteschlange</a><?php endif; ?>
<?php if ($staff['role'] === 'admin'): ?><a href="/staff/login_log.php" class="<?= $activePage==='login_log'?'active':'' ?>">Anmelde-Wächter</a><?php endif; ?>
<?php if (has_permission($staff, 'manage_email_addresses')): ?><a href="/staff/email_addresses.php" class="<?= $activePage==='email_addresses'?'active':'' ?>">E-Mail-Adressen</a><?php endif; ?>
<?php if (has_permission($staff, 'manage_email_templates')): ?><a href="/staff/email_templates.php" class="<?= $activePage==='email_templates'?'active':'' ?>">E-Mail-Vorlagen</a><?php endif; ?>
<?php if (has_permission($staff, 'manage_kb')): ?><a href="/staff/kb_manage.php" class="<?= $activePage==='kb'?'active':'' ?>">Wissensdatenbank</a><?php endif; ?>
+57 -3
View File
@@ -108,10 +108,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($action === 'save_settings') {
$onVacation = !empty($_POST['is_on_vacation']) ? 1 : 0;
$substituteId = ($_POST['vacation_substitute_id'] ?? '') !== '' ? (int)$_POST['vacation_substitute_id'] : null;
$beforeRow = $pdo->prepare('SELECT is_on_vacation, vacation_substitute_id FROM staff WHERE id = ?');
$beforeRow->execute([$staff['id']]);
$beforeRow = $beforeRow->fetch() ?: ['is_on_vacation' => 0, 'vacation_substitute_id' => null];
$pdo->prepare('UPDATE staff SET is_on_vacation=?, vacation_substitute_id=? WHERE id=?')
->execute([$onVacation, $substituteId, $staff['id']]);
audit_log($staff['id'], $onVacation ? 'Abwesenheit aktiviert' : 'Abwesenheit deaktiviert');
flash('success', 'Einstellungen gespeichert.');
// Offene Tickets an die Vertretung weitergeben bzw. nach dem Urlaub zurückholen
[$handed, $back] = vacation_apply_change($pdo, (int) $staff['id'], [$beforeRow['is_on_vacation'], $beforeRow['vacation_substitute_id']], [$onVacation, $substituteId], !empty($_POST['hand_over']));
flash('success', 'Einstellungen gespeichert.' . ($handed ? ' ' . $handed . ' offene Tickets wurden an die Vertretung weitergegeben.' : '') . ($back ? ' ' . $back . ' Tickets sind wieder bei Ihnen.' : ''));
redirect('/staff/profile.php?tab=settings');
}
@@ -129,6 +134,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
redirect('/staff/profile.php?tab=account');
}
// ── Gemerktes Gerät entfernen (Anmelde-Wächter) ────────────────
if ($action === 'forget_device') {
$pdo->prepare('DELETE FROM login_devices WHERE id = ? AND staff_id = ?')->execute([(int) ($_POST['device_id'] ?? 0), $staff['id']]);
flash('success', 'Gerät entfernt.');
redirect('/staff/profile.php?tab=security');
}
// ── 2FA aktivieren ─────────────────────────────────────────────
if ($action === 'enable_2fa') {
$code = trim($_POST['totp_code'] ?? '');
@@ -352,7 +364,7 @@ require __DIR__ . '/_header.php';
<input type="checkbox" name="is_on_vacation" value="1" style="width:auto; margin-top:3px; flex-shrink:0" <?= $me['is_on_vacation'] ? 'checked' : '' ?>>
<span>
<strong>Urlaubsmodus aktiv</strong><br>
<span class="muted" style="font-size:.84rem">Neue Tickets werden nicht automatisch diesem Konto zugewiesen, während der Urlaubsmodus aktiv ist. Bereits zugewiesene Tickets bleiben unverändert.</span>
<span class="muted" style="font-size:.84rem">Neue Tickets werden nicht automatisch diesem Konto zugewiesen, während der Urlaubsmodus aktiv ist.</span>
</span>
</label>
<label style="margin-top:14px">Vertretung (optional)</label>
@@ -362,7 +374,11 @@ require __DIR__ . '/_header.php';
<option value="<?= $a['id'] ?>" <?= ($me['vacation_substitute_id'] ?? '') == $a['id'] ? 'selected' : '' ?>><?= e($a['name']) ?></option>
<?php endforeach; ?>
</select>
<p class="muted" style="font-size:.8rem">Neue Tickets werden während Ihrer Abwesenheit automatisch dieser Person zugewiesen.</p>
<p class="muted" style="font-size:.8rem">Neue Tickets werden während Ihrer Abwesenheit automatisch dieser Person zugewiesen. Sie sieht dafür auch Ihre Abteilungen.</p>
<label style="display:flex; align-items:flex-start; gap:12px; cursor:pointer; font-weight:400; margin-top:10px">
<input type="checkbox" name="hand_over" value="1" style="width:auto; margin-top:3px; flex-shrink:0" checked>
<span><strong>Meine offenen Tickets an die Vertretung weitergeben</strong><br><span class="muted" style="font-size:.84rem">Beim Speichern gehen Ihre offenen Tickets an die Vertretung. Wenn Sie den Urlaubsmodus beenden, kommen die Tickets zurück, die dann noch offen bei ihr liegen. Ohne Vertretung passiert nichts.</span></span>
</label>
<?php if ($me['is_on_vacation']): ?>
<div class="flash info" style="margin-top:8px">Urlaubsmodus ist aktuell <strong>aktiv</strong>. Sie erhalten keine automatischen Ticket-Zuweisungen.</div>
<?php endif; ?>
@@ -480,6 +496,44 @@ $setupSecret = $_SESSION['totp_setup_secret'] ?? '';
</form>
<?php endif; ?>
</div>
<?php
$myDevices = $pdo->prepare('SELECT * FROM login_devices WHERE staff_id = ? ORDER BY last_seen DESC');
$myDevices->execute([$staff['id']]);
$myDevices = $myDevices->fetchAll();
$myEvents = $pdo->prepare('SELECT * FROM login_events WHERE staff_id = ? ORDER BY id DESC LIMIT 10');
$myEvents->execute([$staff['id']]);
$myEvents = $myEvents->fetchAll();
$eventLabels = login_guard_event_labels();
?>
<div class="card" style="margin-top:20px">
<h3>🛡️ Meine Geräte und Anmeldungen</h3>
<p class="muted" style="font-size:.88rem">Von diesen Geräten haben Sie sich schon angemeldet. Meldet sich jemand von einem neuen Gerät oder Ort an, bekommen Sie eine Mail. Ein Gerät, das Sie nicht kennen, können Sie hier entfernen; ändern Sie dann auch Ihr Passwort.</p>
<?php if (!$myDevices): ?><p class="muted">Noch keine Geräte gemerkt.</p><?php else: ?>
<div style="overflow-x:auto"><table>
<thead><tr><th>Gerät</th><th>Letzter Ort</th><th>Zuletzt gesehen</th><th></th></tr></thead>
<tbody>
<?php foreach ($myDevices as $d): ?>
<tr>
<td><?= e($d['label']) ?><div class="muted" style="font-size:.76rem"><?= $d['channel'] === 'app' ? 'App' : 'Browser' ?>, seit <span><?= e(date('d.m.Y', strtotime((string) $d['first_seen']))) ?></span></div></td>
<td><?= e($d['place']) ?><div class="muted" style="font-size:.76rem"><?= e($d['last_ip']) ?></div></td>
<td><?= e(date('d.m.Y H:i', strtotime((string) $d['last_seen']))) ?></td>
<td><form method="post" onsubmit="return confirm('Dieses Gerät entfernen? Die nächste Anmeldung davon löst wieder eine Warnung aus.')"><?= csrf_field() ?><input type="hidden" name="action" value="forget_device"><input type="hidden" name="device_id" value="<?= (int) $d['id'] ?>"><button class="btn secondary" type="submit" style="padding:3px 8px;font-size:.78rem">Entfernen</button></form></td>
</tr>
<?php endforeach; ?>
</tbody>
</table></div>
<?php endif; ?>
<?php if ($myEvents): ?>
<h4 style="margin:18px 0 6px">Letzte Anmeldungen</h4>
<div style="overflow-x:auto"><table>
<tbody>
<?php foreach ($myEvents as $ev): ?>
<tr><td style="white-space:nowrap"><?= e(date('d.m.Y H:i', strtotime((string) $ev['created_at']))) ?></td><td><?= e($eventLabels[$ev['event']] ?? $ev['event']) ?></td><td><?= e($ev['device']) ?></td><td><?= e($ev['place']) ?> <span class="muted">(<?= e($ev['ip']) ?>)</span></td></tr>
<?php endforeach; ?>
</tbody>
</table></div>
<?php endif; ?>
</div>
<?php endif; ?>
</div>