Jake Vanderwerf
2026-04-26 86c6cd3cc099d2480932ede03c12cea01e625c94
inc/rest/routes/IntegrationsRoutes.php
@@ -1,7 +1,8 @@
<?php
namespace JVBase\rest\routes;
use JVBase\rest\RestRouteManager;
use JVBase\rest\Rest;
use JVBase\rest\Route;
use WP_REST_Request;
use WP_REST_Response;
use Exception;
@@ -10,7 +11,7 @@
   exit; // Exit if accessed directly
}
class IntegrationsRoutes extends RestRouteManager
class IntegrationsRoutes extends Rest
{
   /**
@@ -18,113 +19,28 @@
    */
   public function registerRoutes(): void
   {
      register_rest_route($this->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;
      Route::for('integrations')
         ->post([$this, 'handleAction'])
         ->args([
            'service'   => 'string|required|enum:'.implode(',',JVB()->getAvailableServices()),
            'action' => 'string|required',
            'user_id'   => 'int',
            'context'   => 'string|enum:admin,user',
            'data'      => 'array'
         ])
         ->auth('user')
         ->rateLimit(20)
         ->register();
      Route::for('oath/connect')
         ->post([$this, 'initiateOAuth'])
         ->auth('user')
         ->rateLimit(20)
         ->args([
            'service'   => 'string|required',
            'user_id'   => 'int',
            'return_url'=> 'url'
         ])
         ->register();
   }
   /**
@@ -136,154 +52,51 @@
      $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;
      $theUserID = (user_can($request->get_param('user'), 'manage_options')) ? null : $request->get_param('user');
      $integration = JVB()->connect($service, $theUserID);
      if (!$integration) {
         return new WP_REST_Response([
            'success' => false,
            'message' => 'Service not found'
         ], 404);
         return $this->validationError(['message'=>'Invalid service']);
      }
      $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);
         return $this->success($result);
      } catch (Exception $e) {
         return new WP_REST_Response([
            'success' => false,
            'message' => $e->getMessage()
         ], 400);
         return $this->error($e->getMessage());
      }
   }
   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();
      $user_id = $request->get_param('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);
         return $this->validationError(['message'=>'Invalid service']);
      }
      $auth_url = $integration->getOAuthUrl($return_url);
      if ($auth_url) {
         return new WP_REST_Response([
            'success' => true,
            'auth_url' => $auth_url,
            'popup' => true
         ], 200);
         return $this->success($auth_url);
      }
      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;
      return $this->error('Failed to generate authorization URL');
   }
}