Upload via GUI (275 Dateien)
This commit is contained in:
@@ -54,8 +54,8 @@ function verify_csrf(): void
|
||||
http_response_code(403);
|
||||
die('Ungültige Anfrage (CSRF-Token fehlt oder ist ungültig). Bitte gehen Sie zurück und versuchen Sie es erneut.');
|
||||
}
|
||||
// Token nach Verbrauch rotieren
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||
// Der Token gilt für die ganze Sitzung und wird NICHT nach jeder Benutzung erneuert: Sonst würden alle anderen offenen Tabs desselben
|
||||
// Browsers beim nächsten Absenden "CSRF-Token ungültig" melden (typisch bei mehreren Tickets in Tabs). Er wird beim Anmelden neu erzeugt.
|
||||
}
|
||||
|
||||
function flash(string $type, string $message): void
|
||||
@@ -423,6 +423,90 @@ function staff_department_ids(array $staff): ?array
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* Beim Öffnen eines noch niemandem zugewiesenen Tickets wird es dem öffnenden Mitarbeiter zugewiesen (Einstellung "Beim Öffnen
|
||||
* automatisch zuweisen", Standard an). Nicht bei geschlossenen, gelösten, zusammengeführten oder als Spam markierten Tickets und nicht,
|
||||
* wenn der Mitarbeiter in dieser Abteilung nicht antworten darf. Aktualisiert $ticket (assigned_staff_id, staff_name) und gibt zurück,
|
||||
* ob zugewiesen wurde.
|
||||
*/
|
||||
function ticket_assign_on_open(PDO $pdo, array &$ticket, array $staff): bool
|
||||
{
|
||||
if (get_setting('auto_assign_on_open', '1') !== '1') return false;
|
||||
if (!empty($ticket['assigned_staff_id']) || !empty($ticket['merged_into']) || !empty($ticket['is_spam'])) return false;
|
||||
if (in_array((string) ($ticket['status'] ?? ''), ['closed', 'resolved'], true)) return false;
|
||||
if (!has_permission($staff, 'reply_ticket', (int) ($ticket['department_id'] ?? 0))) return false;
|
||||
$stmt = $pdo->prepare('UPDATE tickets SET assigned_staff_id = ? WHERE id = ? AND assigned_staff_id IS NULL');
|
||||
$stmt->execute([(int) $staff['id'], (int) $ticket['id']]);
|
||||
if ($stmt->rowCount() !== 1) return false;
|
||||
$ticket['assigned_staff_id'] = (int) $staff['id'];
|
||||
$ticket['staff_name'] = $staff['name'] ?? null;
|
||||
log_activity($pdo, (int) $ticket['id'], (int) $staff['id'], 'Beim Öffnen automatisch zugewiesen');
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Arten der automatischen Zuweisung neuer Tickets einer Abteilung. */
|
||||
function department_auto_assign_modes(): array
|
||||
{
|
||||
return ['none' => 'Nicht automatisch zuweisen', 'staff' => 'Immer an einen bestimmten Mitarbeiter', 'round_robin' => 'Reihum an die Mitarbeiter der Abteilung'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Wem ein neues Ticket dieser Abteilung laut Einstellung der Abteilung automatisch zugewiesen wird (Mitarbeiter-ID) oder null.
|
||||
* - "staff": immer derselbe Mitarbeiter; ist er im Urlaub, geht es an seine Vertretung, ohne Vertretung bleibt das Ticket unzugewiesen
|
||||
* - "round_robin": der Reihe nach an die Mitarbeiter der Abteilung (Hauptabteilung oder zusätzlich zugewiesen), die nicht im Urlaub und
|
||||
* gerade erreichbar sind (nicht offline, in der Schicht); ist niemand erreichbar, bekommt der nächste aus der Reihe es trotzdem
|
||||
* Fehlende Spalten (Datenbank noch nicht aktualisiert) und unbekannte Abteilungen ergeben null.
|
||||
*/
|
||||
function department_auto_assignee(PDO $pdo, int $departmentId): ?int
|
||||
{
|
||||
try {
|
||||
$s = $pdo->prepare('SELECT auto_assign_mode, auto_assign_staff_id, auto_assign_last_id FROM departments WHERE id = ?');
|
||||
$s->execute([$departmentId]);
|
||||
$d = $s->fetch();
|
||||
} catch (Throwable $e) {
|
||||
return null;
|
||||
}
|
||||
if (!$d) return null;
|
||||
$mode = (string) ($d['auto_assign_mode'] ?? 'none');
|
||||
|
||||
if ($mode === 'staff') {
|
||||
$id = (int) ($d['auto_assign_staff_id'] ?? 0);
|
||||
if ($id <= 0) return null;
|
||||
$st = $pdo->prepare('SELECT id, is_active, is_on_vacation, vacation_substitute_id FROM staff WHERE id = ?');
|
||||
$st->execute([$id]);
|
||||
$row = $st->fetch();
|
||||
if (!$row || !(int) $row['is_active']) return null;
|
||||
if (!(int) $row['is_on_vacation']) return $id;
|
||||
$sub = (int) ($row['vacation_substitute_id'] ?? 0);
|
||||
if ($sub > 0) {
|
||||
$st->execute([$sub]);
|
||||
$subRow = $st->fetch();
|
||||
if ($subRow && (int) $subRow['is_active'] && !(int) $subRow['is_on_vacation']) return $sub;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($mode === 'round_robin') {
|
||||
$c = $pdo->prepare(
|
||||
'SELECT id FROM staff WHERE is_active = 1 AND is_on_vacation = 0
|
||||
AND (department_id = ? OR id IN (SELECT staff_id FROM staff_department WHERE department_id = ?)) ORDER BY id'
|
||||
);
|
||||
$c->execute([$departmentId, $departmentId]);
|
||||
$candidates = array_map('intval', $c->fetchAll(PDO::FETCH_COLUMN));
|
||||
if (!$candidates) return null;
|
||||
$available = array_values(array_filter($candidates, fn(int $id) => is_staff_available($pdo, $id)));
|
||||
$pool = $available ?: $candidates;
|
||||
$last = (int) ($d['auto_assign_last_id'] ?? 0);
|
||||
$next = null;
|
||||
foreach ($pool as $id) { if ($id > $last) { $next = $id; break; } }
|
||||
$next ??= $pool[0];
|
||||
$pdo->prepare('UPDATE departments SET auto_assign_last_id = ? WHERE id = ?')->execute([$next, $departmentId]);
|
||||
return $next;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Löscht ein Ticket dauerhaft, protokolliert es vorher für Berichte */
|
||||
function delete_ticket(PDO $pdo, array $ticket, ?int $deletedByStaffId): void
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user