query( 'SELECT b.*, s.name AS added_by_name FROM banlist b LEFT JOIN staff s ON s.id = b.created_by ORDER BY b.created_at DESC' )->fetchAll(); api_json([ 'items' => array_map(fn(array $b) => [ 'id' => (int) $b['id'], 'matchType' => $b['match_type'], 'value' => $b['value'], 'reason' => $b['reason'], 'addedByName' => $b['added_by_name'], 'createdAt' => $b['created_at'], ], $entries), ]); } $body = api_request_body(); $action = $body['action'] ?? ''; /** Schließt alle offenen Tickets, die zur gerade gesperrten E-Mail/Domain passen. */ function api_close_banned_tickets(PDO $pdo, string $matchType, string $value): void { $col = $matchType === 'email' ? 'requester_email' : sql_email_domain('requester_email'); $pdo->prepare("UPDATE tickets SET status='closed',closed_at=?,updated_at=? WHERE $col=? AND status NOT IN ('closed')") ->execute([db_now(), db_now(), $value]); } if ($action === 'create') { $matchType = ($body['matchType'] ?? 'email') === 'domain' ? 'domain' : 'email'; $value = trim(strtolower((string) ($body['value'] ?? ''))); $reason = trim((string) ($body['reason'] ?? '')); if ($value === '') { api_error(422, 'VALUE_REQUIRED', 'Bitte einen Wert angeben.'); } if ($matchType === 'email' && !filter_var($value, FILTER_VALIDATE_EMAIL)) { api_error(422, 'INVALID_EMAIL', 'Ungültige E-Mail-Adresse.'); } if ($matchType === 'domain' && (!str_contains($value, '.') || str_contains($value, '@'))) { api_error(422, 'INVALID_DOMAIN', 'Nur Domain angeben, z.B. spam.de (ohne @).'); } $chk = $pdo->prepare('SELECT id FROM banlist WHERE value=?'); $chk->execute([$value]); if (!$chk->fetchColumn()) { $pdo->prepare('INSERT INTO banlist (match_type,value,reason,created_by,created_at) VALUES (?,?,?,?,?)') ->execute([$matchType, $value, $reason ?: null, $staff['id'], db_now()]); api_close_banned_tickets($pdo, $matchType, $value); audit_log($staff['id'], "Sperrliste: {$value} hinzugefügt ({$matchType}, Mobile App)"); } api_json(['ok' => true]); } if ($action === 'bulk_add') { $raw = trim((string) ($body['values'] ?? '')); $reason = trim((string) ($body['reason'] ?? '')); $lines = array_filter(array_map('trim', preg_split('/[\r\n,;]+/', $raw))); $added = 0; $skipped = 0; foreach ($lines as $val) { $val = strtolower($val); $type = str_contains($val, '@') ? 'email' : 'domain'; if ($type === 'email' && !filter_var($val, FILTER_VALIDATE_EMAIL)) { $skipped++; continue; } if ($type === 'domain' && !str_contains($val, '.')) { $skipped++; continue; } $chk = $pdo->prepare('SELECT id FROM banlist WHERE value=?'); $chk->execute([$val]); if ($chk->fetchColumn()) { $skipped++; continue; } $pdo->prepare('INSERT INTO banlist (match_type,value,reason,created_by,created_at) VALUES (?,?,?,?,?)') ->execute([$type, $val, $reason ?: null, $staff['id'], db_now()]); api_close_banned_tickets($pdo, $type, $val); $added++; } audit_log($staff['id'], "Sperrliste Massen-Import: {$added} hinzugefügt, {$skipped} übersprungen (Mobile App)"); api_json(['added' => $added, 'skipped' => $skipped]); } if ($action === 'delete') { $id = (int) ($body['id'] ?? 0); $val = $pdo->prepare('SELECT value FROM banlist WHERE id=?'); $val->execute([$id]); $v = $val->fetchColumn(); if ($v === false) { api_error(404, 'ENTRY_NOT_FOUND', 'Der Eintrag wurde nicht gefunden.'); } $pdo->prepare('DELETE FROM banlist WHERE id=?')->execute([$id]); audit_log($staff['id'], "Sperrliste: {$v} entfernt (Mobile App)"); api_json(['ok' => true]); } api_error(422, 'INVALID_ACTION', 'Unbekannte Aktion.');