Skip to content

Commit

Permalink
Restructure settings, adding advanced settings to allow manual webhoo… (
Browse files Browse the repository at this point in the history
#20)

* Restructure settings, adding advanced settings to allow manual webhook secret setting; bumping release.
  • Loading branch information
ndeet authored Aug 17, 2023
1 parent 241e72b commit 9ee8def
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 28 deletions.
6 changes: 6 additions & 0 deletions assets/css/admin.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.btcpay-connection-success {
color: green;
}
.btcpay-connection-error {
color: red;
}
19 changes: 19 additions & 0 deletions assets/js/apiKeyRedirect.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,23 @@ jQuery(document).ready(function($) {
alert('Please enter a valid url including https:// in the BTCPay Server URL input field.')
}
});

// Handle manual connection settings.
const showDetails = $('#btcpay_gf_connection_details');
const detailFields = $('#btcpay_gf_store_id, #btcpay_gf_whsecret, #btcpay_gf_api_key, #btcpay_gf_whstatus');

toggleFields(showDetails.is(':checked'));

showDetails.on('change', function() {
toggleFields($(this).is(':checked'));
});

function toggleFields(isChecked) {
if (isChecked) {
detailFields.closest('tr').show();
} else {
detailFields.closest('tr').hide();
}
}

});
9 changes: 5 additions & 4 deletions btcpay-greenfield-for-woocommerce.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
* Author URI: https://btcpayserver.org
* Text Domain: btcpay-greenfield-for-woocommerce
* Domain Path: /languages
* Version: 2.1.0
* Version: 2.2.0
* Requires PHP: 7.4
* Tested up to: 6.2
* Tested up to: 6.3
* Requires at least: 5.2
* WC requires at least: 6.0
* WC tested up to: 7.5
* WC tested up to: 8.0
*/

use BTCPayServer\WC\Admin\Notice;
Expand All @@ -25,7 +25,7 @@

defined( 'ABSPATH' ) || exit();

define( 'BTCPAYSERVER_VERSION', '2.1.0' );
define( 'BTCPAYSERVER_VERSION', '2.2.0' );
define( 'BTCPAYSERVER_VERSION_KEY', 'btcpay_gf_version' );
define( 'BTCPAYSERVER_PLUGIN_FILE_PATH', plugin_dir_path( __FILE__ ) );
define( 'BTCPAYSERVER_PLUGIN_URL', plugin_dir_url(__FILE__ ) );
Expand Down Expand Up @@ -373,6 +373,7 @@ function init_btcpay_greenfield() {
if ($apiData->hasSingleStore() && $apiData->hasRequiredPermissions()) {
update_option('btcpay_gf_api_key', $apiData->getApiKey());
update_option('btcpay_gf_store_id', $apiData->getStoreID());
update_option('btcpay_gf_connection_details', 'yes');
Notice::addNotice('success', __('Successfully received api key and store id from BTCPay Server API. Please finish setup by saving this settings form.', 'btcpay-greenfield-for-woocommerce'));
wp_redirect($btcPaySettingsUrl);
} else {
Expand Down
4 changes: 2 additions & 2 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ Contributors: ndeet, kukks, nicolasdorier
Donate link: https://btcpayserver.org/donate/
Tags: bitcoin, btcpay, BTCPay Server, btcpayserver, WooCommerce, payment gateway, accept bitcoin, bitcoin plugin, bitcoin payment processor, bitcoin e-commerce, Lightning Network, Litecoin, cryptocurrency
Requires at least: 5.2
Tested up to: 6.2
Tested up to: 6.3
Requires PHP: 7.4
Stable tag: 2.1.0
Stable tag: 2.2.0
License: MIT
License URI: https://github.com/btcpayserver/woocommerce-greenfield-plugin/blob/master/license.txt

Expand Down
175 changes: 156 additions & 19 deletions src/Admin/GlobalSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
* todo: add validation of host/url
*/
class GlobalSettings extends \WC_Settings_Page {

private GreenfieldApiHelper $apiHelper;
public function __construct()
{
$this->id = 'btcpay_settings';
$this->label = __( 'BTCPay Settings', 'btcpay-greenfield-for-woocommerce' );
$this->apiHelper = new GreenfieldApiHelper();
// Register custom field type order_states with OrderStatesField class.
add_action('woocommerce_admin_field_order_states', [(new OrderStates()), 'renderOrderStatesHtml']);
add_action('woocommerce_admin_field_custom_markup', [$this, 'output_custom_markup_field']);

if (is_admin()) {
// Register and include JS.
Expand All @@ -34,13 +36,20 @@ public function __construct()
[
'url' => admin_url( 'admin-ajax.php' ),
'apiNonce' => wp_create_nonce( 'btcpaygf-api-url-nonce' ),
]);
]
);

// Register and include CSS.
wp_register_style( 'btcpay_gf_admin_styles', BTCPAYSERVER_PLUGIN_URL . 'assets/css/admin.css', array(), BTCPAYSERVER_VERSION );
wp_enqueue_style( 'btcpay_gf_admin_styles' );

}
parent::__construct();
}

