Jake Vanderwerf
2 days ago 235ce5716edc2f7cbe80fdccf26eac7269587839
inc/rest/routes/QueueRoutes.php
@@ -41,14 +41,15 @@
            'limit' => 'integer|default:50|min:1|max:100',
         ])
         ->auth('user')
         ->rateLimit(30)
         ->rateLimit()
         ->post([$this, 'handleAction'])
         ->args([
            'ids' => 'array|required',
            'action' => 'string|required|enum:dismiss,retry,cancel',
         ])
         ->auth('user')
         ->rateLimit(30);
         ->rateLimit()
         ->register();
      // Poll endpoint
      Route::for('queue/poll')
@@ -58,20 +59,23 @@
            'ids' => 'string',
         ])
         ->auth('user')
         ->rateLimit(15);
         ->rateLimit()
         ->register();
      // Errors endpoint
      Route::for('queue/errors')
         ->get([$this, 'getOperationErrors'])
         ->auth('user')
         ->rateLimit(15);
         ->rateLimit()
         ->register();
      // Single operation with dynamic ID
      Route::for(Route::pattern('queue/{id}'))
         ->get([$this, 'getOperation'])
         ->arg('id', 'string|required')
         ->auth('user')
         ->rateLimit(15);
         ->rateLimit()
         ->register();
   }
   /**
@@ -84,8 +88,11 @@
   {
      $params = $request->get_params();
      $user_id = absint($params['user']);
      $this->cache = Cache::for('queue')->user();
      $status = sanitize_text_field($params['status']);
      $ids = array_map('trim', array_map('sanitize_text_field', explode(',', $params['ids'])));
      $ids = !empty($params['ids'])
         ? array_map('trim', array_map('sanitize_text_field', explode(',', $params['ids'])))
         : [];
      $limit = absint($params['limit']);
      $cacheKey = $this->cache->generateKey(compact('user_id', 'status', 'ids', 'limit'));
@@ -93,7 +100,7 @@
         return $cached;
      }
      $data = $this->cache->remember($cacheKey, function() use ($user_id, $params) {
      $data = $this->cache->tag("user:{$user_id}")->remember($cacheKey, function() use ($user_id, $params) {
         $filters = $this->buildFilters($params);
         $operations = JVB()->queue()->getUserOperations($user_id, $filters);
@@ -136,10 +143,15 @@
   public function handleAction(WP_REST_Request $request): WP_REST_Response
   {
      $data = $request->get_params();
      $ids = array_map('trim', array_map('sanitize_text_field', explode(',', $data['ids'])));
      $ids = is_array($data['ids'])
         ? array_map('trim', array_map('sanitize_text_field', $data['ids']))
         : array_map('trim', array_map('sanitize_text_field', explode(',', $data['ids'])));
      $action = sanitize_text_field($data['action'] ?? '');
      $user_id = absint($data['user']);
      $this->cache = Cache::for($user_id.'_queue');
      // Validate input
      if (empty($ids)) {
         return Response::validationError(['ids' => 'Missing or invalid operation IDs']);
@@ -171,6 +183,7 @@
   public function pollQueue(WP_REST_Request $request): WP_REST_Response
   {
      $userId = $request->get_param('user');
      $this->cache = Cache::for($userId.'_queue');
      $since = $request->get_param('since');
      $ids = $request->get_param('ids');
@@ -192,6 +205,7 @@
      $items = array_map(fn($op) => [
         'id' => $op->id,
         'status' => $this->mapStateToStatus($op->state, $op->outcome),
         'progress_percentage'   => $this->formatPercentage($op),
         'progress_count' => $op->processedItems,
         'count' => $op->totalItems,
         'updated_at' => $this->formatTimestamp($op->completedAt ?? $op->startedAt ?? $op->scheduledAt),
@@ -208,6 +222,7 @@
   public function getOperationErrors(WP_REST_Request $request): WP_REST_Response
   {
      $user_id = absint($request->get_param('user'));
      $this->cache = Cache::for($user_id.'_queue');
      $operations = JVB()->queue()->getUserOperations($user_id, [
         'state' => 'completed',
         'outcome' => ['failed', 'failed_permanent', 'partial'],
@@ -233,6 +248,7 @@
   {
      $id = $request->get_param('id');
      $userId = $request->get_param('user');
      $this->cache = Cache::for($userId.'_queue');
      $op = JVB()->queue()->get($id);
@@ -255,21 +271,22 @@
      );
   }
   private function formatOperation(Operation $op, bool $full = false): array
   private function formatOperation(Operation $op, bool $full = true): array
   {
      $formatted = [
         'id' => $op->id,
         'type' => $op->type,
         'status' => $this->mapStateToStatus($op->state, $op->outcome),
         'progress_count' => $op->processedItems,
         'progress_percentage'   => $this->formatPercentage($op),
         'count' => $op->totalItems,
         'title' => $this->getOperationTitle($op->type, $op->requestData),
         'created_at' => $this->formatTimestamp($op->scheduledAt),
         'updated_at' => $this->formatTimestamp($op->completedAt ?? $op->startedAt ?? $op->scheduledAt),
      ];
      if ($op->processedItems > 0 && $op->totalItems > 0) {
         $formatted['progress_percentage'] = round(($op->processedItems / $op->totalItems) * 100);
      if (!empty($op->result['merged_into'])) {
         $formatted['merged_into'] = $op->result['merged_into'];
      }
      if ($op->errorMessage) {
@@ -292,6 +309,18 @@
      return $formatted;
   }
   protected function formatPercentage(Operation $op):int
   {
      if ($op->totalItems > 0){
         return round(($op->processedItems / $op->totalItems) * 100);
      } else {
         return match($op->state) {
            'pending','scheduled=' => 0,
            'processing' => 45,
            'completed' => 100
         };
      }
   }
   /**
    * Map backend state/outcome to frontend status
    * Backend uses: state (pending, scheduled, processing, completed) + outcome (pending, success, partial, failed, failed_permanent)