Merge pull request #1085 from mailpoet/improve-user-sync
Improve user sync [MAILPOET-1073]
This commit is contained in:
@@ -172,7 +172,8 @@ class Migrator {
|
|||||||
'deleted_at TIMESTAMP NULL,',
|
'deleted_at TIMESTAMP NULL,',
|
||||||
'unconfirmed_data longtext,',
|
'unconfirmed_data longtext,',
|
||||||
'PRIMARY KEY (id),',
|
'PRIMARY KEY (id),',
|
||||||
'UNIQUE KEY email (email)'
|
'UNIQUE KEY email (email),',
|
||||||
|
'KEY wp_user_id (wp_user_id)',
|
||||||
);
|
);
|
||||||
return $this->sqlify(__FUNCTION__, $attributes);
|
return $this->sqlify(__FUNCTION__, $attributes);
|
||||||
}
|
}
|
||||||
|
@@ -79,28 +79,109 @@ class WP {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static function synchronizeUsers() {
|
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();
|
$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
|
private static function removeFromTrash() {
|
||||||
$wp_users = \get_users(array(
|
$subscribers_table = Subscriber::$_table;
|
||||||
'count_total' => false,
|
Subscriber::raw_execute(sprintf('
|
||||||
'fields' => 'ID'
|
UPDATE %s
|
||||||
));
|
SET deleted_at = NULL
|
||||||
|
WHERE %s.wp_user_id IS NOT NULL
|
||||||
// update data for each wp user
|
', $subscribers_table, $subscribers_table));
|
||||||
foreach($wp_users as $wp_user_id) {
|
}
|
||||||
static::synchronizeUser($wp_user_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private static function removeOrphanedSubscribers() {
|
||||||
// remove orphaned wp segment subscribers (not having a matching wp user id),
|
// remove orphaned wp segment subscribers (not having a matching wp user id),
|
||||||
// e.g. if wp users were deleted directly from the database
|
// e.g. if wp users were deleted directly from the database
|
||||||
$wp_segment->subscribers()
|
global $wpdb;
|
||||||
->whereNotIn('wp_user_id', $wp_users)
|
|
||||||
|
Subscriber::table_alias('wpms')
|
||||||
|
->leftOuterJoin($wpdb->prefix . 'users', array('wpms.wp_user_id', '=', 'wu.id'), 'wu')
|
||||||
|
->whereNull('wu.id')
|
||||||
->findResultSet()
|
->findResultSet()
|
||||||
->set('wp_user_id', null)
|
->set('wp_user_id', null)
|
||||||
->delete();
|
->delete();
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,55 +1,194 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Test\Segments;
|
|
||||||
|
|
||||||
use MailPoet\Models\Segment;
|
namespace MailPoet\Test\Segments;
|
||||||
use MailPoet\Segments\WP;
|
|
||||||
|
|
||||||
require_once(ABSPATH . 'wp-admin/includes/user.php');
|
require_once(ABSPATH . 'wp-admin/includes/user.php');
|
||||||
|
|
||||||
class WPTest extends \MailPoetTest {
|
use Carbon\Carbon;
|
||||||
function _before() {
|
use MailPoet\Models\Segment;
|
||||||
$this->wp_user_1 = $this->createWPUser('phoenix_test_user');
|
use MailPoet\Models\Subscriber;
|
||||||
$this->wp_user_2 = $this->createWPUser('phoenix_test_user2');
|
use MailPoet\Segments\WP;
|
||||||
$this->wp_segment = Segment::getWPSegment();
|
|
||||||
|
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() {
|
function testItSynchronizesDeletedWPUsersUsingHooks() {
|
||||||
expect($this->getWPSegmentSubscribers()->count())->equals(2);
|
$id = $this->insertUser();
|
||||||
wp_delete_user($this->wp_user_1->ID);
|
$this->insertUser();
|
||||||
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();
|
|
||||||
WP::synchronizeUsers();
|
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() {
|
function testItRemovesOrphanedSubscribers() {
|
||||||
return $this->wp_segment->subscribers()
|
$this->insertUser();
|
||||||
->whereIn(
|
$id = $this->insertUser();
|
||||||
'wp_user_id',
|
WP::synchronizeUsers();
|
||||||
array(
|
$this->deleteWPUser($id);
|
||||||
$this->wp_user_1->ID,
|
WP::synchronizeUsers();
|
||||||
$this->wp_user_2->ID
|
$subscribers = Segment::getWPSegment()->subscribers()->whereIn('wp_user_id', $this->userIds);
|
||||||
)
|
expect($subscribers->count())->equals(1);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createWPUser($login) {
|
function _before() {
|
||||||
$WP_user = wp_create_user($login, 'pass', $login . '@example.com');
|
$this->cleanData();
|
||||||
$WP_user = get_user_by('login', $login);
|
|
||||||
return $WP_user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _after() {
|
function _after() {
|
||||||
\ORM::raw_execute('TRUNCATE ' . Segment::$_table);
|
$this->cleanData();
|
||||||
wp_delete_user($this->wp_user_1->ID);
|
|
||||||
wp_delete_user($this->wp_user_2->ID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Reference in New Issue
Block a user