namespace, '/integrations', [ 'methods' => 'POST', 'callback' => [$this, 'handleAction'], 'permission_callback' => [$this, 'checkPermission'], 'args' => [ 'service' => [ 'required' => true, 'type' => 'string', 'enum' => JVB()->getAvailableServices() ], 'action' => [ 'required' => true, 'sanitize_callback' => 'sanitize_text_field', ], 'user_id' => [ 'required' => false, 'sanitize_callback' => 'absint', ], 'context' => [ 'required' => false, 'default' => 'user', 'sanitize_callback' => 'sanitize_text_field', 'validate_callback' => function($param) { return in_array($param, ['admin', 'user']); } ], 'data' => [ 'required' => false, 'default' => [], ] ] ]); // register_rest_route($this->namespace, '/oauth/callback', [ // 'methods' => 'GET', // 'callback' => [$this, 'handleOAuthCallback'], // 'permission_callback' => '__return_true', // External service callback // 'args' => [ // 'service' => [ // 'required' => true, // 'sanitize_callback' => 'sanitize_text_field', // ], // 'code' => [ // 'required' => false, // 'sanitize_callback' => 'sanitize_text_field', // ], // 'state' => [ // 'required' => false, // 'sanitize_callback' => 'sanitize_text_field', // ], // 'error' => [ // 'required' => false, // 'sanitize_callback' => 'sanitize_text_field', // ] // ] // ]); // Add OAuth initiation route (for AJAX calls) register_rest_route($this->namespace, '/oauth/connect', [ 'methods' => 'POST', 'callback' => [$this, 'initiateOAuth'], 'permission_callback' => [$this, 'checkPermissions'], 'args' => [ 'service' => [ 'required' => true, 'sanitize_callback' => 'sanitize_text_field', ], 'user_id' => [ 'required' => false, 'sanitize_callback' => 'absint', ], 'return_url' => [ 'required' => false, 'sanitize_callback' => 'esc_url_raw', ] ] ]); } /** * Check permissions based on context */ public function checkPermission(\WP_REST_Request $request): bool { parent::checkPermission($request); $context = $request->get_param('context') ?? 'user'; $user_id = $request->get_param('user_id'); // Admin context requires manage_options if ($context === 'admin') { return current_user_can('manage_options'); } // User context if (!is_user_logged_in()) { return false; } $current_user_id = get_current_user_id(); // If user_id provided, verify it matches current user // OR current user is admin if ($user_id && $user_id != $current_user_id) { return current_user_can('manage_options'); } return true; } /** * Handle integration actions */ public function handleAction(WP_REST_Request $request): WP_REST_Response { error_log('[IntegrationsRoutes] handleAction request:'.print_r($request->get_params(), true)); $service = $request->get_param('service'); $action = $request->get_param('action'); // Get the integration instance $userID = absint($request->get_param('user_id')); if (!$this->userCheck($userID)) { return new WP_REST_Response([ 'success' => false, 'message' => 'Invalid User' ]); } $theUserID = (user_can($userID, 'manage_options')) ? null : $userID; $integration = JVB()->connect($service, $theUserID); if (!$integration) { return new WP_REST_Response([ 'success' => false, 'message' => 'Service not found' ], 404); } $integration->getCredentials(); // Handle the action try { // Get data parameter - DON'T convert empty array to null $data = $request->get_param('data'); // Only set to null if it's truly empty or not provided if (!is_array($data) && empty($data)) { $data = null; } error_log('[IntegrationsRoutes] Calling processAction with data: ' . print_r($data, true)); $result = $integration->processAction($action, $data); return new WP_REST_Response($result, 200); } catch (Exception $e) { return new WP_REST_Response([ 'success' => false, 'message' => $e->getMessage() ], 400); } } public function initiateOAuth(WP_REST_Request $request): WP_REST_Response { $service = $request->get_param('service'); $user_id = $request->get_param('user_id') ?: get_current_user_id(); $return_url = $request->get_param('return_url'); $integration = JVB()->connect($service, $user_id); if (!$integration || !$integration->isOAuthService) { return new WP_REST_Response([ 'success' => false, 'message' => 'Invalid OAuth service' ], 400); } $auth_url = $integration->getOAuthUrl($return_url); if ($auth_url) { return new WP_REST_Response([ 'success' => true, 'auth_url' => $auth_url, 'popup' => true ], 200); } return new WP_REST_Response([ 'success' => false, 'message' => 'Failed to generate authorization URL' ], 400); } /** * Handle OAuth callback from external service */ public function handleOAuthCallback(WP_REST_Request $request): WP_REST_Response { $service = $request->get_param('service'); $code = $request->get_param('code'); $state = $request->get_param('state'); $error = $request->get_param('error'); error_log('OAuth Callback - Service: ' . $request->get_param('service')); error_log('OAuth Callback - Code: ' . $request->get_param('code')); error_log('OAuth Callback - State: ' . $request->get_param('state')); error_log('OAuth Callback - Error: ' . $request->get_param('error')); $state_parts = explode('|', $state); $state_key = $state_parts[0] ?? ''; $user_id = intval($state_parts[1] ?? 0); $user_id = ($user_id === 0) ? null : $user_id; $return_url = isset($state_parts[2]) ? base64_decode($state_parts[2]) : admin_url('admin.php?page=jvb-integrations'); $state_data = get_transient('oauth_state_' . $state_key); error_log('State Data: '.print_r($state_data, true)); if (!$state_data || $state_data['service'] !== $service) { wp_die('Invalid state parameter', 'OAuth Error'); } // Delete the transient to prevent reuse delete_transient('oauth_state_' . $state_key); error_log('Return URL: '.print_r($return_url, true)); // Handle error from OAuth provider if ($error) { $error_description = $request->get_param('error_description') ?? 'Authorization denied'; wp_redirect(add_query_arg([ 'page' => 'jvb-integrations', 'error' => 'OAuth authorization denied: ' . $error_description ], $return_url)); exit; } // Get integration instance error_log('User ID: '.print_r($user_id, true)); error_log('Service: '.print_r($service, true)); $integration = JVB()->connect($service, $user_id); if (!$integration) { wp_die('Invalid service: ' . esc_html($service), 'OAuth Error'); } // Exchange code for tokens $result = $integration->handleOAuthCode($code, $state); // Redirect back with result if ($result['success']) { wp_redirect(add_query_arg([ 'page' => 'jvb-integrations', 'success' => 'Successfully connected to ' . $integration->title ], $return_url)); } else { // Handle failure $error_message = $result['message'] ?? 'Failed to complete OAuth authorization'; wp_redirect(add_query_arg([ 'page' => 'jvb-integrations', 'error' => $error_message ], $return_url)); } exit; } }