Upload via GUI (278 Dateien)

This commit is contained in:
2026-10-21 16:44:55 +00:00
parent 30df645ca9
commit 39c0a19cf7
6 changed files with 67 additions and 11 deletions
+21 -10
View File
@@ -19,8 +19,9 @@ $pdo = get_db();
const AVAILABILITY_STATUSES = ['available', 'busy', 'break', 'offline'];
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
staff_run_auto_offline($pdo);
$agents = $pdo->query(
'SELECT s.id, s.name, s.is_on_vacation, sa.status, sa.note, sa.updated_at
'SELECT s.id, s.name, s.is_on_vacation, s.last_active_at, sa.auto_offline, sa.status, sa.note, sa.updated_at
FROM staff s
LEFT JOIN staff_availability sa ON sa.staff_id = s.id
WHERE s.is_active = 1
@@ -37,6 +38,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
'note' => $a['is_on_vacation'] ? 'Urlaub' : ($a['note'] ?? ''),
'isOnVacation' => (bool) $a['is_on_vacation'],
'updatedAt' => $a['updated_at'],
'lastActiveAt' => $a['last_active_at'] ?? null,
'autoOffline' => !empty($a['auto_offline']),
];
$team[] = $entry;
if ((int) $a['id'] === (int) $staff['id']) {
@@ -57,12 +60,20 @@ if (!in_array($newStatus, AVAILABILITY_STATUSES, true)) {
api_error(422, 'INVALID_STATUS', 'Ungültiger Status.');
}
$drv = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
$sql = $drv === 'sqlite'
? 'INSERT INTO staff_availability (staff_id, status, note, updated_at) VALUES (?,?,?,?)
ON CONFLICT(staff_id) DO UPDATE SET status=excluded.status, note=excluded.note, updated_at=excluded.updated_at'
: 'INSERT INTO staff_availability (staff_id, status, note, updated_at) VALUES (?,?,?,?)
ON DUPLICATE KEY UPDATE status=VALUES(status), note=VALUES(note), updated_at=VALUES(updated_at)';
$pdo->prepare($sql)->execute([$staff['id'], $newStatus, $note ?: null, db_now()]);
api_json(['ok' => true, 'status' => $newStatus]);
// Ein Admin darf den Status eines anderen Mitarbeiters setzen (staffId), alle anderen nur den eigenen
$targetId = (int) $staff['id'];
if (isset($body['staffId']) && (int) $body['staffId'] !== $targetId) {
if (($staff['role'] ?? '') !== 'admin') {
api_error(403, 'FORBIDDEN', 'Nur Administratoren dürfen den Status anderer Mitarbeiter ändern.');
}
$targetId = (int) $body['staffId'];
$exists = $pdo->prepare('SELECT COUNT(*) FROM staff WHERE id = ? AND is_active = 1');
$exists->execute([$targetId]);
if ((int) $exists->fetchColumn() === 0) {
api_error(404, 'STAFF_NOT_FOUND', 'Mitarbeiter nicht gefunden.');
}
audit_log((int) $staff['id'], "Status von Mitarbeiter #$targetId auf $newStatus gesetzt");
}
staff_set_status($pdo, $targetId, $newStatus, $note);
staff_touch_activity($pdo, (int) $staff['id']);
api_json(['ok' => true, 'status' => $newStatus, 'staffId' => $targetId]);
+5
View File
@@ -138,6 +138,11 @@ function api_require_staff(): array
->execute([db_now(), $staff['mobile_token_id']]);
}
// Aktionen in der App (Schreib-Aufrufe) zählen als Aktivität; reines Abfragen im Hintergrund und die Push-Anmeldung nicht
if ($_SERVER['REQUEST_METHOD'] !== 'GET' && !in_array(basename((string) ($_SERVER['SCRIPT_NAME'] ?? '')), ['push_device.php', 'crash_report.php', 'logout.php'], true)) {
staff_touch_activity($pdo, (int) $staff['id']);
}
// "Eingebauter" Ersatz für echte Server-Cronjobs (siehe includes/pseudo_cron.php):
// auch App-Nutzung hält die automatischen Hintergrund-Jobs am Laufen.
pseudo_cron_schedule_background();
@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/common.php';
/**
* Absturzbericht der Android-App (wird beim nächsten Start nach der Anmeldung gesendet) und im Aktivitätsprotokoll abgelegt.
* POST {appVersion, device, trace}
*/
api_require_method('POST');
$staff = api_require_staff();
$body = api_request_body();
$trace = trim((string) ($body['trace'] ?? ''));
if ($trace === '') api_error(422, 'TRACE_REQUIRED', 'Kein Absturzbericht übermittelt.');
$line = 'App-Absturz v' . mb_substr((string) ($body['appVersion'] ?? '?'), 0, 12) . ' ' . mb_substr((string) ($body['device'] ?? '?'), 0, 30) . ': ' . mb_substr(preg_replace('/\s+/', ' ', $trace), 0, 190);
// Pro Mitarbeiter höchstens 20 Berichte pro Tag (Schutz vor Absturzschleifen); der Zähler steht als "Datum:Anzahl" in einer Einstellung je Mitarbeiter
$key = 'crash_count_' . (int) $staff['id'];
[$day, $n] = array_pad(explode(':', (string) get_setting($key, '')), 2, '0');
$n = $day === date('Ymd') ? (int) $n : 0;
if ($n < 20) {
set_setting($key, date('Ymd') . ':' . ($n + 1));
audit_log((int) $staff['id'], $line);
}
api_json(['received' => true], 201);