164 lines
8.4 KiB
PHP
164 lines
8.4 KiB
PHP
<?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.');
|