Commit bd0cd991 authored by Richard Mansfield's avatar Richard Mansfield
Browse files

Add new admin page for bulk user actions (bug #801069)



This page takes a list of user ids, filters it using the admin's
institutions (if institutional admin), and displays the list.

The admin can then either download the list as a CSV file, or suspend,
delete or change the auth instance of all the users in the list at once.

Change-Id: I792fa29403a0b5f818dceff1d9aab9e9cbd42661
Signed-off-by: default avatarRichard Mansfield <richard.mansfield@catalyst.net.nz>
parent efd2c596
<?php
/**
* Mahara: Electronic portfolio, weblog, resume builder and social networking
* Copyright (C) 2011 Catalyst IT Ltd and others; see:
* http://wiki.mahara.org/Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package mahara
* @subpackage admin
* @author Richard Mansfield
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
*
*/
define('INTERNAL', 1);
define('INSTITUTIONALADMIN', 1);
define('MENUITEM', 'configusers');
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
define('TITLE', get_string('bulkactions', 'admin'));
$userids = array_map('intval', param_variable('users'));
$ph = $userids;
$institutionsql = '';
if (!$USER->get('admin')) {
// Filter the users by the admin's institutions
$institutions = array_values($USER->get('admininstitutions'));
$ph = array_merge($ph, $institutions);
$institutionsql = '
AND id IN (
SELECT usr FROM {usr_institution} WHERE institution IN (' . join(',', array_fill(0, count($institutions), '?')) . ')
)';
}
$users = get_records_sql_assoc('
SELECT
u.id, u.username, u.email, u.firstname, u.lastname, u.suspendedcusr, u.authinstance, u.studentid,
u.preferredname, CHAR_LENGTH(u.password) AS haspassword, aru.remoteusername AS remoteuser
FROM {usr} u
LEFT JOIN {auth_remote_user} aru ON u.id = aru.localusr AND u.authinstance = aru.authinstance
WHERE id IN (' . join(',', array_fill(0, count($userids), '?')) . ')
AND deleted = 0' . $institutionsql . '
ORDER BY username',
$ph
);
$userids = array_keys($users);
// Export CSV
$csv = "username,email,firstname,lastname,studentid,preferredname,remoteuser\n";
foreach ($users as $user) {
$u = array();
foreach (array('username', 'email', 'firstname', 'lastname', 'studentid', 'preferredname', 'remoteuser') as $f) {
$u[] = str_replace('"', '""', $user->$f);
}
$csv .= '"' . join('","', $u) . '"' . "\n";
}
$USER->set_download_file($csv, 'users.csv', 'text/csv');
// Hidden drop-down to submit the list of users back to this page.
// Used in all three forms
$userelement = array(
'type' => 'select',
'class' => 'hidden',
'multiple' => 'true',
'options' => array_combine($userids, $userids),
'value' => $userids,
);
// Change authinstance
if ($USER->get('admin')) {
$authinstances = auth_get_auth_instances();
}
else {
$admininstitutions = $USER->get('admininstitutions');
$authinstances = auth_get_auth_instances_for_institutions($admininstitutions);
}
$options = array();
$default = null;
foreach ($authinstances as $authinstance) {
$options[$authinstance->id] = $authinstance->displayname. ': '.$authinstance->instancename;
if (!$default && $authinstance->name == 'mahara') {
$default = $authinstance->id;
}
}
$changeauthform = pieform(array(
'name' => 'changeauth',
'class' => 'bulkactionform',
'renderer' => 'oneline',
'dieaftersubmit' => false,
'elements' => array(
'users' => $userelement,
'title' => array(
'type' => 'html',
'class' => 'bulkaction-title',
'value' => get_string('changeauthmethod', 'admin') . ': ',
),
'authinstance' => array(
'type' => 'select',
'options' => $options,
'defaultvalue' => $default,
),
'changeauth' => array(
'type' => 'submit',
'value' => get_string('submit'),
),
),
));
// Suspend users
$suspendform = pieform(array(
'name' => 'suspend',
'class' => 'bulkactionform',
'renderer' => 'oneline',
'elements' => array(
'users' => $userelement,
'title' => array(
'type' => 'html',
'class' => 'bulkaction-title',
'value' => get_string('suspendusers', 'admin') . ': ',
),
'suspend' => array(
'type' => 'submit',
'value' => get_string('Suspend', 'admin'),
),
'reason' => array(
'type' => 'text',
'title' => ' ' . get_string('reason') . ': ',
),
),
));
// Delete users
$deleteform = pieform(array(
'name' => 'delete',
'class' => 'bulkactionform delete',
'renderer' => 'oneline',
'elements' => array(
'users' => $userelement,
'title' => array(
'type' => 'html',
'class' => 'bulkaction-title',
'value' => get_string('deleteusers', 'admin') . ': ',
),
'delete' => array(
'type' => 'submit',
'confirm' => get_string('confirmdeleteusers', 'admin'),
'value' => get_string('delete'),
),
),
));
$smarty = smarty();
$smarty->assign('PAGEHEADING', TITLE);
$smarty->assign('users', $users);
$smarty->assign('changeauthform', $changeauthform);
$smarty->assign('suspendform', $suspendform);
$smarty->assign('deleteform', $deleteform);
$smarty->display('admin/users/bulk.tpl');
function changeauth_validate(Pieform $form, $values) {
global $userids, $SESSION;
// Make sure all users are members of the institution that
// this authinstance belongs to.
$authobj = AuthFactory::create($values['authinstance']);
if ($authobj->institution != 'mahara') {
$ph = $userids;
$ph[] = $authobj->institution;
$institutionusers = count_records_sql('
SELECT COUNT(usr)
FROM {usr_institution}
WHERE usr IN (' . join(',', array_fill(0, count($userids), '?')) . ') AND institution = ?',
$ph
);
if ($institutionusers != count($userids)) {
$SESSION->add_error_msg(get_string('someusersnotinauthinstanceinstitution', 'admin'));
$form->set_error('authinstance', get_string('someusersnotinauthinstanceinstitution', 'admin'));
}
}
}
function changeauth_submit(Pieform $form, $values) {
global $users, $SESSION, $authinstances;
$newauth = AuthFactory::create($values['authinstance']);
$needspassword = method_exists($newauth, 'change_password');
$updated = 0;
$needpassword = 0;
db_begin();
foreach ($users as $user) {
if ($user->authinstance != $values['authinstance']) {
if ($user->haspassword && !$needspassword) {
$user->password = '';
}
else if ($needspassword && !$user->haspassword) {
$needpassword++;
}
$user->authinstance = $values['authinstance'];
update_record('usr', $user, 'id');
$updated++;
}
}
db_commit();
if ($needpassword) {
// Inform the user that they may need to reset passwords
$SESSION->add_info_msg(get_string('bulkchangeauthmethodresetpassword', 'admin', $needpassword));
}
$message = get_string('bulkchangeauthmethodsuccess', 'admin', $updated);
$form->reply(PIEFORM_OK, array('message' => $message));
}
function suspend_submit(Pieform $form, $values) {
global $users, $SESSION;
$suspended = 0;
db_begin();
foreach ($users as $user) {
if (!$user->suspendedcusr) {
suspend_user($user->id, $values['reason']);
$suspended++;
}
}
db_commit();
$SESSION->add_ok_msg(get_string('bulksuspenduserssuccess', 'admin', $suspended));
redirect('/admin/users/suspended.php');
}
function delete_submit(Pieform $form, $values) {
global $users, $editable, $SESSION;
db_begin();
foreach ($users as $user) {
delete_user($user->id);
}
db_commit();
$SESSION->add_ok_msg(get_string('bulkdeleteuserssuccess', 'admin', count($users)));
redirect('/admin/users/search.php');
}
......@@ -1325,4 +1325,26 @@ class LiveUser extends User {
));
}
/**
* Writes a file to dataroot and saves details in the session,
* for later download by the user
*
* @param $content string file contents
* @param $name string filename to be used when downloading the file
* @param $mimetype string
*/
public function set_download_file($content, $name, $mimetype) {
global $SESSION;
$filename = get_random_key();
$dir = get_config('dataroot') . 'export/' . $this->id . '/';
check_dir_exists($dir);
file_put_contents($dir . $filename, $content);
$SESSION->set('downloadfile', array(
'file' => $filename,
'name' => $name,
'mimetype' => $mimetype,
));
}
}
<?php
/**
* Mahara: Electronic portfolio, weblog, resume builder and social networking
* Copyright (C) 2011 Catalyst IT Ltd and others; see:
* http://wiki.mahara.org/Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package mahara
* @subpackage core
* @author Richard Mansfield
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
*
*/
define('INTERNAL', 1);
require('init.php');
require_once('file.php');
$data = $SESSION->get('downloadfile');
if (!$USER->is_logged_in() || empty($data) || empty($data['file'])) {
throw new NotFoundException(get_string('filenotfound'));
}
$path = get_config('dataroot') . 'export/' . $USER->get('id') . '/' . $data['file'];
if (!file_exists($path)) {
throw new NotFoundException(get_string('filenotfound'));
}
serve_file($path, $data['name'], $data['mimetype']);
......@@ -752,6 +752,22 @@ $string['requestto'] = 'Request to';
$string['useradded'] = 'User added';
$string['invitationsent'] = 'Invitation sent';
// Bulk actions
$string['bulkactions'] = 'Bulk actions';
$string['editselectedusersdescription'] = 'Suspend, delete, change authentication method, or download a CSV file of the users you have selected on the search page.';
$string['exportusersascsv'] = 'Export users in CSV format';
$string['Download'] = 'Download';
$string['suspendusers'] = 'Suspend users';
$string['Suspend'] = 'Suspend';
$string['bulksuspenduserssuccess'] = 'Suspended %d user(s)';
$string['changeauthmethod'] = 'Change authentication method';
$string['someusersnotinauthinstanceinstitution'] = 'Some of the users you have selected are not in the institution associated with this authentication method.';
$string['bulkchangeauthmethodsuccess'] = 'Reset authentication method for %d user(s)';
$string['bulkchangeauthmethodresetpassword'] = 'You have chosen an authentication method that requires a password. %d user(s) do not have a password, and will be unable to log in until their passwords are reset.';
$string['bulkdeleteuserssuccess'] = 'Deleted %d user(s)';
$string['selectedusers'] = 'Selected users';
$string['remoteuser'] = 'Remote username';
// general stuff
$string['notificationssaved'] = 'Notification settings saved';
$string['onlyshowingfirst'] = 'Only showing first';
......
......@@ -947,3 +947,6 @@ $string['howtodisable'] = 'You have hidden the information box. You can control
// Blocktype
$string['setblocktitle'] = 'Set a block title';
// Download
$string['filenotfound'] = 'File not found';
\ No newline at end of file
......@@ -675,3 +675,13 @@ form#uploadcsv {
.admin-warning-box h3 {
color: #CA0000;
}
.bulkactionform {
margin: .25em 0;
float: left;
width: 49%;
}
.bulkaction-title {
font-weight: bold;
margin: 0 .25em 0 0;
}
......@@ -532,6 +532,10 @@ input.submit, input.cancel, button, .buttondk, input.button, input.select, input
* overflow: visible;
* width: 1;
}
form.delete input.submit {
color: #dd0221;
border: 1px solid #DBA0A9;
}
/** hover for buttons **/
.btn:hover, input.submit:hover, input.cancel:hover, button:hover, .buttondk:hover, input.button:hover, input.select:hover, input#files_filebrowser_edit_artefact:hover {
background: #FFF url(../images/btn-bkgd-hover.gif) repeat-x left top;
......
{include file="header.tpl"}
<p>{str tag=editselectedusersdescription section=admin}</p>
<div>
<div class="bulkactionform">
<span class="bulkaction-title">{str tag=exportusersascsv section=admin}:</span>
<a href="{$WWWROOT}download.php" target="_blank">{str tag=Download section=admin}</a>
</div>
{$suspendform|safe}
</div>
<div>
{$changeauthform|safe}
{$deleteform|safe}
</div>
<div class="cl"></div>
<h2>{str tag=selectedusers section=admin} ({count($users)})</h2>
<table class="fullwidth">
<thead>
<tr>
<th>{str tag=username}</th>
<th>{str tag=email}</th>
<th>{str tag=firstname}</th>
<th>{str tag=lastname}</th>
<th>{str tag=studentid}</th>
<th>{str tag=preferredname}</th>
<th>{str tag=remoteuser section=admin}</th>
</tr>
</thead>
<tbody>
{foreach from=$users item=user}
<tr class="{cycle values='r0,r1'}">
<td>{$user->username}</td>
<td>{$user->email}</td>
<td>{$user->firstname}</td>
<td>{$user->lastname}</td>
<td>{$user->studentid}</td>
<td>{$user->preferredname}</td>
<td>{$user->remoteuser}</td>
</tr>
{/foreach}
</tbody>
</table>
{include file="footer.tpl"}
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