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

feature(mvp): Stage 4 - add activator and uninstaller #298

Merged
merged 7 commits into from
Apr 21, 2023
Merged
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
159 changes: 159 additions & 0 deletions includes/class-activator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<?php
/**
* Notifications API:Activator class
*
* @package wordpress/wp-feature-notifications
*/

namespace WP\Notifications;

use WP\Notifications\Database;

/**
* Class Activator.
*
* Defines the plugin's activation procedure.
*/
class Activator {

/**
* The default options array.
*
* @var array $default_options
*/
private static $default_options = array();

/**
* Initialize the default options.
*
* @return void
*/
public static function init_options() {

self::$default_options = array(
'version' => WP_FEATURE_NOTIFICATION_PLUGIN_VERSION,
'max_lifespan' => 1000 * 60 * 60 * 24 * 31 * 6, // 6 months
'delete_on_dismiss' => false,
);
}

/**
* Create or Update the WP_Notifications options.
*
* @return void
*/
public static function update_options() {

self::init_options();

$options = get_option( 'wp_notifications_options' );

if ( false !== $options ) {

// Update the plugin options but add the new options automatically
if ( isset( $options['version'] ) ) {
unset( $options['version'] );
}

// Merge previous options, preserve the previously modified options as default.
$new_options = array_merge( self::$default_options, $options );

update_option( 'wp_notifications_options', $new_options );
} else {
// If the plugin options are missing, initialize the plugin with the default options.
$new_options = array_merge( self::$default_options );

add_option( 'wp_notifications_options', $new_options );
}
}

/**
* Install the WP Notifications plugin.
*
* Create the plugin's database tables and options
*
* @return void
*/
public static function install() {
global $wpdb;

// Engage multisite if in the middle of turning it on from network.php.
$is_multisite = is_multisite() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK );

if ( $is_multisite ) {
// Get all blogs in the network and uninstall the plugin on each one.
$blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" );

// Loop over the individual sites and create tables for each.
foreach ( $blog_ids as $blog_id ) {
switch_to_blog( $blog_id );

self::create_tables();

restore_current_blog();
}
}

// Always create the main site database tables and options.
self::create_tables();
}

/**
* Activate the WP Notifications plugin.
*
* @return void
*/
public static function activate() {
self::install();
set_transient( 'wp_notifications_activation', true );
}

/**
* Create the WP Notifications tables and options.
*
* @return void
*/
public static function create_tables() {
$db_version = get_option( 'wp_notifications_db_version' );

if ( ! $db_version ) {
self::create_tables_v1();
update_option( 'wp_notifications_db_version', WP_FEATURE_NOTIFICATION_DB_VERSION );
}

// If the options do not exist then create them
self::update_options();
}

/**
* Create v1 WP Notifications tables and options.
*
* @return void
*/
public static function create_tables_v1() {
global $wpdb;

require_once ABSPATH . 'wp-admin/includes/upgrade.php';
require_once WP_FEATURE_NOTIFICATION_PLUGIN_DIR . '/includes/database/class-schema.php';

$tables = $wpdb->get_results( 'SHOW TABLES' );

// Create the messages table
if ( ! in_array( $wpdb->prefix . 'notifications_messages', $tables, true ) ) {
$messages_sql = Database\Schema::messages_table_v1();
dbDelta( $messages_sql );
}

// Create the subscriptions table
if ( ! in_array( $wpdb->prefix . 'notifications_subscriptions', $tables, true ) ) {
$subscriptions_sql = Database\Schema::subscriptions_table_v1();
dbDelta( $subscriptions_sql );
}

// Create the queue table
if ( ! in_array( $wpdb->prefix . 'notifications_queue', $tables, true ) ) {
$queue_sql = Database\Schema::queue_table_v1();
dbDelta( $queue_sql );
}
}
}
87 changes: 87 additions & 0 deletions includes/class-uninstaller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php
/**
* Notifications API:Uninstaller class
*
* @package wordpress/wp-feature-notifications
*/

namespace WP\Notifications;

/**
* Class Uninstaller.
*
* Defines the plugin's uninstall procedure.
*
* @package wordpress/wp-feature-notifications
*/
class Uninstaller {

/**
* Uninstall the plugin and reinstall.
*
* @return void
*/
public static function full_reset() {
self::uninstall();

require_once WP_FEATURE_NOTIFICATION_PLUGIN_DIR . '/includes/class-activator.php';

Activator::install();
}


/**
* Uninstall the WP Notifications plugin.
*
* Delete the plugin's database tables and options.
*
* @return void
*/
public static function uninstall() {
global $wpdb;

// Engage multisite if in the middle of turning it on from network.php.
$is_multisite = is_multisite() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK );

if ( $is_multisite ) {
// Get all blogs in the network and uninstall the plugin on each one.
$blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" );

foreach ( $blog_ids as $blog_id ) {
switch_to_blog( $blog_id );

self::drop_tables();
self::delete_options();

restore_current_blog();
}
}

// Always remove the main site database tables and options.
self::drop_tables();
self::delete_options();
}

