Commit 350ef921 authored by Hugh Davenport's avatar Hugh Davenport
Browse files

Add a page to update group members via CSV file



You can now use the web API server for groups to update
group members by uploading a CSV file to update membership

The new page is below, and gives all the details about the format
/admin/groups/uploadmemberscsv.php

Change-Id: I0351b21a933646d7e528852680f457ac6ea93596
Signed-off-by: default avatarHugh Davenport <hugh@catalyst.net.nz>
parent d022f93a
<?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 Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
* @copyright (C) 2011 Catalyst IT Ltd http://catalyst.net.nz
*
*/
define('INTERNAL', 1);
define('INSTITUTIONALADMIN', 1);
define('MENUITEM', 'managegroups/uploadmemberscsv');
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
define('TITLE', get_string('uploadgroupmemberscsv', 'admin'));
require_once('pieforms/pieform.php');
require_once(get_config('libroot') . 'group.php');
require_once(get_config('libroot') . 'institution.php');
safe_require('artefact', 'internal');
raise_memory_limit("512M");
// Turn on autodetecting of line endings, so mac newlines (\r) will work
ini_set('auto_detect_line_endings', 1);
$FORMAT = array();
$ALLOWEDKEYS = array(
'shortname',
'username',
'role',
);
$MANDATORYFIELDS = array(
'shortname',
'username',
'role',
);
$MEMBERS = array(); // Store the members
$GROUPS = array(); // Map gid to group shortnames
$form = array(
'name' => 'uploadcsv',
'elements' => array(
'institution' => get_institution_selector(),
'file' => array(
'type' => 'file',
'title' => get_string('csvfile', 'admin'),
'description' => get_string('groupmemberscsvfiledescription', 'admin'),
'rules' => array(
'required' => true
)
),
'submit' => array(
'type' => 'submit',
'value' => get_string('uploadgroupmemberscsv', 'admin')
)
)
);
/**
* The CSV file is parsed here so validation errors can be returned to the
* user. The data from a successful parsing is stored in the <var>$CVSDATA</var>
* array so it can be accessed by the submit function
*
* @param Pieform $form The form to validate
* @param array $values The values submitted
*/
function uploadcsv_validate(Pieform $form, $values) {
global $CSVDATA, $ALLOWEDKEYS, $MANDATORYFIELDS, $FORMAT, $USER, $UPDATES, $MEMBERS, $GROUPS;
// Don't even start attempting to parse if there are previous errors
if ($form->has_errors()) {
return;
}
if ($values['file']['size'] == 0) {
$form->set_error('file', $form->i18n('rule', 'required', 'required', array()));
return;
}
$institution = $values['institution'];
if (!$USER->can_edit_institution($institution)) {
$form->set_error('institution', get_string('notadminforinstitution', 'admin'));
return;
}
require_once('csvfile.php');
$csvgroups = new CsvFile($values['file']['tmp_name']);
$csvgroups->set('allowedkeys', $ALLOWEDKEYS);
$csvgroups->set('mandatoryfields', $MANDATORYFIELDS);
$csvdata = $csvgroups->get_data();
if (!empty($csvdata->errors['file'])) {
$form->set_error('file', $csvdata->errors['file']);
return;
}
$csverrors = new CSVErrors();
$formatkeylookup = array_flip($csvdata->format);
$shortnames = array();
$hadadmin = array();
foreach ($csvdata->data as $key => $line) {
// If headers exists, increment i = key + 2 for actual line number
$i = ($csvgroups->get('headerExists')) ? ($key + 2) : ($key + 1);
// Trim non-breaking spaces -- they get left in place by File_CSV
foreach ($line as &$field) {
$field = preg_replace('/^(\s|\xc2\xa0)*(.*?)(\s|\xc2\xa0)*$/', '$2', $field);
}
$shortname = $line[$formatkeylookup['shortname']];
$username = $line[$formatkeylookup['username']];
$role = $line[$formatkeylookup['role']];
$gid = get_field('group', 'id', 'shortname', $shortname, 'institution', $institution);
if (!$gid) {
$csverrors->add($i, get_string('uploadgroupmemberscsverrornosuchshortname', 'admin', $i, $shortname, $institution));
continue;
}
$uid = get_field_sql('SELECT id FROM {usr} WHERE LOWER(username) = ?', array(strtolower($username)));
if (!$uid) {
$csverrors->add($i, get_string('uploadgroupmemberscsverrornosuchusername', 'admin', $i, $username));
continue;
}
if ($institution != 'mahara' && !record_exists('usr_institution', 'usr', $uid, 'institution', $institution)) {
$csverrors->add($i, get_string('uploadgroupmemberscsverrorusernotininstitution', 'admin', $i, $username, $institution));
continue;
}
if (!in_array($role, array_keys(group_get_role_info($gid)))) {
$csverrors->add($i, get_string('uploadgroupmemberscsverrorinvalidrole', 'admin', $i, $role));
continue;
}
if (!isset($MEMBERS[$gid])) {
$MEMBERS[$gid] = array();
}
if (isset($MEMBERS[$gid][$uid])) {
$csverrors->add($i, get_string('uploadgroupmemberscsverrorduplicateusername', 'admin', $i, $shortname, $username));
continue;
}
$MEMBERS[$gid][$uid] = $role;
$GROUPS[$gid] = $shortname;
if ($role == 'admin') {
$hasadmin[$shortname] = 1;
}
}
foreach ($GROUPS as $shortname) {
if (!isset($hasadmin[$shortname])) {
$csverrors->add($i, get_string('uploadgroupmemberscsverrornoadminlisted', 'admin', $i, $shortname));
}
}
if ($errors = $csverrors->process()) {
$form->set_error('file', clean_html($errors));
return;
}
$FORMAT = $csvdata->format;
$CSVDATA = $csvdata->data;
}
/**
* Add the users to the system. Make sure that they have to change their
* password on next login also.
*/
function uploadcsv_submit(Pieform $form, $values) {
global $SESSION, $CSVDATA, $FORMAT, $UPDATES, $USER, $MEMBERS, $GROUPS;
$formatkeylookup = array_flip($FORMAT);
$institution = $values['institution'];
db_begin();
foreach ($MEMBERS as $gid => $members) {
$updates = group_update_members($gid, $members);
if (empty($updates)) {
unset($UPDATES[$GROUPS[$gid]]);
}
else {
$UPDATES[$GROUPS[$gid]] = $updates;
log_debug('updated group members ' . $GROUPS[$gid] . ' (' . implode(', ', array_keys((array)$updates)) . ')');
}
}
db_commit();
// TODO: Fix this to show correct info
$SESSION->add_ok_msg(get_string('csvfileprocessedsuccessfully', 'admin'));
if ($UPDATES) {
$updatemsg = smarty_core();
$updatemsg->assign('updates', $UPDATES);
$SESSION->add_info_msg($updatemsg->fetch('admin/groups/memberscsvupdatemessage.tpl'), false);
}
else {
$SESSION->add_ok_msg(get_string('numbergroupsupdated', 'admin', 0));
}
redirect('/admin/groups/uploadmemberscsv.php');
}
$uploadcsvpagedescription = get_string('uploadgroupmemberscsvpagedescription2', 'admin',
get_config('wwwroot') . 'admin/groups/uploadcsv.php',
get_string('uploadgroupcsv', 'admin'));
$form = pieform($form);
$smarty = smarty(array('adminuploadcsv'));
$smarty->assign('uploadcsvpagedescription', $uploadcsvpagedescription);
$smarty->assign('uploadcsvform', $form);
$smarty->assign('PAGEHEADING', TITLE);
$smarty->display('admin/groups/uploadcsv.tpl');
......@@ -101,6 +101,7 @@ $string['adminnotificationsdescription'] = 'Overview of how administrators recei
$string['uploadcsv'] = 'Add Users by CSV';
$string['uploadcsvdescription'] = 'Upload a CSV file containing new users';
$string['uploadgroupcsv'] = 'Add Groups by CSV';
$string['uploadgroupmemberscsv'] = 'Update Group Members by CSV';
$string['usersearch'] = 'User Search';
$string['usersearchdescription'] = 'Search all users and perform administrative actions on them';
$string['usersearchinstructions'] = 'You can search for users by clicking on the initials of their first and last names, or by entering a name in the search box. You can also enter an email address in the search box if you would like to search email addresses.';
......@@ -109,6 +110,7 @@ $string['administergroups'] = 'Administer Groups';
$string['administergroupsdescription'] = 'Appoint group administrators and delete groups';
$string['groupcategoriesdescription'] = 'Add and edit group categories';
$string['uploadgroupcsvdescription'] = 'Upload a CSV file containing new groups';
$string['uploadgroupmemberscsvdescription'] = 'Upload a CSV file containing members for groups';
$string['institutionmembersdescription'] = 'Associate users with institutions';
$string['institutionstaffdescription'] = 'Assign users Staff permissions';
......@@ -413,6 +415,7 @@ $string['uploadcsvinstitution'] = 'The institution and authentication method for
$string['configureauthplugin'] = 'You must configure an authentication plugin before you can add users';
$string['csvfiledescription'] = 'The file containing users to add';
$string['groupcsvfiledescription'] = 'The file containing groups to add';
$string['groupmemberscsvfiledescription'] = 'The file containing group members to update';
$string['csverroremptyfile'] = 'The csv file is empty.';
$string['invalidfilename'] = 'The file "%s" does not exist';
$string['uploadcsverrorinvalidfieldname'] = 'The field name "%s" is invalid, or you have more fields than your header row specifies';
......@@ -472,6 +475,23 @@ $string['uploadgroupcsvpagedescription2'] = '<p>You may use this facility to upl
<p>Your CSV file may include any other fields as you require. The full list of fields is:</p>
%s';
$string['uploadgroupmemberscsverrorduplicateusername'] = 'Error on line %s of your file: The shortname "%s" and username "%s" have already been specified in this file';
$string['uploadgroupmemberscsverrorinvalidrole'] = 'Error on line %s of your file: The role "%s" is invalid for the specified group';
$string['uploadgroupmemberscsverrornoadminlisted'] = 'Error on line %s of your file: The group shortname "%s" did not have any users with the "admin" role specified';
$string['uploadgroupmemberscsverrornosuchshortname'] = 'Error on line %s of your file: The group shortname "%s" does not exist, or is not part of the institution "%s"';
$string['uploadgroupmemberscsverrornosuchusername'] = 'Error on line %s of your file: The username "%s" does not exist';
$string['uploadgroupmemberscsverrorusernotininstitution'] = 'Error on line %s of your file: The username "%s" is not part of the institution "%s"';
$string['uploadgroupmemberscsvpagedescription2'] = '<p>You may use this facility to update group members in groups controlled by this institution. You can upload new members via a <acronym title="Comma Separated Values">CSV</acronym> file.</p>
<p>The first row of your CSV file should specify the format of your CSV data. For example, it should look like this:</p>
<pre>shortname,username,role</pre>
<p>This row must include all the fields mentioned above, but can be in any order</p>
<p>The shortname field must be the same as the shortname you used to create the group <a href="%s" title="%s">here</a>.</p>
<p>The role field can have any of the following, depending on the type of group <tt>admin</tt>, <tt>member</tt>, or <tt>tutor</tt></p>';
$string['uploadcsvsomeuserscouldnotbeemailed'] = 'Some users could not be e-mailed. Their e-mail addresses may be invalid, or the server Mahara is running on might not be configured to send e-mail properly. The server error log has more details. For now, you may want to contact these people manually:';
$string['uploadcsvfailedusersexceedmaxallowed'] = 'No users have been added because there are too many users in your file. The number of users in the institution would have exceeded the maximum number allowed.';
$string['updateusers'] = 'Update Users';
......
......@@ -699,24 +699,37 @@ function group_update_members($groupid, $members) {
$oldmembers = get_records_assoc('group_member', 'group', $groupid, '', 'member,role');
$added = 0;
$removed = 0;
$updated = 0;
db_begin();
foreach ($members as $userid => $role) {
if (!isset($oldmembers[$userid])) {
group_add_user($groupid, $userid, $role);
$added ++;
}
else if ($oldmembers[$userid]->role != $role) {
set_field('group_member', 'role', $role, 'group', $groupid, 'member', $userid);
$updated ++;
}
}
foreach (array_keys($oldmembers) as $userid) {
if (!isset($members[$userid])) {
group_remove_user($groupid, $userid, true);
$removed ++;
}
}
db_commit();
if ($added == 0 && $removed == 0 && $updated == 0) {
return null;
}
return array('added' => $added, 'removed' => $removed, 'updated' => $updated);
}
/**
......
......@@ -1795,6 +1795,12 @@ function admin_nav() {
'title' => get_string('uploadgroupcsv', 'admin'),
'weight' => 30,
),
'managegroups/uploadmemberscsv' => array(
'path' => 'managegroups/uploadmemberscsv',
'url' => 'admin/groups/uploadmemberscsv.php',
'title' => get_string('uploadgroupmemberscsv', 'admin'),
'weight' => 40,
),
'manageinstitutions' => array(
'path' => 'manageinstitutions',
'url' => 'admin/users/institutions.php',
......@@ -1922,6 +1928,12 @@ function institutional_admin_nav() {
'title' => get_string('uploadgroupcsv', 'admin'),
'weight' => 10,
),
'managegroups/uploadmemberscsv' => array(
'path' => 'managegroups/uploadmemberscsv',
'url' => 'admin/groups/uploadmemberscsv.php',
'title' => get_string('uploadgroupmemberscsv', 'admin'),
'weight' => 20,
),
'manageinstitutions' => array(
'path' => 'manageinstitutions',
'url' => 'admin/users/institutions.php',
......
{str tag=numbergroupsupdated section=admin arg1=count($updates)}
<a href="" onclick="toggleElementClass('hidden', 'csvupdateinfo'); return false;">{str tag=showupdatedetails section=admin}</a>
<div id="csvupdateinfo" class="hidden">
{foreach from=$updates key=shortname item=fields}{strip}
<div>&nbsp;{$shortname}:&nbsp;
{foreach from=$fields key=k item=v name=fields}
{$k} &rarr; {$v}{if !$dwoo.foreach.fields.last},&nbsp;{/if}
{/foreach}
</div>{/strip}
{/foreach}
</div>
......@@ -100,6 +100,7 @@
<li><strong><a href="{$WWWROOT}admin/groups/groups.php">{str tag=administergroups section=admin}</a></strong> - {str tag=administergroupsdescription section=admin}</li>
<li><strong><a href="{$WWWROOT}admin/groups/groupcategories.php">{str tag=groupcategories section=admin}</a></strong> - {str tag=groupcategoriesdescription section=admin}</li>
<li><strong><a href="{$WWWROOT}admin/groups/uploadcsv.php">{str tag=uploadgroupcsv section=admin}</a></strong> - {str tag=uploadgroupcsvdescription section=admin}</li>
<li><strong><a href="{$WWWROOT}admin/groups/uploadmemberscsv.php">{str tag=uploadgroupmemberscsv section=admin}</a></strong> - {str tag=uploadgroupmemberscsvdescription section=admin}</li>
</ul>
<h3>{str tag=manageinstitutions section=admin}</h3>
......
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