public function output(): void
{
echo '<h1>' . _x('BTCPay Server Payments settings', 'global_settings', 'btcpay-greenfield-for-woocommerce') . '</h1>';
$settings = $this->get_settings_for_default_section();
\WC_Admin_Settings::output_fields($settings);
}
Expand All @@ -53,16 +62,44 @@ public function get_settings_for_default_section(): array
public function getGlobalSettings(): array
{
Logger::debug('Entering Global Settings form.');

// Check setup status and prepare output.
$setupStatus = '';
if ($this->apiHelper->configured) {
$setupStatus = '<p class="btcpay-connection-success">' . _x('BTCPay Server connected.', 'global_settings', 'btcpay-greenfield-for-woocommerce') . '</p>';
} else {
$setupStatus = '<p class="btcpay-connection-error">' . _x('Not connected. Please use the setup wizard above or check advanced settings to manually enter connection settings.', 'global_settings', 'btcpay-greenfield-for-woocommerce') . '</p>';
}

// Check webhook status and prepare output.
$whStatus = '';
$whId = '';
// Can't use apiHelper because of caching.
if ($webhookConfig = get_option('btcpay_gf_webhook')) {
$whId = $webhookConfig['id'];
}

if ($this->apiHelper->webhookIsSetup()) {
$whStatus = '<p class="btcpay-connection-success">' . _x('Webhook setup automatically.', 'global_settings', 'btcpay-greenfield-for-woocommerce') . ' ID: ' . $whId . '</p>';
} else {
$whStatus = '<p class="btcpay-connection-error">' . _x('No webhook setup, yet.', 'global_settings', 'btcpay-greenfield-for-woocommerce') . '</p>';
}

if ($this->apiHelper->webhookIsSetupManual()) {
$whStatus = '<p class="btcpay-connection-success">' . _x('Webhook setup manually with webhook secret.', 'global_settings', 'btcpay-greenfield-for-woocommerce') . ' ID: ' . $whId . '</p>';
}

return [
'title' => [
// Section connection.
'title_connection' => [
'title' => esc_html_x(
'BTCPay Server Payments Settings',
'Connection settings',
'global_settings',
'btcpay-greenfield-for-woocommerce'
),
'type' => 'title',
'desc' => sprintf( _x( 'This plugin version is %s and your PHP version is %s. Check out our <a href="https://docs.btcpayserver.org/WooCommerce/" target="_blank">installation instructions</a>. If you need assistance, please come on our <a href="https://chat.btcpayserver.org" target="_blank">chat</a>. Thank you for using BTCPay!', 'global_settings', 'btcpay-greenfield-for-woocommerce' ), BTCPAYSERVER_VERSION, PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION ),
'id' => 'btcpay_gf'
'id' => 'btcpay_gf_connection'
],
'url' => [
'title' => esc_html_x(
Expand All @@ -76,10 +113,29 @@ public function getGlobalSettings(): array
'desc_tip' => true,
'id' => 'btcpay_gf_url'
],
'wizard' => [
'title' => esc_html_x( 'Setup wizard', 'global_settings','btcpay-greenfield-for-woocommerce' ),
'type' => 'custom_markup',
'markup' => '<button class="button button-primary btcpay-api-key-link" target="_blank">Generate API key</button>',
'id' => 'btcpay_gf_wizard_button' // a unique ID
],
'status' => [
'title' => esc_html_x( 'Setup status', 'global_settings','btcpay-greenfield-for-woocommerce' ),
'type' => 'custom_markup',
'markup' => $setupStatus,
'id' => 'btcpay_gf_status'
],
'connection_details' => [
'title' => __( 'Advanced settings', 'btcpay-greenfield-for-woocommerce' ),
'type' => 'checkbox',
'default' => 'no',
'desc' => _x( 'Show all connection settings / manual setup.', 'global_settings', 'btcpay-greenfield-for-woocommerce' ),
'id' => 'btcpay_gf_connection_details'
],
'api_key' => [
'title' => esc_html_x( 'BTCPay API Key', 'global_settings','btcpay-greenfield-for-woocommerce' ),
'type' => 'text',
'desc' => _x( 'Your BTCPay API Key. If you do not have any yet <a href="#" class="btcpay-api-key-link" target="_blank">click here to generate API keys.</a>', 'global_settings', 'btcpay-greenfield-for-woocommerce' ),
'desc' => _x( 'Your BTCPay API Key. If you do not have any yet use the setup wizard above.', 'global_settings', 'btcpay-greenfield-for-woocommerce' ),
'default' => '',
'id' => 'btcpay_gf_api_key'
],
Expand All @@ -90,6 +146,33 @@ public function getGlobalSettings(): array
'default' => '',
'id' => 'btcpay_gf_store_id'
],
'whsecret' => [
'title' => esc_html_x( 'Webhook secret (optional)', 'global_settings','btcpay-greenfield-for-woocommerce' ),
'type' => 'text',
'desc' => _x( 'If left empty an webhook will created automatically on save. Only fill out if you know the webhook secret and the webhook was created manually on BTCPay Server.', 'global_settings', 'btcpay-greenfield-for-woocommerce' ),
'default' => '',
'id' => 'btcpay_gf_whsecret'
],
'whstatus' => [
'title' => esc_html_x( 'Webhook status', 'global_settings','btcpay-greenfield-for-woocommerce' ),
'type' => 'custom_markup',
'markup' => $whStatus,
'id' => 'btcpay_gf_whstatus'
],
'sectionend_connection' => [
'type' => 'sectionend',
'id' => 'btcpay_gf_connection',
],
// Section general.
'title' => [
'title' => esc_html_x(
'General settings',
'global_settings',
'btcpay-greenfield-for-woocommerce'
),
'type' => 'title',
'id' => 'btcpay_gf'
],
'default_description' => [
'title' => esc_html_x( 'Default Customer Message', 'btcpay-greenfield-for-woocommerce' ),
'type' => 'textarea',
Expand Down Expand Up @@ -170,6 +253,7 @@ public function save() {
$apiUrl = esc_url_raw( $_POST['btcpay_gf_url'] );
$apiKey = sanitize_text_field( $_POST['btcpay_gf_api_key'] );
$storeId = sanitize_text_field( $_POST['btcpay_gf_store_id'] );
$manualWhSecret = sanitize_text_field( $_POST['btcpay_gf_whsecret'] );

// todo: fix change of url + key + storeid not leading to recreation of webhook.
// Check if the provided API key has the right scope and permissions.
Expand Down Expand Up @@ -227,20 +311,58 @@ public function save() {
// Continue creating the webhook if the API key permissions are OK.
if ( false === $hasError ) {
// Check if we already have a webhook registered for that store.
if ( GreenfieldApiWebhook::webhookExists( $apiUrl, $apiKey, $storeId ) ) {
$messageReuseWebhook = __( 'Webhook already exists, skipping webhook creation.', 'btcpay-greenfield-for-woocommerce' );
Notice::addNotice('info', $messageReuseWebhook, true);
Logger::debug($messageReuseWebhook);
} else {
// Register a new webhook.
if ( GreenfieldApiWebhook::registerWebhook( $apiUrl, $apiKey, $storeId ) ) {
$messageWebhookSuccess = __( 'Successfully registered a new webhook on BTCPay Server.', 'btcpay-greenfield-for-woocommerce' );
Notice::addNotice('success', $messageWebhookSuccess, true );
Logger::debug( $messageWebhookSuccess );
if ( GreenfieldApiWebhook::webhookExists( $apiUrl, $apiKey, $storeId, $manualWhSecret ) ) {

if ( $manualWhSecret && $this->apiHelper->webhook['secret'] !== $manualWhSecret) {
// Store manual webhook in options table.
update_option(
'btcpay_gf_webhook',
[
'id' => 'manual',
'secret' => $manualWhSecret,
'url' => 'manual'
]
);

$messageWebhookManual = __( 'Successfully setup manual webhook.', 'btcpay-greenfield-for-woocommerce' );
Notice::addNotice('success', $messageWebhookManual, true );
Logger::debug( $messageWebhookManual );
} else {
$messageWebhookError = __( 'Could not register a new webhook on the store.', 'btcpay-greenfield-for-woocommerce' );
Notice::addNotice('error', $messageWebhookError );
Logger::debug($messageWebhookError, true);
$messageReuseWebhook = __( 'Webhook already exists, skipping webhook creation.', 'btcpay-greenfield-for-woocommerce' );
Notice::addNotice('info', $messageReuseWebhook, true);
Logger::debug($messageReuseWebhook);
}
} else {
// When the webhook secret was set manually we just store it and not try to create it.
if ( $manualWhSecret ) {
// Store manual webhook in options table.
update_option(
'btcpay_gf_webhook',
[
'id' => 'manual',
'secret' => $manualWhSecret,
'url' => 'manual'
]
);

$messageWebhookManual = __( 'Successfully setup manual webhook.', 'btcpay-greenfield-for-woocommerce' );
Notice::addNotice('success', $messageWebhookManual, true );
Logger::debug( $messageWebhookManual );
}

// Register a new webhook automatically.
if ( empty($manualWhSecret) ) {
if ( GreenfieldApiWebhook::registerWebhook( $apiUrl, $apiKey, $storeId ) ) {
$messageWebhookSuccess = __( 'Successfully registered a new webhook on BTCPay Server.', 'btcpay-greenfield-for-woocommerce' );
Notice::addNotice('success', $messageWebhookSuccess, true );
Logger::debug( $messageWebhookSuccess );
} else {
$messageWebhookError = __( 'Could not register a new webhook on the store.', 'btcpay-greenfield-for-woocommerce' );
Notice::addNotice('error', $messageWebhookError );
Logger::debug($messageWebhookError, true);
// Cleanup existing conf.
delete_option('btcpay_gf_webhook');
}
}
}

Expand Down Expand Up @@ -293,4 +415,19 @@ private function hasNeededApiCredentials(): bool {
}
return false;
}

public function output_custom_markup_field($value) {
echo '<tr valign="top">';
if (!empty($value['title'])) {
echo '<th scope="row" class="titledesc">' . esc_html($value['title']) . '</th>';
} else {
echo '<th scope="row" class="titledesc">&nbsp;</th>';
}

echo '<td class="forminp" id="' . $value['id'] . '">';
echo $value['markup'];
echo '</td>';
echo '</tr>';
}

}
12 changes: 10 additions & 2 deletions src/Helper/GreenfieldApiAuthorization.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ class GreenfieldApiAuthorization {
public const REQUIRED_PERMISSIONS = [
'btcpay.store.canviewinvoices',
'btcpay.store.cancreateinvoice',
'btcpay.store.webhooks.canmodifywebhooks',
'btcpay.store.canviewstoresettings',
'btcpay.store.canmodifyinvoices'
];
public const OPTIONAL_PERMISSIONS = [
'btcpay.store.cancreatenonapprovedpullpayments'
'btcpay.store.cancreatenonapprovedpullpayments',
'btcpay.store.webhooks.canmodifywebhooks',
];

private $apiKey;
Expand Down Expand Up @@ -83,4 +83,12 @@ public function hasRefundsPermission(): bool {

return in_array('btcpay.store.cancreatenonapprovedpullpayments', $permissions, true);
}

public function hasWebhookPermission(): bool {
$permissions = array_reduce($this->permissions, static function (array $carry, string $permission) {
return array_merge($carry, [explode(':', $permission)[0]]);
}, []);

return in_array('btcpay.store.webhooks.canmodifywebhooks', $permissions, true);
}
}
18 changes: 18 additions & 0 deletions src/Helper/GreenfieldApiHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,24 @@ public static function apiCredentialsExist(string $apiUrl, string $apiKey, strin
return false;
}

public static function webhookIsSetup(): bool {
if ($config = self::getConfig()) {
return !empty($config['webhook']['secret']);
}

return false;
}

public static function webhookIsSetupManual(): bool {
if ($config = self::getConfig()) {
return !empty($config['webhook']['secret']) && $config['webhook']['id'] === 'manual';
}

return false;
}



/**
* Checks if a given invoice id has status of fully paid (settled) or paid late.
*/
Expand Down
Loading

0 comments on commit 9ee8def

Please sign in to comment.