purge_users-8.x-2.0/tests/src/Functional/NotificationTest.php
tests/src/Functional/NotificationTest.php
<?php
namespace Drupal\Tests\purge_users\Functional;
use Drupal\Core\Test\AssertMailTrait;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\Traits\Core\CronRunTrait;
use Drupal\user\UserInterface;
/**
* Test all purge notifications.
*
* @group purge_users
*/
class NotificationTest extends BrowserTestBase {
use AssertMailTrait;
use CronRunTrait;
/**
* {@inheritdoc}
*/
protected static $modules = ['purge_users'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* Notify manager.
*
* @var \Drupal\purge_users\Services\UserManagementServiceInterface
*/
protected $notifyManager;
/**
* An admin user.
*
* @var \Drupal\user\UserInterface
*/
protected $admin;
/**
* An active user.
*
* @var \Drupal\user\UserInterface
*/
protected $activeUser;
/**
* Blocked user to be pre-notified and purged.
*
* @var \Drupal\user\UserInterface
*/
protected $blockedUser7Days;
/**
* Blocked user to be pre-notified.
*
* @var \Drupal\user\UserInterface
*/
protected $blockedUser4Days;
/**
* An inactive user to be pre-notified and purged.
*
* @var \Drupal\user\UserInterface
*/
protected $inactiveUser7Days;
/**
* An inactive user to be pre-notified.
*
* @var \Drupal\user\UserInterface
*/
protected $inactiveUser4Days;
/**
* A user not logged in for 7 days.
*
* To be pre-notified and purged.
*
* @var \Drupal\user\UserInterface
*/
protected $lastloginUser7Days;
/**
* A user not logged in for 4 days.
*
* To be pre-notified.
*
* @var \Drupal\user\UserInterface
*/
protected $lastloginUser4Days;
/**
* A user that never logged in to be pre-notified and purged.
*
* @var \Drupal\user\UserInterface
*/
protected $neverLoggedUser7Days;
/**
* A user that never logged in to be pre-notified.
*
* @var \Drupal\user\UserInterface
*/
protected $neverLoggedUser4Days;
/**
* User storage.
*
* @var \Drupal\user\UserStorageInterface
*/
protected $userStorage;
/**
* {@inheritdoc}
*/
public function setUp(): void {
parent::setUp();
$this->config('purge_users.settings')
// Purge authenticated, but don't purge administrator.
->set('purge_excluded_users_roles', ['administrator'])
->set('purge_included_users_roles', ['authenticated'])
// Set purge email subject + body.
// The text must be like this, to match the text in the assertions.
->set('inactive_user_notify_subject', 'Dear user')
->set('inactive_user_notify_text', 'Dear User, Your account has been deleted due the website’s policy to automatically remove users who match certain criteria. If you have concerns regarding the deletion, please talk to the administrator of the website. Thank you')
// Set pre-notify email subject + body.
->set('user_before_deletion_subject', 'Dear user')
->set('user_before_deletion_text', 'Dear User, Your account will be deleted soon due the website’s policy to automatically remove users who match certain criteria. If you have concerns regarding the deletion, please talk to the administrator of the website. Thank you')
// Purge regular users after 5 days of not logging in.
->set('user_lastlogin_value', '5')
->set('user_lastlogin_period', 'days')
->set('enabled_loggedin_users', TRUE)
// Purge never-logged-in users after 5 days.
->set('user_never_lastlogin_value', '5')
->set('user_never_lastlogin_period', 'days')
->set('enabled_never_loggedin_users', TRUE)
// Purge blocked users after 5 days.
->set('user_blocked_value', '5')
->set('user_blocked_period', 'days')
->set('enabled_blocked_users', TRUE)
// Purge inactive users after 5 days.
->set('user_inactive_value', '5')
->set('user_inactive_period', 'days')
->set('enabled_inactive_users', TRUE)
// Send pre-notification after 2 days.
->set('user_before_notification_value', '2')
->set('user_before_notification_period', 'days')
->set('send_email_user_before_notification', TRUE)
// Send purge email.
->set('send_email_notification', TRUE)
// Delete users on purge.
->set('purge_user_cancel_method', 'user_cancel_block')
// Purge on cron run.
->set('purge_on_cron', TRUE)
->save();
$this->admin = $this->createUser([
'administer site configuration',
'administer permissions',
'administer account settings',
'administer users',
], NULL, TRUE, [
'mail' => 'admin@test.test',
]);
$this->activeUser = $this->createUser([], NULL, FALSE, [
'mail' => 'activeUser@test.test',
'created' => strtotime('-2 day'),
'login' => strtotime('-1 day'),
'status' => 1,
]);
$this->inactiveUser7Days = $this->createUser([], NULL, FALSE, [
'mail' => 'inactiveUser7Days@test.test',
'created' => strtotime('-7 day'),
'login' => 0,
'status' => 0,
]);
$this->inactiveUser4Days = $this->createUser([], NULL, FALSE, [
'mail' => 'inactiveUser4Days@test.test',
'created' => strtotime('-4 day'),
'login' => 0,
'status' => 0,
]);
$this->lastloginUser7Days = $this->createUser([], NULL, FALSE, [
'mail' => 'lastloginUser7Days@test.test',
'created' => strtotime('-7 day'),
'login' => strtotime('-7 day'),
'status' => 1,
]);
$this->lastloginUser4Days = $this->createUser([], NULL, FALSE, [
'mail' => 'lastloginUser4Days@test.test',
'created' => strtotime('-4 day'),
'login' => strtotime('-4 day'),
'status' => 1,
]);
$this->blockedUser7Days = $this->createUser([], NULL, FALSE, [
'mail' => 'blockedUser7Days@test.test',
'created' => strtotime('-7 day'),
'login' => strtotime('-7 day'),
'status' => 0,
]);
$this->blockedUser4Days = $this->createUser([], NULL, FALSE, [
'mail' => 'blockedUser4Days@test.test',
'created' => strtotime('-4 day'),
'login' => strtotime('-4 day'),
'status' => 0,
]);
$this->neverLoggedUser7Days = $this->createUser([], NULL, FALSE, [
'mail' => 'neverLoggedUser7Days@test.test',
'created' => strtotime('-7 day'),
'login' => 0,
'status' => 1,
]);
$this->neverLoggedUser4Days = $this->createUser([], NULL, FALSE, [
'mail' => 'neverLoggedUser4Days@test.test',
'created' => strtotime('-4 day'),
'login' => 0,
'status' => 1,
]);
$this->notifyManager = $this->container->get('purge_users.user_management');
/** @var \Drupal\Core\Entity\EntityTypeManagerInterface $etm */
$etm = $this->container->get('entity_type.manager');
$this->userStorage = $etm->getStorage('user');
$this->drupalLogin($this->admin);
}
/**
* Tests purging without email notifications.
*
* @param string $mode
* One of 'form' or 'cron'.
*
* @testWith ["form"]
* ["cron"]
*/
public function testNoEmails(string $mode): void {
$this->config('purge_users.settings')
->set('send_email_user_before_notification', FALSE)
->set('send_email_notification', FALSE)
->save();
$this->runPurgeOperation($mode);
// No emails are sent.
$this->assertCount(0, $this->getMails());
}
/**
* Tests basic notifications after a purge operation.
*
* @param string $mode
* One of 'form' or 'cron'.
*
* @testWith ["form"]
* ["cron"]
*/
public function testNotifications(string $mode): void {
// Run the purge operation with default settings from setUp().
$this->runPurgeOperation($mode);
// Users who are already blocked are not being purged.
$this->assertPurgeEmail($this->lastloginUser7Days);
$this->assertPurgeEmail($this->neverLoggedUser7Days);
// The 4 day users receive a pre-notification email.
$this->assertPreNotificationEmail($this->inactiveUser4Days);
$this->assertPreNotificationEmail($this->lastloginUser4Days);
$this->assertPreNotificationEmail($this->blockedUser4Days);
$this->assertPreNotificationEmail($this->neverLoggedUser4Days);
// No further emails.
$this->assertCount(6, $this->getMails());
// Run the purge operation again. This should have no effect.
$this->runPurgeOperation($mode);
// No additional emails are sent.
$this->assertCount(6, $this->getMails());
}
/**
* Tests purging users who were pre-notified in the past.
*
* @param string $mode
* One of 'form' or 'cron'.
*
* @testWith ["form"]
* ["cron"]
*/
public function testPreNotifiedUsers(string $mode): void {
// Simulate users having been notified in the past.
$this->preNotifyUsers();
$this->assertPreNotificationEmail($this->inactiveUser7Days);
$this->assertPreNotificationEmail($this->lastloginUser7Days);
$this->assertPreNotificationEmail($this->blockedUser7Days);
$this->assertPreNotificationEmail($this->neverLoggedUser7Days);
$this->assertPreNotificationEmail($this->inactiveUser4Days);
$this->assertPreNotificationEmail($this->lastloginUser4Days);
$this->assertPreNotificationEmail($this->blockedUser4Days);
$this->assertPreNotificationEmail($this->neverLoggedUser4Days);
// No further emails.
$this->assertCount(8, $this->getMails());
$this->runPurgeOperation($mode);
// Users who were not already blocked are not being purged.
$this->assertPurgeEmail($this->lastloginUser7Days);
$this->assertPurgeEmail($this->neverLoggedUser7Days);
// No further emails.
// No further pre-notifications are sent.
$this->assertCount(10, $this->getMails());
$this->runPurgeOperation($mode);
// Verify no additional emails are sent.
$this->assertCount(10, $this->getMails());
}
/**
* Tests purging of users who have been purged and unblocked in the past.
*
* @param string $mode
* One of 'form' or 'cron'.
*
* @testWith ["form"]
* ["cron"]
*/
public function testBlockUnblockBlock(string $mode): void {
// Run the purge operation with default settings from setUp().
$this->runPurgeOperation($mode);
// Users who are already blocked are not being purged.
$this->assertPurgeEmail($this->lastloginUser7Days);
$this->assertPurgeEmail($this->neverLoggedUser7Days);
// The 4 day users receive a pre-notification email.
$this->assertPreNotificationEmail($this->inactiveUser4Days);
$this->assertPreNotificationEmail($this->lastloginUser4Days);
$this->assertPreNotificationEmail($this->blockedUser4Days);
$this->assertPreNotificationEmail($this->neverLoggedUser4Days);
// No further emails.
$this->assertCount(6, $this->getMails());
// Run the purge operation again. This should have no effect.
$this->runPurgeOperation($mode);
// No additional emails are sent.
$this->assertCount(6, $this->getMails());
// Unblock one user.
// This should be done with a fresh instance for the user object.
/** @var \Drupal\user\UserInterface $user */
$user = $this->userStorage->loadUnchanged($this->lastloginUser7Days->id());
$user->activate();
$user->save();
// The user is now unblocked.
/** @var \Drupal\user\UserInterface $user */
$user = $this->userStorage->loadUnchanged($this->lastloginUser7Days->id());
self::assertFalse($user->isBlocked());
// User receives an unblock email from core user module.
$this->assertMail('id', 'user_status_activated');
$this->assertCount(7, $this->getMails());
// Run the purge operation again. This should have no effect.
$this->runPurgeOperation($mode);
// The user is now blocked.
/** @var \Drupal\user\UserInterface $user */
$user = $this->userStorage->loadUnchanged($this->lastloginUser7Days->id());
self::assertTrue($user->isBlocked());
// And yet, no additional emails was sent.
// @todo Decide if this is the correct behavior.
$this->assertCount(7, $this->getMails());
}
/**
* Tests that a user who must be purged only receives the deletion email.
*/
public function testUserDeletionNotification(): void {
$user = $this->createUser([], NULL, FALSE, [
'mail' => 'inactiveUser11Days@test.test',
'created' => strtotime('-11 day'),
'login' => 0,
'status' => 0,
]);
// Override the configuration to only target this user.
$this->config('purge_users.settings')
// Disable all but one purge condition.
->set('enabled_loggedin_users', FALSE)
->set('enabled_never_loggedin_users', FALSE)
->set('enabled_blocked_users', FALSE)
// Purge condition: Inactive users, 10 days.
// This does not match for any of the users in setUp().
->set('user_inactive_value', '10')
->set('user_inactive_period', 'days')
->set('enabled_inactive_users', TRUE)
// Send pre-notification after 8 days.
->set('user_before_notification_value', '8')
->set('user_before_notification_period', 'days')
->set('send_email_user_before_notification', TRUE)
// Send purge email.
->set('send_email_notification', TRUE)
// Change the purge method, to be sure the user is being deleted.
->set('purge_user_cancel_method', 'user_cancel_delete')
->save();
$this->drupalGet('admin/people/purge-rule/confirm');
$this->submitForm([], 'Confirm');
$this->assertPurgeEmail($user);
// No further emails.
// One deletion email and 2 pre-notification emails (4 days and 7 days).
$this->assertCount(3, $this->getMails());
$this->cronRun();
// Check the user does not receive any other notification.
$this->assertCount(3, $this->getMails());
}
/**
* Tests notification with user settings and purge notifications.
*/
public function testUserAccountSettingsNotification() {
$this->config('user.settings')
// Send core user module notifications when user is blocked.
->set('notify.status_blocked', TRUE)
->save();
$this->config('purge_users.settings')
// Don't send purge email.
->set('send_email_notification', FALSE)
->save();
$this->drupalGet('admin/people/purge-rule/confirm');
$this->submitForm([], 'Confirm');
// Two of the 7 day users are now blocked, who were not blocked before.
// These receive an email from core user module.
$this->assertAccountSettingsEmail($this->lastloginUser7Days);
$this->assertAccountSettingsEmail($this->neverLoggedUser7Days);
// The 4 day users all receive the pre-notification email.
$this->assertPreNotificationEmail($this->inactiveUser4Days);
$this->assertPreNotificationEmail($this->lastloginUser4Days);
$this->assertPreNotificationEmail($this->blockedUser4Days);
$this->assertPreNotificationEmail($this->neverLoggedUser4Days);
// No further emails.
$this->assertCount(6, $this->getMails());
$this->drupalGet('admin/people/purge-rule/confirm');
$this->submitForm([], 'Confirm');
// Verify no additional emails are sent.
$this->assertCount(6, $this->getMails());
}
/**
* Asserts the purge email.
*
* @param \Drupal\user\UserInterface $user
* The user email.
*/
protected function assertPurgeEmail(UserInterface $user): void {
$expected = [
'id' => 'purge_users_delete_users',
'module' => 'purge_users',
'key' => 'delete_users',
'to' => $user->getEmail(),
'from' => 'simpletest@example.com',
'reply-to' => NULL,
'langcode' => 'en',
'params' => [
'subject' => 'Dear user',
'body' => 'Dear User, Your account has been deleted due the website’s policy to automatically remove users who match certain criteria. If you have concerns regarding the deletion, please talk to the administrator of the website. Thank you',
],
'send' => TRUE,
'subject' => 'Dear user',
'body' => "Dear User, Your account has been deleted due the website’s policy to \nautomatically remove users who match certain criteria. If you have concerns \nregarding the deletion, please talk to the administrator of the website. \nThank you\n",
'headers' => [
'MIME-Version' => '1.0',
'Content-Type' => 'text/plain; charset=UTF-8; format=flowed; delsp=yes',
'X-Mailer' => 'Drupal',
'Return-Path' => 'simpletest@example.com',
'Sender' => 'simpletest@example.com',
'From' => 'Drupal <simpletest@example.com>',
'Content-Transfer-Encoding' => '8Bit',
],
];
$actual = $this->getMails([
'to' => $user->getEmail(),
'key' => 'delete_users',
])[0];
$this->assertEquals($expected, $actual);
}
/**
* Asserts the pre-notification email.
*
* @param \Drupal\user\UserInterface $user
* The user email.
*/
protected function assertPreNotificationEmail(UserInterface $user): void {
$expected = [
'id' => 'purge_users_cancel_users',
'module' => 'purge_users',
'key' => 'cancel_users',
'to' => $user->getEmail(),
'from' => 'simpletest@example.com',
'reply-to' => NULL,
'langcode' => 'en',
'params' => [
'subject' => 'Dear user',
'body' => 'Dear User, Your account will be deleted soon due the website’s policy to automatically remove users who match certain criteria. If you have concerns regarding the deletion, please talk to the administrator of the website. Thank you',
],
'send' => TRUE,
'subject' => 'Dear user',
'body' => "Dear User, Your account will be deleted soon due the website’s policy to \nautomatically remove users who match certain criteria. If you have concerns \nregarding the deletion, please talk to the administrator of the website. \nThank you\n",
'headers' => [
'MIME-Version' => '1.0',
'Content-Type' => 'text/plain; charset=UTF-8; format=flowed; delsp=yes',
'X-Mailer' => 'Drupal',
'Return-Path' => 'simpletest@example.com',
'Sender' => 'simpletest@example.com',
'From' => 'Drupal <simpletest@example.com>',
'Content-Transfer-Encoding' => '8Bit',
],
];
$actual = $this->getMails([
'to' => $user->getEmail(),
'key' => 'cancel_users',
])[0];
$this->assertEquals($expected, $actual);
}
/**
* Asserts the account settings email.
*
* @param \Drupal\user\UserInterface $user
* The notified user.
*/
protected function assertAccountSettingsEmail(UserInterface $user): void {
$username = $user->getDisplayName();
$expected = [
'id' => 'user_status_blocked',
'module' => 'user',
'key' => 'status_blocked',
'to' => $user->getEmail(),
'from' => 'simpletest@example.com',
'reply-to' => 'simpletest@example.com',
'langcode' => 'en',
'send' => TRUE,
'subject' => "Account details for $username at Drupal (blocked)",
'body' => "$username,\n\nYour account on Drupal has been blocked.\n\n-- Drupal team\n",
'headers' => [
'MIME-Version' => '1.0',
'Content-Type' => 'text/plain; charset=UTF-8; format=flowed; delsp=yes',
'Content-Transfer-Encoding' => '8Bit',
'X-Mailer' => 'Drupal',
'Return-Path' => 'simpletest@example.com',
'Sender' => 'simpletest@example.com',
'From' => 'Drupal <simpletest@example.com>',
'Reply-to' => 'simpletest@example.com',
],
];
$actual = $this->getMails([
'to' => $user->getEmail(),
'key' => 'status_blocked',
])[0];
// Unset params, it contains the account object
// with dynamic data such as password.
unset($actual['params']);
$this->assertEquals($expected, $actual);
}
/**
* Sends pre-notifications to all test users.
*/
protected function preNotifyUsers(): void {
$this->notifyManager->notifyUser($this->inactiveUser7Days);
$this->notifyManager->notifyUser($this->lastloginUser7Days);
$this->notifyManager->notifyUser($this->blockedUser7Days);
$this->notifyManager->notifyUser($this->neverLoggedUser7Days);
$this->notifyManager->notifyUser($this->inactiveUser4Days);
$this->notifyManager->notifyUser($this->lastloginUser4Days);
$this->notifyManager->notifyUser($this->blockedUser4Days);
$this->notifyManager->notifyUser($this->neverLoggedUser4Days);
}
/**
* Purges users through the admin UI or cron.
*
* @param string $mode
* One of 'form' or 'cron'.
*/
protected function runPurgeOperation(string $mode): void {
if ($mode === 'form') {
$this->drupalGet('admin/people/purge-rule/confirm');
$this->submitForm([], 'Confirm');
}
elseif ($mode === 'cron') {
$this->cronRun();
}
else {
// Detect programming errors.
throw new \InvalidArgumentException('Invalid purge mode provided.');
}
}
}
