Skip to content
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

Fix/55 Fix anonymize functionality from CLI #77

Open
wants to merge 6 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 57 additions & 48 deletions includes/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@
*
* @return void
*/
function add_admin_hooks(){
function add_admin_hooks() {

if ( true !== apply_filters( 'safety_net_hide_admin', false ) ) {
// Skip the admin page and options if the `safety_net_hide_admin` filter returns true.
add_action( 'admin_enqueue_scripts', __NAMESPACE__ . '\enqueue_scripts' );
add_action( 'admin_menu', __NAMESPACE__ . '\create_options_menu' );
add_action( 'admin_init', __NAMESPACE__ . '\settings_init' );
add_action( 'wp_ajax_safety_net_anonymize_users', __NAMESPACE__ . '\handle_ajax_anonymize_users' );
add_action( 'wp_ajax_safety_net_scrub_options', __NAMESPACE__ . '\handle_ajax_scrub_options' );
add_action( 'wp_ajax_safety_net_deactivate_plugins', __NAMESPACE__ . '\handle_ajax_deactivate_plugins' );
add_action( 'wp_ajax_safety_net_delete_users', __NAMESPACE__ . '\handle_ajax_delete_users' );
Expand All @@ -45,14 +44,15 @@ function enqueue_scripts( string $hook_suffix ) {
return;
}

wp_enqueue_script( 'safety-net-admin', SAFETY_NET_URL . 'assets/js/safety-net-admin.js', [ 'jquery' ], '1.0', true );
$admin_script_path = SAFETY_NET_URL . 'assets/js/safety-net-admin.js';
wp_enqueue_script( 'safety-net-admin', $admin_script_path, array( 'jquery' ), filemtime( $admin_script_path ), true );

wp_localize_script(
'safety-net-admin',
'safety_net_params',
[
array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
]
)
);

wp_enqueue_style( 'safety-net-admin-style', SAFETY_NET_URL . 'assets/css/admin.css', array(), '0.0' );
Expand Down Expand Up @@ -100,12 +100,12 @@ function settings_init() {
__NAMESPACE__ . '\render_field',
'safety_net_options',
'safety_net_option',
[
'type' => 'button',
'id' => 'safety-net-scrub-options',
array(
'type' => 'button',
'id' => 'safety-net-scrub-options',
'button_text' => esc_html__( 'Scrub Options', 'safety-net' ),
'description' => esc_html__( 'Clears specific denylisted options, such as API keys, which could cause problems on a development site.', 'safety-net' ),
]
)
);

add_settings_field(
Expand All @@ -114,12 +114,12 @@ function settings_init() {
__NAMESPACE__ . '\render_field',
'safety_net_options',
'safety_net_option',
[
'type' => 'button',
'id' => 'safety-net-deactivate-plugins',
array(
'type' => 'button',
'id' => 'safety-net-deactivate-plugins',
'button_text' => esc_html__( 'Deactivate Plugins', 'safety-net' ),
'description' => esc_html__( 'Deactivates a handful of denylisted plugins. Also, runs through installed Woo payment gateways and deactivates them (deactivates the actual plugin, not from the checkout settings).', 'safety-net' ),
]
)
);

add_settings_field(
Expand All @@ -128,12 +128,12 @@ function settings_init() {
__NAMESPACE__ . '\render_field',
'safety_net_options',
'safety_net_option',
[
'type' => 'button',
'id' => 'safety-net-delete-users',
array(
'type' => 'button',
'id' => 'safety-net-delete-users',
'button_text' => esc_html__( 'Delete', 'safety-net' ),
'description' => esc_html__( 'Deletes all non-admin users, as well as WooCommerce orders and subscriptions.', 'safety-net' ),
]
)
);

add_settings_field(
Expand All @@ -158,27 +158,29 @@ function settings_init() {
*
* @return void
*/
function render_field( array $args = [] ) {
function render_field( array $args = array() ) {
if ( ! isset( $args['type'] ) ) {
return;
} ?>

<?php if ( 'checkbox' === $args['type'] ) :
<?php
Comment on lines 164 to +166
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Closing and opening PHP tags aren't needed here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ nitpicking 🤣

if ( 'checkbox' === $args['type'] ) :
$checked = '';
if ( 'on' === get_option( $args['name'] ) ) {
$checked = ' checked="checked" ';
} ?>
<input id="<?php echo esc_attr( $args['name'] ) ?>" class="<?php echo esc_attr( $args['class'] ) ?>" name="<?php echo esc_attr( $args['name'] ) ?>" type="checkbox" <?php echo $checked ?> />
$checked = ' checked="checked" ';
}
?>
<input id="<?php echo esc_attr( $args['name'] ); ?>" class="<?php echo esc_attr( $args['class'] ); ?>" name="<?php echo esc_attr( $args['name'] ); ?>" type="checkbox" <?php echo $checked; ?> />
<?php endif; ?>

<?php if ( 'button' === $args['type'] ) : ?>
<button type="button" id="<?php echo esc_attr( $args['id'] ); ?>" class="button button-large" data-nonce="<?php echo wp_create_nonce( $args['id'] ); ?>">
<?php echo esc_html( $args['button_text' ] ) ?>
<?php echo esc_html( $args['button_text'] ); ?>
</button>
<?php endif; ?>

<?php if ( isset( $args['description' ] ) ) : ?>
<p class="description" id="tagline-description"><?php echo esc_html( $args['description' ] ); ?></p>
<?php if ( isset( $args['description'] ) ) : ?>
<p class="description" id="tagline-description"><?php echo esc_html( $args['description'] ); ?></p>
<?php endif; ?>
<?php
}
Expand All @@ -205,12 +207,14 @@ function render_options_html() {
<form action="options.php" method="post">
<?php
settings_fields( 'safety-net' );
do_settings_sections( 'safety_net_options' ); ?>
do_settings_sections( 'safety_net_options' );
?>
<input name="Submit" type="submit" class="button button-primary safety-net-save" value="<?php esc_attr_e( 'Save Changes' ); ?>" />
</form>
</div>
<div class="loading-overlay"></div>
<?php }
<?php
}
}

/**
Expand All @@ -224,27 +228,27 @@ function handle_ajax_scrub_options() {
if ( is_production() ) {
// Send an AJAX warning.
echo json_encode(
[
array(
'warning' => true,
'message' => esc_html__( 'You can not run these tools on a production site. Please set the environment type correctly.' ),
]
)
);
die();
}

// Permissions and security checks.
check_the_permissions();
check_the_nonce( $_POST['nonce'],'safety-net-scrub-options' );
check_the_nonce( $_POST['nonce'], 'safety-net-scrub-options' );

// Checks passed. Scrub the options.
scrub_options();

// Send the AJAX response.
echo json_encode(
[
array(
'success' => true,
'message' => esc_html__( 'Options have been scrubbed.' ),
]
)
);

die();
Expand All @@ -261,27 +265,27 @@ function handle_ajax_deactivate_plugins() {
if ( is_production() ) {
// Send an AJAX warning.
echo json_encode(
[
array(
'warning' => true,
'message' => esc_html__( 'You can not run these tools on a production site. Please set the environment type correctly.' ),
]
)
);
die();
}

// Permissions and security checks.
check_the_permissions();
check_the_nonce( $_POST['nonce'],'safety-net-deactivate-plugins' );
check_the_nonce( $_POST['nonce'], 'safety-net-deactivate-plugins' );

// Checks passed. Scrub the options.
deactivate_plugins();

// Send the AJAX response.
echo json_encode(
[
array(
'success' => true,
'message' => esc_html__( 'Plugins have been deactivated.' ),
]
)
);

die();
Expand All @@ -298,10 +302,10 @@ function handle_ajax_delete_users() {
if ( is_production() ) {
// Send an AJAX warning.
echo json_encode(
[
array(
'warning' => true,
'message' => esc_html__( 'You can not run these tools on a production site. Please set the environment type correctly.' ),
]
)
);
die();
}
Expand All @@ -314,10 +318,10 @@ function handle_ajax_delete_users() {
delete_users_and_orders();

echo json_encode(
[
array(
'success' => true,
'message' => esc_html__( 'Users, orders, and subscriptions have been successfully deleted!' ),
]
)
);

die();
Expand All @@ -331,10 +335,10 @@ function handle_ajax_delete_users() {
function check_the_permissions() {
if ( ! current_user_can( 'manage_options' ) ) {
echo json_encode(
[
array(
'success' => false,
'message' => esc_html__( 'You do not have permission to do that.' ),
]
)
);

die();
Expand All @@ -352,10 +356,10 @@ function check_the_permissions() {
function check_the_nonce( string $nonce, $action ) {
if ( ! wp_verify_nonce( $nonce, $action ) ) {
echo json_encode(
[
array(
'success' => false,
'message' => esc_html__( 'Security check failed. Refresh the page and try again.' ),
]
)
);

die();
Expand Down Expand Up @@ -383,9 +387,14 @@ function add_action_links( $actions ) {
function pause_renewal_actions() {
if ( 'on' === get_option( 'safety_net_pause_renewal_actions_toggle' ) ) {
require_once __DIR__ . '/classes/class-actionscheduler-custom-dbstore.php';
add_filter( 'action_scheduler_store_class', function( $class ) {
return 'SafetyNet\ActionScheduler_Custom_DBStore';
}, 101, 1 );
add_filter(
'action_scheduler_store_class',
function( $class ) {
return 'SafetyNet\ActionScheduler_Custom_DBStore';
},
101,
1
);
}
}

Expand Down
30 changes: 30 additions & 0 deletions includes/anonymize.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,22 @@
* @return void
*/
function anonymize_data() {

copy_and_clear_user_tables();

dispatch_anonymize_users();

dispatch_anonymize_orders();

dispatch_anonymize_customers();
}

/**
* Copy the user and user_meta tables to new temporary tables and delete all the non-admin data from the original tables.
*
* @return void
*/
function copy_and_clear_user_tables() {
global $wpdb;

// Copy user table to a temporary table that will be anonymized later.
Expand All @@ -36,6 +52,20 @@ function anonymize_data() {
dispatch_anonymize_customers();
}

/**
* Move all the anonymized users and their meta from the temp table to the real ones and remove the temp tables.
*
* @return void
*/
function store_anonymized_user_data() {
global $wpdb;

$wpdb->query( "INSERT INTO $wpdb->users (SELECT * FROM {$wpdb->users}_temp WHERE id NOT IN (SELECT ID FROM $wpdb->users))" );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error handling needed for non-standard table that might not exist.

$wpdb->query( "DROP TABLE {$wpdb->users}_temp" );
$wpdb->query( "INSERT INTO $wpdb->usermeta (SELECT * FROM {$wpdb->usermeta}_temp WHERE user_id NOT IN (SELECT user_id FROM $wpdb->usermeta))" );
$wpdb->query( "DROP TABLE {$wpdb->usermeta}_temp" );
}

/**
* Dispatches a background process to anonymize users.
*/
Expand Down
7 changes: 3 additions & 4 deletions includes/classes/background-anonymize-user.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace SafetyNet;

use function SafetyNet\Anonymize\anonymize_users;
use function SafetyNet\Anonymize\store_anonymized_user_data;

/**
* Background Anonymize User class
Expand Down Expand Up @@ -51,10 +52,8 @@ protected function complete() {
// Have to call complete function in the parent's class.
parent::complete();

$wpdb->query( "INSERT INTO $wpdb->users (SELECT * FROM {$wpdb->users}_temp WHERE id NOT IN (SELECT ID FROM $wpdb->users))" );
$wpdb->query( "DROP TABLE {$wpdb->users}_temp" );
$wpdb->query( "INSERT INTO $wpdb->usermeta (SELECT * FROM {$wpdb->usermeta}_temp WHERE user_id NOT IN (SELECT user_id FROM $wpdb->usermeta))" );
$wpdb->query( "DROP TABLE {$wpdb->usermeta}_temp" );
// Store the anonymized users to the default tables.
store_anonymized_user_data();

// Flush the cache.
wp_cache_flush();
Expand Down
19 changes: 19 additions & 0 deletions includes/cli/anonymize.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?php

use function SafetyNet\Anonymize\anonymize_orders;
use function SafetyNet\Anonymize\copy_and_clear_user_tables;
use function SafetyNet\Anonymize\store_anonymized_user_data;
use function SafetyNet\Anonymize\anonymize_users;
use function SafetyNet\Anonymize\anonymize_customers;
use function SafetyNet\Delete\delete_users_and_orders;
Expand All @@ -19,10 +21,27 @@ class SafetyNet_CLI extends WP_CLI_Command {
*
*/
public function anonymize( $args ) {

$info = WP_CLI::colorize( '%pThis process will anonymize your current users, orders and customers with dummy data.%n ' );
WP_CLI::log( $info );

WP_CLI::warning( 'Please proceed with caution if you have a site with a large number of users/orders/customers' );

WP_CLI::confirm( 'Are you sure you want to do this?' );

WP_CLI::log( '- Copying users to temporary tables ...' );
copy_and_clear_user_tables();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do any of these functions return data that could be shown to the user? e.g error handling, success message, count of changes rows etc?


WP_CLI::log( '- Anonymizing users ... ' );
anonymize_users();

WP_CLI::log( '- Storing the anonymized users to the default tables ... ' );
store_anonymized_user_data();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each of these steps definitely needs some more verbosity. A nice success message if everything goes to plan, and a detailed error output if not ideally.


WP_CLI::log( '- Anonymizing orders ... ' );
anonymize_orders();

WP_CLI::log( '- Anonymizing customers ... ' );
anonymize_customers();

update_option( 'anonymized_status', true, false );
Expand Down