Commit 2dbbe1fb authored by Robert Lyon's avatar Robert Lyon
Browse files

Bug 1760767: Create a cli script to allow for bulk delete of users from commandline



To allow a server admin to clean up a site

The script should be able to:
- delete all users that have never logged in (created by admin)
- and/or delete all users that have not logged in since a certain date
- and/or delete only those users from a certain institution

The script has a 'dryrun' flag set to false by default to allow one to
check how many users will be deleted before actually doing the deletion

TODO
- do more checks

behatnotneeded

Change-Id: Ie73eb2daa6e8e1ae52d560ebcd149fec886d204c
Signed-off-by: Robert Lyon's avatarRobert Lyon <robertl@catalyst.net.nz>
parent 0c79b7c5
<?php
/**
*
* @package mahara
* @subpackage core
* @author Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
define('INTERNAL', 1);
define('CLI', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
require_once(get_config('docroot') . 'auth/lib.php');
require(get_config('libroot') . 'cli.php');
$cli = get_cli();
$options = array();
$options['dryrun'] = (object) array(
'shortoptions' => array('d'),
'description' => get_string('cli_deleteinactiveusers_dryrun', 'admin'),
'required' => false,
'defaultvalue' => true,
);
$options['institution'] = (object) array(
'shortoptions' => array('i'),
'description' => get_string('institutionshortname', 'admin'),
'required' => false,
'defaultvalue' => false,
'examplevalue' => 'mahara',
);
$options['beforedate'] = (object) array(
'shortoptions' => array('b'),
'description' => get_string('cli_deleteinactiveusers_beforedate', 'admin'),
'required' => false,
'defaultvalue' => false,
);
$options['limit'] = (object) array(
'shortoptions' => array('l'),
'description' => get_string('cli_deleteinactiveusers_limit', 'admin'),
'required' => false,
'defaultvalue' => 100,
);
define('CLI_DELETEINACTIVE_CLEANUSERS_DEFAULT', -1);
$options['cleanusers'] = (object) array(
'shortoptions' => array('c'),
'description' => get_string('cli_deleteinactiveusers_cleanusers', 'admin'),
'required' => false,
'defaultvalue' => CLI_DELETEINACTIVE_CLEANUSERS_DEFAULT,
);
define('CLI_DELETEINACTIVE_NEVERLOGGEDIN_DEFAULT', -1);
$options['neverloggedin'] = (object) array(
'shortoptions' => array('n'),
'description' => get_string('cli_deleteinactiveusers_neverloggedin', 'admin'),
'required' => false,
'defaultvalue' => CLI_DELETEINACTIVE_NEVERLOGGEDIN_DEFAULT,
);
$settings = (object) array(
'info' => get_string('cli_deleteinactiveusers_info', 'admin'),
'options' => $options,
);
$cli->setup($settings);
$dryrun = $cli->get_cli_param_boolean('dryrun');
$institution = $cli->get_cli_param('institution');
// Retrieve & validate the before date
$beforedate = $cli->get_cli_param('beforedate');
if ($beforedate) {
if (strtotime($beforedate)) {
$beforedate = date('Y-m-d H:i:s', strtotime($beforedate));
}
else {
$cli->cli_exit(get_string('cli_deleteinactiveusers_baddate', 'admin', $beforedate), true);
}
}
// Determine whether or not to clean up all user data incl info from forum posts / usr table.
if ($cli->get_cli_param('cleanusers') === CLI_DELETEINACTIVE_CLEANUSERS_DEFAULT) {
// The default behavior
$cleanusers = false;
}
else {
// If they specified the cleanusers param, we respect that
$cleanusers = $cli->get_cli_param_boolean('cleanusers');
}
// Determine whether or not to only delete users that have never logged in.
if ($cli->get_cli_param('neverloggedin') === CLI_DELETEINACTIVE_NEVERLOGGEDIN_DEFAULT) {
// The default behavior
$neverloggedin = true;
}
else {
// If they specified the neverloggedin param, we respect that
$neverloggedin = $cli->get_cli_param_boolean('neverloggedin');
}
// Find all the users we need to deal with based on the params provided
$selectsql = "SELECT u.id, u.username FROM {usr} u";
$joinsql = "";
$wheresql = " WHERE u.id != 0";
$values = array();
if ($institution) {
$joinsql .= " JOIN {usr_institution} ui ON ui.usr = u.id";
$wheresql .= " AND ui.institution = ?";
$values[] = $institution;
}
if ($beforedate && $neverloggedin) {
$wheresql .= " AND (u.lastlogin < DATE(?) OR u.lastlogin IS NULL)";
$values[] = $beforedate;
}
else if ($beforedate && !$neverloggedin) {
$wheresql .= " AND u.lastlogin < DATE(?)";
$values[] = $beforedate;
}
else if ($neverloggedin) {
$wheresql .= " AND u.lastlogin IS NULL";
}
if (!$beforedate && !$neverloggedin) {
// If we do not set a before date and / or never logged in flag then we are only using this script to
// try and clean up the deleted users from the 'usr' table
$wheresql .= " AND u.deleted = 1";
}
else if (!$cleanusers) {
$wheresql .= " AND u.deleted = 0";
}
if ($dryrun) {
$cli->cli_print(get_string('cli_deleteinactiveusers_onlydryrun', 'admin', $institution, $beforedate, $cleanusers, $neverloggedin));
}
if ($records = get_records_sql_array($selectsql . $joinsql . $wheresql, $values)) {
$total = count($records);
$cli->cli_print(get_string('cli_deleteinactiveusers_usercount', 'admin', $total));
// We will need to batch things so the database/site doesn't stress out
$count = 0;
$limit = $cli->get_cli_param('limit');
if (!$dryrun) {
$cli->cli_print("--- " . date('Y-m-d H:i:s', time()) . " ---");
foreach ($records as $record) {
delete_user($record->id);
if ($cleanusers) {
try {
$DB_IGNORE_SQL_EXCEPTIONS = true;
delete_records('usr', 'id', $record->id);
$DB_IGNORE_SQL_EXCEPTIONS = false;
}
catch (SQLException $e) {
$cli->cli_print(get_string('cli_deleteinactiveusers_userunabletoclean', 'admin', $record->username, $record->id));
}
}
$count++;
if (($count % $limit) == 0 || $count == $total) {
$cli->cli_print("$count/$total");
set_time_limit(30);
}
}
$cli->cli_print("--- " . date('Y-m-d H:i:s', time()) . " ---");
}
}
else {
$cli->cli_print(get_string('cli_deleteinactiveusers_nouserstodelete', 'admin'));
}
$cli->cli_exit(get_string('done'));
\ No newline at end of file
......@@ -1333,6 +1333,23 @@ $string['cli_unabletoupdatecron'] = 'Unable to update the search cron database r
$string['cli_problemindexing'] = 'A problem occurred while indexing';
$string['cli_done'] = 'Indexing finished';
// Clean up old users
$string['cli_deleteinactiveusers_dryrun'] = 'Dry run to indicate what will happen. Set to "true" by default. Need to set -d=false to actually update database.';
$string['cli_deleteinactiveusers_beforedate'] = 'Delete users that have not logged in after this date';
$string['cli_deleteinactiveusers_limit'] = 'Limit of users to work with for each delete run';
$string['cli_deleteinactiveusers_cleanusers'] = 'Delete users from the "usr" table as well';
$string['cli_deleteinactiveusers_info'] = 'This command-line PHP script allows you to delete old users. This will only work for users who either have not logged in or have never made a forum post.';
$string['cli_deleteinactiveusers_neverloggedin'] = 'Delete users that have never logged in (were setup by an admin)';
$string['cli_deleteinactiveusers_baddate'] = 'The supplied date "%s" is not valid.';
$string['cli_deleteinactiveusers_usercount'] = 'There are "%s" users to delete';
$string['cli_deleteinactiveusers_userunabletoclean'] = 'Unable to fully delete user "%s" (ID %s)';
$string['cli_deleteinactiveusers_nouserstodelete'] = 'There are no users to delete.';
$string['cli_deleteinactiveusers_onlydryrun'] = 'This is only a dry run with the following settings
Institution: %s
Before date: %s
Delete users from "usr" table: %s
Never logged in: %s';
$string['withselectedcontentexport'] = 'Re-queue items into the export queue';
$string['withselectedcontentdelete'] = 'Delete selected items from the export queue';
$string['allothers'] = 'All others';
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment