false, 'error' => 'Not authenticated']); exit; } // CSRF Protection require_once dirname(__DIR__) . '/middleware/CsrfMiddleware.php'; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $csrfToken = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? ''; if (!CsrfMiddleware::validateToken($csrfToken)) { http_response_code(403); echo json_encode(['success' => false, 'error' => 'Invalid CSRF token']); exit; } } // Check admin status - bulk operations are admin-only $isAdmin = $_SESSION['user']['is_admin'] ?? false; if (!$isAdmin) { echo json_encode(['success' => false, 'error' => 'Admin access required']); exit; } // Get request data $data = json_decode(file_get_contents('php://input'), true); $operationType = $data['operation_type'] ?? null; $ticketIds = $data['ticket_ids'] ?? []; $parameters = $data['parameters'] ?? null; // Validate input if (!$operationType || empty($ticketIds)) { echo json_encode(['success' => false, 'error' => 'Operation type and ticket IDs required']); exit; } // Validate ticket IDs are integers foreach ($ticketIds as $ticketId) { if (!is_numeric($ticketId)) { echo json_encode(['success' => false, 'error' => 'Invalid ticket ID format']); exit; } } // Use centralized database connection $conn = Database::getConnection(); $bulkOpsModel = new BulkOperationsModel($conn); $ticketModel = new TicketModel($conn); // Verify user can access all tickets in the bulk operation // (Admins can access all, but this is defense-in-depth) $accessibleTicketIds = []; $inaccessibleCount = 0; $tickets = $ticketModel->getTicketsByIds($ticketIds); foreach ($ticketIds as $ticketId) { $ticketId = trim($ticketId); $ticket = $tickets[$ticketId] ?? null; if ($ticket && $ticketModel->canUserAccessTicket($ticket, $_SESSION['user'])) { $accessibleTicketIds[] = $ticketId; } else { $inaccessibleCount++; } } if (empty($accessibleTicketIds)) { echo json_encode(['success' => false, 'error' => 'No accessible tickets in selection']); exit; } // Use only accessible ticket IDs $ticketIds = $accessibleTicketIds; // Create bulk operation record $operationId = $bulkOpsModel->createBulkOperation($operationType, $ticketIds, $_SESSION['user']['user_id'], $parameters); if (!$operationId) { echo json_encode(['success' => false, 'error' => 'Failed to create bulk operation']); exit; } // Process the bulk operation $result = $bulkOpsModel->processBulkOperation($operationId); $conn->close(); if (isset($result['error'])) { echo json_encode([ 'success' => false, 'error' => $result['error'] ]); } else { $message = "Bulk operation completed: {$result['processed']} succeeded, {$result['failed']} failed"; if ($inaccessibleCount > 0) { $message .= " ($inaccessibleCount skipped - no access)"; } echo json_encode([ 'success' => true, 'operation_id' => $operationId, 'processed' => $result['processed'], 'failed' => $result['failed'], 'skipped' => $inaccessibleCount, 'message' => $message ]); }