| | |
| | | |
| | | trait OAuth |
| | | { |
| | | use _Base, Admin; |
| | | use _Base, Admin, ServiceMap; |
| | | protected OAuthURLs $oauth; |
| | | /** |
| | | * Child classes must set this (e.g. 'https://api.example.com/v1/') |
| | |
| | | { |
| | | return $this->getRequestHeaders(); |
| | | } |
| | | public function getOAuthBaseURL():?string |
| | | { |
| | | return $this->baseOAuthUrl; |
| | | } |
| | | |
| | | /** |
| | | * Default to the base handleResponse method, but extensions can modify accordingly |
| | |
| | | |
| | | function addOAuthActions():void |
| | | { |
| | | $actions = [ |
| | | [ |
| | | 'name' => 'Connect to Service', |
| | | 'label' => 'Connect', |
| | | 'icon' => 'plugs-connected', |
| | | 'action' => [$this, 'handleOAuthConnect'] |
| | | ], |
| | | [ |
| | | 'name' => 'Disconnect from Service', |
| | | 'icon' => 'plugs-disconnected', |
| | | 'action' => [$this, 'handleOAuthDisconnect'] |
| | | ], |
| | | if ($this->isSetUp()) { |
| | | $actions = [ |
| | | [ |
| | | 'name' => 'Connect to Service', |
| | | 'label' => 'Connect', |
| | | 'icon' => 'plugs-connected', |
| | | 'action' => [$this, 'handleOAuthConnect'] |
| | | ], |
| | | [ |
| | | 'name' => 'Disconnect from Service', |
| | | 'label' => 'Disconnect', |
| | | 'icon' => 'plugs-disconnected', |
| | | 'action' => [$this, 'handleOAuthDisconnect'] |
| | | ], |
| | | // [ |
| | | // 'name' => 'Refresh Token', |
| | | // 'icon' => 'arrows-clockwise', |
| | | // 'action' => [$this, 'handleOAuthRefreshToken'] |
| | | // ] |
| | | ]; |
| | | foreach ($actions as $a) { |
| | | $this->addAction($a['name'], $a['action'], $a['slug']??null, $a['icon']??null, $a['label']??null); |
| | | ]; |
| | | foreach ($actions as $a) { |
| | | $this->addAction($a['name'], $a['action'], $a['slug']??null, $a['icon']??null, $a['label']??null); |
| | | } |
| | | } |
| | | } |
| | | public function hasOAuthCredentials(?int $userID = null):bool |
| | |
| | | |
| | | public function revokeOAuth():bool |
| | | { |
| | | if (empty($this->oauth['revoke'])) { |
| | | if (empty($this->oauth->getRevoke())) { |
| | | error_log('No revoke url set for '.$this->service_name); |
| | | return false; |
| | | } |
| | |
| | | if (empty($credentials['access_token'])) { |
| | | error_log('Could not send revoke request, no access_token for '.$this->service_name); |
| | | } else { |
| | | $response = $this->postOAuthRequest($this->oauth['revoke'], [ |
| | | $response = $this->postOAuthRequest($this->oauth->getRevoke(), [ |
| | | 'body' => [ |
| | | 'token' => $credentials['access_token'] |
| | | ] |
| | |
| | | } |
| | | |
| | | // Get integration instance |
| | | $integration = JVB()->connect($this->service_name, $user_id); |
| | | $integration = $this->getService($this->service_name); |
| | | |
| | | if (!$integration) { |
| | | if (!$integration || !method_exists($integration, 'switchUser')) { |
| | | wp_die('Invalid service: ' . esc_html($this->service_name), 'OAuth Error'); |
| | | } |
| | | |
| | | $integration->switchUser($user_id); |
| | | |
| | | |
| | | // Exchange code for tokens |
| | | $result = $integration->handleOAuthCode($code, $state); |
| | |
| | | $credentials = $this->loadCredentials(); |
| | | $hasCredentials = $this->hasValidOAuth(); |
| | | $returnURL = $this->getReturnURL(); |
| | | |
| | | if ($hasCredentials) { |
| | | if (!$this->isSetUp()) { |
| | | return ''; |
| | | } |
| | | if (!$hasCredentials) { |
| | | return sprintf( |
| | | '<div class="oauth-connect"> |
| | | <h3>Connect to your %s account</h3> |
| | | <a href="%s" class="btn jvb-oauth-connect" data-service="%s">%s Authorize Connection</a>', |
| | | <a href="%s" class="btn jvb-oauth-connect" data-service="%s">%s Authorize Connection</a> |
| | | </div>', |
| | | $this->title, |
| | | $this->getOAuthURL($returnURL), |
| | | esc_attr($this->service_name), |
| | | $this->outputIcon($this->icon) |
| | | ); |
| | | } |
| | | $form = sprintf( |
| | | '<details open> |
| | | } else { |
| | | $form = sprintf( |
| | | '<details open> |
| | | <summary>Connected Account |
| | | <div class="connection-status connected"> |
| | | <span class="status-indicator">●</span> |
| | |
| | | </summary> |
| | | <span class="label">OAuth Redirect URL:</span> |
| | | <code>%s</code>', |
| | | $this->getRedirectUri() |
| | | ); |
| | | if (!empty($credentials['updated_at'])) { |
| | | $form .= sprintf( |
| | | '<div class="oauth-meta"><small>Token expires: %s</small></div>', |
| | | array_key_exists('expires_at', $credentials) ? |
| | | $this->getRedirectUri() |
| | | ); |
| | | if (!empty($credentials['updated_at'])) { |
| | | $form .= sprintf( |
| | | '<div class="oauth-meta"><small>Token expires: %s</small></div>', |
| | | array_key_exists('expires_at', $credentials) ? |
| | | human_time_diff($credentials['expires_at']) : |
| | | 'Never' |
| | | ); |
| | | ); |
| | | } |
| | | // |
| | | if (method_exists($this, 'renderOAuthConnectedOptions')) { |
| | | $form .= $this->renderOAuthConnectedOptions(); |
| | | } |
| | | $form .= '</details>'; |
| | | return $form; |
| | | } |
| | | // |
| | | if (method_exists($this, 'renderOAuthConnectedOptions')) { |
| | | $form .= $this->renderOAuthConnectedOptions(); |
| | | } |
| | | $form .= '</details'; |
| | | return $form; |
| | | } |
| | | |
| | | /** |
| | |
| | | { |
| | | |
| | | $credentials = $this->loadCredentials(); |
| | | if (empty($this->oauth['authorize'])) { |
| | | if (empty($this->oauth->getAuthorize())) { |
| | | $this->logError('getOAuthUrl', 'OAuth authorize URL not configured'); |
| | | return ''; |
| | | } |
| | |
| | | $params = $this->addOAuthParams($params); |
| | | } |
| | | |
| | | return $this->oauth['authorize'] . '?' . http_build_query($params); |
| | | return $this->oauth->getAuthorize() . '?' . http_build_query($params); |
| | | } |
| | | |
| | | protected function getRedirectUri():string |