diff --git a/.gitignore b/.gitignore index bbba19d5cb..f9468e402f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,22 @@ -.DS_Store -TODO -composer.phar -/vendor -tests/_output/* -tests/acceptance.suite.yml -tests/_support/_generated/* -node_modules -.env -npm-debug.log -!tasks/** -/views/cache/** -temp -.idea -mailpoet.zip -tests/javascript/testBundles -assets/css/*.css -assets/js/*.js -.vagrant -lang -.mp_svn +.DS_Store +TODO +composer.phar +/vendor +tests/_output/* +tests/acceptance.suite.yml +tests/_support/_generated/* +node_modules +.env +npm-debug.log +!tasks/** +/views/cache/** +temp +.idea +mailpoet.zip +tests/javascript/testBundles +assets/css/*.css +assets/js/*.js +.vagrant +lang +.mp_svn +/nbproject/ \ No newline at end of file diff --git a/assets/css/src/admin.styl b/assets/css/src/admin.styl index 866f4d26db..aae0060e1f 100644 --- a/assets/css/src/admin.styl +++ b/assets/css/src/admin.styl @@ -22,3 +22,5 @@ @require 'progress_bar' @require 'subscribers' + +@require 'mp2migrator' diff --git a/assets/css/src/mp2migrator.styl b/assets/css/src/mp2migrator.styl new file mode 100644 index 0000000000..bddcfefb9f --- /dev/null +++ b/assets/css/src/mp2migrator.styl @@ -0,0 +1,33 @@ +#logger + width: 100% + height: 300px + background-color: transparent + border: 0 + border-top: 1px #aba9a9 solid + padding: 2px + overflow: scroll + resize: both + font-size: 0.85em + margin-top: 20px + +#progressbar + width: 50% + background-color: #d8d8d8 + border-radius: 5px + +progressbar_color = #fecf23 +progressbar_gradient_to_color = #fd9215 + +.ui-progressbar .ui-progressbar-value + height: 100% + background-color: progressbar_color + background-image: linear-gradient(to bottom, progressbar_color, progressbar_gradient_to_color) + border-radius: 3px + box-shadow: 0 1px 0 rgba(255,255,255,0.5) inset + border 0 + +.mailpoet_progress_label + font-size: 15px + +.error_msg + color: #f00 diff --git a/assets/js/src/mp2migrator.js b/assets/js/src/mp2migrator.js new file mode 100644 index 0000000000..ae03914f67 --- /dev/null +++ b/assets/js/src/mp2migrator.js @@ -0,0 +1,187 @@ +define('mp2migrator', ['mailpoet', 'jquery'], function(MailPoet, jQuery) { + 'use strict'; + MailPoet.MP2Migrator = { + + fatal_error: '', + is_logging: false, + + startLogger: function () { + MailPoet.MP2Migrator.is_logging = true; + clearTimeout(MailPoet.MP2Migrator.displayLogs_timeout); + clearTimeout(MailPoet.MP2Migrator.updateProgressbar_timeout); + clearTimeout(MailPoet.MP2Migrator.update_wordpress_info_timeout); + setTimeout(MailPoet.MP2Migrator.updateDisplay, 1000) + }, + + stopLogger: function () { + MailPoet.MP2Migrator.is_logging = false; + }, + + updateDisplay: function () { + MailPoet.MP2Migrator.displayLogs(); + MailPoet.MP2Migrator.updateProgressbar(); + }, + + displayLogs: function () { + jQuery.ajax({ + url: mailpoet_mp2_migrator.log_file_url, + cache: false + }).done(function (result) { + jQuery("#logger").html(''); + result.split("\n").forEach(function (row) { + if(row.substr(0, 7) === '[ERROR]' || row.substr(0, 9) === '[WARNING]' || row === MailPoet.I18n.t('import_stopped_by_user')) { + row = '' + row + ''; // Mark the errors in red + } + // Test if the import is complete + else if(row === MailPoet.I18n.t('import_complete')) { + jQuery('#import-actions').hide(); + jQuery('#upgrade-completed').show(); + } + jQuery("#logger").append(row + "
\n"); + + }); + jQuery("#logger").append('' + MailPoet.MP2Migrator.fatal_error + '' + "
\n"); + }).always(function () { + if(MailPoet.MP2Migrator.is_logging) { + MailPoet.MP2Migrator.displayLogs_timeout = setTimeout(MailPoet.MP2Migrator.displayLogs, 1000); + } + }); + }, + + updateProgressbar: function () { + jQuery.ajax({ + url: mailpoet_mp2_migrator.progress_url, + cache: false, + dataType: 'json' + }).always(function (result) { + // Move the progress bar + var progress = 0; + if((result.total !== undefined) && (Number(result.total) !== 0)) { + progress = Math.round(Number(result.current) / Number(result.total) * 100); + } + jQuery('#progressbar').progressbar('option', 'value', progress); + jQuery('#progresslabel').html(progress + '%'); + if(Number(result.current !== 0)) { + jQuery('#skip-import').hide(); + } + if(MailPoet.MP2Migrator.is_logging) { + MailPoet.MP2Migrator.updateProgressbar_timeout = setTimeout(MailPoet.MP2Migrator.updateProgressbar, 1000); + } + }); + }, + + startImport: function () { + MailPoet.MP2Migrator.fatal_error = ''; + // Start displaying the logs + MailPoet.MP2Migrator.startLogger(); + + // Disable the import button + MailPoet.MP2Migrator.import_button_label = jQuery('#import').val(); + jQuery('#import').val(MailPoet.I18n.t('importing')).attr('disabled', 'disabled'); + // Hide the Skip button + jQuery('#skip-import').hide(); + // Show the stop button + jQuery('#stop-import').show(); + + // Run the import + MailPoet.Ajax.post({ + api_version: window.mailpoet_api_version, + endpoint: 'MP2Migrator', + action: 'import', + data: { + } + }).always(function () { + MailPoet.MP2Migrator.stopLogger(); + MailPoet.MP2Migrator.updateDisplay(); // Get the latest information after the import was stopped + MailPoet.MP2Migrator.reactivateImportButton(); + }).done(function (response) { + if(response) { + MailPoet.MP2Migrator.fatal_error = response.data; + } + }).fail(function (response) { + if(response.errors.length > 0) { + MailPoet.Notice.error( + response.errors.map(function (error) { + return error.message; + }), + {scroll: true} + ); + } + }); + return false; + }, + + reactivateImportButton: function () { + jQuery('#import').val(MailPoet.MP2Migrator.import_button_label).removeAttr('disabled'); + jQuery('#stop-import').hide(); + }, + + stopImport: function () { + jQuery('#stop-import').attr('disabled', 'disabled'); + // Stop the import + MailPoet.Ajax.post({ + api_version: window.mailpoet_api_version, + endpoint: 'MP2Migrator', + action: 'stopImport', + data: { + } + }).always(function () { + jQuery('#stop-import').removeAttr('disabled'); // Enable the button + MailPoet.MP2Migrator.reactivateImportButton(); + MailPoet.MP2Migrator.updateDisplay(); // Get the latest information after the import was stopped + }); + MailPoet.MP2Migrator.stopLogger(); + return false; + }, + + skipImport: function () { + MailPoet.Ajax.post({ + api_version: window.mailpoet_api_version, + endpoint: 'MP2Migrator', + action: 'skipImport', + data: { + } + }).done(function () { + MailPoet.MP2Migrator.gotoWelcomePage(); + }); + return false; + }, + + gotoWelcomePage: function () { + window.location.href = 'admin.php?page=mailpoet-welcome'; + return false; + } + + }; + + /** + * Actions to run when the DOM is ready + */ + jQuery(function () { + jQuery('#progressbar').progressbar({value: 0}); + + // Import button + jQuery('#import').click(function() { + MailPoet.MP2Migrator.startImport(); + }); + + // Stop import button + jQuery('#stop-import').click(function() { + MailPoet.MP2Migrator.stopImport(); + }); + + // Skip import link + jQuery('#skip-import').click(function() { + MailPoet.MP2Migrator.skipImport(); + }); + + // Go to welcome page + jQuery('#goto-welcome').click(function() { + MailPoet.MP2Migrator.gotoWelcomePage(); + }); + + // Update the display + MailPoet.MP2Migrator.updateDisplay(); + }); + +}); diff --git a/lib/API/JSON/v1/MP2Migrator.php b/lib/API/JSON/v1/MP2Migrator.php new file mode 100644 index 0000000000..67d851ae21 --- /dev/null +++ b/lib/API/JSON/v1/MP2Migrator.php @@ -0,0 +1,64 @@ +MP2Migrator = new \MailPoet\Config\MP2Migrator(); + } + + /** + * Import end point + * + * @param object $data + * @return object + */ + public function import($data) { + try { + $process = $this->MP2Migrator->import($data); + return $this->successResponse($process); + } catch(\Exception $e) { + return $this->errorResponse(array( + $e->getCode() => $e->getMessage() + )); + } + } + + /** + * Stop import end point + * + * @param object $data + * @return object + */ + public function stopImport($data) { + try { + $process = $this->MP2Migrator->stopImport(); + return $this->successResponse($process); + } catch(\Exception $e) { + return $this->errorResponse(array( + $e->getCode() => $e->getMessage() + )); + } + } + + /** + * Skip import end point + * + * @param object $data + * @return object + */ + public function skipImport($data) { + try { + $process = $this->MP2Migrator->skipImport(); + return $this->successResponse($process); + } catch(\Exception $e) { + return $this->errorResponse(array( + $e->getCode() => $e->getMessage() + )); + } + } + +} diff --git a/lib/Config/Changelog.php b/lib/Config/Changelog.php index 7c0b61a1f9..59295e0beb 100644 --- a/lib/Config/Changelog.php +++ b/lib/Config/Changelog.php @@ -34,12 +34,23 @@ class Changelog { $version = Setting::getValue('version', null); $redirect_url = null; - if($version === null) { - // new install - $redirect_url = admin_url('admin.php?page=mailpoet-welcome'); - } else if($version !== Env::$version) { - // update - $redirect_url = admin_url('admin.php?page=mailpoet-update'); + $mp2_migrator = new MP2Migrator(); + if(!in_array($_GET['page'], array('mailpoet-migration', 'mailpoet-settings')) && $mp2_migrator->isMigrationStartedAndNotCompleted()) { + // Force the redirection if the migration has started but is not completed + $redirect_url = admin_url('admin.php?page=mailpoet-migration'); + } else { + if($version === null) { + // new install + if($mp2_migrator->isMigrationNeeded()) { + // Migration from MP2 + $redirect_url = admin_url('admin.php?page=mailpoet-migration'); + } else { + $redirect_url = admin_url('admin.php?page=mailpoet-welcome'); + } + } else if($version !== Env::$version) { + // update + $redirect_url = admin_url('admin.php?page=mailpoet-update'); + } } if($redirect_url !== null) { diff --git a/lib/Config/Database.php b/lib/Config/Database.php index cee44d7339..2756a7a09c 100644 --- a/lib/Config/Database.php +++ b/lib/Config/Database.php @@ -77,6 +77,7 @@ class Database { $statistics_opens = Env::$db_prefix . 'statistics_opens'; $statistics_unsubscribes = Env::$db_prefix . 'statistics_unsubscribes'; $statistics_forms = Env::$db_prefix . 'statistics_forms'; + $mapping_to_external_entities = Env::$db_prefix . 'mapping_to_external_entities'; define('MP_SETTINGS_TABLE', $settings); define('MP_SEGMENTS_TABLE', $segments); @@ -98,6 +99,7 @@ class Database { define('MP_STATISTICS_OPENS_TABLE', $statistics_opens); define('MP_STATISTICS_UNSUBSCRIBES_TABLE', $statistics_unsubscribes); define('MP_STATISTICS_FORMS_TABLE', $statistics_forms); + define('MP_MAPPING_TO_EXTERNAL_ENTITIES_TABLE', $mapping_to_external_entities); } } } diff --git a/lib/Config/MP2Migrator.php b/lib/Config/MP2Migrator.php new file mode 100644 index 0000000000..95481590f9 --- /dev/null +++ b/lib/Config/MP2Migrator.php @@ -0,0 +1,742 @@ +defineMP2Tables(); + $log_filename = 'mp2migration.log'; + $this->log_file = Env::$temp_path . '/' . $log_filename; + $this->log_file_url = Env::$temp_url . '/' . $log_filename; + $this->progressbar = new ProgressBar('mp2migration'); + } + + private function defineMP2Tables() { + global $wpdb; + + if(!defined('MP2_CAMPAIGN_TABLE')) { + define('MP2_CAMPAIGN_TABLE', $wpdb->prefix . 'wysija_campaign'); + } + if(!defined('MP2_CUSTOM_FIELD_TABLE')) { + define('MP2_CUSTOM_FIELD_TABLE', $wpdb->prefix . 'wysija_custom_field'); + } + if(!defined('MP2_EMAIL_TABLE')) { + define('MP2_EMAIL_TABLE', $wpdb->prefix . 'wysija_email'); + } + if(!defined('MP2_FORM_TABLE')) { + define('MP2_FORM_TABLE', $wpdb->prefix . 'wysija_form'); + } + if(!defined('MP2_LIST_TABLE')) { + define('MP2_LIST_TABLE', $wpdb->prefix . 'wysija_list'); + } + if(!defined('MP2_USER_TABLE')) { + define('MP2_USER_TABLE', $wpdb->prefix . 'wysija_user'); + } + if(!defined('MP2_USER_LIST_TABLE')) { + define('MP2_USER_LIST_TABLE', $wpdb->prefix . 'wysija_user_list'); + } + } + + /** + * Test if the migration is already started but is not completed + * + * @return boolean + */ + public function isMigrationStartedAndNotCompleted() { + return Setting::getValue('mailpoet_migration_started', false) && !Setting::getValue('mailpoet_migration_complete', false); + } + + /** + * Test if the migration is needed + * + * @return boolean + */ + public function isMigrationNeeded() { + if(Setting::getValue('mailpoet_migration_complete')) { + return false; + } else { + return $this->tableExists(MP2_CAMPAIGN_TABLE); // Check if the MailPoet 2 tables exist + } + } + + /** + * Store the "Skip import" choice + * + */ + public function skipImport() { + Setting::setValue('mailpoet_migration_complete', true); + } + + /** + * Test if a table exists + * + * @param string $table Table name + * @return boolean + */ + private function tableExists($table) { + global $wpdb; + + try { + $sql = "SHOW TABLES LIKE '{$table}'"; + $result = $wpdb->query($sql); + return !empty($result); + } catch (Exception $e) { + // Do nothing + } + + return false; + } + + /** + * Initialize the migration page + * + */ + public function init() { + if(!Setting::getValue('mailpoet_migration_started', false)) { + $this->emptyLog(); + $this->progressbar->setTotalCount(0); + } + $this->enqueueScripts(); + } + + /** + * Register the JavaScript for the admin area. + * + */ + private function enqueueScripts() { + wp_enqueue_script('jquery-ui-progressbar'); + } + + /** + * Write a message in the log file + * + * @param string $message + */ + private function log($message) { + file_put_contents($this->log_file, "$message\n", FILE_APPEND); + } + + /** + * Import the data from MailPoet 2 + * + * @return string Result + */ + public function import() { + set_time_limit(self::IMPORT_TIMEOUT_IN_SECONDS); + ob_start(); + $datetime = new \MailPoet\WP\DateTime(); + $this->log(sprintf('=== ' . __('START IMPORT', 'mailpoet') . ' %s ===', $datetime->formatTime(time(), \MailPoet\WP\DateTime::DEFAULT_DATE_TIME_FORMAT))); + Setting::setValue('import_stopped', false); // Reset the stop import action + + if(!Setting::getValue('mailpoet_migration_started', false)) { + $this->eraseMP3Data(); + Setting::setValue('mailpoet_migration_started', true); + $this->displayDataToMigrate(); + } + + $this->importSegments(); + $this->importCustomFields(); + $this->importSubscribers(); + + if(!$this->importStopped()) { + Setting::setValue('mailpoet_migration_complete', true); + $this->log(__('IMPORT COMPLETE', 'mailpoet')); + } + + $this->log(sprintf('=== ' . __('END IMPORT', 'mailpoet') . ' %s ===', $datetime->formatTime(time(), \MailPoet\WP\DateTime::DEFAULT_DATE_TIME_FORMAT))); + $result = ob_get_contents(); + ob_clean(); + return $result; + } + + /** + * Empty the log file + * + */ + private function emptyLog() { + file_put_contents($this->log_file, ''); + } + + /** + * Erase all the MailPoet 3 data + * + */ + private function eraseMP3Data() { + Activator::deactivate(); + Activator::activate(); + + $this->deleteSegments(); + $this->resetMigrationCounters(); + $this->log(__("MailPoet data erased", 'mailpoet')); + } + + /** + * Reset the migration counters + * + */ + private function resetMigrationCounters() { + Setting::setValue('last_imported_user_id', 0); + Setting::setValue('last_imported_list_id', 0); + } + + /** + * Delete the existing segments except the wp_users segment + * + */ + private function deleteSegments() { + global $wpdb; + + $table = MP_SEGMENTS_TABLE; + $wpdb->query("DELETE FROM {$table} WHERE type != '" . Segment::TYPE_WP_USERS . "'"); + } + + /** + * Stop the import + * + */ + public function stopImport() { + Setting::setValue('import_stopped', true); + $this->log(__('IMPORT STOPPED BY USER', 'mailpoet')); + } + + /** + * Test if the import must stop + * + * @return boolean Import must stop or not + */ + private function importStopped() { + return Setting::getValue('import_stopped', false); + } + + /** + * Display the number of data to migrate + * + */ + private function displayDataToMigrate() { + $data = $this->getDataToMigrateAndResetProgressBar(); + $this->log($data); + } + + /** + * Get the data to migrate + * + * @return string Data to migrate + */ + private function getDataToMigrateAndResetProgressBar() { + $result = ''; + $total_count = 0; + + $this->progressbar->setTotalCount(0); + + $result .= __('MailPoet 2 data found:', 'mailpoet') . "\n"; + + // User Lists + $users_lists_count = \ORM::for_table(MP2_LIST_TABLE)->count(); + $total_count += $users_lists_count; + $result .= sprintf(_n('%d subscribers list', '%d subscribers lists', $users_lists_count, 'mailpoet'), $users_lists_count) . "\n"; + + // Users + $users_count = \ORM::for_table(MP2_USER_TABLE)->count(); + $total_count += $users_count; + $result .= sprintf(_n('%d subscriber', '%d subscribers', $users_count, 'mailpoet'), $users_count) . "\n"; + + // TODO to reactivate during the next phases + /* + // Emails + $emails_count = \ORM::for_table(MP2_EMAIL_TABLE)->count(); + $total_count += $emails_count; + $result .= sprintf(_n('%d newsletter', '%d newsletters', $emails_count, 'mailpoet'), $emails_count) . "\n"; + + // Forms + $forms_count = \ORM::for_table(MP2_FORM_TABLE)->count(); + $total_count += $forms_count; + $result .= sprintf(_n('%d form', '%d forms', $forms_count, 'mailpoet'), $forms_count) . "\n"; + */ + + $this->progressbar->setTotalCount($total_count); + + return $result; + } + + /** + * Import the subscribers segments + * + */ + private function importSegments() { + $imported_segments_count = 0; + if($this->importStopped()) { + $this->segments_mapping = $this->getImportedMapping('segments'); + return; + } + $this->log(__("Importing segments...", 'mailpoet')); + do { + if($this->importStopped()) { + break; + } + $lists = $this->getLists(self::CHUNK_SIZE); + $lists_count = count($lists); + + if(is_array($lists)) { + foreach($lists as $list) { + $segment = $this->importSegment($list); + if(!empty($segment)) { + $imported_segments_count++; + } + } + } + $this->progressbar->incrementCurrentCount($lists_count); + } while(($lists != null) && ($lists_count > 0)); + + $this->segments_mapping = $this->getImportedMapping('segments'); + + $this->log(sprintf(_n("%d segment imported", "%d segments imported", $imported_segments_count, 'mailpoet'), $imported_segments_count)); + } + + /** + * Get the Mailpoet 2 users lists + * + * @global object $wpdb + * @param int $limit Number of users max + * @return array Users Lists + */ + private function getLists($limit) { + global $wpdb; + $lists = array(); + + $last_id = Setting::getValue('last_imported_list_id', 0); + $table = MP2_LIST_TABLE; + $sql = " + SELECT l.list_id, l.name, l.description, l.is_enabled, l.created_at + FROM `$table` l + WHERE l.list_id > '$last_id' + ORDER BY l.list_id + LIMIT $limit + "; + $lists = $wpdb->get_results($sql, ARRAY_A); + + return $lists; + } + + /** + * Import a segment + * + * @param array $list_data List data + * @return Segment + */ + private function importSegment($list_data) { + $datetime = new \MailPoet\WP\DateTime(); + if($list_data['is_enabled']) { + $segment = Segment::createOrUpdate(array( + 'name' => $list_data['name'], + 'type' => 'default', + 'description' => !empty($list_data['description']) ? $list_data['description'] : '', + 'created_at' => $datetime->formatTime($list_data['created_at'], \MailPoet\WP\DateTime::DEFAULT_DATE_TIME_FORMAT), + )); + } else { + $segment = Segment::getWPSegment(); + } + if(!empty($segment)) { + // Map the segment with its old ID + $mapping = new MappingToExternalEntities(); + $mapping->create(array( + 'old_id' => $list_data['list_id'], + 'type' => 'segments', + 'new_id' => $segment->id, + 'created_at' => $datetime->formatTime(time(), \MailPoet\WP\DateTime::DEFAULT_DATE_TIME_FORMAT), + )); + } + Setting::setValue('last_imported_list_id', $list_data['list_id']); + return $segment; + } + + /** + * Import the custom fields + * + */ + private function importCustomFields() { + $imported_custom_fields_count = 0; + if($this->importStopped()) { + return; + } + $this->log(__("Importing custom fields...", 'mailpoet')); + $custom_fields = $this->getCustomFields(); + + foreach($custom_fields as $custom_field) { + $result = $this->importCustomField($custom_field); + if(!empty($result)) { + $imported_custom_fields_count++; + } + } + + $this->log(sprintf(_n("%d custom field imported", "%d custom fields imported", $imported_custom_fields_count, 'mailpoet'), $imported_custom_fields_count)); + } + + /** + * Get the Mailpoet 2 custom fields + * + * @global object $wpdb + * @return array Custom fields + */ + private function getCustomFields() { + global $wpdb; + $custom_fields = array(); + + $table = MP2_CUSTOM_FIELD_TABLE; + $sql = " + SELECT cf.id, cf.name, cf.type, cf.required, cf.settings + FROM `$table` cf + "; + $custom_fields = $wpdb->get_results($sql, ARRAY_A); + + return $custom_fields; + } + + /** + * Import a custom field + * + * @param array $custom_field MP2 custom field + * @return CustomField + */ + private function importCustomField($custom_field) { + $data = array( + 'id' => $custom_field['id'], + 'name' => $custom_field['name'], + 'type' => $this->mapCustomFieldType($custom_field['type']), + 'params' => $this->mapCustomFieldParams($custom_field), + ); + $custom_field = new CustomField(); + $custom_field->createOrUpdate($data); + return $custom_field; + } + + /** + * Map the MailPoet 2 custom field type with the MailPoet custom field type + * + * @param string $mp2_type MP2 custom field type + * @return string MP3 custom field type + */ + private function mapCustomFieldType($mp2_type) { + $type = ''; + switch($mp2_type) { + case 'input': + $type = 'text'; + break; + default: + $type = $mp2_type; + } + return $type; + } + + /** + * Map the MailPoet 2 custom field settings with the MailPoet custom field params + * + * @param array $custom_field MP2 custom field + * @return string serialized MP3 custom field params + */ + private function mapCustomFieldParams($custom_field) { + $params = unserialize($custom_field['settings']); + $params['label'] = $custom_field['name']; + if(isset($params['validate'])) { + $params['validate'] = $this->mapCustomFieldValidateValue($params['validate']); + } + if(isset($params['date_order'])) { // Convert the date_order field + $params['date_format'] = strtoupper($params['date_order']); + unset($params['date_order']); + } + return $params; + } + + /** + * Map the validate value + * + * @param string $mp2_value MP2 value + * @return string MP3 value + */ + private function mapCustomFieldValidateValue($mp2_value) { + $value = ''; + switch($mp2_value) { + case 'onlyLetterSp': + case 'onlyLetterNumber': + $value = 'alphanum'; + break; + case 'onlyNumberSp': + $value = 'number'; + break; + case 'phone': + $value = 'phone'; + break; + } + return $value; + } + + /** + * Import the subscribers + * + */ + private function importSubscribers() { + $imported_subscribers_count = 0; + if($this->importStopped()) { + return; + } + $this->log(__("Importing subscribers...", 'mailpoet')); + $this->wp_users_segment = Segment::getWPSegment(); + do { + if($this->importStopped()) { + break; + } + $users = $this->getUsers(self::CHUNK_SIZE); + $users_count = count($users); + + if(is_array($users)) { + foreach($users as $user) { + $subscriber = $this->importSubscriber($user); + if(!empty($subscriber)) { + $imported_subscribers_count++; + $this->importSubscriberSegments($subscriber, $user['user_id']); + $this->importSubscriberCustomFields($subscriber, $user); + } + } + } + $this->progressbar->incrementCurrentCount($users_count); + } while(($users != null) && ($users_count > 0)); + + $this->log(sprintf(_n("%d subscriber imported", "%d subscribers imported", $imported_subscribers_count, 'mailpoet'), $imported_subscribers_count)); + } + + /** + * Get the Mailpoet 2 users + * + * @global object $wpdb + * @param int $limit Number of users max + * @return array Users + */ + private function getUsers($limit) { + global $wpdb; + $users = array(); + + $last_id = Setting::getValue('last_imported_user_id', 0); + $table = MP2_USER_TABLE; + $sql = " + SELECT u.* + FROM `$table` u + WHERE u.user_id > '$last_id' + ORDER BY u.user_id + LIMIT $limit + "; + $users = $wpdb->get_results($sql, ARRAY_A); + + return $users; + } + + /** + * Import a subscriber + * + * @param array $user_data User data + * @return Subscriber + */ + private function importSubscriber($user_data) { + $datetime = new \MailPoet\WP\DateTime(); + $subscriber = Subscriber::createOrUpdate(array( + 'wp_user_id' => !empty($user_data['wpuser_id']) ? $user_data['wpuser_id'] : null, + 'email' => $user_data['email'], + 'first_name' => $user_data['firstname'], + 'last_name' => $user_data['lastname'], + 'status' => $this->mapUserStatus($user_data['status']), + 'created_at' => $datetime->formatTime($user_data['created_at'], \MailPoet\WP\DateTime::DEFAULT_DATE_TIME_FORMAT), + 'subscribed_ip' => !empty($user_data['ip']) ? $user_data['ip'] : null, + 'confirmed_ip' => !empty($user_data['confirmed_ip']) ? $user_data['confirmed_ip'] : null, + 'confirmed_at' => !empty($user_data['confirmed_at']) ? $datetime->formatTime($user_data['confirmed_at'], \MailPoet\WP\DateTime::DEFAULT_DATE_TIME_FORMAT) : null, + )); + Setting::setValue('last_imported_user_id', $user_data['user_id']); + if(!empty($subscriber)) { + // Map the subscriber with its old ID + $mapping = new MappingToExternalEntities(); + $mapping->create(array( + 'old_id' => $user_data['user_id'], + 'type' => 'subscribers', + 'new_id' => $subscriber->id, + 'created_at' => $datetime->formatTime(time(), \MailPoet\WP\DateTime::DEFAULT_DATE_TIME_FORMAT), + )); + } + return $subscriber; + } + + /** + * Map the MailPoet 2 user status with MailPoet 3 + * + * @param int $mp2_user_status MP2 user status + * @return string MP3 user status + */ + private function mapUserStatus($mp2_user_status) { + switch($mp2_user_status) { + case 1: + $status = 'subscribed'; + break; + case -1: + $status = 'unsubscribed'; + break; + case 0: + default: + $status = 'unconfirmed'; + } + return $status; + } + + /** + * Import the segments for a subscriber + * + * @param Subscriber $subscriber MP3 subscriber + * @param int $user_id MP2 user ID + */ + private function importSubscriberSegments($subscriber, $user_id) { + $user_lists = $this->getUserLists($user_id); + foreach($user_lists as $user_list) { + $this->importSubscriberSegment($subscriber->id, $user_list); + } + } + + /** + * Get the lists for a user + * + * @global object $wpdb + * @param int $user_id User ID + * @return array Users Lists + */ + private function getUserLists($user_id) { + global $wpdb; + $user_lists = array(); + + $table = MP2_USER_LIST_TABLE; + $sql = " + SELECT ul.list_id, ul.sub_date, ul.unsub_date + FROM `$table` ul + WHERE ul.user_id = '$user_id' + "; + $user_lists = $wpdb->get_results($sql, ARRAY_A); + + return $user_lists; + } + + /** + * Import a subscriber segment + * + * @param int $subscriber_id + * @param array $user_list + * @return SubscriberSegment + */ + private function importSubscriberSegment($subscriber_id, $user_list) { + $subscriber_segment = null; + $datetime = new \MailPoet\WP\DateTime(); + if(isset($this->segments_mapping[$user_list['list_id']])) { + $segment_id = $this->segments_mapping[$user_list['list_id']]; + $status = (($segment_id == $this->wp_users_segment->id) || empty($user_list['unsub_date'])) ? 'subscribed' : 'unsubscribed'; // the users belonging to the wp_users segment are always subscribed + $data = array( + 'subscriber_id' => $subscriber_id, + 'segment_id' => $segment_id, + 'status' => $status, + 'created_at' => $datetime->formatTime($user_list['sub_date'], \MailPoet\WP\DateTime::DEFAULT_DATE_TIME_FORMAT), + 'updated_at' => !empty($user_list['unsub_date']) ? $datetime->formatTime($user_list['unsub_date'], \MailPoet\WP\DateTime::DEFAULT_DATE_TIME_FORMAT) : null, + ); + $subscriber_segment = new SubscriberSegment(); + $subscriber_segment->createOrUpdate($data); + } + return $subscriber_segment; + } + + /** + * Import the custom fields values for a subscriber + * + * @param Subscriber $subscriber MP3 subscriber + * @param array $user MP2 user + */ + private function importSubscriberCustomFields($subscriber, $user) { + $imported_custom_fields = $this->getImportedCustomFields(); + foreach($imported_custom_fields as $custom_field) { + $custom_field_column = 'cf_' . $custom_field['id']; + if(isset($custom_field_column)) { + $this->importSubscriberCustomField($subscriber->id, $custom_field, $user[$custom_field_column]); + } + } + } + + /** + * Get the imported custom fields + * + * @global object $wpdb + * @return array Imported custom fields + * + */ + private function getImportedCustomFields() { + global $wpdb; + $table = MP_CUSTOM_FIELDS_TABLE; + $sql = " + SELECT cf.id, cf.name, cf.type + FROM `$table` cf + "; + $custom_fields = $wpdb->get_results($sql, ARRAY_A); + return $custom_fields; + } + + /** + * Import a subscriber custom field + * + * @param int $subscriber_id Subscriber ID + * @param int $custom_field Custom field + * @param string $custom_field_value Custom field value + * @return SubscriberCustomField + */ + private function importSubscriberCustomField($subscriber_id, $custom_field, $custom_field_value) { + if($custom_field['type'] == 'date') { + $datetime = new \MailPoet\WP\DateTime(); + $value = $datetime->formatTime($custom_field_value, \MailPoet\WP\DateTime::DEFAULT_DATE_TIME_FORMAT); // Convert the date field + } else { + $value = $custom_field_value; + } + $data = array( + 'subscriber_id' => $subscriber_id, + 'custom_field_id' => $custom_field['id'], + 'value' => isset($value) ? $value : '', + ); + $subscriber_custom_field = new SubscriberCustomField(); + $subscriber_custom_field->createOrUpdate($data); + return $subscriber_custom_field; + } + + /** + * Get the mapping between the MP2 and the imported MP3 IDs + * + * @param string $model Model (segment,...) + * @return array Mapping + */ + public function getImportedMapping($model) { + $mappings = array(); + $mapping_relations = MappingToExternalEntities::where('type', $model)->findArray(); + foreach($mapping_relations as $relation) { + $mappings[$relation['old_id']] = $relation['new_id']; + } + return $mappings; + } + +} diff --git a/lib/Config/Menu.php b/lib/Config/Menu.php index 42bcdb86ad..9b62cafcf3 100644 --- a/lib/Config/Menu.php +++ b/lib/Config/Menu.php @@ -215,6 +215,18 @@ class Menu { ) ); + add_submenu_page( + true, + $this->setPageTitle(__('Migration', 'mailpoet')), + '', + Env::$required_permission, + 'mailpoet-migration', + array( + $this, + 'migration' + ) + ); + add_submenu_page( true, $this->setPageTitle(__('Update', 'mailpoet')), @@ -279,6 +291,16 @@ class Menu { $this->displayPage('welcome.html', $data); } + function migration() { + $mp2_migrator = new MP2Migrator(); + $mp2_migrator->init(); + $data = array( + 'log_file_url' => $mp2_migrator->log_file_url, + 'progress_url' => $mp2_migrator->progressbar->url, + ); + $this->displayPage('mp2migration.html', $data); + } + function update() { global $wp; $current_url = home_url(add_query_arg($wp->query_string, $wp->request)); diff --git a/lib/Config/Migrator.php b/lib/Config/Migrator.php index 10e22d0e1d..b39c237c1c 100644 --- a/lib/Config/Migrator.php +++ b/lib/Config/Migrator.php @@ -33,7 +33,8 @@ class Migrator { 'statistics_clicks', 'statistics_opens', 'statistics_unsubscribes', - 'statistics_forms' + 'statistics_forms', + 'mapping_to_external_entities' ); } @@ -79,7 +80,7 @@ class Migrator { function settings() { $attributes = array( 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'name varchar(20) NOT NULL,', + 'name varchar(50) NOT NULL,', 'value longtext,', 'created_at TIMESTAMP NULL,', 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', @@ -363,6 +364,18 @@ class Migrator { return $this->sqlify(__FUNCTION__, $attributes); } + function mappingToExternalEntities() { + $attributes = array( + 'old_id mediumint(9) NOT NULL,', + 'type varchar(50) NOT NULL,', + 'new_id mediumint(9) NOT NULL,', + 'created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,', + 'PRIMARY KEY (old_id, type),', + 'KEY new_id (new_id)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + private function sqlify($model, $attributes) { $table = $this->prefix . Helpers::camelCaseToUnderscore($model); diff --git a/lib/Models/MappingToExternalEntities.php b/lib/Models/MappingToExternalEntities.php new file mode 100644 index 0000000000..1175a5d3bf --- /dev/null +++ b/lib/Models/MappingToExternalEntities.php @@ -0,0 +1,15 @@ +hydrate($data); + return $relation->save(); + } + +} \ No newline at end of file diff --git a/lib/Util/Helpers.php b/lib/Util/Helpers.php index fb9922a7d0..89444c2465 100644 --- a/lib/Util/Helpers.php +++ b/lib/Util/Helpers.php @@ -136,4 +136,5 @@ class Helpers { static function splitObject($object = array()) { return explode(self::DIVIDER, $object); } -} \ No newline at end of file + +} diff --git a/lib/Util/ProgressBar.php b/lib/Util/ProgressBar.php new file mode 100644 index 0000000000..cd7b2bbfbe --- /dev/null +++ b/lib/Util/ProgressBar.php @@ -0,0 +1,98 @@ +filename = Env::$temp_path . '/' . $filename; + $this->url = Env::$temp_url . '/' . $filename; + $counters = $this->readProgress(); + if(isset($counters->total)) { + $this->total_count = $counters->total; + } + if(isset($counters->current)) { + $this->current_count = $counters->current; + } + } + + /** + * Get the progress file URL + * + * @return string Progress file URL + */ + public function getUrl() { + return $this->url; + } + + /** + * Read the progress counters + * + * @return array|false Array of counters + */ + private function readProgress() { + if(file_exists($this->filename)) { + $json_content = file_get_contents($this->filename); + return json_decode($json_content); + } else { + return false; + } + } + + /** + * Set the total count + * + * @param int $count Count + */ + public function setTotalCount($count) { + if($count != $this->total_count) { + $this->total_count = $count; + $this->current_count = 0; + $this->saveProgress(); + } + } + + /** + * Increment the current count + * + * @param int $count Count + */ + public function incrementCurrentCount($count) { + $this->current_count += $count; + $this->saveProgress(); + } + + /** + * Save the progress counters + * + */ + private function saveProgress() { + file_put_contents($this->filename, json_encode(array( + 'total' => $this->total_count, + 'current' => $this->current_count, + ))); + } + + } + +} diff --git a/tests/_bootstrap.php b/tests/_bootstrap.php index d2ff50b4c0..f4ce413ef0 100644 --- a/tests/_bootstrap.php +++ b/tests/_bootstrap.php @@ -93,4 +93,22 @@ abstract class MailPoetTest extends \Codeception\TestCase\Test { protected $runTestInSeparateProcess = false; protected $preserveGlobalState = false; protected $inIsolation = false; + + /** + * Call protected/private method of a class. + * + * @param object &$object Instantiated object that we will run method on. + * @param string $methodName Method name to call + * @param array $parameters Array of parameters to pass into method. + * + * @return mixed Method return. + */ + public function invokeMethod(&$object, $methodName, array $parameters = array()) { + $reflection = new \ReflectionClass(get_class($object)); + $method = $reflection->getMethod($methodName); + $method->setAccessible(true); + + return $method->invokeArgs($object, $parameters); + } + } \ No newline at end of file diff --git a/tests/_data/createMP2Tables.sql b/tests/_data/createMP2Tables.sql new file mode 100644 index 0000000000..5cb314dec6 --- /dev/null +++ b/tests/_data/createMP2Tables.sql @@ -0,0 +1,431 @@ +-- phpMyAdmin SQL Dump +-- version 4.4.10 +-- http://www.phpmyadmin.net +-- +-- Client : localhost:3306 +-- Généré le : Mer 26 Avril 2017 à 17:52 +-- Version du serveur : 5.5.42 +-- Version de PHP : 7.0.0 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +SET time_zone = "+00:00"; + +-- +-- Base de données : `mailpoet` +-- + +-- -------------------------------------------------------- + +-- +-- Structure de la table `wp_wysija_campaign` +-- + +DROP TABLE IF EXISTS `wp_wysija_campaign`; +CREATE TABLE `wp_wysija_campaign` ( + `campaign_id` int(10) unsigned NOT NULL, + `name` varchar(250) DEFAULT NULL, + `description` text +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `wp_wysija_campaign_list` +-- + +DROP TABLE IF EXISTS `wp_wysija_campaign_list`; +CREATE TABLE `wp_wysija_campaign_list` ( + `list_id` int(10) unsigned NOT NULL, + `campaign_id` int(10) unsigned NOT NULL, + `filter` text +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `wp_wysija_custom_field` +-- + +DROP TABLE IF EXISTS `wp_wysija_custom_field`; +CREATE TABLE `wp_wysija_custom_field` ( + `id` mediumint(9) NOT NULL, + `name` tinytext NOT NULL, + `type` tinytext NOT NULL, + `required` tinyint(1) NOT NULL DEFAULT '0', + `settings` text +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `wp_wysija_email` +-- + +DROP TABLE IF EXISTS `wp_wysija_email`; +CREATE TABLE `wp_wysija_email` ( + `email_id` int(10) unsigned NOT NULL, + `campaign_id` int(10) unsigned NOT NULL DEFAULT '0', + `subject` varchar(250) NOT NULL DEFAULT '', + `body` longtext, + `created_at` int(10) unsigned DEFAULT NULL, + `modified_at` int(10) unsigned DEFAULT NULL, + `sent_at` int(10) unsigned DEFAULT NULL, + `from_email` varchar(250) DEFAULT NULL, + `from_name` varchar(250) DEFAULT NULL, + `replyto_email` varchar(250) DEFAULT NULL, + `replyto_name` varchar(250) DEFAULT NULL, + `attachments` text, + `status` tinyint(4) NOT NULL DEFAULT '0', + `type` tinyint(4) NOT NULL DEFAULT '1', + `number_sent` int(10) unsigned NOT NULL DEFAULT '0', + `number_opened` int(10) unsigned NOT NULL DEFAULT '0', + `number_clicked` int(10) unsigned NOT NULL DEFAULT '0', + `number_unsub` int(10) unsigned NOT NULL DEFAULT '0', + `number_bounce` int(10) unsigned NOT NULL DEFAULT '0', + `number_forward` int(10) unsigned NOT NULL DEFAULT '0', + `params` text, + `wj_data` longtext, + `wj_styles` longtext +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `wp_wysija_email_user_stat` +-- + +DROP TABLE IF EXISTS `wp_wysija_email_user_stat`; +CREATE TABLE `wp_wysija_email_user_stat` ( + `user_id` int(10) unsigned NOT NULL, + `email_id` int(10) unsigned NOT NULL, + `sent_at` int(10) unsigned NOT NULL, + `opened_at` int(10) unsigned DEFAULT NULL, + `status` tinyint(4) NOT NULL DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `wp_wysija_email_user_url` +-- + +DROP TABLE IF EXISTS `wp_wysija_email_user_url`; +CREATE TABLE `wp_wysija_email_user_url` ( + `email_id` int(10) unsigned NOT NULL, + `user_id` int(10) unsigned NOT NULL, + `url_id` int(10) unsigned NOT NULL, + `clicked_at` int(10) unsigned DEFAULT NULL, + `number_clicked` int(10) unsigned NOT NULL DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `wp_wysija_form` +-- + +DROP TABLE IF EXISTS `wp_wysija_form`; +CREATE TABLE `wp_wysija_form` ( + `form_id` int(10) unsigned NOT NULL, + `name` tinytext CHARACTER SET utf8 COLLATE utf8_bin, + `data` longtext CHARACTER SET utf8 COLLATE utf8_bin, + `styles` longtext CHARACTER SET utf8 COLLATE utf8_bin, + `subscribed` int(10) unsigned NOT NULL DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `wp_wysija_list` +-- + +DROP TABLE IF EXISTS `wp_wysija_list`; +CREATE TABLE `wp_wysija_list` ( + `list_id` int(10) unsigned NOT NULL, + `name` varchar(250) DEFAULT NULL, + `namekey` varchar(255) DEFAULT NULL, + `description` text, + `unsub_mail_id` int(10) unsigned NOT NULL DEFAULT '0', + `welcome_mail_id` int(10) unsigned NOT NULL DEFAULT '0', + `is_enabled` tinyint(3) unsigned NOT NULL DEFAULT '0', + `is_public` tinyint(3) unsigned NOT NULL DEFAULT '0', + `created_at` int(10) unsigned DEFAULT NULL, + `ordering` int(10) unsigned NOT NULL DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `wp_wysija_queue` +-- + +DROP TABLE IF EXISTS `wp_wysija_queue`; +CREATE TABLE `wp_wysija_queue` ( + `user_id` int(10) unsigned NOT NULL, + `email_id` int(10) unsigned NOT NULL, + `send_at` int(10) unsigned NOT NULL DEFAULT '0', + `priority` tinyint(4) NOT NULL DEFAULT '0', + `number_try` tinyint(3) unsigned NOT NULL DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `wp_wysija_url` +-- + +DROP TABLE IF EXISTS `wp_wysija_url`; +CREATE TABLE `wp_wysija_url` ( + `url_id` int(10) unsigned NOT NULL, + `name` varchar(250) DEFAULT NULL, + `url` text +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `wp_wysija_url_mail` +-- + +DROP TABLE IF EXISTS `wp_wysija_url_mail`; +CREATE TABLE `wp_wysija_url_mail` ( + `email_id` int(11) NOT NULL, + `url_id` int(10) unsigned NOT NULL, + `unique_clicked` int(10) unsigned NOT NULL DEFAULT '0', + `total_clicked` int(10) unsigned NOT NULL DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `wp_wysija_user` +-- + +DROP TABLE IF EXISTS `wp_wysija_user`; +CREATE TABLE `wp_wysija_user` ( + `user_id` int(10) unsigned NOT NULL, + `wpuser_id` int(10) unsigned NOT NULL DEFAULT '0', + `email` varchar(255) NOT NULL, + `firstname` varchar(255) NOT NULL DEFAULT '', + `lastname` varchar(255) NOT NULL DEFAULT '', + `ip` varchar(100) NOT NULL, + `confirmed_ip` varchar(100) NOT NULL DEFAULT '0', + `confirmed_at` int(10) unsigned DEFAULT NULL, + `last_opened` int(10) unsigned DEFAULT NULL, + `last_clicked` int(10) unsigned DEFAULT NULL, + `keyuser` varchar(255) NOT NULL DEFAULT '', + `created_at` int(10) unsigned DEFAULT NULL, + `status` tinyint(4) NOT NULL DEFAULT '0', + `domain` varchar(255) DEFAULT '', + `cf_1` varchar(100) DEFAULT NULL, + `cf_3` varchar(255) DEFAULT NULL, + `cf_4` varchar(255) DEFAULT NULL, + `cf_5` tinyint(1) DEFAULT NULL, + `cf_6` varchar(255) DEFAULT NULL, + `cf_7` int(20) DEFAULT NULL, + `cf_8` varchar(100) DEFAULT NULL, + `cf_9` varchar(100) DEFAULT NULL, + `cf_10` varchar(100) DEFAULT NULL, + `cf_11` varchar(100) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `wp_wysija_user_field` +-- + +DROP TABLE IF EXISTS `wp_wysija_user_field`; +CREATE TABLE `wp_wysija_user_field` ( + `field_id` int(10) unsigned NOT NULL, + `name` varchar(250) DEFAULT NULL, + `column_name` varchar(250) NOT NULL DEFAULT '', + `type` tinyint(3) unsigned DEFAULT '0', + `values` text, + `default` varchar(250) NOT NULL DEFAULT '', + `is_required` tinyint(3) unsigned NOT NULL DEFAULT '0', + `error_message` varchar(250) NOT NULL DEFAULT '' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `wp_wysija_user_history` +-- + +DROP TABLE IF EXISTS `wp_wysija_user_history`; +CREATE TABLE `wp_wysija_user_history` ( + `history_id` int(10) unsigned NOT NULL, + `user_id` int(10) unsigned NOT NULL, + `email_id` int(10) unsigned DEFAULT '0', + `type` varchar(250) NOT NULL DEFAULT '', + `details` text, + `executed_at` int(10) unsigned DEFAULT NULL, + `executed_by` int(10) unsigned DEFAULT NULL, + `source` text +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Structure de la table `wp_wysija_user_list` +-- + +DROP TABLE IF EXISTS `wp_wysija_user_list`; +CREATE TABLE `wp_wysija_user_list` ( + `list_id` int(10) unsigned NOT NULL, + `user_id` int(10) unsigned NOT NULL, + `sub_date` int(10) unsigned DEFAULT '0', + `unsub_date` int(10) unsigned DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Index pour les tables exportées +-- + +-- +-- Index pour la table `wp_wysija_campaign` +-- +ALTER TABLE `wp_wysija_campaign` + ADD PRIMARY KEY (`campaign_id`); + +-- +-- Index pour la table `wp_wysija_campaign_list` +-- +ALTER TABLE `wp_wysija_campaign_list` + ADD PRIMARY KEY (`list_id`,`campaign_id`); + +-- +-- Index pour la table `wp_wysija_custom_field` +-- +ALTER TABLE `wp_wysija_custom_field` + ADD PRIMARY KEY (`id`); + +-- +-- Index pour la table `wp_wysija_email` +-- +ALTER TABLE `wp_wysija_email` + ADD PRIMARY KEY (`email_id`); + +-- +-- Index pour la table `wp_wysija_email_user_stat` +-- +ALTER TABLE `wp_wysija_email_user_stat` + ADD PRIMARY KEY (`user_id`,`email_id`); + +-- +-- Index pour la table `wp_wysija_email_user_url` +-- +ALTER TABLE `wp_wysija_email_user_url` + ADD PRIMARY KEY (`user_id`,`email_id`,`url_id`); + +-- +-- Index pour la table `wp_wysija_form` +-- +ALTER TABLE `wp_wysija_form` + ADD PRIMARY KEY (`form_id`); + +-- +-- Index pour la table `wp_wysija_list` +-- +ALTER TABLE `wp_wysija_list` + ADD PRIMARY KEY (`list_id`); + +-- +-- Index pour la table `wp_wysija_queue` +-- +ALTER TABLE `wp_wysija_queue` + ADD PRIMARY KEY (`user_id`,`email_id`), + ADD KEY `SENT_AT_INDEX` (`send_at`); + +-- +-- Index pour la table `wp_wysija_url` +-- +ALTER TABLE `wp_wysija_url` + ADD PRIMARY KEY (`url_id`); + +-- +-- Index pour la table `wp_wysija_url_mail` +-- +ALTER TABLE `wp_wysija_url_mail` + ADD PRIMARY KEY (`email_id`,`url_id`); + +-- +-- Index pour la table `wp_wysija_user` +-- +ALTER TABLE `wp_wysija_user` + ADD PRIMARY KEY (`user_id`), + ADD UNIQUE KEY `EMAIL_UNIQUE` (`email`); + +-- +-- Index pour la table `wp_wysija_user_field` +-- +ALTER TABLE `wp_wysija_user_field` + ADD PRIMARY KEY (`field_id`); + +-- +-- Index pour la table `wp_wysija_user_history` +-- +ALTER TABLE `wp_wysija_user_history` + ADD PRIMARY KEY (`history_id`); + +-- +-- Index pour la table `wp_wysija_user_list` +-- +ALTER TABLE `wp_wysija_user_list` + ADD PRIMARY KEY (`list_id`,`user_id`); + +-- +-- AUTO_INCREMENT pour les tables exportées +-- + +-- +-- AUTO_INCREMENT pour la table `wp_wysija_campaign` +-- +ALTER TABLE `wp_wysija_campaign` + MODIFY `campaign_id` int(10) unsigned NOT NULL AUTO_INCREMENT; +-- +-- AUTO_INCREMENT pour la table `wp_wysija_custom_field` +-- +ALTER TABLE `wp_wysija_custom_field` + MODIFY `id` mediumint(9) NOT NULL AUTO_INCREMENT; +-- +-- AUTO_INCREMENT pour la table `wp_wysija_email` +-- +ALTER TABLE `wp_wysija_email` + MODIFY `email_id` int(10) unsigned NOT NULL AUTO_INCREMENT; +-- +-- AUTO_INCREMENT pour la table `wp_wysija_form` +-- +ALTER TABLE `wp_wysija_form` + MODIFY `form_id` int(10) unsigned NOT NULL AUTO_INCREMENT; +-- +-- AUTO_INCREMENT pour la table `wp_wysija_list` +-- +ALTER TABLE `wp_wysija_list` + MODIFY `list_id` int(10) unsigned NOT NULL AUTO_INCREMENT; +-- +-- AUTO_INCREMENT pour la table `wp_wysija_url` +-- +ALTER TABLE `wp_wysija_url` + MODIFY `url_id` int(10) unsigned NOT NULL AUTO_INCREMENT; +-- +-- AUTO_INCREMENT pour la table `wp_wysija_url_mail` +-- +ALTER TABLE `wp_wysija_url_mail` + MODIFY `email_id` int(11) NOT NULL AUTO_INCREMENT; +-- +-- AUTO_INCREMENT pour la table `wp_wysija_user` +-- +ALTER TABLE `wp_wysija_user` + MODIFY `user_id` int(10) unsigned NOT NULL AUTO_INCREMENT; +-- +-- AUTO_INCREMENT pour la table `wp_wysija_user_field` +-- +ALTER TABLE `wp_wysija_user_field` + MODIFY `field_id` int(10) unsigned NOT NULL AUTO_INCREMENT; +-- +-- AUTO_INCREMENT pour la table `wp_wysija_user_history` +-- +ALTER TABLE `wp_wysija_user_history` + MODIFY `history_id` int(10) unsigned NOT NULL AUTO_INCREMENT; \ No newline at end of file diff --git a/tests/_data/dropMP2Tables.sql b/tests/_data/dropMP2Tables.sql new file mode 100644 index 0000000000..8ca6cb6239 --- /dev/null +++ b/tests/_data/dropMP2Tables.sql @@ -0,0 +1,15 @@ +DROP TABLE IF EXISTS `wp_wysija_campaign`; +DROP TABLE IF EXISTS `wp_wysija_campaign_list`; +DROP TABLE IF EXISTS `wp_wysija_custom_field`; +DROP TABLE IF EXISTS `wp_wysija_email`; +DROP TABLE IF EXISTS `wp_wysija_email_user_stat`; +DROP TABLE IF EXISTS `wp_wysija_email_user_url`; +DROP TABLE IF EXISTS `wp_wysija_form`; +DROP TABLE IF EXISTS `wp_wysija_list`; +DROP TABLE IF EXISTS `wp_wysija_queue`; +DROP TABLE IF EXISTS `wp_wysija_url`; +DROP TABLE IF EXISTS `wp_wysija_url_mail`; +DROP TABLE IF EXISTS `wp_wysija_user`; +DROP TABLE IF EXISTS `wp_wysija_user_field`; +DROP TABLE IF EXISTS `wp_wysija_user_history`; +DROP TABLE IF EXISTS `wp_wysija_user_list`; diff --git a/tests/_data/populateMP2Tables.sql b/tests/_data/populateMP2Tables.sql new file mode 100644 index 0000000000..fbb24e4047 --- /dev/null +++ b/tests/_data/populateMP2Tables.sql @@ -0,0 +1,170 @@ +-- phpMyAdmin SQL Dump +-- version 4.4.10 +-- http://www.phpmyadmin.net +-- +-- Client : localhost:3306 +-- Généré le : Mer 26 Avril 2017 à 17:44 +-- Version du serveur : 5.5.42 +-- Version de PHP : 7.0.0 + +SET NAMES utf8; +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +SET time_zone = "+00:00"; + +-- +-- Base de données : `mailpoet` +-- + +-- +-- Vider la table avant d'insérer `wp_wysija_campaign` +-- + +TRUNCATE TABLE `wp_wysija_campaign`; +-- +-- Contenu de la table `wp_wysija_campaign` +-- + +INSERT INTO `wp_wysija_campaign` (`campaign_id`, `name`, `description`) VALUES +(1, 'Guide d''utilisation', ''); + +-- +-- Vider la table avant d'insérer `wp_wysija_campaign_list` +-- + +TRUNCATE TABLE `wp_wysija_campaign_list`; +-- +-- Vider la table avant d'insérer `wp_wysija_custom_field` +-- + +TRUNCATE TABLE `wp_wysija_custom_field`; +-- +-- Contenu de la table `wp_wysija_custom_field` +-- + +INSERT INTO `wp_wysija_custom_field` (`id`, `name`, `type`, `required`, `settings`) VALUES +(1, 'Pays', 'input', 0, 'a:2:{s:8:"required";s:1:"0";s:8:"validate";s:12:"onlyLetterSp";}'), +(3, 'Commentaires', 'textarea', 0, 'a:2:{s:8:"required";s:1:"0";s:8:"validate";s:0:"";}'), +(4, 'Pour ou contre', 'radio', 1, 'a:2:{s:6:"values";a:2:{i:0;a:2:{s:5:"value";s:4:"Pour";s:10:"is_checked";i:0;}i:1;a:2:{s:5:"value";s:6:"Contre";s:10:"is_checked";i:0;}}s:8:"required";s:1:"1";}'), +(5, 'Réglement', 'checkbox', 1, 'a:2:{s:6:"values";a:1:{i:0;a:2:{s:5:"value";s:23:"J''accepte le réglement";s:10:"is_checked";i:1;}}s:8:"required";s:1:"1";}'), +(6, 'Langue', 'select', 0, 'a:2:{s:6:"values";a:2:{i:0;a:2:{s:5:"value";s:9:"Français";s:10:"is_checked";i:0;}i:1;a:2:{s:5:"value";s:7:"Anglais";s:10:"is_checked";i:0;}}s:8:"required";s:1:"0";}'), +(7, 'Date d''activation', 'date', 0, 'a:3:{s:9:"date_type";s:14:"year_month_day";s:16:"is_default_today";s:1:"0";s:10:"date_order";s:10:"mm/dd/yyyy";}'), +(8, 'Chiffres', 'input', 0, 'a:2:{s:8:"required";s:1:"0";s:8:"validate";s:12:"onlyNumberSp";}'), +(9, 'Lettres', 'input', 0, 'a:2:{s:8:"required";s:1:"0";s:8:"validate";s:12:"onlyLetterSp";}'), +(10, 'Alphanumerique', 'input', 0, 'a:2:{s:8:"required";s:1:"0";s:8:"validate";s:16:"onlyLetterNumber";}'), +(11, 'Téléphone', 'input', 0, 'a:2:{s:8:"required";s:1:"0";s:8:"validate";s:5:"phone";}'); + +-- +-- Vider la table avant d'insérer `wp_wysija_email` +-- + +TRUNCATE TABLE `wp_wysija_email`; +-- +-- Contenu de la table `wp_wysija_email` +-- + +INSERT INTO `wp_wysija_email` (`email_id`, `campaign_id`, `subject`, `body`, `created_at`, `modified_at`, `sent_at`, `from_email`, `from_name`, `replyto_email`, `replyto_name`, `attachments`, `status`, `type`, `number_sent`, `number_opened`, `number_clicked`, `number_unsub`, `number_bounce`, `number_forward`, `params`, `wj_data`, `wj_styles`) VALUES +(1, 1, 'Guide d''utilisation', '\n\n\n \n \n Guide d''utilisation\n \n\n\n\n\n\n \n \n \n \n \n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n

Problèmes d'affichage ? Affichez cette newsletter dans votre navigateur.

\n
\n \n\n \n \n \n
\n \n \n
\n
\n \n\n\n \n \n \n \n \n \n
\n \n

Étape 1 : hé, vous, cliquez sur ce texte !

Cliquer sur ce bloc de texte pour le modifier.

\n
\n\n\n \n \n \n
\n
\n ---\n
\n
\n\n\n\n \n \n \n \n \n \n
\n \n

Étape 2 : manipuler l''image

\n
\n\n\n \n \n \n \n \n \n
\n \n \n \n \n \n \n \n
\n
\n \n \n
\n
\n\n

Survoler avec votre souris l''image à gauche.

\n
\n\n\n \n \n \n
\n
\n ---\n
\n
\n\n\n\n \n \n \n \n \n \n
\n \n

Étape 3 : déposer du contenu ici

Glisser et déposer textes, articles, séparateurs. Regardez à droite !

Vous pouvez même déposer vos icônes de réseaux sociaux comme ceci :

\n
\n\n \n \n \n
\n\n\n \n \n \n
\n
\n ---\n
\n
\n\n\n\n \n \n \n \n \n \n
\n \n

Étape 4 : et le pied de page ?

Changer le contenu du pied de page dans les Paramètres de MailPoet.

\n
\n
\n \n\n \n \n \n\n
\n

Se désabonner

\n
\n
\n
\n\n', 1486319877, 1486319877, NULL, 'info@localhost', 'Fred', 'info@localhost', 'Fred', NULL, 0, 1, 0, 0, 0, 0, 0, 0, 'YToxOntzOjE0OiJxdWlja3NlbGVjdGlvbiI7YToxOntzOjY6IndwLTMwMSI7YTo1OntzOjEwOiJpZGVudGlmaWVyIjtzOjY6IndwLTMwMSI7czo1OiJ3aWR0aCI7aToyODE7czo2OiJoZWlnaHQiO2k6MTkwO3M6MzoidXJsIjtzOjExODoiaHR0cDovL2xvY2FsaG9zdC93b3JkcHJlc3MtbWFpbHBvZXQvd3AtY29udGVudC9wbHVnaW5zL3d5c2lqYS1uZXdzbGV0dGVycy9pbWcvZGVmYXVsdC1uZXdzbGV0dGVyL25ld3NsZXR0ZXIvcGlnZW9uLnBuZyI7czo5OiJ0aHVtYl91cmwiO3M6MTI2OiJodHRwOi8vbG9jYWxob3N0L3dvcmRwcmVzcy1tYWlscG9ldC93cC1jb250ZW50L3BsdWdpbnMvd3lzaWphLW5ld3NsZXR0ZXJzL2ltZy9kZWZhdWx0LW5ld3NsZXR0ZXIvbmV3c2xldHRlci9waWdlb24tMTUweDE1MC5wbmciO319fQ==', 'YTo0OntzOjc6InZlcnNpb24iO3M6NToiMi43LjciO3M6NjoiaGVhZGVyIjthOjU6e3M6NDoidGV4dCI7TjtzOjU6ImltYWdlIjthOjU6e3M6Mzoic3JjIjtzOjExODoiaHR0cDovL2xvY2FsaG9zdC93b3JkcHJlc3MtbWFpbHBvZXQvd3AtY29udGVudC9wbHVnaW5zL3d5c2lqYS1uZXdzbGV0dGVycy9pbWcvZGVmYXVsdC1uZXdzbGV0dGVyL25ld3NsZXR0ZXIvaGVhZGVyLnBuZyI7czo1OiJ3aWR0aCI7aTo2MDA7czo2OiJoZWlnaHQiO2k6NzI7czo5OiJhbGlnbm1lbnQiO3M6NjoiY2VudGVyIjtzOjY6InN0YXRpYyI7YjowO31zOjk6ImFsaWdubWVudCI7czo2OiJjZW50ZXIiO3M6Njoic3RhdGljIjtiOjA7czo0OiJ0eXBlIjtzOjY6ImhlYWRlciI7fXM6NDoiYm9keSI7YTo5OntzOjc6ImJsb2NrLTEiO2E6Njp7czo0OiJ0ZXh0IjthOjE6e3M6NToidmFsdWUiO3M6MTY0OiJQR2d5UGp4emRISnZibWMrdzRsMFlYQmxJREVnT2p3dmMzUnliMjVuUGlCb3c2a3NJSFp2ZFhNc0lHTnNhWEYxWlhvZ2MzVnlJR05sSUhSbGVIUmxJQ0U4TDJneVBqeHdQa05zYVhGMVpYSWdjM1Z5SUdObElHSnNiMk1nWkdVZ2RHVjRkR1VnY0c5MWNpQnNaU0J0YjJScFptbGxjaTQ4TDNBKyI7fXM6NToiaW1hZ2UiO047czo5OiJhbGlnbm1lbnQiO3M6NDoibGVmdCI7czo2OiJzdGF0aWMiO2I6MDtzOjg6InBvc2l0aW9uIjtpOjE7czo0OiJ0eXBlIjtzOjc6ImNvbnRlbnQiO31zOjc6ImJsb2NrLTIiO2E6NTp7czo4OiJwb3NpdGlvbiI7aToyO3M6NDoidHlwZSI7czo3OiJkaXZpZGVyIjtzOjM6InNyYyI7czo4MDoiaHR0cDovL2xvY2FsaG9zdC93b3JkcHJlc3MtbWFpbHBvZXQvd3AtY29udGVudC91cGxvYWRzL3d5c2lqYS9kaXZpZGVycy9zb2xpZC5qcGciO3M6NToid2lkdGgiO2k6NTY0O3M6NjoiaGVpZ2h0IjtpOjE7fXM6NzoiYmxvY2stMyI7YTo2OntzOjQ6InRleHQiO2E6MTp7czo1OiJ2YWx1ZSI7czo3MjoiUEdneVBqeHpkSEp2Ym1jK3c0bDBZWEJsSURJZ09qd3ZjM1J5YjI1blBpQnRZVzVwY0hWc1pYSWdiQ2RwYldGblpUd3ZhREkrIjt9czo1OiJpbWFnZSI7TjtzOjk6ImFsaWdubWVudCI7czo0OiJsZWZ0IjtzOjY6InN0YXRpYyI7YjowO3M6ODoicG9zaXRpb24iO2k6MztzOjQ6InR5cGUiO3M6NzoiY29udGVudCI7fXM6NzoiYmxvY2stNCI7YTo2OntzOjQ6InRleHQiO2E6MTp7czo1OiJ2YWx1ZSI7czo3MjoiUEhBK1UzVnlkbTlzWlhJZ1lYWmxZeUIyYjNSeVpTQnpiM1Z5YVhNZ2JDZHBiV0ZuWlNERG9DQm5ZWFZqYUdVdVBDOXdQZz09Ijt9czo1OiJpbWFnZSI7YTo1OntzOjM6InNyYyI7czoxMTg6Imh0dHA6Ly9sb2NhbGhvc3Qvd29yZHByZXNzLW1haWxwb2V0L3dwLWNvbnRlbnQvcGx1Z2lucy93eXNpamEtbmV3c2xldHRlcnMvaW1nL2RlZmF1bHQtbmV3c2xldHRlci9uZXdzbGV0dGVyL3BpZ2Vvbi5wbmciO3M6NToid2lkdGgiO2k6MjgxO3M6NjoiaGVpZ2h0IjtpOjE5MDtzOjk6ImFsaWdubWVudCI7czo0OiJsZWZ0IjtzOjY6InN0YXRpYyI7YjowO31zOjk6ImFsaWdubWVudCI7czo0OiJsZWZ0IjtzOjY6InN0YXRpYyI7YjowO3M6ODoicG9zaXRpb24iO2k6NDtzOjQ6InR5cGUiO3M6NzoiY29udGVudCI7fXM6NzoiYmxvY2stNSI7YTo1OntzOjg6InBvc2l0aW9uIjtpOjU7czo0OiJ0eXBlIjtzOjc6ImRpdmlkZXIiO3M6Mzoic3JjIjtzOjgwOiJodHRwOi8vbG9jYWxob3N0L3dvcmRwcmVzcy1tYWlscG9ldC93cC1jb250ZW50L3VwbG9hZHMvd3lzaWphL2RpdmlkZXJzL3NvbGlkLmpwZyI7czo1OiJ3aWR0aCI7aTo1NjQ7czo2OiJoZWlnaHQiO2k6MTt9czo3OiJibG9jay02IjthOjY6e3M6NDoidGV4dCI7YToxOntzOjU6InZhbHVlIjtzOjMzNjoiUEdneVBqeHpkSEp2Ym1jK3c0bDBZWEJsSURNZ09qd3ZjM1J5YjI1blBpQmt3Nmx3YjNObGNpQmtkU0JqYjI1MFpXNTFJR2xqYVR3dmFESStQSEErUjJ4cGMzTmxjaUJsZENCa3c2bHdiM05sY2lBOGMzUnliMjVuUG5SbGVIUmxjeXdnWVhKMGFXTnNaWE1zSUhQRHFYQmhjbUYwWlhWeWN5NDhMM04wY205dVp6NGdVbVZuWVhKa1pYb2d3NkFnWkhKdmFYUmxJQ0U4TDNBK1BIQStWbTkxY3lCd2IzVjJaWG9nYmNPcWJXVWdaTU9wY0c5elpYSWdQSE4wY205dVp6NTJiM01nYVdQRHRHNWxjeUJrWlNCeXc2bHpaV0YxZUNCemIyTnBZWFY0UEM5emRISnZibWMrSUdOdmJXMWxJR05sWTJrZ09qd3ZjRDQ9Ijt9czo1OiJpbWFnZSI7TjtzOjk6ImFsaWdubWVudCI7czo0OiJsZWZ0IjtzOjY6InN0YXRpYyI7YjowO3M6ODoicG9zaXRpb24iO2k6NjtzOjQ6InR5cGUiO3M6NzoiY29udGVudCI7fXM6NzoiYmxvY2stNyI7YTo1OntzOjU6IndpZHRoIjtpOjE4NDtzOjk6ImFsaWdubWVudCI7czo2OiJjZW50ZXIiO3M6NToiaXRlbXMiO2E6Mzp7aTowO2E6Nzp7czozOiJ1cmwiO3M6Mzg6Imh0dHA6Ly93d3cuZmFjZWJvb2suY29tL21haWxwb2V0cGx1Z2luIjtzOjM6ImFsdCI7czo4OiJGYWNlYm9vayI7czo5OiJjZWxsV2lkdGgiO2k6NjE7czoxMDoiY2VsbEhlaWdodCI7aTozMjtzOjM6InNyYyI7czo5NDoiaHR0cDovL2xvY2FsaG9zdC93b3JkcHJlc3MtbWFpbHBvZXQvd3AtY29udGVudC91cGxvYWRzL3d5c2lqYS9ib29rbWFya3MvbWVkaXVtLzAyL2ZhY2Vib29rLnBuZyI7czo1OiJ3aWR0aCI7aTozMjtzOjY6ImhlaWdodCI7aTozMjt9aToxO2E6Nzp7czozOiJ1cmwiO3M6MzI6Imh0dHA6Ly93d3cudHdpdHRlci5jb20vbWFpbF9wb2V0IjtzOjM6ImFsdCI7czo3OiJUd2l0dGVyIjtzOjk6ImNlbGxXaWR0aCI7aTo2MTtzOjEwOiJjZWxsSGVpZ2h0IjtpOjMyO3M6Mzoic3JjIjtzOjkzOiJodHRwOi8vbG9jYWxob3N0L3dvcmRwcmVzcy1tYWlscG9ldC93cC1jb250ZW50L3VwbG9hZHMvd3lzaWphL2Jvb2ttYXJrcy9tZWRpdW0vMDIvdHdpdHRlci5wbmciO3M6NToid2lkdGgiO2k6MzI7czo2OiJoZWlnaHQiO2k6MzI7fWk6MjthOjc6e3M6MzoidXJsIjtzOjMzOiJodHRwczovL3BsdXMuZ29vZ2xlLmNvbS8rTWFpbHBvZXQiO3M6MzoiYWx0IjtzOjY6Ikdvb2dsZSI7czo5OiJjZWxsV2lkdGgiO2k6NjE7czoxMDoiY2VsbEhlaWdodCI7aTozMjtzOjM6InNyYyI7czo5MjoiaHR0cDovL2xvY2FsaG9zdC93b3JkcHJlc3MtbWFpbHBvZXQvd3AtY29udGVudC91cGxvYWRzL3d5c2lqYS9ib29rbWFya3MvbWVkaXVtLzAyL2dvb2dsZS5wbmciO3M6NToid2lkdGgiO2k6MzI7czo2OiJoZWlnaHQiO2k6MzI7fX1zOjg6InBvc2l0aW9uIjtpOjc7czo0OiJ0eXBlIjtzOjc6ImdhbGxlcnkiO31zOjc6ImJsb2NrLTgiO2E6NTp7czo4OiJwb3NpdGlvbiI7aTo4O3M6NDoidHlwZSI7czo3OiJkaXZpZGVyIjtzOjM6InNyYyI7czo4MDoiaHR0cDovL2xvY2FsaG9zdC93b3JkcHJlc3MtbWFpbHBvZXQvd3AtY29udGVudC91cGxvYWRzL3d5c2lqYS9kaXZpZGVycy9zb2xpZC5qcGciO3M6NToid2lkdGgiO2k6NTY0O3M6NjoiaGVpZ2h0IjtpOjE7fXM6NzoiYmxvY2stOSI7YTo2OntzOjQ6InRleHQiO2E6MTp7czo1OiJ2YWx1ZSI7czoyMDA6IlBHZ3lQanh6ZEhKdmJtYyt3NGwwWVhCbElEUWdPand2YzNSeWIyNW5QaUJsZENCc1pTQndhV1ZrSUdSbElIQmhaMlVnUHp3dmFESStQSEErUTJoaGJtZGxjaUJzWlNCamIyNTBaVzUxSUdSMUlIQnBaV1FnWkdVZ2NHRm5aU0JrWVc1eklHeGxjeUE4YzNSeWIyNW5QbEJoY21GdHc2aDBjbVZ6UEM5emRISnZibWMrSUdSbElFMWhhV3hRYjJWMExqd3ZjRDQ9Ijt9czo1OiJpbWFnZSI7TjtzOjk6ImFsaWdubWVudCI7czo0OiJsZWZ0IjtzOjY6InN0YXRpYyI7YjowO3M6ODoicG9zaXRpb24iO2k6OTtzOjQ6InR5cGUiO3M6NzoiY29udGVudCI7fX1zOjY6ImZvb3RlciI7YTo1OntzOjQ6InRleHQiO047czo1OiJpbWFnZSI7YTo1OntzOjM6InNyYyI7czoxMTg6Imh0dHA6Ly9sb2NhbGhvc3Qvd29yZHByZXNzLW1haWxwb2V0L3dwLWNvbnRlbnQvcGx1Z2lucy93eXNpamEtbmV3c2xldHRlcnMvaW1nL2RlZmF1bHQtbmV3c2xldHRlci9uZXdzbGV0dGVyL2Zvb3Rlci5wbmciO3M6NToid2lkdGgiO2k6NjAwO3M6NjoiaGVpZ2h0IjtpOjQ2O3M6OToiYWxpZ25tZW50IjtzOjY6ImNlbnRlciI7czo2OiJzdGF0aWMiO2I6MDt9czo5OiJhbGlnbm1lbnQiO3M6NjoiY2VudGVyIjtzOjY6InN0YXRpYyI7YjowO3M6NDoidHlwZSI7czo2OiJmb290ZXIiO319', 'YToxMDp7czo0OiJodG1sIjthOjE6e3M6MTA6ImJhY2tncm91bmQiO3M6NjoiZThlOGU4Ijt9czo2OiJoZWFkZXIiO2E6MTp7czoxMDoiYmFja2dyb3VuZCI7czo2OiJlOGU4ZTgiO31zOjQ6ImJvZHkiO2E6NDp7czo1OiJjb2xvciI7czo2OiIwMDAwMDAiO3M6NjoiZmFtaWx5IjtzOjU6IkFyaWFsIjtzOjQ6InNpemUiO2k6MTY7czoxMDoiYmFja2dyb3VuZCI7czo2OiJmZmZmZmYiO31zOjY6ImZvb3RlciI7YToxOntzOjEwOiJiYWNrZ3JvdW5kIjtzOjY6ImU4ZThlOCI7fXM6MjoiaDEiO2E6Mzp7czo1OiJjb2xvciI7czo2OiIwMDAwMDAiO3M6NjoiZmFtaWx5IjtzOjEyOiJUcmVidWNoZXQgTVMiO3M6NDoic2l6ZSI7aTo0MDt9czoyOiJoMiI7YTozOntzOjU6ImNvbG9yIjtzOjY6IjQyNDI0MiI7czo2OiJmYW1pbHkiO3M6MTI6IlRyZWJ1Y2hldCBNUyI7czo0OiJzaXplIjtpOjMwO31zOjI6ImgzIjthOjM6e3M6NToiY29sb3IiO3M6NjoiNDI0MjQyIjtzOjY6ImZhbWlseSI7czoxMjoiVHJlYnVjaGV0IE1TIjtzOjQ6InNpemUiO2k6MjQ7fXM6MToiYSI7YToyOntzOjU6ImNvbG9yIjtzOjY6IjRhOTFiMCI7czo5OiJ1bmRlcmxpbmUiO2I6MDt9czoxMToidW5zdWJzY3JpYmUiO2E6MTp7czo1OiJjb2xvciI7czo2OiIwMDAwMDAiO31zOjExOiJ2aWV3YnJvd3NlciI7YTozOntzOjU6ImNvbG9yIjtzOjY6IjAwMDAwMCI7czo2OiJmYW1pbHkiO3M6NToiQXJpYWwiO3M6NDoic2l6ZSI7aToxMjt9fQ=='), +(2, 0, 'Confirmation de votre abonnement à Mailpoet', 'Bonjour ! \n\nFélicitations ! Vous êtes abonné(e) à notre site.\nVous devez cependant activer votre abonnement à [lists_to_confirm] en cliquant sur le lien ci-dessous : \n\n[activation_link]Cliquez ici pour confirmer votre abonnement.[/activation_link]\n\nMerci, \n\nL''équipe !\n', 1486319877, 1486319877, NULL, 'info@localhost', 'Fred', 'info@localhost', 'Fred', NULL, 99, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL); + +-- +-- Vider la table avant d'insérer `wp_wysija_email_user_stat` +-- + +TRUNCATE TABLE `wp_wysija_email_user_stat`; +-- +-- Vider la table avant d'insérer `wp_wysija_email_user_url` +-- + +TRUNCATE TABLE `wp_wysija_email_user_url`; +-- +-- Vider la table avant d'insérer `wp_wysija_form` +-- + +TRUNCATE TABLE `wp_wysija_form`; +-- +-- Contenu de la table `wp_wysija_form` +-- + +INSERT INTO `wp_wysija_form` (`form_id`, `name`, `data`, `styles`, `subscribed`) VALUES +(1, 'Abonnez-vous à notre newsletter', 'YTo0OntzOjc6InZlcnNpb24iO3M6MzoiMC40IjtzOjg6InNldHRpbmdzIjthOjQ6e3M6MTA6Im9uX3N1Y2Nlc3MiO3M6NzoibWVzc2FnZSI7czoxNToic3VjY2Vzc19tZXNzYWdlIjtzOjkzOiJWw6lyaWZpZXogdm90cmUgYm/DrnRlIGRlIHLDqWNlcHRpb24gb3Ugdm9zIGluZMOpc2lyYWJsZXMgYWZpbiBkZSBjb25maXJtZXIgdm90cmUgYWJvbm5lbWVudC4iO3M6NToibGlzdHMiO2E6MTp7aTowO3M6MToiMSI7fXM6MTc6Imxpc3RzX3NlbGVjdGVkX2J5IjtzOjU6ImFkbWluIjt9czo0OiJib2R5IjthOjI6e2k6MDthOjQ6e3M6NDoibmFtZSI7czo2OiJFLW1haWwiO3M6NDoidHlwZSI7czo1OiJpbnB1dCI7czo1OiJmaWVsZCI7czo1OiJlbWFpbCI7czo2OiJwYXJhbXMiO2E6Mjp7czo1OiJsYWJlbCI7czo2OiJFLW1haWwiO3M6ODoicmVxdWlyZWQiO2I6MTt9fWk6MTthOjQ6e3M6NDoibmFtZSI7czo3OiJFbnZveWVyIjtzOjQ6InR5cGUiO3M6Njoic3VibWl0IjtzOjU6ImZpZWxkIjtzOjY6InN1Ym1pdCI7czo2OiJwYXJhbXMiO2E6MTp7czo1OiJsYWJlbCI7czoxMzoiSmUgbSdhYm9ubmUgISI7fX19czo3OiJmb3JtX2lkIjtpOjE7fQ==', NULL, 0), +(2, 'Nouveau formulaire', 'YTo0OntzOjc6InZlcnNpb24iO3M6MzoiMC40IjtzOjg6InNldHRpbmdzIjthOjU6e3M6NzoiZm9ybV9pZCI7czoxOiIyIjtzOjU6Imxpc3RzIjthOjI6e2k6MDtzOjE6IjMiO2k6MTtzOjE6IjEiO31zOjEwOiJvbl9zdWNjZXNzIjtzOjc6Im1lc3NhZ2UiO3M6MTU6InN1Y2Nlc3NfbWVzc2FnZSI7czo5MzoiVsOpcmlmaWV6IHZvdHJlIGJvw650ZSBkZSByw6ljZXB0aW9uIG91IHZvcyBpbmTDqXNpcmFibGVzIGFmaW4gZGUgY29uZmlybWVyIHZvdHJlIGFib25uZW1lbnQuIjtzOjE3OiJsaXN0c19zZWxlY3RlZF9ieSI7czo1OiJhZG1pbiI7fXM6NDoiYm9keSI7YTo5OntzOjc6ImJsb2NrLTEiO2E6NTp7czo2OiJwYXJhbXMiO2E6Mjp7czo1OiJsYWJlbCI7czo2OiJFLW1haWwiO3M6ODoicmVxdWlyZWQiO3M6MToiMSI7fXM6ODoicG9zaXRpb24iO2k6MTtzOjQ6InR5cGUiO3M6NToiaW5wdXQiO3M6NToiZmllbGQiO3M6NToiZW1haWwiO3M6NDoibmFtZSI7czo2OiJFLW1haWwiO31zOjc6ImJsb2NrLTIiO2E6NTp7czo2OiJwYXJhbXMiO2E6Mzp7czo1OiJsYWJlbCI7czozOiJOb20iO3M6MTI6ImxhYmVsX3dpdGhpbiI7czoxOiIwIjtzOjg6InJlcXVpcmVkIjtzOjE6IjEiO31zOjg6InBvc2l0aW9uIjtpOjI7czo0OiJ0eXBlIjtzOjU6ImlucHV0IjtzOjU6ImZpZWxkIjtzOjg6Imxhc3RuYW1lIjtzOjQ6Im5hbWUiO3M6MzoiTm9tIjt9czo3OiJibG9jay0zIjthOjU6e3M6NjoicGFyYW1zIjthOjM6e3M6ODoicmVxdWlyZWQiO3M6MToiMCI7czo4OiJ2YWxpZGF0ZSI7czoxMjoib25seUxldHRlclNwIjtzOjU6ImxhYmVsIjtzOjQ6IlBheXMiO31zOjg6InBvc2l0aW9uIjtpOjM7czo0OiJ0eXBlIjtzOjU6ImlucHV0IjtzOjU6ImZpZWxkIjtzOjQ6ImNmXzEiO3M6NDoibmFtZSI7czo0OiJQYXlzIjt9czo3OiJibG9jay00IjthOjU6e3M6NjoicGFyYW1zIjthOjM6e3M6NjoidmFsdWVzIjthOjI6e2k6MDthOjI6e3M6NToidmFsdWUiO3M6OToiRnJhbsOnYWlzIjtzOjEwOiJpc19jaGVja2VkIjtpOjA7fWk6MTthOjI6e3M6NToidmFsdWUiO3M6NzoiQW5nbGFpcyI7czoxMDoiaXNfY2hlY2tlZCI7aTowO319czo4OiJyZXF1aXJlZCI7czoxOiIwIjtzOjU6ImxhYmVsIjtzOjY6Ikxhbmd1ZSI7fXM6ODoicG9zaXRpb24iO2k6NDtzOjQ6InR5cGUiO3M6Njoic2VsZWN0IjtzOjU6ImZpZWxkIjtzOjQ6ImNmXzYiO3M6NDoibmFtZSI7czo2OiJMYW5ndWUiO31zOjc6ImJsb2NrLTUiO2E6NTp7czo2OiJwYXJhbXMiO2E6Mzp7czo2OiJ2YWx1ZXMiO2E6Mjp7aTowO2E6Mjp7czo1OiJ2YWx1ZSI7czo0OiJQb3VyIjtzOjEwOiJpc19jaGVja2VkIjtpOjA7fWk6MTthOjI6e3M6NToidmFsdWUiO3M6NjoiQ29udHJlIjtzOjEwOiJpc19jaGVja2VkIjtpOjA7fX1zOjg6InJlcXVpcmVkIjtzOjE6IjEiO3M6NToibGFiZWwiO3M6MTQ6IlBvdXIgb3UgY29udHJlIjt9czo4OiJwb3NpdGlvbiI7aTo1O3M6NDoidHlwZSI7czo1OiJyYWRpbyI7czo1OiJmaWVsZCI7czo0OiJjZl80IjtzOjQ6Im5hbWUiO3M6MTQ6IlBvdXIgb3UgY29udHJlIjt9czo3OiJibG9jay02IjthOjU6e3M6NjoicGFyYW1zIjthOjM6e3M6ODoicmVxdWlyZWQiO3M6MToiMCI7czo4OiJ2YWxpZGF0ZSI7czowOiIiO3M6NToibGFiZWwiO3M6MTI6IkNvbW1lbnRhaXJlcyI7fXM6ODoicG9zaXRpb24iO2k6NjtzOjQ6InR5cGUiO3M6ODoidGV4dGFyZWEiO3M6NToiZmllbGQiO3M6NDoiY2ZfMyI7czo0OiJuYW1lIjtzOjEyOiJDb21tZW50YWlyZXMiO31zOjc6ImJsb2NrLTciO2E6NTp7czo2OiJwYXJhbXMiO2E6NDp7czo5OiJkYXRlX3R5cGUiO3M6MTQ6InllYXJfbW9udGhfZGF5IjtzOjE2OiJpc19kZWZhdWx0X3RvZGF5IjtzOjE6IjAiO3M6MTA6ImRhdGVfb3JkZXIiO3M6MTA6Im1tL2RkL3l5eXkiO3M6NToibGFiZWwiO3M6MTc6IkRhdGUgZCdhY3RpdmF0aW9uIjt9czo4OiJwb3NpdGlvbiI7aTo3O3M6NDoidHlwZSI7czo0OiJkYXRlIjtzOjU6ImZpZWxkIjtzOjQ6ImNmXzciO3M6NDoibmFtZSI7czoxNzoiRGF0ZSBkJ2FjdGl2YXRpb24iO31zOjc6ImJsb2NrLTgiO2E6NTp7czo2OiJwYXJhbXMiO2E6Mzp7czo2OiJ2YWx1ZXMiO2E6MTp7aTowO2E6Mjp7czo1OiJ2YWx1ZSI7czoyMzoiSidhY2NlcHRlIGxlIHLDqWdsZW1lbnQiO3M6MTA6ImlzX2NoZWNrZWQiO2k6MTt9fXM6ODoicmVxdWlyZWQiO3M6MToiMSI7czo1OiJsYWJlbCI7czoxMDoiUsOpZ2xlbWVudCI7fXM6ODoicG9zaXRpb24iO2k6ODtzOjQ6InR5cGUiO3M6ODoiY2hlY2tib3giO3M6NToiZmllbGQiO3M6NDoiY2ZfNSI7czo0OiJuYW1lIjtzOjEwOiJSw6lnbGVtZW50Ijt9czo3OiJibG9jay05IjthOjU6e3M6NjoicGFyYW1zIjthOjE6e3M6NToibGFiZWwiO3M6MTM6IkplIG0nYWJvbm5lICEiO31zOjg6InBvc2l0aW9uIjtpOjk7czo0OiJ0eXBlIjtzOjY6InN1Ym1pdCI7czo1OiJmaWVsZCI7czo2OiJzdWJtaXQiO3M6NDoibmFtZSI7czo3OiJFbnZveWVyIjt9fXM6NzoiZm9ybV9pZCI7aToyO30=', NULL, 0); + +-- +-- Vider la table avant d'insérer `wp_wysija_list` +-- + +TRUNCATE TABLE `wp_wysija_list`; +-- +-- Contenu de la table `wp_wysija_list` +-- + +INSERT INTO `wp_wysija_list` (`list_id`, `name`, `namekey`, `description`, `unsub_mail_id`, `welcome_mail_id`, `is_enabled`, `is_public`, `created_at`, `ordering`) VALUES +(1, 'Ma première liste', 'ma-premiere-liste', 'Cette liste a été créée automatiquement lors de l''installation de MailPoet.', 0, 0, 1, 1, 1486319877, 0), +(2, 'Utilisateurs WordPress', 'users', 'La liste créée automatiquement lors de l''importation des abonnés de l''extension : "WordPress', 0, 0, 0, 0, 1486319877, 0), +(3, 'Ma deuxième liste', 'ma-deuxieme-liste', 'Description de la deuxième liste', 0, 0, 1, 0, 1492605288, 0); + +-- +-- Vider la table avant d'insérer `wp_wysija_queue` +-- + +TRUNCATE TABLE `wp_wysija_queue`; +-- +-- Vider la table avant d'insérer `wp_wysija_url` +-- + +TRUNCATE TABLE `wp_wysija_url`; +-- +-- Vider la table avant d'insérer `wp_wysija_url_mail` +-- + +TRUNCATE TABLE `wp_wysija_url_mail`; +-- +-- Vider la table avant d'insérer `wp_wysija_user` +-- + +TRUNCATE TABLE `wp_wysija_user`; +-- +-- Contenu de la table `wp_wysija_user` +-- + +INSERT INTO `wp_wysija_user` (`user_id`, `wpuser_id`, `email`, `firstname`, `lastname`, `ip`, `confirmed_ip`, `confirmed_at`, `last_opened`, `last_clicked`, `keyuser`, `created_at`, `status`, `domain`, `cf_1`, `cf_3`, `cf_4`, `cf_5`, `cf_6`, `cf_7`, `cf_8`, `cf_9`, `cf_10`, `cf_11`) VALUES +(1, 1, 'test@test.com', '', '', '', '0', NULL, NULL, NULL, '1c1def6103687556a1d399a2dd6c8d39', 1486319878, 1, 'test.com', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(2, 0, 'abonne@gmail.com', 'Frédéric', 'Abonné', '127.0.0.1', '0', NULL, NULL, NULL, '5ae1f4c0881eddb555acc548253a8262', 1492591026, 1, 'gmail.com', 'France', 'Voici mes commentaires\r\nMerci', 'Pour', 1, 'Français', 106444800, '1234567890', 'BÉPO', 'BÉPO123', '0123456789'), +(3, 0, 'nonconfirme@gmail.com', 'Frederic', 'Non confirmé', '127.0.0.1', '0', NULL, NULL, NULL, '6e7a8b8c96ce88d208635258506a211a', 1492591057, 0, 'gmail.com', 'Italie', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(4, 0, 'desabonne@gmail.com', 'Frederic', 'Désabonné', '127.0.0.1', '0', NULL, NULL, NULL, '16168c16642360b0c03ff73dab044846', 1492591090, -1, 'gmail.com', 'Espagne', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + +-- +-- Vider la table avant d'insérer `wp_wysija_user_field` +-- + +TRUNCATE TABLE `wp_wysija_user_field`; +-- +-- Contenu de la table `wp_wysija_user_field` +-- + +INSERT INTO `wp_wysija_user_field` (`field_id`, `name`, `column_name`, `type`, `values`, `default`, `is_required`, `error_message`) VALUES +(1, 'Prénom', 'firstname', 0, NULL, '', 0, 'Merci de saisir le prénom'), +(2, 'Nom', 'lastname', 0, NULL, '', 0, 'Merci de saisir le nom de famille'); + +-- +-- Vider la table avant d'insérer `wp_wysija_user_history` +-- + +TRUNCATE TABLE `wp_wysija_user_history`; +-- +-- Vider la table avant d'insérer `wp_wysija_user_list` +-- + +TRUNCATE TABLE `wp_wysija_user_list`; +-- +-- Contenu de la table `wp_wysija_user_list` +-- + +INSERT INTO `wp_wysija_user_list` (`list_id`, `user_id`, `sub_date`, `unsub_date`) VALUES +(1, 1, 1486319877, 0), +(1, 2, 1493194576, 0), +(1, 3, 1493019789, 0), +(1, 4, 1493019803, 1493019803), +(2, 1, 1486319877, 0), +(3, 2, 1493194576, 0), +(3, 4, 1493019803, 0); diff --git a/tests/_support/Helper/Database.php b/tests/_support/Helper/Database.php new file mode 100644 index 0000000000..441f73a3f8 --- /dev/null +++ b/tests/_support/Helper/Database.php @@ -0,0 +1,22 @@ +exec($sql); + } + +} diff --git a/tests/unit/Config/MP2MigratorTest.php b/tests/unit/Config/MP2MigratorTest.php new file mode 100644 index 0000000000..f8185a6f48 --- /dev/null +++ b/tests/unit/Config/MP2MigratorTest.php @@ -0,0 +1,352 @@ +MP2Migrator = new MP2Migrator(); + } + + public function _after() { + } + + /** + * Test the isMigrationNeeded function + * + */ + public function testIsMigrationNeeded() { + Database::loadSQL('dropMP2Tables'); + $result = $this->MP2Migrator->isMigrationNeeded(); + expect($result)->false(); + + Database::loadSQL('createMP2Tables'); + $result = $this->MP2Migrator->isMigrationNeeded(); + expect($result)->true(); + } + + /** + * Test the init function + * + */ + public function testInit() { + // Nothing to test + } + + /** + * Test the eraseMP3Data function + * + */ + public function testEraseMP3Data() { + global $wpdb; + + $this->invokeMethod($this->MP2Migrator, 'eraseMP3Data'); + + // Check if the subscribers number is equal to the WordPress users number + $WPUsersCount = \ORM::for_table($wpdb->prefix . 'users')->count(); + expect(Subscriber::count())->equals($WPUsersCount); + + // Check if the custom fields number is 0 + expect(CustomField::count())->equals(0); + + // Check if the subscribers custom fields number is 0 + expect(SubscriberCustomField::count())->equals(0); + } + + /** + * Test the resetMigrationCounters function + * + */ + public function testResetMigrationCounters() { + $this->invokeMethod($this->MP2Migrator, 'resetMigrationCounters'); + + // Check if the last imported user ID is 0 + $lastImportedUserID = Setting::getValue('last_imported_user_id', 0); + expect($lastImportedUserID)->equals(0); + + // Check if the last imported list ID is 0 + $lastImportedListID = Setting::getValue('last_imported_list_id', 0); + expect($lastImportedListID)->equals(0); + } + + /** + * Test the stopImport function + * + */ + public function testStopImport() { + delete_option('mailpoet_stopImport'); + $this->MP2Migrator->stopImport(); + $stopImport = !empty(Setting::getValue('import_stopped', false)); + expect($stopImport)->true(); + } + + /** + * Create the MP2 tables and erase the MP3 data + * + */ + private function initImport() { + Database::loadSQL('createMP2Tables'); + $this->invokeMethod($this->MP2Migrator, 'eraseMP3Data'); + } + + /** + * Populate the MP2 tables with some samples data + * + */ + private function loadMP2Fixtures() { + Database::loadSQL('populateMP2Tables'); + } + + /** + * Test the importSegments function + * + * @global object $wpdb + */ + public function testImportSegments() { + global $wpdb; + + // Check the segments number + $this->initImport(); + $this->loadMP2Fixtures(); + $this->invokeMethod($this->MP2Migrator, 'importSegments'); + expect(Segment::count())->equals(3); + + // Check a segment data + $this->initImport(); + $id = 999; + $name = 'Test list'; + $description = 'Description of the test list'; + $timestamp = 1486319877; + $wpdb->insert($wpdb->prefix . 'wysija_list', array( + 'list_id' => $id, + 'name' => $name, + 'description' => $description, + 'is_enabled' => 1, + 'is_public' => 1, + 'created_at' => $timestamp, + )); + $this->invokeMethod($this->MP2Migrator, 'importSegments'); + $importedSegmentsMapping = $this->MP2Migrator->getImportedMapping('segments'); + $table = MP_SEGMENTS_TABLE; + $segment = $wpdb->get_row("SELECT * FROM $table WHERE id=" . $importedSegmentsMapping[$id]); + expect($segment->name)->equals($name); + expect($segment->description)->equals($description); + } + + /** + * Test the importCustomFields function + * + * @global object $wpdb + */ + public function testImportCustomFields() { + global $wpdb; + + // Check the custom fields number + $this->initImport(); + $this->loadMP2Fixtures(); + $this->invokeMethod($this->MP2Migrator, 'importCustomFields'); + expect(CustomField::count())->equals(10); + + // Check a custom field data + $this->initImport(); + $id = 999; + $name = 'Test field'; + $type = 'input'; + $required = 1; + $settings = array( + 'required' => '1', + 'validate' => 'onlyLetterSp', + ); + $wpdb->insert($wpdb->prefix . 'wysija_custom_field', array( + 'id' => $id, + 'name' => $name, + 'type' => $type, + 'required' => $required, + 'settings' => serialize($settings), + )); + $this->invokeMethod($this->MP2Migrator, 'importCustomFields'); + $table = MP_CUSTOM_FIELDS_TABLE; + $custom_field = $wpdb->get_row("SELECT * FROM $table WHERE id=$id"); + expect($custom_field->id)->equals($id); + expect($custom_field->name)->equals($name); + expect($custom_field->type)->equals('text'); + $custom_field_params = unserialize($custom_field->params); + expect($custom_field_params['required'])->equals($settings['required']); + expect($custom_field_params['validate'])->equals('alphanum'); + expect($custom_field_params['label'])->equals($name); + } + + /** + * Test the importSubscribers function + * + * @global object $wpdb + */ + public function testImportSubscribers() { + global $wpdb; + + // Check a subscriber data + $this->initImport(); + $id = 999; + $wp_id = 1; + $email = 'test@test.com'; + $firstname = 'Test firstname'; + $lastname = 'Test lastname'; + $ip = '127.0.0.1'; + $confirmed_ip = $ip; + $wpdb->insert($wpdb->prefix . 'wysija_user', array( + 'user_id' => $id, + 'wpuser_id' => $wp_id, + 'email' => $email, + 'firstname' => $firstname, + 'lastname' => $lastname, + 'ip' => $ip, + 'confirmed_ip' => $confirmed_ip, + 'status' => '1', + )); + $this->invokeMethod($this->MP2Migrator, 'importSubscribers'); + $table = MP_SUBSCRIBERS_TABLE; + $subscriber = $wpdb->get_row("SELECT * FROM $table WHERE email='$email'"); + expect($subscriber->email)->equals($email); + expect($subscriber->first_name)->equals($firstname); + expect($subscriber->last_name)->equals($lastname); + expect($subscriber->subscribed_ip)->equals($ip); + expect($subscriber->confirmed_ip)->equals($confirmed_ip); + expect($subscriber->status)->equals('subscribed'); + } + + /** + * Test the importSubscriberSegments function + * + * @global object $wpdb + */ + public function testImportSubscriberSegments() { + global $wpdb; + + // Check a subscriber segment data + + // Insert a list + $this->initImport(); + $list_id = 998; + $list_name = 'Test list'; + $description = 'Description of the test list'; + $timestamp = 1486319877; + $wpdb->insert($wpdb->prefix . 'wysija_list', array( + 'list_id' => $list_id, + 'name' => $list_name, + 'description' => $description, + 'is_enabled' => 1, + 'is_public' => 1, + 'created_at' => $timestamp, + )); + + // Insert a user + $user_id = 999; + $wp_id = 1; + $email = 'test@test.com'; + $wpdb->insert($wpdb->prefix . 'wysija_user', array( + 'user_id' => $user_id, + 'wpuser_id' => $wp_id, + 'email' => $email, + )); + + // Insert a user list + $wpdb->insert($wpdb->prefix . 'wysija_user_list', array( + 'list_id' => $list_id, + 'user_id' => $user_id, + 'sub_date' => $timestamp, + )); + + $this->invokeMethod($this->MP2Migrator, 'importSegments'); + $this->invokeMethod($this->MP2Migrator, 'importSubscribers'); + $importedSegmentsMapping = $this->MP2Migrator->getImportedMapping('segments'); + $importedSubscribersMapping = $this->MP2Migrator->getImportedMapping('subscribers'); + $table = MP_SUBSCRIBER_SEGMENT_TABLE; + $segment_id = $importedSegmentsMapping[$list_id]; + $subscriber_id = $importedSubscribersMapping[$user_id]; + $subscriber_segment = $wpdb->get_row("SELECT * FROM $table WHERE subscriber_id='$subscriber_id' AND segment_id='$segment_id'"); + expect($subscriber_segment)->notNull(); + } + + /** + * Test the importSubscriberCustomFields function + * + * @global object $wpdb + */ + public function testImportSubscriberCustomFields() { + global $wpdb; + + // Check the subscriber custom fields number + $this->initImport(); + $this->loadMP2Fixtures(); + $this->invokeMethod($this->MP2Migrator, 'importCustomFields'); + $this->invokeMethod($this->MP2Migrator, 'importSubscribers'); + expect(SubscriberCustomField::count())->equals(40); + + // Check a subscriber custom field data + + $this->initImport(); + // Insert a custom field + $cf_id = 1; + $cf_name = 'Custom field key'; + $cf_type = 'input'; + $cf_required = 1; + $cf_settings = array( + 'required' => '1', + 'validate' => 'onlyLetterSp', + ); + $wpdb->insert($wpdb->prefix . 'wysija_custom_field', array( + 'id' => $cf_id, + 'name' => $cf_name, + 'type' => $cf_type, + 'required' => $cf_required, + 'settings' => serialize($cf_settings), + )); + + // Insert a user + $user_id = 999; + $wp_id = 1; + $email = 'test@test.com'; + $custom_field_value = 'Test custom field value'; + $wpdb->insert($wpdb->prefix . 'wysija_user', array( + 'user_id' => $user_id, + 'wpuser_id' => $wp_id, + 'email' => $email, + 'cf_' . $cf_id => $custom_field_value, + )); + + $this->invokeMethod($this->MP2Migrator, 'importCustomFields'); + $this->invokeMethod($this->MP2Migrator, 'importSubscribers'); + $importedSubscribersMapping = $this->MP2Migrator->getImportedMapping('subscribers'); + $table = MP_SUBSCRIBER_CUSTOM_FIELD_TABLE; + $subscriber_id = $importedSubscribersMapping[$user_id]; + $subscriber_custom_field = $wpdb->get_row("SELECT * FROM $table WHERE subscriber_id='$subscriber_id' AND custom_field_id='$cf_id'"); + expect($subscriber_custom_field->value)->equals($custom_field_value); + } + + /** + * Test the getImportedMapping function + * + */ + public function testGetImportedMapping() { + $this->initImport(); + $mapping = new MappingToExternalEntities(); + $old_id = 999; + $new_id = 500; + $type = 'testMapping'; + $mapping->create(array( + 'old_id' => $old_id, + 'type' => $type, + 'new_id' => $new_id, + )); + $result = $this->invokeMethod($this->MP2Migrator, 'getImportedMapping', array('testMapping')); + expect($result[$old_id])->equals($new_id); + } + +} diff --git a/views/mp2migration.html b/views/mp2migration.html new file mode 100644 index 0000000000..ba04bc17a7 --- /dev/null +++ b/views/mp2migration.html @@ -0,0 +1,67 @@ +<% extends 'layout.html' %> + +<% block content %> + +
+

<%= __('Welcome to MailPoet version 3!') %> <%= settings.version %>

+ +

<%= __('This new version is quite an upgrade.') %> <%= __('Since this new version is completely new, we first need to update your database before we begin.') %>

+ +

<%= __('What will be kept in MailPoet 3') %>

+ + +
+
+ +
+
+ + +
+ 0% +
+ + + +
+ <%= __('Log...') %> +
+ +
+ +
+<% endblock %> + +<% block after_javascript %> + <%= javascript( + 'mp2migrator.js' + )%> + +<% endblock %> + +<% block translations %> + <%= localize({ + 'import_complete' : __('IMPORT COMPLETE'), + 'importing' : __('Importing…'), + 'import_stopped_by_user' : __('IMPORT STOPPED BY USER'), + }) %> +<% endblock %> diff --git a/webpack.config.js b/webpack.config.js index a2cd138d50..d9d5c16645 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -238,6 +238,20 @@ config.push(_.extend({}, baseConfig, { } })); +// mp2migrator +config.push(_.extend({}, baseConfig, { + name: 'mp2migrator', + entry: { + mp2migrator: [ + 'mp2migrator.js' + ] + }, + externals: { + 'jquery': 'jQuery', + 'mailpoet': 'MailPoet' + } +})); + // Test config.push(_.extend({}, baseConfig, { name: 'test',