Files
2026-10-16 19:12:13 +00:00

164 lines
8.4 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
require_once __DIR__ . '/common.php';
api_require_method('GET', 'POST');
$me = api_require_staff();
api_require_admin_or_permission($me, 'manage_staff');
$isFullAdmin = $me['role'] === 'admin';
$pdo = get_db();
/** Setzt den erweiterten Abteilungszugriff (inkl. Rolle pro Abteilung) neu. */
function api_save_staff_access(PDO $pdo, int $staffId, ?int $primaryDeptId, array $entries): void
{
$pdo->prepare('DELETE FROM staff_department WHERE staff_id = ?')->execute([$staffId]);
$ins = $pdo->prepare('INSERT INTO staff_department (staff_id, department_id, notify, role_id) VALUES (?,?,?,?)');
$validRoles = array_map('intval', $pdo->query('SELECT id FROM roles')->fetchAll(PDO::FETCH_COLUMN));
$seen = [];
foreach ($entries as $entry) {
$dId = (int) ($entry['departmentId'] ?? 0);
if ($dId === 0 || $dId === (int) $primaryDeptId || isset($seen[$dId])) continue;
$seen[$dId] = true;
$rid = (int) ($entry['roleId'] ?? 0);
$ins->execute([$staffId, $dId, !empty($entry['notify']) ? 1 : 0, in_array($rid, $validRoles, true) ? $rid : null]);
}
}
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$allStaff = $pdo->query(
'SELECT s.*, d.name AS department_name FROM staff s LEFT JOIN departments d ON d.id = s.department_id ORDER BY s.name'
)->fetchAll();
$departments = $pdo->query('SELECT id, name FROM departments ORDER BY name')->fetchAll();
$roles = $pdo->query('SELECT id, name FROM roles ORDER BY name')->fetchAll();
$teams = $pdo->query('SELECT id, name FROM teams ORDER BY name')->fetchAll();
$teamStmt = $pdo->prepare('SELECT team_id FROM team_members WHERE staff_id = ?');
$extraStmt = $pdo->prepare('SELECT department_id, notify, role_id FROM staff_department WHERE staff_id = ?');
$items = [];
foreach ($allStaff as $s) {
$extraStmt->execute([$s['id']]);
$extra = [];
foreach ($extraStmt->fetchAll() as $row) {
$extra[] = ['departmentId' => (int) $row['department_id'], 'notify' => (bool) $row['notify'], 'roleId' => $row['role_id'] !== null ? (int) $row['role_id'] : null];
}
$teamStmt->execute([$s['id']]);
$items[] = [
'id' => (int) $s['id'],
'name' => $s['name'],
'email' => $s['email'],
'role' => $s['role'],
'roleId' => $s['role_id'] !== null ? (int) $s['role_id'] : null,
'departmentId' => $s['department_id'] !== null ? (int) $s['department_id'] : null,
'departmentName' => $s['department_name'],
'isActive' => (bool) $s['is_active'],
'signature' => $s['signature'],
'extraDepartments' => $extra,
'teamIds' => array_map('intval', $teamStmt->fetchAll(PDO::FETCH_COLUMN)),
'createdAt' => $s['created_at'] ?? null,
];
}
api_json([
'departments' => array_map(fn(array $d) => ['id' => (int) $d['id'], 'name' => $d['name']], $departments),
'roles' => array_map(fn(array $r) => ['id' => (int) $r['id'], 'name' => $r['name']], $roles),
'teams' => array_map(fn(array $t) => ['id' => (int) $t['id'], 'name' => $t['name']], $teams),
'canManageTeams' => has_permission($me, 'manage_teams'),
'items' => $items,
]);
}
$body = api_request_body();
$action = $body['action'] ?? '';
if ($action === 'save') {
$id = (int) ($body['id'] ?? 0);
$name = trim((string) ($body['name'] ?? ''));
$email = trim((string) ($body['email'] ?? ''));
// Nur echte Administratoren dürfen die Administrator-Rolle vergeben – sonst könnte sich ein
// per Co-Admin-Recht (nur manage_staff) berechtigter Agent selbst (oder andere) zum
// Vollzugriff-Admin machen. Beim Bearbeiten durch einen Co-Admin bleibt die vorhandene
// Rolle des Ziel-Kontos unverändert, statt sie stillschweigend auf "Mitarbeiter" zu setzen.
if ($isFullAdmin) {
$role = ($body['role'] ?? '') === 'admin' ? 'admin' : 'agent';
} elseif ($id !== 0) {
$currentRoleStmt = $pdo->prepare('SELECT role FROM staff WHERE id = ?');
$currentRoleStmt->execute([$id]);
$role = $currentRoleStmt->fetchColumn() === 'admin' ? 'admin' : 'agent';
} else {
$role = 'agent';
}
$roleId = isset($body['roleId']) && $body['roleId'] !== null ? (int) $body['roleId'] : null;
$deptId = isset($body['departmentId']) && $body['departmentId'] !== null ? (int) $body['departmentId'] : null;
$isActive = !empty($body['isActive']) ? 1 : 0;
$password = (string) ($body['password'] ?? '');
$signature = sanitize_staff_html((string) ($body['signature'] ?? ''));
if ($name === '') api_error(422, 'NAME_REQUIRED', 'Bitte einen Namen angeben.');
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) api_error(422, 'INVALID_EMAIL', 'Bitte eine gültige E-Mail-Adresse angeben.');
$dup = $pdo->prepare('SELECT COUNT(*) FROM staff WHERE LOWER(email) = LOWER(?) AND id <> ?');
$dup->execute([$email, $id]);
if ((int) $dup->fetchColumn() > 0) {
api_error(422, 'EMAIL_TAKEN', 'Ein Mitarbeiter mit dieser E-Mail-Adresse existiert bereits.');
}
if ($id !== 0 && $id === (int) $me['id'] && !$isActive) {
api_error(422, 'CANNOT_DEACTIVATE_SELF', 'Sie können Ihr eigenes Konto nicht deaktivieren.');
}
if ($id === 0) {
$pwErr = validate_password_strength($password);
if ($pwErr) api_error(422, 'WEAK_PASSWORD', $pwErr);
$pdo->prepare('INSERT INTO staff (name, email, password_hash, role, role_id, department_id, signature, is_active, created_at) VALUES (?,?,?,?,?,?,?,?,?)')
->execute([$name, $email, password_hash($password, PASSWORD_DEFAULT), $role, $roleId, $deptId, $signature ?: null, $isActive, db_now()]);
$newId = (int) $pdo->lastInsertId();
audit_log($me['id'], "Mitarbeiter angelegt: {$name} ({$email}) (Mobile App)");
} else {
$newId = $id;
if ($password !== '') {
$pwErr = validate_password_strength($password);
if ($pwErr) api_error(422, 'WEAK_PASSWORD', $pwErr);
$pdo->prepare('UPDATE staff SET name=?, email=?, role=?, role_id=?, department_id=?, signature=?, is_active=?, password_hash=? WHERE id=?')
->execute([$name, $email, $role, $roleId, $deptId, $signature ?: null, $isActive, password_hash($password, PASSWORD_DEFAULT), $id]);
} else {
$pdo->prepare('UPDATE staff SET name=?, email=?, role=?, role_id=?, department_id=?, signature=?, is_active=? WHERE id=?')
->execute([$name, $email, $role, $roleId, $deptId, $signature ?: null, $isActive, $id]);
}
audit_log($me['id'], "Mitarbeiter aktualisiert: {$name} ({$email}) (Mobile App)");
}
// Optional im selben Aufruf: erweiterter Zugriff und Team-Mitgliedschaften
if (array_key_exists('extraDepartments', $body)) {
api_save_staff_access($pdo, $newId, $deptId, (array) $body['extraDepartments']);
}
if (array_key_exists('teamIds', $body) && has_permission($me, 'manage_teams')) {
$pdo->prepare('DELETE FROM team_members WHERE staff_id = ?')->execute([$newId]);
$ins = $pdo->prepare('INSERT INTO team_members (team_id, staff_id) VALUES (?,?)');
foreach (array_unique(array_filter(array_map('intval', (array) $body['teamIds']))) as $tid) $ins->execute([$tid, $newId]);
}
api_json(['id' => $newId]);
}
if ($action === 'save_access') {
$id = (int) ($body['id'] ?? 0);
$stmt = $pdo->prepare('SELECT department_id FROM staff WHERE id = ?');
$stmt->execute([$id]);
$primaryDeptId = (int) $stmt->fetchColumn();
api_save_staff_access($pdo, $id, $primaryDeptId, (array) ($body['extraDepartments'] ?? []));
audit_log($me['id'], "Abteilungszugriff geändert für Mitarbeiter #{$id} (Mobile App)");
api_json(['ok' => true]);
}
if ($action === 'delete') {
$id = (int) ($body['id'] ?? 0);
if ($id === (int) $me['id']) {
api_error(422, 'CANNOT_DELETE_SELF', 'Sie können Ihr eigenes Konto nicht löschen.');
}
$pdo->prepare('UPDATE tickets SET assigned_staff_id = NULL WHERE assigned_staff_id = ?')->execute([$id]);
$pdo->prepare('DELETE FROM staff WHERE id = ?')->execute([$id]);
audit_log($me['id'], "Mitarbeiter gelöscht: #{$id} (Mobile App)");
api_json(['ok' => true]);
}
api_error(422, 'INVALID_ACTION', 'Unbekannte Aktion.');