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.');