ajax = true; $this->content_only = true; $this->controller_type = 'module'; $this->errorHandler = $this->module->getService(ErrorHandler::class); try { $this->psAccountsAdapterService = $this->module->getService(PsAccountsAdapterService::class); $this->proxyService = $this->module->getService(ProxyService::class); $this->authorizationService = $this->module->getService(ApiAuthorizationService::class); $this->synchronizationService = $this->module->getService(SynchronizationService::class); } catch (\Exception $exception) { $this->errorHandler->handle($exception); $this->exitWithExceptionMessage($exception); } $this->eventbusSyncRepository = $this->module->getService(EventbusSyncRepository::class); $this->languageRepository = $this->module->getService(LanguageRepository::class); $this->incrementalSyncRepository = $this->module->getService(IncrementalSyncRepository::class); } /** * @return bool|void * * @throws UnauthorizedException */ public function init() { $this->startTime = time(); try { $this->authorize(); } catch (\Exception $exception) { // For ApiHealthCheck, handle the error, and throw UnauthorizedException directly, to catch-up at top level. if (strpos($this->page_name, 'apiHealthCheck') !== false) { $this->errorHandler->handle($exception); throw new UnauthorizedException('You are not allowed to access to this resource'); } if ($exception instanceof \PrestaShopDatabaseException) { $this->errorHandler->handle($exception); $this->exitWithExceptionMessage($exception); } elseif ($exception instanceof EnvVarException) { $this->errorHandler->handle($exception); $this->exitWithExceptionMessage($exception); } elseif ($exception instanceof FirebaseException) { $this->errorHandler->handle($exception); $this->exitWithExceptionMessage($exception); } } } /** * @return void * * @throws \PrestaShopDatabaseException|EnvVarException|FirebaseException */ private function authorize() { /** @var string $jobId */ $jobId = \Tools::getValue('job_id', 'empty_job_id'); $authorizationResponse = $this->authorizationService->authorizeCall($jobId); if (is_array($authorizationResponse)) { $this->exitWithResponse($authorizationResponse); } elseif (!$authorizationResponse) { throw new \PrestaShopDatabaseException('Failed saving job id to database'); } try { $token = $this->psAccountsAdapterService->getOrRefreshToken(); } catch (\Exception $exception) { throw new FirebaseException($exception->getMessage()); } if (!$token) { throw new FirebaseException('Invalid token'); } } /** * @param PaginatedApiDataProviderInterface $dataProvider * * @return array */ protected function handleDataSync(PaginatedApiDataProviderInterface $dataProvider) { /** @var bool $debug */ $debug = \Tools::getValue('debug') == 1; /** @var string $jobId */ $jobId = \Tools::getValue('job_id'); /** @var string $langIso */ $langIso = \Tools::getValue('lang_iso', $this->languageRepository->getDefaultLanguageIsoCode()); /** @var int $limit */ $limit = \Tools::getValue('limit', 50); if ($limit < 0) { $this->exitWithExceptionMessage(new QueryParamsException('Invalid URL Parameters', Config::INVALID_URL_QUERY)); } /** @var bool $initFullSync */ $initFullSync = \Tools::getValue('full', 0) == 1; /** @var \PrestaShop\Module\PsEventbus\Repository\ConfigurationRepository $configurationRepository */ $configurationRepository = $this->module->getService(\PrestaShop\Module\PsEventbus\Repository\ConfigurationRepository::class); $timezone = (string) $configurationRepository->get('PS_TIMEZONE'); $dateNow = (new \DateTime('now', new \DateTimeZone($timezone)))->format(MYSQL_DATE_FORMAT); $offset = 0; $incrementalSync = false; $response = []; try { $typeSync = $this->eventbusSyncRepository->findTypeSync($this->type, $langIso); if ($debug) { $response = $dataProvider->getQueryForDebug($offset, $limit, $langIso); return array_merge( [ 'object_type' => $this->type, ], $response ); } if ($typeSync !== false && is_array($typeSync)) { $offset = (int) $typeSync['offset']; if ((int) $typeSync['full_sync_finished'] === 1 && !$initFullSync) { $incrementalSync = true; } elseif ($initFullSync) { $offset = 0; $this->eventbusSyncRepository->updateTypeSync( $this->type, $offset, $dateNow, false, $langIso ); $this->incrementalSyncRepository->removeIncrementaSyncObjectByType($this->type); } } else { $this->eventbusSyncRepository->insertTypeSync($this->type, $offset, $dateNow, $langIso); } if ($incrementalSync) { $response = $this->synchronizationService->handleIncrementalSync( $dataProvider, $this->type, $jobId, $limit, $langIso, $this->startTime, $initFullSync ); } else { $response = $this->synchronizationService->handleFullSync( $dataProvider, $this->type, $jobId, $langIso, $offset, $limit, $dateNow, $this->startTime, $initFullSync ); } return array_merge( [ 'job_id' => $jobId, 'object_type' => $this->type, 'syncType' => $incrementalSync ? 'incremental' : 'full', ], $response ); } catch (\PrestaShopDatabaseException $exception) { $this->errorHandler->handle($exception); $this->exitWithExceptionMessage($exception); } catch (EnvVarException $exception) { $this->errorHandler->handle($exception); $this->exitWithExceptionMessage($exception); } catch (FirebaseException $exception) { $this->errorHandler->handle($exception); $this->exitWithExceptionMessage($exception); } catch (\Exception $exception) { $this->errorHandler->handle($exception); $this->exitWithExceptionMessage($exception); } return $response; } /** * @param array|null $value * @param string|null $controller * @param string|null $method * * @return void * * @throws \PrestaShopException */ public function ajaxDie($value = null, $controller = null, $method = null) { parent::ajaxDie(json_encode($value) ?: null, $controller, $method); } /** * @param array $response * * @return void */ protected function exitWithResponse($response) { $httpCode = isset($response['httpCode']) ? (int) $response['httpCode'] : 200; $this->dieWithResponse($response, $httpCode); } /** * @param \Exception $exception * * @return void */ protected function exitWithExceptionMessage(\Exception $exception) { $code = $exception->getCode() == 0 ? 500 : $exception->getCode(); if ($exception instanceof \PrestaShopDatabaseException) { $code = Config::DATABASE_QUERY_ERROR_CODE; } elseif ($exception instanceof EnvVarException) { $code = Config::ENV_MISCONFIGURED_ERROR_CODE; } elseif ($exception instanceof FirebaseException) { $code = Config::REFRESH_TOKEN_ERROR_CODE; } elseif ($exception instanceof QueryParamsException) { $code = Config::INVALID_URL_QUERY; } $response = [ 'object_type' => $this->type, 'status' => false, 'httpCode' => $code, 'message' => $exception->getMessage(), ]; $this->dieWithResponse($response, (int) $code); } /** * @param array $response * @param int $code * * @return void */ private function dieWithResponse($response, $code) { $httpStatusText = "HTTP/1.1 $code"; if (array_key_exists((int) $code, Config::HTTP_STATUS_MESSAGES)) { $httpStatusText .= ' ' . Config::HTTP_STATUS_MESSAGES[(int) $code]; } elseif (isset($response['body']['statusText'])) { $httpStatusText .= ' ' . $response['body']['statusText']; } $response['httpCode'] = (int) $code; header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0'); header('Content-Type: application/json;charset=utf-8'); header($httpStatusText); echo json_encode($response, JSON_UNESCAPED_SLASHES); exit; } }