427 lines
11 KiB
PHP
427 lines
11 KiB
PHP
<?php
|
|
/**
|
|
* Copyright (C) 2020 Futurenext srl
|
|
*
|
|
* This file is part of Zakeke.
|
|
*
|
|
* Zakeke Interactive Product Designer can not be copied and/or distributed
|
|
* without the express permission of Futurenext srl
|
|
*
|
|
* @author Futurenext srl <help@zakeke.com>
|
|
* @copyright 2019 Futurenext srl
|
|
* @license https://www.zakeke.com/privacy/#general_conditions
|
|
*/
|
|
|
|
class ZakekeApi
|
|
{
|
|
const ZAKEKE_API_URL = 'https://zakeke-api-frontdoor.azurefd.net';
|
|
|
|
/** @var bool Enable debug mode */
|
|
protected $debug = false;
|
|
|
|
/**
|
|
* Check if the design identifier is valid by throwing an exception
|
|
*
|
|
* @param $designId
|
|
* @throws Exception
|
|
*/
|
|
private static function checkDesignId($designId)
|
|
{
|
|
if (strpos($designId, 'Testing-') === 0) {
|
|
return;
|
|
}
|
|
if (!preg_match('/\d\d\d-\w{22}/', $designId)) {
|
|
throw new Exception($designId . ' is not a valid design identifier');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ZakekeApi constructor.
|
|
*
|
|
* @param bool $debug
|
|
*/
|
|
public function __construct($debug)
|
|
{
|
|
$this->debug = $debug;
|
|
}
|
|
|
|
/**
|
|
* Associate the guest with a customer
|
|
*
|
|
* @param string $guestCode Guest identifier.
|
|
* @param string $customerId Customer identifier.
|
|
*
|
|
* @throws Exception
|
|
* @return void
|
|
*/
|
|
public function associateGuest($guestCode, $customerId)
|
|
{
|
|
$data = $this->authMinimalData();
|
|
$data['visitorcode'] = $guestCode;
|
|
$data['customercode'] = $customerId;
|
|
|
|
$this->authToken($data);
|
|
}
|
|
|
|
/**
|
|
* Get the minimal data required to get the authentication token
|
|
*
|
|
* @return array
|
|
*/
|
|
private function authMinimalData()
|
|
{
|
|
$data = array(
|
|
'api_client_id' => Configuration::get('ZAKEKE_API_CLIENT_ID'),
|
|
'api_secret_key' => Configuration::get('ZAKEKE_API_SECRET_KEY')
|
|
);
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Zakeke authentication token.
|
|
*
|
|
* @param array $data
|
|
* @param array $authData
|
|
*
|
|
* @throws Exception
|
|
* @return string
|
|
*/
|
|
public function authToken($data, $authData = null)
|
|
{
|
|
if (is_null($authData)) {
|
|
$authData = $this->authMinimalData();
|
|
}
|
|
|
|
$url = ZakekeApi::ZAKEKE_API_URL . '/token';
|
|
$postfields = http_build_query(array_merge($data, array(
|
|
'grant_type' => 'client_credentials'
|
|
)), null, '&');
|
|
|
|
$headers = array(
|
|
'Content-Type: application/x-www-form-urlencoded',
|
|
'Accept: application/json',
|
|
'User-Agent: prestashop-zakeke/' . ZAKEKE_VERSION . '; Prestashop/' . _PS_VERSION_ . '; ' . __PS_BASE_URI__
|
|
);
|
|
|
|
$curl = curl_init();
|
|
curl_setopt_array(
|
|
$curl,
|
|
array(
|
|
CURLOPT_URL => $url,
|
|
CURLOPT_USERPWD => $authData['api_client_id'] . ':' . $authData['api_secret_key'],
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_VERBOSE => true,
|
|
CURLOPT_TIMEOUT => 30,
|
|
CURLOPT_CUSTOMREQUEST => 'POST',
|
|
CURLOPT_POSTFIELDS => $postfields,
|
|
CURLOPT_HTTPHEADER => $headers
|
|
)
|
|
);
|
|
|
|
$rawResponse = curl_exec($curl);
|
|
$error = curl_error($curl);
|
|
$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
|
curl_close($curl);
|
|
|
|
$this->maybeLog($url, 'POST', $data, $rawResponse, $statusCode);
|
|
|
|
if ($error || !$this->isStatusCodeOk($statusCode)) {
|
|
$msg = '$zakekeApi authToken: status: ' . $statusCode
|
|
. ' ' . $error . ', response: ' . $rawResponse;
|
|
throw new Exception($msg);
|
|
}
|
|
|
|
$result = json_decode($rawResponse, true);
|
|
|
|
return $result['access_token'];
|
|
}
|
|
|
|
/**
|
|
* Performs the underlying HTTP request.
|
|
*
|
|
* @param string $method HTTP method (GET|POST|PUT|PATCH|DELETE)
|
|
* @param string $resource MailChimp API resource to be called
|
|
* @param array $args array of parameters to be passed
|
|
* @param string $authToken Authentication token
|
|
*
|
|
* @throws Exception
|
|
* @return array array of decoded result
|
|
*/
|
|
protected function request($method, $resource, $args = array(), $authToken = null)
|
|
{
|
|
$url = ZakekeApi::ZAKEKE_API_URL . $resource;
|
|
|
|
// attach arguments (in body or URL)
|
|
$postfields = '';
|
|
if (!empty($args)) {
|
|
if ($method === 'GET') {
|
|
$url .= '?' . http_build_query($args);
|
|
} else {
|
|
$postfields = json_encode($args);
|
|
}
|
|
}
|
|
|
|
$headers = array(
|
|
'Content-Type: application/json',
|
|
'Accept: application/json',
|
|
'User-Agent: prestashop-zakeke/' . ZAKEKE_VERSION . '; Prestashop/' . _PS_VERSION_ . '; ' . __PS_BASE_URI__
|
|
);
|
|
|
|
if ($authToken != null) {
|
|
$headers[] = 'Authorization: Bearer ' . $authToken;
|
|
}
|
|
|
|
$curl = curl_init();
|
|
curl_setopt_array(
|
|
$curl,
|
|
array(
|
|
CURLOPT_URL => $url,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_VERBOSE => true,
|
|
CURLOPT_TIMEOUT => 30,
|
|
CURLOPT_CUSTOMREQUEST => $method,
|
|
CURLOPT_POSTFIELDS => $postfields,
|
|
CURLOPT_HTTPHEADER => $headers
|
|
)
|
|
);
|
|
|
|
$rawResponse = curl_exec($curl);
|
|
$error = curl_error($curl);
|
|
$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
|
curl_close($curl);
|
|
|
|
$this->maybeLog($resource, $method, $args, $rawResponse, $statusCode);
|
|
|
|
if ($error ||!$this->isStatusCodeOk($statusCode)) {
|
|
$msg = '$zakekeApi request: ' . $resource . ', status: ' . $statusCode
|
|
. ' ' . $error . ', response: ' . $rawResponse;
|
|
throw new Exception($msg);
|
|
}
|
|
|
|
$result = json_decode($rawResponse, true);
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Remove sensitive information from the logs
|
|
*
|
|
* @param string $message
|
|
* @return string
|
|
*/
|
|
private static function sanitizeLog($message)
|
|
{
|
|
$zakeke_api_secret = Configuration::get('ZAKEKE_API_SECRET_KEY');
|
|
if ($zakeke_api_secret) {
|
|
$message = str_replace($zakeke_api_secret, 'ZAKEKE_API_SECRET_KEY', $message);
|
|
}
|
|
|
|
return $message;
|
|
}
|
|
|
|
/**
|
|
* Conditionally log Zakeke API Call
|
|
*
|
|
* @param string $url Zakeke url
|
|
* @param string $method HTTP Method
|
|
* @param array $args HTTP Request Body
|
|
* @param string $response HTTP Response
|
|
* @param int $statusCode HTTP status code
|
|
*
|
|
* @return void
|
|
*/
|
|
private function maybeLog($url, $method, $args, $response, $statusCode)
|
|
{
|
|
if (!$this->debug) {
|
|
return;
|
|
}
|
|
|
|
PrestaShopLogger::addLog(
|
|
self::sanitizeLog(
|
|
'Zakeke Webservice Call URL: ' . $method . ' ' . $url . ' METHOD: $method BODY: ' . print_r(
|
|
$args,
|
|
true
|
|
) . ' RESPONSE: ' . $statusCode . ' - ' . $response
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Check if the response was successful.
|
|
*
|
|
* @param int $statusCode HTTP status code
|
|
*
|
|
* @return bool
|
|
*/
|
|
protected function isStatusCodeOk($statusCode)
|
|
{
|
|
return $statusCode >= 200 && $statusCode < 400;
|
|
}
|
|
|
|
/**
|
|
* Get the needed data for adding a product to the cart
|
|
*
|
|
* @param string $designId Zakeke design identifier
|
|
* @param int $qty Quantity
|
|
*
|
|
* @throws Exception
|
|
* @return object
|
|
*/
|
|
public function cartInfo($designId, $qty)
|
|
{
|
|
self::checkDesignId($designId);
|
|
|
|
$authToken = $this->authToken(array());
|
|
|
|
$url = '/api/designdocs/' . $designId . '/cartinfo';
|
|
$data = array(
|
|
'qty' => $qty
|
|
);
|
|
|
|
$json = $this->request('GET', $url, $data, $authToken);
|
|
|
|
$res = new stdClass();
|
|
|
|
$res->pricing = $json['pricing'];
|
|
|
|
$preview = new stdClass();
|
|
$preview->url = $json['tempPreviewUrl'];
|
|
$preview->label = '';
|
|
|
|
$res->previews = array($preview);
|
|
|
|
return $res;
|
|
}
|
|
|
|
/**
|
|
* Get the needed data for adding a product to the cart
|
|
*
|
|
* @param string $configurationId Zakeke configuration identifier
|
|
* @param int $qty Quantity
|
|
*
|
|
* @throws Exception
|
|
* @return array
|
|
*/
|
|
public function configuratorCartInfo($configurationId, $qty)
|
|
{
|
|
self::checkDesignId($configurationId);
|
|
|
|
$authToken = $this->authToken(array(
|
|
'access_type' => 'S2S'
|
|
));
|
|
|
|
$url = '/v1/compositions/' . $configurationId . '/cartinfo';
|
|
$data = array(
|
|
'qty' => $qty
|
|
);
|
|
|
|
return $this->request('GET', $url, $data, $authToken);
|
|
}
|
|
|
|
/**
|
|
* Order containing Zakeke customized products placed.
|
|
*
|
|
* @param array $data The data of the order
|
|
*
|
|
* @throws Exception
|
|
* @return void
|
|
*/
|
|
public function placeOrder($data)
|
|
{
|
|
$authData = array();
|
|
if (isset($data['customerID'])) {
|
|
$authData['customercode'] = $data['customerID'];
|
|
} elseif (isset($data['visitorID'])) {
|
|
$authData['visitorcode'] = $data['visitorID'];
|
|
}
|
|
|
|
$authToken = $this->authToken($authData);
|
|
|
|
$data['marketplaceID'] = '1';
|
|
|
|
$this->request('POST', '/api/orderdocs', $data, $authToken);
|
|
}
|
|
|
|
/**
|
|
* Get the Zakeke design preview files
|
|
*
|
|
* @param string $designId Zakeke design identifier
|
|
*
|
|
* @throws Exception
|
|
* @return array
|
|
*/
|
|
public function getPreviews($designId)
|
|
{
|
|
self::checkDesignId($designId);
|
|
|
|
$authToken = $this->authToken(array());
|
|
|
|
$data = array(
|
|
'docid' => $designId
|
|
);
|
|
|
|
$json = self::request(
|
|
'GET',
|
|
'/api/designs/0/previewfiles',
|
|
$data,
|
|
$authToken
|
|
);
|
|
|
|
$previews = array();
|
|
foreach ($json as $preview) {
|
|
if ($preview['format'] == 'SVG') {
|
|
continue;
|
|
}
|
|
|
|
$previewObj = new stdClass();
|
|
$previewObj->url = $preview['url'];
|
|
$previewObj->label = $preview['sideName'];
|
|
$previews[] = $previewObj;
|
|
}
|
|
|
|
return $previews;
|
|
}
|
|
|
|
/**
|
|
* Get the Zakeke design output zip
|
|
*
|
|
* @param string $designId Zakeke design identifier
|
|
*
|
|
* @throws Exception
|
|
* @return string
|
|
*/
|
|
public function getZakekeOutputZip($designId)
|
|
{
|
|
self::checkDesignId($designId);
|
|
|
|
$authToken = $this->authToken(array());
|
|
|
|
$data = array(
|
|
'docid' => $designId
|
|
);
|
|
$json = $this->request(
|
|
'GET',
|
|
'/api/designs/0/outputfiles/zip',
|
|
$data,
|
|
$authToken
|
|
);
|
|
|
|
return $json['url'];
|
|
}
|
|
|
|
public function checkCredentials($clientId, $secretKey)
|
|
{
|
|
try {
|
|
$this->authToken(array(), array(
|
|
'api_client_id' => $clientId,
|
|
'api_secret_key' => $secretKey
|
|
));
|
|
|
|
return true;
|
|
} catch (Exception $e) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|