/**
* Drop the WP Notifications database tables.
*
* @return void
*/
public static function drop_tables() {
global $wpdb;

$wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'notifications_messages' );
$wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'notifications_subscriptions' );
$wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'notifications_queue' );
}

/**
* Delete the WP Notifications options.
*
* @return void
*/
public static function delete_options() {
delete_option( 'wp_notifications_db_version' );
delete_option( 'wp_notifications_options' );
}
}
66 changes: 66 additions & 0 deletions includes/database/class-schema.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php
/**
* Notifications API:Schema class
*
* @package wordpress/wp-feature-notifications
*/

namespace WP\Notifications\Database;

/**
* Class Schema
*
* Static class representing the database schema.
*/
final class Schema {

public static function messages_table_v1() {
global $wpdb;

$charset_collate = $wpdb->get_charset_collate();

return 'CREATE TABLE `' . $wpdb->prefix . "notifications_messages` (
`id` BIGINT(20) NOT NULL,
`channel_name` VARCHAR(50) NOT NULL,
`channel_title` TINYTEXT NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP(),
`expires_at` DATETIME NULL,
`severity` VARCHAR(16) NULL,
`title` TINYTEXT NULL,
`message` TINYTEXT NULL,
`meta` TEXT NULL,
PRIMARY KEY (`id`),
KEY `channel_name` (`channel_name`)
) $charset_collate;\n";
}


public static function subscriptions_table_v1() {
global $wpdb;

$charset_collate = $wpdb->get_charset_collate();

return 'CREATE TABLE `' . $wpdb->prefix . "notifications_subscriptions` (
`user_id` BIGINT(20) NOT NULL,
`channel_name` VARCHAR(50) NOT NULL,
`snoozed_until` DATETIME NULL,
KEY `user_id` (`user_id`),
KEY `channel_name` (`channel_name`)
) $charset_collate;\n";
}

public static function queue_table_v1() {
global $wpdb;

$charset_collate = $wpdb->get_charset_collate();

return 'CREATE TABLE `' . $wpdb->prefix . "notifications_queue` (
`message_id` BIGINT(20) NOT NULL,
`user_id` BIGINT(20) NOT NULL,
`dismissed_at` DATETIME NULL,
`displayed_at` DATETIME NULL,
KEY `message_id` (`message_id`),
KEY `user_id` (`user_id`)
) $charset_collate;\n";
}
}
1 change: 1 addition & 0 deletions tests/phpunit/includes/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@ function handle_wp_setup_failure( $message ) {
remove_filter( 'wp_die_handler', 'handle_wp_setup_failure' );

require dirname( __FILE__ ) . '/class-testcase.php';
require dirname( __FILE__ ) . '/class-db-testcase.php';
32 changes: 32 additions & 0 deletions tests/phpunit/includes/class-db-testcase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace WP\Notifications\Tests;

use PHPUnit_Adapter_TestCase;

class DB_TestCase extends PHPUnit_Adapter_TestCase {

/**
* Check if a table exists in the database.
*
* @param string $table_name The name of the table to check.
*
* @return bool Whether the database exists.
*/
protected function table_exists( string $table_name ): bool {
global $wpdb;

$expected = $wpdb->prefix . $table_name;

$actual = $wpdb->get_var(
$wpdb->prepare(
'SHOW TABLES LIKE %s',
$wpdb->esc_like( $wpdb->prefix . $table_name )
)
);

return $expected === $actual;

}

}
18 changes: 18 additions & 0 deletions tests/phpunit/includes/class-testcase.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,22 @@

class TestCase extends PHPUnit_Adapter_TestCase {

/**
* Asserts that the contents of two un-keyed, single arrays are the same, without accounting for the order of elements.
*
* Copied from WP_UnitTestCase_Base.
*
* @param array $expected Expected array.
* @param array $actual Array to check.
* @param string $message Optional. Message to display when the assertion fails.
*/
public function assertSameSets( $expected, $actual, $message = '' ) {
$this->assertIsArray( $expected, $message . ' Expected value must be an array.' );
$this->assertIsArray( $actual, $message . ' Value under test is not an array.' );

sort( $expected );
sort( $actual );
$this->assertSame( $expected, $actual, $message );
}

}
Loading