purge_users-8.x-2.0/purge_users.module
purge_users.module
<?php
/**
* @file
* Purge users module file.
*/
use Drupal\Component\Utility\Html;
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Implements hook_help().
*/
function purge_users_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.purge_users':
$text = file_get_contents(__DIR__ . '/README.md');
if (!\Drupal::moduleHandler()->moduleExists('markdown')) {
return '<pre>' . Html::escape($text) . '</pre>';
}
else {
// Use the Markdown filter to render the README.
$filter_manager = \Drupal::service('plugin.manager.filter');
$settings = \Drupal::configFactory()->get('markdown.settings')->getRawData();
$config = ['settings' => $settings];
$filter = $filter_manager->createInstance('markdown', $config);
return $filter->process($text, 'en');
}
}
return NULL;
}
/**
* Implements hook_cron().
*/
function purge_users_cron() {
$config = \Drupal::config('purge_users.settings');
if ($config->get('purge_on_cron') == 1) {
$op = 'purge_users';
$user_ids = purge_users_get_user_ids($op);
// Add items to queue.
/** @var \Drupal\Core\Queue\QueueFactory $queue_factory */
$queue_factory = \Drupal::service('queue');
$queue = $queue_factory->get($op);
// Process the queue till it is empty.
if ($queue->numberOfItems() == 0) {
foreach ($user_ids as $user_id) {
$queue->createItem($user_id);
}
}
}
if ($config->get('send_email_user_before_notification') == 1) {
$op = 'notification_users';
$user_ids = array_unique(purge_users_get_user_ids($op));
// Add items to queue.
/** @var \Drupal\Core\Queue\QueueFactory $queue_factory */
$queue_factory = \Drupal::service('queue');
$queue = $queue_factory->get($op);
// Process the queue till it is empty.
if ($queue->numberOfItems() == 0) {
foreach ($user_ids as $user_id) {
$queue->createItem($user_id);
}
}
}
}
/**
* Get users who never login at all.
*/
function purge_users_never_loggedin_user_ids($param, $included_user_roles = [], $excluded_user_roles = []) {
// Query through db table to get users ids.
$db = \Drupal::database();
$query = _purge_users_query_initialize($db);
if (!empty($param['never_login_date'])) {
$query->condition('u.created', $param['never_login_date'], '<');
$query->condition('u.login', 0);
}
if ($param['disregard_blocked_users']) {
$query->condition('u.status', 1);
}
_purge_users_query_included_user_roles($db, $query, $included_user_roles);
_purge_users_query_excluded_user_roles($db, $query, $excluded_user_roles);
$uids = $query->execute()->fetchCol();
// Allow other modules to modify the result.
\Drupal::moduleHandler()->alter('purge_never_loggedin_user_ids', $uids);
return $uids;
}
/**
* Get users who didn't login at all.
*/
function purge_users_not_loggedin_user_ids($param, $included_user_roles = [], $excluded_user_roles = []) {
// Query through db table to get users ids.
$db = \Drupal::database();
$query = _purge_users_query_initialize($db);
if (!empty($param['login_date'])) {
$query->condition('u.login', $param['login_date'], '<');
$query->condition('u.login', 0, '!=');
}
if ($param['disregard_blocked_users']) {
$query->condition('u.status', 1);
}
_purge_users_query_ignore_author_or_commenter($query, $param);
_purge_users_query_included_user_roles($db, $query, $included_user_roles);
_purge_users_query_excluded_user_roles($db, $query, $excluded_user_roles);
$uids = $query->execute()->fetchCol();
// Allow other modules to modify the result.
\Drupal::moduleHandler()->alter('purge_not_loggedin_user_ids', $uids);
return $uids;
}
/**
* Get inactive user ids.
*/
function purge_users_inactive_user_ids($param, $included_user_roles = [], $excluded_user_roles = []) {
// Query through db table to get users ids.
$db = \Drupal::database();
$query = _purge_users_query_initialize($db);
if (!empty($param['inactive_date'])) {
$query->condition('u.created', $param['inactive_date'], '<');
$query->condition('u.login', 0);
$query->condition('u.status', 0);
}
_purge_users_query_included_user_roles($db, $query, $included_user_roles);
_purge_users_query_excluded_user_roles($db, $query, $excluded_user_roles);
$uids = $query->execute()->fetchCol();
// Allow other modules to modify the result.
\Drupal::moduleHandler()->alter('purge_inactive_user_ids', $uids);
return $uids;
}
/**
* Get blocked user ids.
*/
function purge_users_blocked_user_ids($param, $included_user_roles = [], $excluded_user_roles = []) {
// Query through db table to get users ids.
$db = \Drupal::database();
$query = _purge_users_query_initialize($db);
if (!empty($param['blocked_date'])) {
$query->condition('u.created', $param['blocked_date'], '<');
$query->condition('u.login', $param['blocked_date'], '<');
$query->condition('u.login', 0, '!=');
$query->condition('u.status', 0);
}
_purge_users_query_ignore_author_or_commenter($query, $param);
_purge_users_query_included_user_roles($db, $query, $included_user_roles);
_purge_users_query_excluded_user_roles($db, $query, $excluded_user_roles);
$uids = $query->execute()->fetchCol();
// Allow other modules to modify the result.
\Drupal::moduleHandler()->alter('purge_blocked_user_ids', $uids);
return $uids;
}
/**
* Initialize the user query.
*
* We filter out the "root" user.
*
* @param \Drupal\Core\Database\Connection $db
* The database connection.
*
* @return \Drupal\Core\Database\Query\SelectInterface
* The query object.
*/
function _purge_users_query_initialize(Connection $db): SelectInterface {
$query = $db->select('users_field_data', 'u')->distinct();
$query->fields('u', ['uid']);
$query->condition('u.uid', 1, '>');
return $query;
}
/**
* Add user roles to include in the query.
*
* @param \Drupal\Core\Database\Connection $db
* The database object.
* @param \Drupal\Core\Database\Query\SelectInterface $query
* The query object.
* @param array $included_user_roles
* An array of roles to include.
*/
function _purge_users_query_included_user_roles(Connection $db, SelectInterface $query, array $included_user_roles) {
$query->leftjoin('user__roles', 'ur', 'ur.entity_id = u.uid');
$exist_query = $db->select('user__roles', 'ur');
$exist_query->fields('ur', ['entity_id']);
$exist_query->where('ur.entity_id = u.uid');
$exist_query->condition('ur.roles_target_id', $included_user_roles, 'IN');
if (in_array(AccountInterface::AUTHENTICATED_ROLE, $included_user_roles)) {
$db_or = $db->condition('OR');
$db_or->isNull('ur.roles_target_id');
$db_or->exists($exist_query);
$query->condition($db_or);
}
else {
$query->exists($exist_query);
}
}
/**
* Add user roles to exclude from the query.
*
* @param \Drupal\Core\Database\Connection $db
* The database object.
* @param \Drupal\Core\Database\Query\SelectInterface $query
* The query object.
* @param array $excluded_user_roles
* An array of roles to exclude.
*/
function _purge_users_query_excluded_user_roles(Connection $db, SelectInterface $query, array $excluded_user_roles) {
if (!empty($excluded_user_roles)) {
$not_exist_query = $db->select('user__roles', 'ur');
$not_exist_query->fields('ur', ['entity_id']);
$not_exist_query->where('ur.entity_id = u.uid');
$not_exist_query->condition('ur.roles_target_id', $excluded_user_roles, 'IN');
$query->notExists($not_exist_query);
}
}
/**
* Filter out author or commenter if configured.
*
* @param \Drupal\Core\Database\Query\SelectInterface $query
* The query.
* @param array $param
* The parameters.
*/
function _purge_users_query_ignore_author_or_commenter(SelectInterface $query, array $param) {
if ($param['enabled_do_not_purge_authors']) {
$query->leftjoin('node_field_data', 'nfd', 'nfd.uid = u.uid');
$query->isNull('nfd.uid');
}
if ($param['enabled_do_not_purge_commenters']) {
$query->leftjoin('comment_field_data', 'cfd', 'cfd.uid = u.uid');
$query->isNull('cfd.uid');
}
}
/**
* The batch finish handler.
*/
function purge_users_batch_completed($success, $results, $operations) {
if ($success) {
$purged = $results['purged'] ?? 0;
$message = t('@count Users has been purged.', ['@count' => $purged]);
\Drupal::messenger()->addMessage($message);
}
else {
$error_operation = reset($operations);
$message = t('An error occurred while processing %error_operation with arguments: @arguments', [
'%error_operation' => $error_operation[0],
'@arguments' => print_r($error_operation[1], TRUE),
]);
\Drupal::messenger()->addError($message);
}
return new RedirectResponse(Url::fromRoute('purge_users.settings')
->toString());
}
/**
* Get user ids to purge.
*
* @param string $op
* One of 'purge_users' or 'notification_users'.
*
* @return int[]
* User ids to purge or to pre-notify.
*/
function purge_users_get_user_ids(string $op = 'purge_users') {
$user_ids = _purge_users_get_user_ids($op);
if ($op === 'purge_users') {
return $user_ids;
}
// Don't pre-notify users who are being purged.
return array_diff($user_ids, _purge_users_get_user_ids());
}
/**
* Get user ids to purge.
*
* @param string $op
* One of 'purge_users' or 'notification_users'.
*
* @return int[]
* User ids to purge or to pre-notify.
*/
function _purge_users_get_user_ids(string $op = 'purge_users') {
// Get form submissions.
$config = \Drupal::config('purge_users.settings');
$enable_never_loggedin = $config->get('enabled_never_loggedin_users');
$enable_loggedin = $config->get('enabled_loggedin_users');
$enable_inactive = $config->get('enabled_inactive_users');
$enable_blocked = $config->get('enabled_blocked_users');
$send_email_user_before_notification = $config->get('send_email_user_before_notification');
$param['disregard_blocked_users'] = $config->get('disregard_blocked_users');
$param['enabled_do_not_purge_authors'] = $config->get('enabled_do_not_purge_authors');
$param['enabled_do_not_purge_commenters'] = $config->get('enabled_do_not_purge_commenters');
if ($enable_never_loggedin) {
$param['never_login_date'] = strtotime('-' . $config->get('user_never_lastlogin_value') . ' ' . $config->get('user_never_lastlogin_period'));
}
if ($enable_loggedin) {
$param['login_date'] = strtotime('-' . $config->get('user_lastlogin_value') . ' ' . $config->get('user_lastlogin_period'));
}
if ($enable_inactive) {
$param['inactive_date'] = strtotime('-' . $config->get('user_inactive_value') . ' ' . $config->get('user_inactive_period'));
}
if ($enable_blocked) {
$param['blocked_date'] = strtotime('-' . $config->get('user_blocked_value') . ' ' . $config->get('user_blocked_period'));
}
if ($op == 'notification_users' && $send_email_user_before_notification == 1) {
$user_before_notification_value = $config->get('user_before_notification_value');
$user_before_notification_period = $config->get('user_before_notification_period');
$notification_interval = '+' . $user_before_notification_value . ' ' . $user_before_notification_period;
if ($enable_never_loggedin) {
$param['never_login_date'] = strtotime($notification_interval, $param['never_login_date']);
}
if ($enable_loggedin) {
$param['login_date'] = strtotime($notification_interval, $param['login_date']);
}
if ($enable_inactive) {
$param['inactive_date'] = strtotime($notification_interval, $param['inactive_date']);
}
if ($enable_blocked) {
$param['blocked_date'] = strtotime($notification_interval, $param['blocked_date']);
}
}
$included_user_roles = array_filter($config->get('purge_included_users_roles'));
$excluded_user_roles = array_filter($config->get('purge_excluded_users_roles'));
// Get user ids to purge.
$never_loggedin_users = [];
$not_loggedin_users = [];
$inactive_users = [];
$blocked_users = [];
// Get users who have never logged in at all.
if ($enable_never_loggedin == 1) {
$never_loggedin_users = purge_users_never_loggedin_user_ids($param, $included_user_roles, $excluded_user_roles);
}
// Get users who have not logged in at all.
if ($enable_loggedin == 1) {
$not_loggedin_users = purge_users_not_loggedin_user_ids($param, $included_user_roles, $excluded_user_roles);
}
// Get users who didn't activate their account.
if ($enable_inactive == 1) {
$inactive_users = purge_users_inactive_user_ids($param, $included_user_roles, $excluded_user_roles);
}
// Get the users who are blocked.
if ($enable_blocked == 1) {
$blocked_users = purge_users_blocked_user_ids($param, $included_user_roles, $excluded_user_roles);
}
// Merge results to create an array of user ids to purge.
$result = array_merge($never_loggedin_users, $not_loggedin_users, $inactive_users, $blocked_users);
return array_unique($result);
}
/**
* Send notification email.
*/
function purge_users_send_notification_email($account, $op = 'user_deletion') {
// Email to be sent to this Email ID.
/** @var \Drupal\Core\Mail\MailManagerInterface $mailManager */
$mailManager = \Drupal::service('plugin.manager.mail');
$module = 'purge_users';
$key = 'delete_users';
$to = $account->get('mail')->value;
if (empty($to)) {
$logger = \Drupal::logger('notification_users');
$logger->notice('Cannot send notification to user "%name", his email is undefined.', [
'%name' => $account->getAccountName(),
]);
return FALSE;
}
$language_manager = \Drupal::languageManager();
$langcode = $account->getPreferredLangcode();
$language = $language_manager->getLanguage($langcode);
$original_language = $language_manager->getConfigOverrideLanguage();
$language_manager->setConfigOverrideLanguage($language);
$config = \Drupal::config('purge_users.settings');
$message = $config->get('inactive_user_notify_text');
$subject = $config->get('inactive_user_notify_subject');
if ($op == 'notification_users') {
$key = 'cancel_users';
$subject = $config->get('user_before_deletion_subject');
$message = $config->get('user_before_deletion_text');
}
$moduleHandler = \Drupal::service('module_handler');
if ($moduleHandler->moduleExists('token')) {
$token_service = \Drupal::token();
$message = $token_service->replace($message, ['user' => $account]);
}
$params = [
'subject' => $subject,
'body' => $message,
];
$send = TRUE;
$result = $mailManager->mail($module, $key, $to, $langcode, $params, NULL, $send);
$language_manager->setConfigOverrideLanguage($original_language);
return $result['result'] ?? FALSE;
}
/**
* Implements hook_mail().
*/
function purge_users_mail($key, &$message, $params) {
switch ($key) {
case 'delete_users':
case 'cancel_users':
$message['subject'] = $params['subject'];
$message['body'][] = $params['body'];
break;
}
}
/**
* Implements hook_entity_delete().
*/
function purge_users_entity_delete(EntityInterface $entity) {
if ($entity->getEntityTypeId() !== 'user') {
return;
}
/** @var \Drupal\purge_users\Services\UserManagementServiceInterface $userManager */
$userManager = \Drupal::service('purge_users.user_management');
$userManager->removeNotificationFlags($entity->id());
}
