uc_gc_client-8.x-1.x-dev/src/Controller/GoCardlessPartner.php
src/Controller/GoCardlessPartner.php
<?php
namespace Drupal\uc_gc_client\Controller;
use Drupal\Core\Controller\ControllerBase;
use GuzzleHttp\Exception\RequestException;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
/**
* Functions for communicating with the GoCardless partner: Seamless-CMS.co.uk.
*/
class GoCardlessPartner extends ControllerBase {
/**
* The module settings and payment method settings.
*
* @var array
*/
public $settings;
/**
* The logger.
*
* @var \Psr\Log\LoggerInterface
*/
private $logger;
/**
* The currently active request object.
*
* @var \Symfony\Component\HttpFoundation\Session\Session
*/
protected $session;
/**
* The httpClient service.
*
* @var \GuzzleHttp\Psr7\Response
*/
protected $httpClient;
/**
* Constructs the GoCardlessPartner object.
*/
public function __construct() {
$this->settings = $this->getSettings();
$this->logger = $this->getLogger('uc_gc_client');
$this->session = \Drupal::request()->getSession();
$this->httpClient = \Drupal::httpClient();
}
/**
* Gets the GoCardless webhook password.
*
* @return string
* The password, depending on if the payment method is in live or sandbox
* mode.
*/
public static function getPartnerWebhook() {
return GoCardlessPartner::getSettings()['partner_webhook'];
}
/**
* Gets the module and the payment gateway settings combined.
*
* @return array
* The settings.
*/
public static function getSettings() {
$config_id = \Drupal::state()->get('uc_gc_client_payment_method_id');
if (!is_null($config_id)) {
$settings = \Drupal::config($config_id)->get('settings');
$default_settings = \Drupal::config('uc_gc_client.settings');
$settings['config_id'] = explode('.', $config_id)[2];
$default_settings->get('sandbox') ? $settings['sandbox'] = 1 : $settings['sandbox'] = 0;
$default_settings->get('sandbox') ? $ext = '_sandbox' : $ext = '_live';
$settings['partner_user'] = $default_settings->get('partner_user' . $ext);
$settings['partner_pass'] = $default_settings->get('partner_pass' . $ext);
$settings['partner_webhook'] = $default_settings->get('partner_webhook' . $ext);
$settings['org_id'] = $default_settings->get('org_id' . $ext);
$settings['partner_url'] = $default_settings->get('partner_url');
return $settings;
}
}
/**
* Handles session authentication with GC Partner site.
*
* @return mixed
* If the site is already connected to the Partner site then the status
* code 200 is returned as an integer. If a new connection is attempted,
* and suceeds, the respose code (200) from the Partner site is returned,
* and if the attempt fails FALSE is returned. If the username and / or
* password are not set then a string is returned.
*/
protected function authenticate() {
if (isset($_SESSION['uc_gc_client_cookie_created']) && $_SESSION['uc_gc_client_cookie_created'] < REQUEST_TIME - 1800) {
unset($_SESSION['uc_gc_client_cookie']);
unset($_SESSION['uc_gc_client_cookie_created']);
}
if (!isset($_SESSION['uc_gc_client_cookie_created'])) {
$user_name = $this->settings['partner_user'];
$user_pass = $this->settings['partner_pass'];
// Attempt session authentication if user name and password set.
if (isset($user_name) && isset($user_pass)) {
$data = [
'username' => $user_name,
'password' => $user_pass,
];
$data = json_encode($data);
$uri = $this->settings['partner_url'] . '/gc_connect/user/login';
try {
$result = $this->httpClient
->post($uri, [
'headers' => ['Content-Type' => 'application/json'],
'body' => $data,
]
);
$result_data = (string) $result->getBody();
if (empty($result_data)) {
return FALSE;
}
$result_data = json_decode($result_data);
}
catch (RequestException $e) {
return FALSE;
}
if ($result->getStatusCode() == 200) {
// Get X-CRSF token, and save cookie and token.
$_SESSION['uc_gc_client_cookie'] = $result_data->session_name . '=' . $result_data->sessid;
$_SESSION['uc_gc_client_cookie_created'] = REQUEST_TIME;
$xcrf_uri = $this->settings['partner_url'] . '/services/session/token';
try {
$xcrf_result = $this->httpClient
->get($xcrf_uri, [
'headers' => ['Cookie' => $_SESSION['uc_gc_client_cookie']],
]
);
$xcrf_result_data = (string) $xcrf_result->getBody();
if (empty($xcrf_result_data)) {
return FALSE;
}
$_SESSION['uc_gc_client_token'] = $xcrf_result_data;
}
catch (RequestException $e) {
return FALSE;
}
}
return $result->getStatusCode();
}
else {
return $result = 'User name and password not set';
}
}
else {
// Already logged in.
return $result = 200;
}
}
/**
* Performs a GET request on the the Partner site.
*/
public function get($data = NULL) {
$auth = $this->authenticate();
if ($auth != 200) {
return $auth;
}
$this->settings['sandbox'] ? $data['environment'] = 'SANDBOX' : $data['environment'] = 'LIVE';
$headers = [
'Content-Type' => 'application/json',
'Cookie' => $_SESSION['uc_gc_client_cookie'],
'X-CSRF-Token' => $_SESSION['uc_gc_client_token'],
];
$data = json_encode($data);
$uri = $this->settings['partner_url'] . '/gc/client/' . $this->settings['org_id'];
try {
$response = $this->httpClient->get($uri, [
'headers' => $headers,
'body' => $data,
]);
$response_data = (string) $response->getBody();
if (empty($response_data)) {
return FALSE;
}
return $response_data = json_decode($response_data);
}
catch (RequestException $e) {
return FALSE;
}
}
/**
* Callback function: Saves key variables for connecting with Partner site.
*
* Variables are posted here from Partner site, following completion of
* GoCardless OAuth flow.
*
* @return object
* A new Symfony\Component\HttpFoundation\Response.
*/
public static function connect() {
if (isset($_POST['environ'])) {
$settings = \Drupal::service('config.factory')->getEditable('uc_gc_client.settings');
$_POST['environ'] == 'SANDBOX' ? $ext = '_sandbox' : $ext = '_live';
if (isset($_POST['id'])) {
$settings->set('org_id' . $ext, $_POST['id'])->save();
}
if (isset($_POST['name'])) {
$settings->set('partner_user' . $ext, $_POST['name'])->save();
}
if (isset($_POST['pass'])) {
$settings->set('partner_pass' . $ext, $_POST['pass'])->save();
}
}
return new Response();
}
/**
* Redirects user to GC settings page upon completion of OAuth flow.
*
* @return object
* A new Symfony\Component\HttpFoundation\RedirectResponse.
*/
public static function connectComplete() {
if (isset($_GET['status'])) {
if ($_GET['status'] == 'insecure') {
drupal_set_message(t('Connection cannot be created because site must be secure (https) to use LIVE environment'), 'error');
}
elseif ($_GET['status'] == 'connected') {
drupal_set_message(t('You have connected successfully with GoCardless'));
}
}
$config_id = \Drupal::state()->get('uc_gc_client_payment_method_id');
$config_id = explode('.', $config_id)[2];
return new RedirectResponse('/admin/store/config/payment/method/' . $config_id);
}
/**
* Handles API requests to GC Partner site, and optionally logs results.
*
* @params array
* The parameters for the request.
*
* @return mixed
* If authentication fails then the result from the authentication attempt
* is returned. If authentication is successfull then:
* - if the request succeeds and the response is successful, the response
* is returned as an array;
* - if the request succeeds but the response is an error, a string is
* returned containing the error code and message.
* - if the request succeeds but the response is empty, return FALSE;
* - if the request fails the RequestException error code is returned;
*/
public function api($params) {
$auth = $this->authenticate();
if ($auth == 200) {
$headers = [
'Content-Type' => 'application/json',
'Cookie' => $_SESSION['uc_gc_client_cookie'],
'X-CSRF-Token' => $_SESSION['uc_gc_client_token'],
];
$this->settings['sandbox'] ? $params['environment'] = 'SANDBOX' : $params['environment'] = 'LIVE';
$uri = $this->settings['partner_url'] . '/gc/client/' . $this->settings['org_id'];
try {
$response = $this->httpClient
->post($uri, [
'headers' => $headers,
'body' => json_encode($params),
]
);
$result = (string) $response->getBody();
if (empty($result)) {
return FALSE;
}
$result = json_decode($result);
if (isset($result->error)) {
$message = $this->t('Error code @code (@error)', ['@code' => $result->code, '@error' => $result->error]);
drupal_set_message($message, 'error');
if ($this->settings['log_api']) {
$this->logger->error('<pre>' . $message . '<br />' . print_r($result, TRUE) . '</pre>', []);
}
return $message;
}
elseif ($this->settings['log_api']) {
$this->logger->notice('<pre>GoCardless API response: <br />' . print_r($result, TRUE) . '</pre>', []);
}
return $result;
}
catch (RequestException $e) {
return $e->getCode();
}
}
else {
drupal_set_message($this->t('Error @code connecting with partner site', ['@code' => $auth]), 'error');
if ($this->settings['log_api']) {
$this->logger->error('<pre>' . print_r($auth, TRUE) . '</pre>', []);
}
return $auth;
}
}
}
