Merge pull request #259 from woocommerce/webhooks-status-page

Webhooks status page
This commit is contained in:
Emili Castells 2021-09-16 17:02:06 +02:00 committed by GitHub
commit efb5ab3d14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 5522 additions and 29 deletions

View file

@ -118,6 +118,46 @@ class WebhookEndpoint {
return $hook;
}
/**
* Loads the webhooks list for the current auth token.
*
* @return Webhook[]
* @throws RuntimeException If the request fails.
* @throws PayPalApiException If the request fails.
*/
public function list(): array {
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v1/notifications/webhooks';
$args = array(
'method' => 'GET',
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
),
);
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
throw new RuntimeException(
__( 'Not able to load webhooks list.', 'woocommerce-paypal-payments' )
);
}
$json = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 200 !== $status_code ) {
throw new PayPalApiException(
$json,
$status_code
);
}
return array_map(
array( $this->webhook_factory, 'from_paypal_response' ),
$json->webhooks
);
}
/**
* Deletes a webhook.
*

View file

@ -9,6 +9,8 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
use stdClass;
/**
* Class Webhook
*/
@ -71,13 +73,38 @@ class Webhook {
/**
* Returns the event types.
*
* @return array
* @return stdClass[]
*/
public function event_types(): array {
return $this->event_types;
}
/**
* Returns the human-friendly names of the event types.
*
* @return string[]
*/
public function humanfriendly_event_names(): array {
return array_map(
function ( $event ): string {
return Webhook::get_humanfriendly_event_name( $event->name );
},
$this->event_types
);
}
/**
* Converts event names to more human-friendly form.
*
* @param string $name The event name like 'CHECKOUT.ORDER.APPROVED'.
* @return string
*/
public static function get_humanfriendly_event_name( string $name ): string {
return strtolower( str_replace( '.', ' ', $name ) );
}
/**
* Returns the object as array.
*

View file

@ -38,6 +38,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsListener;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
return array(
'wcgateway.paypal-gateway' => static function ( $container ): PayPalGateway {
@ -118,7 +119,7 @@ return array(
}
$section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : '';
return in_array( $section, array( PayPalGateway::ID, CreditCardGateway::ID ), true );
return in_array( $section, array( PayPalGateway::ID, CreditCardGateway::ID, WebhooksStatusPage::ID ), true );
},
'wcgateway.current-ppcp-settings-page-id' => static function ( $container ): string {
@ -700,7 +701,7 @@ return array(
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => 'all',
'gateway' => array( 'paypal', 'dcc' ),
),
'logging_enabled' => array(
'title' => __( 'Logging', 'woocommerce-paypal-payments' ),

View file

@ -19,6 +19,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
use Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
/**
* Class PayPalGateway
@ -224,7 +225,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
),
);
$should_show_enabled_checkbox = ! $this->is_credit_card_tab() && ( $this->config->has( 'merchant_email' ) && $this->config->get( 'merchant_email' ) );
$should_show_enabled_checkbox = $this->is_paypal_tab() && ( $this->config->has( 'merchant_email' ) && $this->config->get( 'merchant_email' ) );
if ( ! $should_show_enabled_checkbox ) {
unset( $this->form_fields['enabled'] );
}
@ -308,6 +309,9 @@ class PayPalGateway extends \WC_Payment_Gateway {
if ( $this->is_credit_card_tab() ) {
return __( 'PayPal Card Processing', 'woocommerce-paypal-payments' );
}
if ( $this->is_webhooks_tab() ) {
return __( 'Webhooks Status', 'woocommerce-paypal-payments' );
}
if ( $this->is_paypal_tab() ) {
return __( 'PayPal Checkout', 'woocommerce-paypal-payments' );
}
@ -326,6 +330,12 @@ class PayPalGateway extends \WC_Payment_Gateway {
'woocommerce-paypal-payments'
);
}
if ( $this->is_webhooks_tab() ) {
return __(
'Status of the webhooks subscription.',
'woocommerce-paypal-payments'
);
}
return __(
'Accept PayPal, Pay Later and alternative payment types.',
@ -346,6 +356,16 @@ class PayPalGateway extends \WC_Payment_Gateway {
}
/**
* Whether we are on the Webhooks Status tab.
*
* @return bool
*/
private function is_webhooks_tab() : bool {
return is_admin()
&& WebhooksStatusPage::ID === $this->page_id;
}
/**
* Whether we are on the PayPal settings tab.
*

View file

@ -0,0 +1,49 @@
<?php
/**
* PageMatcherTrait.
*
* @package WooCommerce\PayPalCommerce\WcGateway\Settings
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
use WooCommerce\PayPalCommerce\AdminNotices\Entity\Message;
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use Woocommerce\PayPalCommerce\WcGateway\Helper\DccProductStatus;
use Woocommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
/**
* Class PageMatcherTrait.
*/
trait PageMatcherTrait {
/**
* Checks whether the field config matches the current page (can be rendered here).
*
* @param array $field_config The field config (from wcgateway.settings.fields).
* @param string $current_page_id ID of the current PPCP gateway settings page.
* @return bool
*/
protected function field_matches_page( array $field_config, string $current_page_id ): bool {
$allowed_gateways = $field_config['gateway'];
if ( ! is_array( $allowed_gateways ) ) {
$allowed_gateways = array( $allowed_gateways );
}
$gateway_page_id_map = array(
PayPalGateway::ID => 'paypal',
CreditCardGateway::ID => 'dcc', // TODO: consider using just the gateway ID for PayPal and DCC too.
WebhooksStatusPage::ID => WebhooksStatusPage::ID,
);
return array_key_exists( $current_page_id, $gateway_page_id_map )
&& in_array( $gateway_page_id_map[ $current_page_id ], $allowed_gateways, true );
}
}

View file

@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
/**
* Class SectionsRenderer
@ -53,8 +54,9 @@ class SectionsRenderer {
}
$sections = array(
PayPalGateway::ID => __( 'PayPal Checkout', 'woocommerce-paypal-payments' ),
CreditCardGateway::ID => __( 'PayPal Card Processing', 'woocommerce-paypal-payments' ),
PayPalGateway::ID => __( 'PayPal Checkout', 'woocommerce-paypal-payments' ),
CreditCardGateway::ID => __( 'PayPal Card Processing', 'woocommerce-paypal-payments' ),
WebhooksStatusPage::ID => __( 'Webhooks Status', 'woocommerce-paypal-payments' ),
);
echo '<ul class="subsubsub">';

View file

@ -23,6 +23,8 @@ use WooCommerce\PayPalCommerce\Webhooks\WebhookRegistrar;
*/
class SettingsListener {
use PageMatcherTrait;
const NONCE = 'ppcp-settings';
private const CREDENTIALS_ADDED = 'credentials_added';
@ -360,16 +362,7 @@ class SettingsListener {
if ( ! in_array( $this->state->current_state(), $config['screens'], true ) ) {
continue;
}
if (
'dcc' === $config['gateway']
&& CreditCardGateway::ID !== $this->page_id
) {
continue;
}
if (
'paypal' === $config['gateway']
&& PayPalGateway::ID !== $this->page_id
) {
if ( ! $this->field_matches_page( $config, $this->page_id ) ) {
continue;
}
switch ( $config['type'] ) {

View file

@ -24,6 +24,8 @@ use Woocommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
*/
class SettingsRenderer {
use PageMatcherTrait;
/**
* The Settings status helper.
*
@ -309,6 +311,60 @@ class SettingsRenderer {
return $html;
}
/**
* Renders the table row.
*
* @param array $data Values of the row cells.
* @param string $tag HTML tag ('td', 'th').
* @return string
*/
public function render_table_row( array $data, string $tag = 'td' ): string {
$cells = array_map(
function ( $value ) use ( $tag ): string {
return "<$tag>" . (string) $value . "</$tag>";
},
$data
);
return '<tr>' . implode( $cells ) . '</tr>';
}
/**
* Renders the table field.
*
* @param string $field The current field HTML.
* @param string $key The key.
* @param array $config The configuration of the field.
* @param array $value The current value.
*
* @return string HTML.
*/
public function render_table( $field, $key, $config, $value ): string {
if ( 'ppcp-table' !== $config['type'] ) {
return $field;
}
$data = $value['data'];
if ( empty( $data ) ) {
$empty_placeholder = $value['empty_placeholder'] ?? ( $config['empty_placeholder'] ?? null );
if ( $empty_placeholder ) {
return $empty_placeholder;
}
}
$header_row_html = $this->render_table_row( $value['headers'], 'th' );
$data_rows_html = implode(
array_map(
array( $this, 'render_table_row' ),
$data
)
);
return "<table>
$header_row_html
$data_rows_html
</table>";
}
/**
* Renders the settings.
*/
@ -325,10 +381,7 @@ class SettingsRenderer {
if ( ! in_array( $this->state->current_state(), $config['screens'], true ) ) {
continue;
}
if ( $is_dcc && ! in_array( $config['gateway'], array( 'all', 'dcc' ), true ) ) {
continue;
}
if ( ! $is_dcc && ! in_array( $config['gateway'], array( 'all', 'paypal' ), true ) ) {
if ( ! $this->field_matches_page( $config, $this->page_id ) ) {
continue;
}
if (
@ -349,7 +402,7 @@ class SettingsRenderer {
) {
continue;
}
$value = $this->settings->has( $field ) ? $this->settings->get( $field ) : null;
$value = $this->settings->has( $field ) ? $this->settings->get( $field ) : ( isset( $config['value'] ) ? $config['value']() : null );
$key = 'ppcp[' . $field . ']';
$id = 'ppcp-' . $field;
$config['id'] = $id;

View file

@ -214,6 +214,7 @@ class WcGatewayModule implements ModuleInterface {
$field = $renderer->render_password( $field, $key, $args, $value );
$field = $renderer->render_text_input( $field, $key, $args, $value );
$field = $renderer->render_heading( $field, $key, $args, $value );
$field = $renderer->render_table( $field, $key, $args, $value );
return $field;
},
10,

2
modules/ppcp-webhooks/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
node_modules
assets

View file

@ -9,4 +9,40 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Webhooks;
return array();
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
return array(
'wcgateway.settings.fields' => static function ( $container, array $fields ): array {
$status_page_fields = array(
'webhooks_list' => array(
'title' => __( 'Subscribed webhooks', 'woocommerce-paypal-payments' ),
'type' => 'ppcp-table',
'screens' => array(
State::STATE_PROGRESSIVE,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => WebhooksStatusPage::ID,
'classes' => array( 'ppcp-webhooks-table' ),
'value' => function () use ( $container ) : array {
return $container->get( 'webhook.status.registered-webhooks-data' );
},
),
'webhooks_resubscribe' => array(
'title' => __( 'Resubscribe webhooks', 'woocommerce-paypal-payments' ),
'type' => 'ppcp-text',
'text' => '<button type="button" class="button ppcp-webhooks-resubscribe">' . esc_html__( 'Resubscribe', 'woocommerce-paypal-payments' ) . '</button>',
'screens' => array(
State::STATE_PROGRESSIVE,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => WebhooksStatusPage::ID,
'description' => __( 'Click to remove the current webhook subscription and subscribe again, for example, if the website domain or URL structure changed.', 'woocommerce-paypal-payments' ),
),
);
return array_merge( $fields, $status_page_fields );
},
);

View file

@ -0,0 +1,23 @@
{
"name": "ppcp-webhooks",
"version": "1.0.0",
"license": "GPL-3.0-or-later",
"main": "resources/js/status-page.js",
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.9.5",
"babel-loader": "^8.1.0",
"cross-env": "^5.0.1",
"file-loader": "^4.2.0",
"node-sass": "^4.13.0",
"sass-loader": "^8.0.0",
"webpack": "^4.42.1",
"webpack-cli": "^3.1.2",
"babel-plugin-transform-object-rest-spread": "^6.26.0"
},
"scripts": {
"build": "cross-env BABEL_ENV=default NODE_ENV=production webpack",
"watch": "cross-env BABEL_ENV=default NODE_ENV=production webpack --watch",
"dev": "cross-env BABEL_ENV=default webpack --watch"
}
}

View file

@ -0,0 +1,23 @@
.ppcp-webhooks-table {
.error {
color: red;
font-weight: bold;
}
table {
border-collapse: collapse;
th {
border-bottom: 1px solid black;
}
td, th {
padding: 10px 15px;
}
td:first-child {
vertical-align: top;
width: 450px;
}
}
}

View file

@ -0,0 +1,42 @@
document.addEventListener(
'DOMContentLoaded',
() => {
const resubscribeBtn = jQuery(PayPalCommerceGatewayWebhooksStatus.resubscribe.button);
resubscribeBtn.click(async () => {
resubscribeBtn.prop('disabled', true);
const response = await fetch(
PayPalCommerceGatewayWebhooksStatus.resubscribe.endpoint,
{
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(
{
nonce: PayPalCommerceGatewayWebhooksStatus.resubscribe.nonce,
}
)
}
);
const reportError = error => {
const msg = PayPalCommerceGatewayWebhooksStatus.resubscribe.failureMessage + ' ' + error;
alert(msg);
}
if (!response.ok) {
try {
const result = await response.json();
reportError(result.data);
} catch (exc) {
console.error(exc);
reportError(response.status);
}
}
window.location.reload();
});
}
);

View file

@ -9,6 +9,11 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Webhooks;
use Exception;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\WebhookEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Webhook;
use WooCommerce\PayPalCommerce\WcGateway\Assets\WebhooksStatusPageAssets;
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\ResubscribeEndpoint;
use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutOrderApproved;
use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutOrderCompleted;
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureCompleted;
@ -18,7 +23,7 @@ use Psr\Container\ContainerInterface;
return array(
'webhook.registrar' => function( $container ) : WebhookRegistrar {
'webhook.registrar' => function( $container ) : WebhookRegistrar {
$factory = $container->get( 'api.factory.webhook' );
$endpoint = $container->get( 'api.endpoint.webhook' );
$rest_endpoint = $container->get( 'webhook.endpoint.controller' );
@ -30,7 +35,7 @@ return array(
$logger
);
},
'webhook.endpoint.controller' => function( $container ) : IncomingWebhookEndpoint {
'webhook.endpoint.controller' => function( $container ) : IncomingWebhookEndpoint {
$webhook_endpoint = $container->get( 'api.endpoint.webhook' );
$webhook_factory = $container->get( 'api.factory.webhook' );
$handler = $container->get( 'webhook.endpoint.handler' );
@ -45,7 +50,7 @@ return array(
... $handler
);
},
'webhook.endpoint.handler' => function( $container ) : array {
'webhook.endpoint.handler' => function( $container ) : array {
$logger = $container->get( 'woocommerce.logger.woocommerce' );
$prefix = $container->get( 'api.prefix' );
$order_endpoint = $container->get( 'api.endpoint.order' );
@ -57,4 +62,71 @@ return array(
new PaymentCaptureCompleted( $logger, $prefix ),
);
},
'webhook.status.registered-webhooks' => function( $container ) : array {
$endpoint = $container->get( 'api.endpoint.webhook' );
assert( $endpoint instanceof WebhookEndpoint );
return $endpoint->list();
},
'webhook.status.registered-webhooks-data' => function( $container ) : array {
$empty_placeholder = __( 'No webhooks found.', 'woocommerce-paypal-payments' );
$webhooks = array();
try {
$webhooks = $container->get( 'webhook.status.registered-webhooks' );
} catch ( Exception $exception ) {
$empty_placeholder = sprintf(
'<span class="error">%s</span>',
__( 'Failed to load webhooks.', 'woocommerce-paypal-payments' )
);
}
return array(
'headers' => array(
__( 'URL', 'woocommerce-paypal-payments' ),
__( 'Tracked events', 'woocommerce-paypal-payments' ),
),
'data' => array_map(
function ( Webhook $webhook ): array {
return array(
esc_html( $webhook->url() ),
implode(
',<br/>',
array_map(
'esc_html',
$webhook->humanfriendly_event_names()
)
),
);
},
$webhooks
),
'empty_placeholder' => $empty_placeholder,
);
},
'webhook.status.assets' => function( $container ) : WebhooksStatusPageAssets {
return new WebhooksStatusPageAssets(
$container->get( 'webhook.module-url' )
);
},
'webhook.endpoint.resubscribe' => static function ( $container ) : ResubscribeEndpoint {
$registrar = $container->get( 'webhook.registrar' );
$request_data = $container->get( 'button.request-data' );
return new ResubscribeEndpoint(
$registrar,
$request_data
);
},
'webhook.module-url' => static function ( $container ): string {
return plugins_url(
'/modules/ppcp-webhooks/',
dirname( __FILE__, 3 ) . '/woocommerce-paypal-payments.php'
);
},
);

View file

@ -0,0 +1,79 @@
<?php
/**
* The endpoint for resubscribing webhooks.
*
* @package WooCommerce\PayPalCommerce\Webhooks\Endpoint
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Webhooks\Endpoint;
use Exception;
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
use WooCommerce\PayPalCommerce\Webhooks\WebhookRegistrar;
/**
* Class ResubscribeEndpoint
*/
class ResubscribeEndpoint {
const ENDPOINT = 'ppc-webhooks-resubscribe';
/**
* The webhooks registrar.
*
* @var WebhookRegistrar
*/
private $registrar;
/**
* The Request Data helper object.
*
* @var RequestData
*/
private $request_data;
/**
* ResubscribeEndpoint constructor.
*
* @param WebhookRegistrar $registrar The webhooks registrar.
* @param RequestData $request_data The Request Data helper object.
*/
public function __construct( WebhookRegistrar $registrar, RequestData $request_data ) {
$this->registrar = $registrar;
$this->request_data = $request_data;
}
/**
* Returns the nonce for the endpoint.
*
* @return string
*/
public static function nonce(): string {
return self::ENDPOINT;
}
/**
* Handles the incoming request.
*/
public function handle_request() {
try {
// Validate nonce.
$this->request_data->read_request( $this->nonce() );
$this->registrar->unregister();
if ( ! $this->registrar->register() ) {
wp_send_json_error( 'Webhook subscription failed.', 500 );
return false;
}
wp_send_json_success();
return true;
} catch ( Exception $error ) {
wp_send_json_error( $error->getMessage(), 403 );
return false;
}
}
}

View file

@ -0,0 +1,92 @@
<?php
/**
* Register and configure assets for webhooks status page.
*
* @package WooCommerce\PayPalCommerce\Webhooks\Status\Assets
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\WcGateway\Assets;
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\ResubscribeEndpoint;
/**
* Class WebhooksStatusPageAssets
*/
class WebhooksStatusPageAssets {
/**
* The URL to the module.
*
* @var string
*/
private $module_url;
/**
* WebhooksStatusPageAssets constructor.
*
* @param string $module_url The URL to the module.
*/
public function __construct(
string $module_url
) {
$this->module_url = untrailingslashit( $module_url );
}
/**
* Registers the scripts and styles.
*
* @return void
*/
public function register(): void {
wp_register_style(
'ppcp-webhooks-status-page-style',
$this->module_url . '/assets/css/status-page.css',
array(),
1
);
wp_register_script(
'ppcp-webhooks-status-page',
$this->module_url . '/assets/js/status-page.js',
array(),
1,
true
);
wp_localize_script(
'ppcp-webhooks-status-page',
'PayPalCommerceGatewayWebhooksStatus',
$this->get_script_data()
);
}
/**
* Returns the data for the script.
*
* @return array
*/
public function get_script_data() {
return array(
'resubscribe' => array(
'endpoint' => home_url( \WC_AJAX::get_endpoint( ResubscribeEndpoint::ENDPOINT ) ),
'nonce' => wp_create_nonce( ResubscribeEndpoint::nonce() ),
'button' => '.ppcp-webhooks-resubscribe',
'failureMessage' => __( 'Operation failed. Check WooCommerce logs for more details.', 'woocommerce-paypal-payments' ),
),
);
}
/**
* Enqueues the necessary scripts.
*
* @return void
*/
public function enqueue(): void {
wp_enqueue_style( 'ppcp-webhooks-status-page-style' );
wp_enqueue_script( 'ppcp-webhooks-status-page' );
}
}

View file

@ -0,0 +1,18 @@
<?php
/**
* Status page.
*
* @package WooCommerce\PayPalCommerce\Webhooks\Status
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Webhooks\Status;
/**
* Class WebhooksStatusPage
*/
class WebhooksStatusPage {
const ID = 'ppcp-webhooks-status-page';
}

View file

@ -11,8 +11,13 @@ namespace WooCommerce\PayPalCommerce\Webhooks;
use Dhii\Container\ServiceProvider;
use Dhii\Modular\Module\ModuleInterface;
use Exception;
use Interop\Container\ServiceProviderInterface;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
use WooCommerce\PayPalCommerce\WcGateway\Assets\WebhooksStatusPageAssets;
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\ResubscribeEndpoint;
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
/**
* Class WebhookModule
@ -37,6 +42,9 @@ class WebhookModule implements ModuleInterface {
* @param ContainerInterface|null $container The Container.
*/
public function run( ContainerInterface $container ): void {
$logger = $container->get( 'woocommerce.logger.woocommerce' );
assert( $logger instanceof LoggerInterface );
add_action(
'rest_api_init',
static function () use ( $container ) {
@ -75,6 +83,50 @@ class WebhookModule implements ModuleInterface {
$registrar->unregister();
}
);
add_action(
'wc_ajax_' . ResubscribeEndpoint::ENDPOINT,
static function () use ( $container ) {
$endpoint = $container->get( 'webhook.endpoint.resubscribe' );
assert( $endpoint instanceof ResubscribeEndpoint );
$endpoint->handle_request();
}
);
$page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
if ( WebhooksStatusPage::ID === $page_id ) {
$GLOBALS['hide_save_button'] = true;
$asset_loader = $container->get( 'webhook.status.assets' );
assert( $asset_loader instanceof WebhooksStatusPageAssets );
add_action(
'init',
array( $asset_loader, 'register' )
);
add_action(
'admin_enqueue_scripts',
array( $asset_loader, 'enqueue' )
);
try {
$webhooks = $container->get( 'webhook.status.registered-webhooks' );
if ( empty( $webhooks ) ) {
$registrar = $container->get( 'webhook.registrar' );
assert( $registrar instanceof WebhookRegistrar );
// Looks like we cannot call rest_url too early.
add_action(
'init',
function () use ( $registrar ) {
$registrar->register();
}
);
}
} catch ( Exception $exception ) {
$logger->error( 'Failed to load webhooks list: ' . $exception->getMessage() );
}
}
}
/**

View file

@ -92,10 +92,10 @@ class WebhookRegistrar {
self::KEY,
$created->to_array()
);
$this->logger->info( 'Webhooks registered.' );
$this->logger->info( 'Webhooks subscribed.' );
return true;
} catch ( RuntimeException $error ) {
$this->logger->error( 'Failed to register webhooks: ' . $error->getMessage() );
$this->logger->error( 'Failed to subscribe webhooks: ' . $error->getMessage() );
return false;
}
}

View file

@ -0,0 +1,36 @@
const path = require('path');
const isProduction = process.env.NODE_ENV === 'production';
module.exports = {
devtool: 'sourcemap',
mode: isProduction ? 'production' : 'development',
target: 'web',
entry: {
'status-page': path.resolve('./resources/js/status-page.js'),
'status-page-style': path.resolve('./resources/css/status-page.scss'),
},
output: {
path: path.resolve(__dirname, 'assets/'),
filename: 'js/[name].js',
},
module: {
rules: [{
test: /\.js?$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
{
test: /\.scss$/,
exclude: /node_modules/,
use: [
{
loader: 'file-loader',
options: {
name: 'css/[name].css',
}
},
{loader:'sass-loader'}
]
}]
}
};

File diff suppressed because it is too large Load diff