Skip to content

Commit

Permalink
Merge pull request bitpay#91 from SUMO-Kwiatkowski/SP-940
Browse files Browse the repository at this point in the history
SP-940 Adding BitPay Support Package download button
  • Loading branch information
p-maguire authored Sep 13, 2024
2 parents 33c958a + 7556aae commit b587a3e
Show file tree
Hide file tree
Showing 8 changed files with 279 additions and 4 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ codeception.yml
logs/*.*
/.idea/
/vendor
/build
/build
.phpunit.result.cache
tests/.env
tests/Unit/wp-config.php
8 changes: 6 additions & 2 deletions BitPayLib/class-bitpaylogger.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ class BitPayLogger {

public function execute( $msg, string $type, bool $is_array = false, $error = false ): void {
$bitpay_checkout_options = get_option( 'woocommerce_bitpay_checkout_gateway_settings' );
$log_directory = plugin_dir_path( __FILE__ ) . '..' . DIRECTORY_SEPARATOR . '..'
. DIRECTORY_SEPARATOR . 'logs/';
$log_directory = $this->get_log_directory();
if ( ! file_exists( $log_directory ) && ! mkdir( $log_directory ) && ! is_dir( $log_directory ) ) {
throw new \RuntimeException( sprintf( 'Directory "%s" was not created', esc_html( $log_directory ) ) );
}
Expand Down Expand Up @@ -47,4 +46,9 @@ public function execute( $msg, string $type, bool $is_array = false, $error = fa
}
// @codingStandardsIgnoreEnd
}

public function get_log_directory(): string {
return plugin_dir_path( __FILE__ ) . '..' . DIRECTORY_SEPARATOR . '..'
. DIRECTORY_SEPARATOR . 'logs/';
}
}
16 changes: 16 additions & 0 deletions BitPayLib/class-bitpaypluginsetup.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class BitPayPluginSetup {
private BitPayPaymentSettings $bitpay_payment_settings;
private BitPayInvoiceCreate $bitpay_invoice_create;
private BitPayCheckoutTransactions $bitpay_checkout_transactions;
private BitPaySupportPackage $bitpay_support_package;

public function __construct() {
$this->bitpay_payment_settings = new BitPayPaymentSettings();
Expand All @@ -42,6 +43,10 @@ public function __construct() {
$wordpress_helper,
$logger
);
$this->bitpay_support_package = new BitPaySupportPackage(
$wordpress_helper,
$logger
);
}

public function execute(): void {
Expand Down Expand Up @@ -82,6 +87,17 @@ function () {
'permission_callback' => '__return_true',
)
);
register_rest_route(
'bitpay/site',
'/health-status',
array(
'methods' => 'GET',
'callback' => array( $this->bitpay_support_package, 'get_zip' ),
'permission_callback' => function () {
return current_user_can( 'manage_woocommerce' );
},
)
);
}
);
}
Expand Down
198 changes: 198 additions & 0 deletions BitPayLib/class-bitpaysupportpackage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
<?php

declare(strict_types=1);

namespace BitPayLib;

use WP_HTTP_Response;
use WP_REST_Response;

class BitPaySupportPackage {

private BitPayWordpressHelper $bitpay_wordpress;
private BitPayLogger $bitpay_logger;

public function __construct(
BitPayWordpressHelper $bitpay_wordpress,
BitPayLogger $bitpay_logger
) {
$this->bitpay_wordpress = $bitpay_wordpress;
$this->bitpay_logger = $bitpay_logger;
}

public function get_zip(): WP_REST_Response {
$zipfile_string = $this->create_site_info_zip();

return $this->get_zip_rest_response( $zipfile_string );
}

private function create_site_info_zip(): string {
$json_data = $this->get_site_data_as_json();
$tmp_file = tmpfile();
$tmp_location = stream_get_meta_data( $tmp_file )['uri'];

$zip = new \ZipArchive();

if ( true !== $zip->open( $tmp_location, \ZipArchive::CREATE ) ) {
throw new \RuntimeException( 'Could not create zip file' );
}

$zip->addFromString( 'site-info.json', $json_data );
$log_directory = $this->bitpay_logger->get_log_directory();

if ( is_readable( $log_directory ) ) {
$zip->addGlob(
$log_directory . '*.log',
0,
array(
'remove_all_path' => true,
)
);
}

$zip->close();
$file_contents = file_get_contents( $tmp_location );

// This removes the file.
fclose( $tmp_file );

return $file_contents;
}

private function get_site_data_as_json(): bool|string {
$active_plugins = get_plugins();
$active_plugin_data = array();

foreach ( $active_plugins as $plugin_path => $plugin_data ) {
if ( is_plugin_active( $plugin_path ) ) {
$active_plugin_data[] = array(
'name' => $plugin_data['Name'],
'version' => $plugin_data['Version'],
);
}
}

$wpdb = $this->bitpay_wordpress->get_wpdb();
$extension = null;

// Populate the database debug fields.
if ( is_object( $wpdb->dbh ) ) {
// mysqli or PDO.
$extension = get_class( $wpdb->dbh );
}

$json_data = array(
'bitpay_plugin_version' => BitPayPluginSetup::VERSION,
'plugins' => $active_plugin_data,
'database' => array(
array(
'dbms' => $extension,
'dbms_version' => $wpdb->get_var( 'SELECT VERSION()' ), // phpcs:ignore
'char_set' => $wpdb->charset,
'collation' => $wpdb->collate,
'tables' => array(
array(
'table' => '_bitpay_checkout_transactions',
'exists' => $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}_bitpay_checkout_transactions'" ) ? 'yes' : 'no',
),
),
),
),
'wordpress' => array(
array(
'url' => home_url(),
'version' => get_bloginfo( 'version' ),
),
),
'server' => array(
array(
'software' => $_SERVER['SERVER_SOFTWARE'], // phpcs:ignore
'document_root' => $_SERVER['DOCUMENT_ROOT'], // phpcs:ignore
),
),
'php' => array(
'version' => phpversion(),
'memory_limit' => ini_get( 'memory_limit' ),
'max_execution_time' => ini_get( 'max_execution_time' ),
'max_file_upload_size' => ini_get( 'upload_max_filesize' ),
'max_post_size' => ini_get( 'post_max_size' ),
'max_input_variables' => ini_get( 'max_input_vars' ),
'curl_enabled' => function_exists( 'curl_version' ) ? 'yes' : 'no',
'curl_version' => function_exists( 'curl_version' ) ? curl_version()['version'] : '',
'openssl_version' => defined( 'OPENSSL_VERSION_TEXT' ) ? OPENSSL_VERSION_TEXT : '',
'mcrypt_enabled' => function_exists( 'mcrypt_encrypt' ) ? 'yes' : 'no',
'mbstring_enabled' => function_exists( 'mb_detect_encoding' ) ? 'yes' : 'no',
'extensions' => get_loaded_extensions(),
),
);

return json_encode( $json_data, JSON_PRETTY_PRINT );
}

/**
* Serves a zip via the REST endpoint.
*
* By default, every REST response is passed through json_encode(), as the
* typical REST response contains JSON data.
*
* This method hooks into the REST server to return a binary zip.
*
* @param string $data Data of the ZIP to serve.
*
* @return WP_REST_Response The REST response object to serve the zip.
*/
private function get_zip_rest_response( string $data ): WP_REST_Response {
$response = new WP_REST_Response();

$response->set_data( $data );
$response->set_headers(
array(
'Content-Type' => 'application/zip',
'Content-Length' => strlen( $data ),
)
);

// This filter will return our binary zip.
add_filter( 'rest_pre_serve_request', array( $this, 'serve_zip_action_handler' ), 0, 2 );

return $response;
}

/**
* Action handler that is used by `get_zip_rest_response()` to serve a binary image
* instead of a JSON string.
*
* @param bool $served Whether the request has already been served. Default false.
* @param WP_HTTP_Response $result Result to send to the client. Usually a WP_REST_Response.
*
* @return bool Returns true, if the image was served; this will skip the
* default REST response logic.
*
* @see https://developer.wordpress.org/reference/hooks/rest_pre_serve_request/
* */
public function serve_zip_action_handler( bool $served, WP_HTTP_Response $result ): bool {
$is_zip = false;
$zip_data = null;

// Check the "Content-Type" header to confirm that we really want to return
// binary zip data.
foreach ( $result->get_headers() as $header => $value ) {
if ( 'content-type' === strtolower( $header ) ) {
$is_zip = 0 === strpos( $value, 'application/zip' );
$zip_data = $result->get_data();
break;
}
}

// Output the binary data and tell the REST server to not send any other
// details (via "return true").
if ( $is_zip && is_string( $zip_data ) ) {
// phpcs:ignore
echo $zip_data;

return true;
}

return $served;
}
}
20 changes: 20 additions & 0 deletions BitPayLib/class-wcgatewaybitpay.php
Original file line number Diff line number Diff line change
Expand Up @@ -344,4 +344,24 @@ private function get_bitpay_version_info(): string {

return $plugin_name . ' ' . $plugin_data['Version'];
}

public function admin_options(): void {
parent::admin_options();
$this->add_support_package_download_button();
}

private function add_support_package_download_button() {
?>
<div style="display: flex; align-items: center">
<div style="padding-right: 24px;">
<p style="color: #1d2327; font-weight: 600; font-size: 14px; padding: 20px 10px 20px 0; width: 200px">Support Package </p>
</div>
<div style="padding: 15px 0; margin-top: 9px;">
<button type="button" style="height: 36px;" class="button button-secondary" id="download_support_package">Download</button>
<p style="margin-top: 2px; margin-bottom: 0;">Select to download a package of files that can be used for technical support. No personal
information will be captured.</p>
</div>
</div>
<?php
}
}
25 changes: 25 additions & 0 deletions js/wc_gateway_bitpay.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,30 @@ jQuery( document ).ready(
dark.html( '<img src="' + url + '" style="background-color: black"/>' );
}
)

function downloadZipFile(blob, name) {
const a = document.createElement( 'a' );
a.href = URL.createObjectURL( blob );
a.download = name;
a.click();
}

document.getElementById( 'download_support_package' ).addEventListener(
'click',
async function () {
const nonce = document.getElementById( '_wpnonce' );
wp.apiFetch.use( wp.apiFetch.createNonceMiddleware( nonce ) );

const response = await wp.apiFetch(
{
path: '/bitpay/site/health-status',
parse: false
}
);
const blob = await response.blob();

downloadZipFile( blob, 'bitpay-support-package.zip' );
}
);
}
);
9 changes: 8 additions & 1 deletion phpcs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,11 @@
<exclude name="WordPress.WP.AlternativeFunctions"/>
<exclude name="WordPress.DateTime.RestrictedFunctions"/>
</rule>
</ruleset>
<rule ref="WordPress.WP.Capabilities">
<properties>
<property name="custom_capabilities" type="array">
<element value="manage_woocommerce" />
</property>
</properties>
</rule>
</ruleset>
2 changes: 2 additions & 0 deletions scoper.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ static function (string $filePath, string $prefix, string $contents): string {
'WP_User',
'WC_Order',
'WP_REST_Request',
'WP_Rest_Response',
'WP_Http_Response',
'WC_Admin_Settings',
'Automattic\WooCommerce\Blocks\Package',
'Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry',
Expand Down

0 comments on commit b587a3e

Please sign in to comment.