Merge pull request #1085 from mailpoet/improve-user-sync

Improve user sync [MAILPOET-1073]
This commit is contained in:
stoletniy
2017-09-11 14:56:41 +03:00
committed by GitHub
3 changed files with 274 additions and 53 deletions

View File

@@ -172,7 +172,8 @@ class Migrator {
'deleted_at TIMESTAMP NULL,',
'unconfirmed_data longtext,',
'PRIMARY KEY (id),',
'UNIQUE KEY email (email)'
'UNIQUE KEY email (email),',
'KEY wp_user_id (wp_user_id)',
);
return $this->sqlify(__FUNCTION__, $attributes);
}

View File

@@ -79,28 +79,109 @@ class WP {
}
static function synchronizeUsers() {
// get wordpress users list
self::updateSubscribersEmails();
self::insertSubscribers();
self::removeFromTrash();
self::updateFirstNames();
self::updateLastNames();
self::updateFristNameIfMissing();
self::insertUsersToSegment();
self::removeOrphanedSubscribers();
return true;
}
private static function updateSubscribersEmails() {
global $wpdb;
$subscribers_table = Subscriber::$_table;
Subscriber::raw_execute(sprintf('
UPDATE IGNORE %s
JOIN %susers as wu ON %s.wp_user_id = wu.id
SET email = user_email
WHERE %s.wp_user_id IS NOT NULL
', $subscribers_table, $wpdb->prefix, $subscribers_table, $subscribers_table));
}
private static function insertSubscribers() {
global $wpdb;
$subscribers_table = Subscriber::$_table;
Subscriber::raw_execute(sprintf('
INSERT IGNORE INTO %s(wp_user_id, email, status, created_at)
SELECT wu.id, wu.user_email, "subscribed", CURRENT_TIMESTAMP() FROM %susers wu
LEFT JOIN %s mps ON wu.id = mps.wp_user_id
WHERE mps.wp_user_id IS NULL
', $subscribers_table, $wpdb->prefix, $subscribers_table));
}
private static function updateFirstNames() {
global $wpdb;
$subscribers_table = Subscriber::$_table;
Subscriber::raw_execute(sprintf('
UPDATE %s
JOIN %susermeta as wpum ON %s.wp_user_id = wpum.user_id AND meta_key = "first_name"
SET first_name = meta_value
WHERE %s.first_name = ""
AND %s.wp_user_id IS NOT NULL
', $subscribers_table, $wpdb->prefix, $subscribers_table, $subscribers_table, $subscribers_table));
}
private static function updateLastNames() {
global $wpdb;
$subscribers_table = Subscriber::$_table;
Subscriber::raw_execute(sprintf('
UPDATE %s
JOIN %susermeta as wpum ON %s.wp_user_id = wpum.user_id AND meta_key = "last_name"
SET last_name = meta_value
WHERE %s.last_name = ""
AND %s.wp_user_id IS NOT NULL
', $subscribers_table, $wpdb->prefix, $subscribers_table, $subscribers_table, $subscribers_table));
}
private static function updateFristNameIfMissing() {
global $wpdb;
$subscribers_table = Subscriber::$_table;
Subscriber::raw_execute(sprintf('
UPDATE %s
JOIN %susers wu ON %s.wp_user_id = wu.id
SET first_name = display_name
WHERE %s.first_name = ""
AND %s.wp_user_id IS NOT NULL
', $subscribers_table, $wpdb->prefix, $subscribers_table, $subscribers_table, $subscribers_table));
}
private static function insertUsersToSegment() {
$wp_segment = Segment::getWPSegment();
$subscribers_table = Subscriber::$_table;
$wp_mailpoet_subscriber_segment_table = SubscriberSegment::$_table;
Subscriber::raw_execute(sprintf('
INSERT IGNORE INTO %s(subscriber_id, segment_id, created_at)
SELECT mps.id, "%s", CURRENT_TIMESTAMP() FROM %s mps
WHERE mps.wp_user_id IS NOT NULL
', $wp_mailpoet_subscriber_segment_table, $wp_segment->id, $subscribers_table));
}
// fetch all wp users id
$wp_users = \get_users(array(
'count_total' => false,
'fields' => 'ID'
));
// update data for each wp user
foreach($wp_users as $wp_user_id) {
static::synchronizeUser($wp_user_id);
}
private static function removeFromTrash() {
$subscribers_table = Subscriber::$_table;
Subscriber::raw_execute(sprintf('
UPDATE %s
SET deleted_at = NULL
WHERE %s.wp_user_id IS NOT NULL
', $subscribers_table, $subscribers_table));
}
private static function removeOrphanedSubscribers() {
// remove orphaned wp segment subscribers (not having a matching wp user id),
// e.g. if wp users were deleted directly from the database
$wp_segment->subscribers()
->whereNotIn('wp_user_id', $wp_users)
global $wpdb;
Subscriber::table_alias('wpms')
->leftOuterJoin($wpdb->prefix . 'users', array('wpms.wp_user_id', '=', 'wu.id'), 'wu')
->whereNull('wu.id')
->findResultSet()
->set('wp_user_id', null)
->delete();
return true;
}
}

View File

@@ -1,55 +1,194 @@
<?php
namespace MailPoet\Test\Segments;
use MailPoet\Models\Segment;
use MailPoet\Segments\WP;
namespace MailPoet\Test\Segments;
require_once(ABSPATH . 'wp-admin/includes/user.php');
class WPTest extends \MailPoetTest {
function _before() {
$this->wp_user_1 = $this->createWPUser('phoenix_test_user');
$this->wp_user_2 = $this->createWPUser('phoenix_test_user2');
$this->wp_segment = Segment::getWPSegment();
use Carbon\Carbon;
use MailPoet\Models\Segment;
use MailPoet\Models\Subscriber;
use MailPoet\Segments\WP;
class WPTest extends \MailPoetTest {
private $userIds = array();
function testItSynchronizeUsers() {
$this->insertUser();
$this->insertUser();
WP::synchronizeUsers();
$subscribersCount = $this->getSubscribersCount();
expect($subscribersCount)->equals(2);
}
function testItSynchronizeNewUsers() {
$this->insertUser();
$this->insertUser();
WP::synchronizeUsers();
$this->insertUser();
WP::synchronizeUsers();
$subscribersCount = $this->getSubscribersCount();
expect($subscribersCount)->equals(3);
}
function testItSynchronizeEmails() {
$id = $this->insertUser();
WP::synchronizeUsers();
$this->updateWPUserEmail($id, 'user-sync-test-xx@email.com');
WP::synchronizeUsers();
$subscriber = Subscriber::where('wp_user_id', $id)->findOne();
expect($subscriber->email)->equals('user-sync-test-xx@email.com');
}
function testItSynchronizeFirstNames() {
$id = $this->insertUser();
WP::synchronizeUsers();
update_user_meta($id, 'first_name', 'First name');
WP::synchronizeUsers();
$subscriber = Subscriber::where('wp_user_id', $id)->findOne();
expect($subscriber->first_name)->equals('First name');
}
function testItSynchronizeLastNames() {
$id = $this->insertUser();
WP::synchronizeUsers();
update_user_meta($id, 'last_name', 'Last name');
WP::synchronizeUsers();
$subscriber = Subscriber::where('wp_user_id', $id)->findOne();
expect($subscriber->last_name)->equals('Last name');
}
function testItSynchronizeFirstNamesUsingDisplayName() {
$id = $this->insertUser();
WP::synchronizeUsers();
$this->updateWPUserDisplayName($id, 'First name');
WP::synchronizeUsers();
$subscriber = Subscriber::where('wp_user_id', $id)->findOne();
expect($subscriber->first_name)->equals('First name');
}
function testItSynchronizeSegment() {
$this->insertUser();
$this->insertUser();
$this->insertUser();
WP::synchronizeUsers();
$subscribers = Segment::getWPSegment()->subscribers()->whereIn('wp_user_id', $this->userIds);
expect($subscribers->count())->equals(3);
}
function testItRemovesUsersFromTrash() {
$id = $this->insertUser();
WP::synchronizeUsers();
$subscriber = Subscriber::where("wp_user_id", $id)->findOne();
$subscriber->deleted_at = Carbon::now();
$subscriber->save();
WP::synchronizeUsers();
$subscriber = Subscriber::where("wp_user_id", $id)->findOne();
expect($subscriber->deleted_at)->null();
}
function testItSynchronizesDeletedWPUsersUsingHooks() {
expect($this->getWPSegmentSubscribers()->count())->equals(2);
wp_delete_user($this->wp_user_1->ID);
expect($this->getWPSegmentSubscribers()->count())->equals(1);
}
function testItForciblySynchronizesDeletedWPUsers() {
global $wpdb;
expect($this->getWPSegmentSubscribers()->count())->equals(2);
// Remove a WP user directly from the database
\ORM::for_table($wpdb->prefix . 'users')
->where('id', $this->wp_user_2->ID)
->deleteMany();
$id = $this->insertUser();
$this->insertUser();
WP::synchronizeUsers();
expect($this->getWPSegmentSubscribers()->count())->equals(1);
$subscribersCount = $this->getSubscribersCount();
expect($subscribersCount)->equals(2);
wp_delete_user($id);
$subscribersCount = $this->getSubscribersCount();
expect($subscribersCount)->equals(1);
}
private function getWPSegmentSubscribers() {
return $this->wp_segment->subscribers()
->whereIn(
'wp_user_id',
array(
$this->wp_user_1->ID,
$this->wp_user_2->ID
)
);
function testItRemovesOrphanedSubscribers() {
$this->insertUser();
$id = $this->insertUser();
WP::synchronizeUsers();
$this->deleteWPUser($id);
WP::synchronizeUsers();
$subscribers = Segment::getWPSegment()->subscribers()->whereIn('wp_user_id', $this->userIds);
expect($subscribers->count())->equals(1);
}
private function createWPUser($login) {
$WP_user = wp_create_user($login, 'pass', $login . '@example.com');
$WP_user = get_user_by('login', $login);
return $WP_user;
function _before() {
$this->cleanData();
}
function _after() {
\ORM::raw_execute('TRUNCATE ' . Segment::$_table);
wp_delete_user($this->wp_user_1->ID);
wp_delete_user($this->wp_user_2->ID);
$this->cleanData();
}
}
private function cleanData() {
\ORM::raw_execute('TRUNCATE ' . Segment::$_table);
global $wpdb;
$db = \ORM::getDb();
$db->exec(sprintf('
DELETE FROM
%susers
WHERE
user_email LIKE "user-sync-test%%"
', $wpdb->prefix));
}
private function getSubscribersCount() {
return Subscriber::whereIn("wp_user_id", $this->userIds)->count();
}
/**
* Insert a user without invoking wp hooks.
* Those tests are testing user synchronisation, so we need data in wp_users table which has not been synchronised to
* mailpoet database yet. We cannot use wp_insert_user functions because they would do the sync on insert.
*
* @return string
*/
private function insertUser() {
global $wpdb;
$db = \ORM::getDb();
$db->exec(sprintf('
INSERT INTO
%susers(user_login, user_email, user_registered)
VALUES
(
CONCAT("user-sync-test", rand()),
CONCAT("user", rand(), "@example.com"),
"2017-01-02 12:31:12"
)', $wpdb->prefix));
$id = $db->lastInsertId();
$this->userIds[] = $id;
return $id;
}
private function updateWPUserEmail($id, $email) {
global $wpdb;
$db = \ORM::getDb();
$db->exec(sprintf('
UPDATE
%susers
SET user_email = "%s"
WHERE
id = %s
', $wpdb->prefix, $email, $id));
}
private function updateWPUserDisplayName($id, $name) {
global $wpdb;
$db = \ORM::getDb();
$db->exec(sprintf('
UPDATE
%susers
SET display_name = "%s"
WHERE
id = %s
', $wpdb->prefix, $name, $id));
}
private function deleteWPUser($id) {
global $wpdb;
$db = \ORM::getDb();
$db->exec(sprintf('
DELETE FROM
%susers
WHERE
id = %s
', $wpdb->prefix, $id));
}
}