“, siehe includes/login_guard.php) * - Anmeldungen der Apps (Android, Windows-Programm, Chrome-Erweiterung): ihre Tokens werden gelöscht, die Programme fragen danach neu nach der Anmeldung * - Push: Browser-Abonnements und Android-Geräte, damit ein verlorenes Gerät keine Benachrichtigungen mehr bekommt * - Ticket-Sperren des Mitarbeiters und laufende Zeiterfassung * Das Passwort bleibt unverändert; wer es zusätzlich ändern will, tut das im Profil oder über „Das war ich nicht“. */ /** * @param bool $keepCurrentSession true = die Sitzung, in der das gerade geschieht, bleibt angemeldet (nur bei eigener Abmeldung sinnvoll) * @return array{at:int,apps:int,browsers:int,devices:int,locks:int} */ function staff_sign_out_everywhere(PDO $pdo, int $staffId, ?int $byStaffId = null, bool $keepCurrentSession = false): array { $st = $pdo->prepare('SELECT id, name, email FROM staff WHERE id = ?'); $st->execute([$staffId]); $staff = $st->fetch(); $res = ['at' => 0, 'apps' => 0, 'browsers' => 0, 'devices' => 0, 'locks' => 0]; if (!$staff) return $res; $count = function (string $table) use ($pdo, $staffId): int { try { $c = $pdo->prepare("SELECT COUNT(*) FROM {$table} WHERE staff_id = ?"); $c->execute([$staffId]); return (int) $c->fetchColumn(); } catch (Throwable $e) { return 0; } }; $res['apps'] = $count('mobile_api_tokens'); $res['browsers'] = $count('push_subscriptions'); $res['devices'] = $count('push_devices'); $at = time(); $res['at'] = $at; set_setting('login_guard_revoke_' . $staffId, (string) $at); foreach (['mobile_api_tokens', 'push_subscriptions', 'push_devices'] as $table) { try { $pdo->prepare("DELETE FROM {$table} WHERE staff_id = ?")->execute([$staffId]); } catch (Throwable $e) { error_log('signout ' . $table . ': ' . $e->getMessage()); } } try { $l = $pdo->prepare('UPDATE tickets SET locked_by = NULL, locked_at = NULL, updated_at = updated_at WHERE locked_by = ?'); $l->execute([$staffId]); $res['locks'] = $l->rowCount(); } catch (Throwable $e) { error_log('signout locks: ' . $e->getMessage()); } if (function_exists('finalize_all_sessions_for_staff')) { try { finalize_all_sessions_for_staff($pdo, $staffId); } catch (Throwable $e) { error_log('signout time: ' . $e->getMessage()); } } // Die eigene Sitzung bleibt, wenn gewünscht: Ihr Anmeldezeitpunkt liegt dann hinter dem Zeitpunkt des Widerrufs if ($keepCurrentSession && $byStaffId === $staffId && PHP_SAPI !== 'cli' && session_status() === PHP_SESSION_ACTIVE) { $_SESSION['staff_login_at'] = $at + 1; } $self = $byStaffId === null || $byStaffId === $staffId; $detail = $self ? 'Von allen Geräten abgemeldet (eigene Veranlassung)' : 'Von allen Geräten abgemeldet durch Administrator #' . (int) $byStaffId; try { login_guard_record($pdo, 'signout', $staffId, (string) $staff['email'], 'web', $detail); } catch (Throwable $e) { error_log('signout log: ' . $e->getMessage()); } audit_log($byStaffId ?? $staffId, "Mitarbeiter #{$staffId} von allen Geräten abgemeldet ({$res['apps']} App-Anmeldungen, {$res['browsers']} Browser-Push, {$res['devices']} App-Geräte)"); if (!$self && trim((string) $staff['email']) !== '') { send_mail((string) $staff['email'], 'Sie wurden von allen Geräten abgemeldet', email_wrap('

Von allen Geräten abgemeldet

Ein Administrator hat Ihre Anmeldungen in DeskHub beendet. Bitte melden Sie sich neu an. Haben Sie das nicht erwartet, wenden Sie sich an Ihre Administration.

')); } return $res; } /** Aktive App-Anmeldungen eines Mitarbeiters (Android, Windows, Chrome) für die Anzeige. @return list> */ function staff_app_logins(PDO $pdo, int $staffId): array { $s = $pdo->prepare('SELECT device_name, last_used_at, created_at FROM mobile_api_tokens WHERE staff_id = ? AND revoked_at IS NULL AND expires_at > ? ORDER BY COALESCE(last_used_at, created_at) DESC'); $s->execute([$staffId, db_now()]); return $s->fetchAll(); }