| | |
| | | use DateTimeZone; |
| | | |
| | | if (!defined('ABSPATH')) { |
| | | exit; // Exit if accessed directly |
| | | exit; // Exit if accessed directly |
| | | } |
| | | |
| | | class QueueRoutes extends RestRouteManager |
| | | { |
| | | public function __construct() |
| | | { |
| | | $this->cache_name = 'queue'; |
| | | $this->cache_ttl = 300; |
| | | parent::__construct(); |
| | | public function __construct() |
| | | { |
| | | $this->cache_name = 'queue'; |
| | | $this->cache_ttl = 300; |
| | | parent::__construct(); |
| | | |
| | | if (JVB_TESTING) { |
| | | $this->cache->flush(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Registers queue routes |
| | | * @return void |
| | | */ |
| | | /** |
| | | * Registers queue routes |
| | | * @return void |
| | | */ |
| | | public function registerRoutes():void |
| | | { |
| | | register_rest_route($this->namespace, '/queue', [ |
| | |
| | | ] |
| | | ] |
| | | ]); |
| | | |
| | | register_rest_route($this->namespace, '/queue/errors', [ |
| | | 'methods' => 'GET', |
| | | 'callback' => [$this, 'getOperationErrors'], |
| | | 'permission_callback' => [$this, 'checkPermission'], |
| | | ]); |
| | | |
| | | register_rest_route($this->namespace, '/queue/poll', [ |
| | | 'methods' => 'GET', |
| | | 'callback' => [$this, 'pollQueue'], |
| | | 'permission_callback' => [$this, 'checkPermission'], |
| | | 'args' => [ |
| | | 'since' => [ |
| | | 'type' => 'string', |
| | | 'description' => 'ISO timestamp - only return operations updated after this' |
| | | ], |
| | | 'ids' => [ |
| | | 'type' => 'string', |
| | | 'description' => 'Comma-separated IDs to check' |
| | | ] |
| | | ] |
| | | ]); |
| | | |
| | | register_rest_route($this->namespace, '/queue/(?P<id>[a-zA-Z0-9_-]+)', [ |
| | | 'methods' => 'GET', |
| | | 'callback' => [$this, 'getOperation'], |
| | | 'permission_callback' => [$this, 'checkPermission'], |
| | | 'args' => [ |
| | | 'id' => [ |
| | | 'required' => true, |
| | | 'type' => 'string', |
| | | ] |
| | | ] |
| | | ]); |
| | | } |
| | | |
| | | /** |
| | | * Get queue operations with optional filtering |
| | | * |
| | | * @param WP_REST_Request $request |
| | | * @return WP_REST_Response |
| | | */ |
| | | /** |
| | | * Get queue operations with optional filtering |
| | | * |
| | | * @param WP_REST_Request $request |
| | | * @return WP_REST_Response |
| | | */ |
| | | public function getQueue(WP_REST_Request $request): WP_REST_Response |
| | | { |
| | | $user_id = $request->get_param('user'); |
| | |
| | | /** |
| | | * Format Operation object for API response |
| | | */ |
| | | protected function formatOperationFromObject(\JVBase\managers\queue\Operation $op, bool $full = false): array |
| | | protected function formatOperationFromObject(\JVBase\managers\queue\Operation $op): array |
| | | { |
| | | $formatted = [ |
| | | 'id' => $op->id, |
| | |
| | | 'status' => $this->mapStateToStatus($op->state, $op->outcome), |
| | | 'progress_count' => $op->processedItems, |
| | | '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), |
| | | 'retries' => $op->retries, |
| | | 'data' => $op->requestData, |
| | | 'result' => $op->result ?? [], |
| | | ]; |
| | | |
| | | if ($op->processedItems > 0 && $op->totalItems > 0) { |
| | | $formatted['progress_percentage'] = round(($op->processedItems / $op->totalItems) * 100); |
| | | $formatted['created_at'] = $this->formatTimestamp($op->scheduledAt); |
| | | $formatted['updated_at'] = $this->formatTimestamp($op->completedAt ?? $op->startedAt ?? $op->scheduledAt); |
| | | |
| | | if ($op->state === 'completed' && $op->completedAt) { |
| | | $formatted['completed_at'] = $this->formatTimestamp($op->completedAt); |
| | | } |
| | | |
| | | if ($op->errorMessage) { |
| | | $formatted['error_message'] = $op->errorMessage; |
| | | } |
| | | |
| | | // Only include heavy data when requested |
| | | if ($full) { |
| | | $formatted['data'] = $op->requestData; |
| | | $formatted['result'] = $op->result ?? []; |
| | | $formatted['retries'] = $op->retries; |
| | | $formatted['user_dismissed'] = $op->userDismissed; |
| | | |
| | | if ($op->state === 'completed' && $op->completedAt) { |
| | | $formatted['completed_at'] = $this->formatTimestamp($op->completedAt); |
| | | } |
| | | if ($formatted['count'] > 0) { |
| | | $formatted['progress_percentage'] = round( |
| | | ($formatted['progress_count'] / $formatted['count']) * 100 |
| | | ); |
| | | } |
| | | |
| | | $formatted['title'] = $this->getOperationTitle($op->type, $op->requestData); |
| | | $formatted['user_dismissed'] = $op->userDismissed; |
| | | |
| | | return $formatted; |
| | | } |
| | | |
| | |
| | | return $base_title; |
| | | } |
| | | |
| | | /** |
| | | * Update operation status (dismiss or retry) |
| | | * |
| | | * @param WP_REST_Request $request |
| | | * @return WP_REST_Response |
| | | */ |
| | | /** |
| | | * Update operation status (dismiss or retry) |
| | | * |
| | | * @param WP_REST_Request $request |
| | | * @return WP_REST_Response |
| | | */ |
| | | public function handleAction(WP_REST_Request $request): WP_REST_Response |
| | | { |
| | | $data = $request->get_json_params(); |
| | |
| | | 'cleanup_reason' => null |
| | | ]; |
| | | } |
| | | |
| | | |
| | | public function pollQueue(WP_REST_Request $request): WP_REST_Response |
| | | { |
| | | $user_id = $request->get_param('user'); |
| | | $since = $request->get_param('since'); |
| | | $ids = $request->get_param('ids'); |
| | | |
| | | $filters = [ |
| | | 'not_dismissed' => true, |
| | | 'limit' => 50, |
| | | ]; |
| | | |
| | | if (!empty($ids)) { |
| | | $filters['ids'] = array_map('trim', explode(',', $ids)); |
| | | } |
| | | |
| | | $operations = JVB()->queue()->getUserOperations($user_id, $filters); |
| | | |
| | | // Filter by timestamp if provided |
| | | if ($since) { |
| | | $sinceTime = strtotime($since); |
| | | $operations = array_filter($operations, function($op) use ($sinceTime) { |
| | | $updatedAt = strtotime($op->completedAt ?? $op->startedAt ?? $op->scheduledAt); |
| | | return $updatedAt > $sinceTime; |
| | | }); |
| | | } |
| | | |
| | | // Return minimal data |
| | | $items = array_map(function($op) { |
| | | return [ |
| | | 'id' => $op->id, |
| | | 'status' => $this->mapStateToStatus($op->state, $op->outcome), |
| | | 'progress_count' => $op->processedItems, |
| | | 'count' => $op->totalItems, |
| | | 'updated_at' => $this->formatTimestamp($op->completedAt ?? $op->startedAt ?? $op->scheduledAt), |
| | | 'error_message' => $op->errorMessage, |
| | | ]; |
| | | }, $operations); |
| | | |
| | | return new WP_REST_Response([ |
| | | 'items' => array_values($items), |
| | | 'server_time' => date('c'), |
| | | 'has_active' => count(array_filter($items, fn($i) => in_array($i['status'], ['pending', 'processing']))) > 0, |
| | | ]); |
| | | } |
| | | |
| | | public function getOperation(WP_REST_Request $request): WP_REST_Response |
| | | { |
| | | $id = $request->get_param('id'); |
| | | $user_id = $request->get_param('user'); |
| | | |
| | | $op = JVB()->queue()->get($id); |
| | | |
| | | if (!$op || $op->userId !== $user_id) { |
| | | return new WP_REST_Response([ |
| | | 'success' => false, |
| | | 'message' => 'Operation not found' |
| | | ], 404); |
| | | } |
| | | |
| | | return new WP_REST_Response([ |
| | | 'success' => true, |
| | | 'operation' => $this->formatOperationFromObject($op, true) // Full data |
| | | ]); |
| | | } |
| | | } |