Skip to content

Commit

Permalink
PIPRES-319: Lock webhook controller
Browse files Browse the repository at this point in the history
  • Loading branch information
mandan2 committed Nov 8, 2023
1 parent 4921d58 commit 7fe65db
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 44 deletions.
121 changes: 77 additions & 44 deletions controllers/front/webhook.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@
* @codingStandardsIgnoreStart
*/

use Mollie\Api\Exceptions\ApiException;
use Mollie\Config\Config;
use Mollie\Controller\AbstractMollieController;
use Mollie\Errors\Http\HttpStatusCode;
use Mollie\Handler\ErrorHandler\ErrorHandler;
use Mollie\Infrastructure\Adapter\Lock;
use Mollie\Logger\PrestaLoggerInterface;
use Mollie\Service\TransactionService;
use Mollie\Utility\TransactionUtility;

Expand All @@ -38,79 +39,111 @@ class MollieWebhookModuleFrontController extends AbstractMollieController
*
* @return void
*/
protected function displayMaintenancePage()
protected function displayMaintenancePage(): void
{
}

/**
* @throws ApiException
* @throws PrestaShopDatabaseException
* @throws PrestaShopException
*/
public function initContent()
public function initContent(): void
{
/** @var PrestaLoggerInterface $logger */
$logger = $this->module->getService(PrestaLoggerInterface::class);

/** @var ErrorHandler $errorHandler */
$errorHandler = $this->module->getService(ErrorHandler::class);

if ((int) Configuration::get(Config::MOLLIE_DEBUG_LOG) === Config::DEBUG_LOG_ALL) {
PrestaShopLogger::addLog('Mollie incoming webhook: ' . Tools::file_get_contents('php://input'));
$logger->info('Mollie incoming webhook: ' . Tools::file_get_contents('php://input'));
}

$transactionId = (string) Tools::getValue('id');

if (!$transactionId) {
$this->respond('failed', HttpStatusCode::HTTP_UNPROCESSABLE_ENTITY, 'Missing transaction id');
}

if (!$this->module->getApiClient()) {
$this->respond('failed', HttpStatusCode::HTTP_UNAUTHORIZED, 'API key is missing or incorrect');
}

/** @var Lock $lock */
$lock = $this->module->getService(Lock::class);

try {
$lock->create($transactionId);

$acquired = $lock->acquire();
} catch (\Throwable $exception) {
$logger->error(
'Failed to lock process',
[
'Exception message' => $exception->getMessage(),
'Exception code' => $exception->getCode(),
'transaction_id' => $transactionId,
]
);

$errorHandler->handle($exception, $exception->getCode(), false);

$this->respond('failed', HttpStatusCode::HTTP_BAD_REQUEST, 'Failed to lock process');
}

if (!$acquired) {

Check failure on line 90 in controllers/front/webhook.php

View workflow job for this annotation

GitHub Actions / PHPStan (1.7.6.8)

Variable $acquired might not be defined.
$this->respond('failed', HttpStatusCode::HTTP_BAD_REQUEST, 'Another process is locked');
}

try {
exit($this->executeWebhook());
$result = $this->executeWebhook($transactionId);
} catch (\Throwable $exception) {
PrestaShopLogger::addLog('Error occurred: ' . $exception->getMessage(), 3, null, 'Mollie');
$logger->error(
'Failed to process webhook',
[
'Exception message' => $exception->getMessage(),
'Exception code' => $exception->getCode(),
'transaction_id' => $transactionId,
]
);

$errorHandler->handle($exception, $exception->getCode(), false);

$this->respond('failed', HttpStatusCode::HTTP_BAD_REQUEST, 'Failed to process webhook');
}

$this->respond('success', HttpStatusCode::HTTP_OK, $result);

Check failure on line 111 in controllers/front/webhook.php

View workflow job for this annotation

GitHub Actions / PHPStan (1.7.6.8)

Variable $result might not be defined.
}

/**
* @return string
*
* @throws ApiException
* @throws PrestaShopDatabaseException
* @throws PrestaShopException
* @throws \Throwable
*/
protected function executeWebhook()
protected function executeWebhook(string $transactionId): string
{
/** @var TransactionService $transactionService */
$transactionService = $this->module->getService(TransactionService::class);

/** @var ErrorHandler $errorHandler */
$errorHandler = $this->module->getService(ErrorHandler::class);

$transactionId = Tools::getValue('id');
if (!$transactionId) {
$this->respond('failed', HttpStatusCode::HTTP_UNPROCESSABLE_ENTITY, 'Missing transaction id');
}
// TODO even if transaction is not found, we should return OK 200

if (!$this->module->getApiClient()) {
$this->respond('failed', HttpStatusCode::HTTP_UNAUTHORIZED, 'API key is missing or incorrect');
}
if (TransactionUtility::isOrderTransaction($transactionId)) {
$transaction = $this->module->getApiClient()->orders->get($transactionId, ['embed' => 'payments']);
} else {
$transaction = $this->module->getApiClient()->payments->get($transactionId);

try {
if (TransactionUtility::isOrderTransaction($transactionId)) {
$transaction = $this->module->getApiClient()->orders->get($transactionId, ['embed' => 'payments']);
} else {
$transaction = $this->module->getApiClient()->payments->get($transactionId);
if ($transaction->orderId) {
$transaction = $this->module->getApiClient()->orders->get($transaction->orderId, ['embed' => 'payments']);
}
if ($transaction->orderId) {
$transaction = $this->module->getApiClient()->orders->get($transaction->orderId, ['embed' => 'payments']);
}
$metaData = $transaction->metadata;
$cartId = $metaData->cart_id ?? 0;
$this->setContext($cartId);
$payment = $transactionService->processTransaction($transaction);
} catch (\Throwable $e) {
$errorHandler->handle($e, $e->getCode(), false);
$this->respond('failed', $e->getCode(), $e->getMessage());
}

/* @phpstan-ignore-next-line */
$metaData = $transaction->metadata;
$cartId = $metaData->cart_id ?? 0;
$this->setContext($cartId);
$payment = $transactionService->processTransaction($transaction);

if (is_string($payment)) {
return $payment;
}

return 'OK';
}

private function setContext(int $cartId)
private function setContext(int $cartId): void
{
if (!$cartId) {
return;
Expand Down
3 changes: 3 additions & 0 deletions src/Logger/PrestaLogger.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

class PrestaLogger implements PrestaLoggerInterface
{
// TODO integrate sentry into logger service
// TODO integrate logs switch into logger service

public function emergency($message, array $context = [])
{
throw new NotImplementedException('not implemented method');
Expand Down

0 comments on commit 7fe65db

Please sign in to comment.