-
Notifications
You must be signed in to change notification settings - Fork 212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ECP-9177] Implement webhook clean-up cronjob for old webhooks #2837
base: main
Are you sure you want to change the base?
Changes from all commits
1e81dcf
aa0d6ea
f64646d
423770e
b62a1e8
eff01fd
d63c6a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<?php | ||
/** | ||
* | ||
* Adyen Payment Module | ||
* | ||
* Copyright (c) 2024 Adyen N.V. | ||
* This file is open source and available under the MIT license. | ||
* See the LICENSE file for more info. | ||
* | ||
* Author: Adyen <[email protected]> | ||
*/ | ||
|
||
namespace Adyen\Payment\Api\Repository; | ||
|
||
use Adyen\Payment\Api\Data\NotificationInterface; | ||
use Magento\Framework\Api\SearchCriteriaInterface; | ||
use Magento\Framework\Api\SearchResultsInterface; | ||
use Magento\Framework\Exception\LocalizedException; | ||
|
||
interface AdyenNotificationRepositoryInterface | ||
{ | ||
/** | ||
* Retrieve Adyen Notification entities which match a specified criteria. | ||
* | ||
* @param SearchCriteriaInterface $searchCriteria | ||
* @return SearchResultsInterface | ||
* | ||
* @throws LocalizedException | ||
*/ | ||
public function getList(SearchCriteriaInterface $searchCriteria): SearchResultsInterface; | ||
|
||
/** | ||
* Deletes a specified Adyen notification. | ||
* | ||
* @param NotificationInterface $entity The notification ID. | ||
* @return bool | ||
*/ | ||
public function delete(NotificationInterface $entity): bool; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
<?php | ||
/** | ||
* | ||
* Adyen Payment module (https://www.adyen.com/) | ||
* | ||
* Copyright (c) 2024 Adyen N.V. (https://www.adyen.com/) | ||
* See LICENSE.txt for license details. | ||
* | ||
* Author: Adyen <[email protected]> | ||
*/ | ||
|
||
namespace Adyen\Payment\Cron; | ||
|
||
use Adyen\Payment\Api\Repository\AdyenNotificationRepositoryInterface; | ||
use Adyen\Payment\Cron\Providers\NotificationsProviderInterface; | ||
use Adyen\Payment\Helper\Config; | ||
use Adyen\Payment\Logger\AdyenLogger; | ||
use Adyen\Payment\Model\Notification; | ||
use Magento\Framework\Exception\NoSuchEntityException; | ||
use Magento\Store\Model\StoreManagerInterface; | ||
|
||
class CleanupNotifications | ||
{ | ||
/** | ||
* @param NotificationsProviderInterface[] $providers | ||
*/ | ||
public function __construct( | ||
private readonly array $providers, | ||
private readonly AdyenLogger $adyenLogger, | ||
private readonly Config $configHelper, | ||
private readonly StoreManagerInterface $storeManager, | ||
private readonly AdyenNotificationRepositoryInterface $adyenNotificationRepository | ||
) { } | ||
|
||
/** | ||
* @return void | ||
* @throws NoSuchEntityException | ||
*/ | ||
public function execute(): void | ||
{ | ||
$storeId = $this->storeManager->getStore()->getId(); | ||
$isWebhookCleanupEnabled = $this->configHelper->getIsWebhookCleanupEnabled($storeId); | ||
|
||
if ($isWebhookCleanupEnabled) { | ||
$numberOfItemsRemoved = 0; | ||
|
||
foreach ($this->providers as $provider) { | ||
/** @var Notification $notificationToCleanup */ | ||
foreach ($provider->provide() as $notificationToCleanup) { | ||
$isSuccessfullyDeleted = $this->adyenNotificationRepository->delete($notificationToCleanup); | ||
|
||
if ($isSuccessfullyDeleted) { | ||
$message = __('%1: Notification with entityId %2 has been deleted.', | ||
$provider->getProviderName(), $notificationToCleanup->getEntityId()); | ||
$this->adyenLogger->addAdyenNotification($message); | ||
|
||
$numberOfItemsRemoved++; | ||
} | ||
} | ||
} | ||
|
||
$successMessage = sprintf( | ||
__('%s webhook notifications have been cleaned-up by the CleanupNotifications job.'), | ||
$numberOfItemsRemoved | ||
); | ||
$this->adyenLogger->addAdyenDebug($successMessage); | ||
} else { | ||
$message = __('Webhook notification clean-up feature is disabled. The job has been skipped!'); | ||
$this->adyenLogger->addAdyenDebug($message); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
/** | ||
* | ||
* Adyen Payment module (https://www.adyen.com/) | ||
* | ||
* Copyright (c) 2024 Adyen N.V. (https://www.adyen.com/) | ||
* See LICENSE.txt for license details. | ||
* | ||
* Author: Adyen <[email protected]> | ||
*/ | ||
|
||
namespace Adyen\Payment\Cron\Providers; | ||
|
||
interface NotificationsProviderInterface | ||
{ | ||
/** | ||
* @return array | ||
*/ | ||
public function provide(): array; | ||
|
||
/** | ||
* @return string | ||
*/ | ||
public function getProviderName(): string; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
<?php | ||
/** | ||
* | ||
* Adyen Payment module (https://www.adyen.com/) | ||
* | ||
* Copyright (c) 2024 Adyen N.V. (https://www.adyen.com/) | ||
* See LICENSE.txt for license details. | ||
* | ||
* Author: Adyen <[email protected]> | ||
*/ | ||
|
||
namespace Adyen\Payment\Cron\Providers; | ||
|
||
use Adyen\Payment\Api\Repository\AdyenNotificationRepositoryInterface; | ||
use Adyen\Payment\Helper\Config; | ||
use Adyen\Payment\Logger\AdyenLogger; | ||
use Magento\Framework\Api\SearchCriteriaBuilder; | ||
use Magento\Framework\Exception\LocalizedException; | ||
use Magento\Store\Model\StoreManagerInterface; | ||
|
||
class ProcessedOldNotificationsProvider implements NotificationsProviderInterface | ||
{ | ||
public function __construct( | ||
private readonly AdyenNotificationRepositoryInterface $adyenNotificationRepository, | ||
private readonly SearchCriteriaBuilder $searchCriteriaBuilder, | ||
private readonly Config $configHelper, | ||
private readonly StoreManagerInterface $storeManager, | ||
private readonly AdyenLogger $adyenLogger | ||
) { } | ||
|
||
public function provide(): array | ||
{ | ||
$storeId = $this->storeManager->getStore()->getId(); | ||
$numberOfDays = $this->configHelper->getRequiredDaysForOldWebhooks($storeId); | ||
|
||
$dateFrom = date('Y-m-d H:i:s', time() - $numberOfDays * 24 * 60 * 60); | ||
|
||
$searchCriteria = $this->searchCriteriaBuilder | ||
->addFilter('done', 1) | ||
->addFilter('processing', 0) | ||
->addFilter('created_at', $dateFrom, 'lteq') | ||
->create(); | ||
|
||
try { | ||
$items = $this->adyenNotificationRepository->getList($searchCriteria); | ||
return $items->getItems(); | ||
} catch (LocalizedException $e) { | ||
$errorMessage = sprintf( | ||
__('An error occurred while providing notifications older than %s days!'), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we add the store name or ID here? Maybe that's useful to see in the log line to be able to debug There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hello @acampos1916, thank you for the review.
|
||
$numberOfDays | ||
); | ||
|
||
$this->adyenLogger->error($errorMessage); | ||
|
||
return []; | ||
} | ||
} | ||
|
||
public function getProviderName(): string | ||
candemiralp marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
return "Adyen processed old webhook notifications"; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
<?php | ||
/** | ||
* | ||
* Adyen Payment module (https://www.adyen.com/) | ||
* | ||
* Copyright (c) 2024 Adyen N.V. (https://www.adyen.com/) | ||
* See LICENSE.txt for license details. | ||
* | ||
* Author: Adyen <[email protected]> | ||
*/ | ||
|
||
namespace Adyen\Payment\Model; | ||
|
||
use Adyen\Payment\Api\Data\NotificationInterface; | ||
use Adyen\Payment\Api\Repository\AdyenNotificationRepositoryInterface; | ||
use Adyen\Payment\Model\ResourceModel\Notification\CollectionFactory; | ||
use Magento\Framework\Api\Search\SearchResultFactory; | ||
use Magento\Framework\Api\SearchCriteria\CollectionProcessor; | ||
use Magento\Framework\Api\SearchCriteriaInterface; | ||
use Magento\Framework\Api\SearchResultsInterface; | ||
use Magento\Framework\ObjectManagerInterface; | ||
|
||
class AdyenNotificationRepository implements AdyenNotificationRepositoryInterface | ||
{ | ||
/** | ||
* @param SearchResultFactory $searchResultsFactory | ||
* @param CollectionFactory $collectionFactory | ||
* @param CollectionProcessor $collectionProcessor | ||
* @param ObjectManagerInterface $objectManager | ||
* @param string $resourceModel | ||
*/ | ||
public function __construct( | ||
private readonly SearchResultFactory $searchResultsFactory, | ||
private readonly CollectionFactory $collectionFactory, | ||
private readonly CollectionProcessor $collectionProcessor, | ||
private readonly ObjectManagerInterface $objectManager, | ||
private readonly string $resourceModel | ||
) { } | ||
|
||
/** | ||
* @param SearchCriteriaInterface $searchCriteria | ||
* @return SearchResultsInterface | ||
*/ | ||
public function getList(SearchCriteriaInterface $searchCriteria): SearchResultsInterface | ||
{ | ||
$searchResult = $this->searchResultsFactory->create(); | ||
$collection = $this->collectionFactory->create(); | ||
$this->collectionProcessor->process($searchCriteria, $collection); | ||
$searchResult->setItems($collection->getItems()); | ||
$searchResult->setTotalCount($collection->getSize()); | ||
|
||
return $searchResult; | ||
} | ||
|
||
public function delete(NotificationInterface $entity): bool | ||
{ | ||
$resource = $this->objectManager->get($this->resourceModel); | ||
$resource->delete($entity); | ||
|
||
return true; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add also here one extra info: Notification with entityId %2 has been deleted because it was processed/received X days ago.
Probably means getting that field from the provider