Commit 65e7b0e6 authored by Richard Mansfield's avatar Richard Mansfield
Browse files

Institution members page (internal search only)

parent 0084b2e5
<?php
/**
* This program is part of Mahara
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* @package mahara
* @subpackage admin
* @author Nigel McNie <nigel@catalyst.net.nz>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
* @copyright (C) 2006,2007 Catalyst IT Ltd http://catalyst.net.nz
*
*/
// NOTE: This script is VERY SIMILAR to the adminusers.php script, a bug fixed
// here might need to be fixed there too.
define('INTERNAL', 1);
define('INSTITUTIONALADMIN', 1);
define('MENUITEM', 'configusers/institutionusers');
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
define('TITLE', get_string('adminusers', 'admin'));
define('SECTION_PLUGINTYPE', 'core');
define('SECTION_PLUGINNAME', 'admin');
define('SECTION_PAGE', 'institutionusers');
require_once('pieforms/pieform.php');
require_once('institution.php');
$institutionelement = get_institution_selector();
global $USER;
$institution = param_alphanum('institution', false);
if (!$institution || !$USER->is_institutional_admin($institution)) {
$institution = empty($institutionelement['value']) ? $institutionelement['defaultvalue'] : $institutionelement['value'];
}
// Show either requesters, members, or nonmembers on the left hand side
$usertype = param_alpha('usertype', 'requesters');
$usertypeselector = pieform(array(
'name' => 'usertypeselect',
'elements' => array(
'usertype' => array(
'type' => 'select',
'title' => get_string('userstodisplay', 'admin'),
'options' => array(
'requesters' => get_string('institutionusersrequesters', 'admin'),
'nonmembers' => get_string('institutionusersnonmembers', 'admin'),
'members' => get_string('institutionusersmembers', 'admin'),
),
'defaultvalue' => $usertype
),
)
));
if ($usertype == 'requesters') {
// LHS shows users who have requested membership, RHS shows users to be added
$userlistelement = array(
'title' => get_string('addnewmembers', 'admin'),
'description' => get_string('addnewmembersdescription', 'admin'),
'lefttitle' => get_string('usersrequested', 'admin'),
'righttitle' => get_string('userstobeadded', 'admin'),
'searchparams' => array('requested' => 1),
);
$submittext = get_string('addmembers', 'admin');
} else if ($usertype == 'members') {
// LHS shows institution members, RHS shows users to be removed
$userlistelement = array(
'title' => get_string('removeusersfrominstitution', 'admin'),
'description' => get_string('removeusersdescription', 'admin'),
'lefttitle' => get_string('currentmembers', 'admin'),
'righttitle' => get_string('userstoberemoved', 'admin'),
'searchparams' => array('member' => 1),
);
$submittext = get_string('removeusers', 'admin');
} else { // $usertype == nonmembers
// Behaviour depends on whether we allow users to have > 1 institution
// LHS either shows all nonmembers or just users with no institution
// RHS shows users to be invited
$userlistelement = array(
'title' => get_string('inviteuserstojoin', 'admin'),
'description' => get_string('inviteusersdescription', 'admin'),
'lefttitle' => get_string('Non-members', 'admin'),
'righttitle' => get_string('userstobeinvited', 'admin'),
'searchparams' => array('member' => 0, 'invited' => 0, 'requested' => 0)
);
$submittext = get_string('inviteusers', 'admin');
}
$userlistelement['type'] = 'userlist';
$userlistelement['filter'] = false;
$userlistelement['searchscript'] = 'admin/users/userinstitutionsearch.json.php';
$userlistelement['defaultvalue'] = array();
$userlistelement['searchparams']['limit'] = 100;
$userlistelement['searchparams']['query'] = '';
$userlistelement['searchparams']['institution'] = $institution;
$userlistform = pieform(array(
'name' => 'institutionusers',
'elements' => array(
'users' => $userlistelement,
'institution' => $institutionelement,
'usertype' => array(
'type' => 'hidden',
'value' => $usertype,
'rules' => array('regex' => '/^[a-z]+$/')
),
'submit' => array(
'type' => 'submit',
'value' => $submittext
)
)
));
function institutionusers_submit(Pieform $form, $values) {
global $SESSION, $USER;
$inst = $values['institution'];
if (empty($inst) || !$USER->is_institutional_admin($inst)) {
$SESSION->add_error_msg(get_string('notadminforinstitution', 'admin'));
redirect('/admin/users/institutionusers.php?usertype='.$values['usertype']);
}
$update = 'update_' . $values['usertype'];
if ($update($values['users'], $values['institution'])) {
$SESSION->add_ok_msg(get_string('usersupdated', 'admin'));
} else {
$SESSION->add_error_msg(get_string('dberrorupdatingusers', 'admin'));
}
redirect('/admin/users/institutionusers.php?usertype='.$values['usertype']);
}
function update_nonmembers($userids, $institution) {
db_begin();
foreach ($userids as $id) {
invite_user_to_institution($id, $institution);
}
db_commit();
return true;
}
function update_requesters($userids, $institution) {
db_begin();
foreach ($userids as $id) {
add_user_to_institution($id, $institution);
}
db_commit();
return true;
}
function update_members($userids, $institution) {
delete_records_select('usr_institution', 'usr IN (' . join(',', $userids) . ') AND institution = ' . db_quote($institution));
return true;
}
$wwwroot = get_config('wwwroot');
$js = <<< EOF
addLoadEvent(function() {
connect($('usertypeselect_usertype'), 'onchange', function () {
window.location.href = '{$wwwroot}admin/users/institutionusers.php?usertype='+$('usertypeselect_usertype').value;
});
});
EOF;
$smarty = smarty();
$smarty->assign('INLINEJAVASCRIPT', $js);
$smarty->assign('usertypeselector', $usertypeselector);
$smarty->assign('institutionusersform', $userlistform);
$smarty->display('admin/users/institutionusers.tpl');
?>
<?php
/**
* This program is part of Mahara
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* @package mahara
* @subpackage core
* @author Martyn Smith <martyn@catalyst.net.nz>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
* @copyright (C) 2006,2007 Catalyst IT Ltd http://catalyst.net.nz
*
*/
define('INTERNAL', 1);
define('JSON', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
require('searchlib.php');
$params = new StdClass;
$params->query = trim(param_variable('query', ''));
$params->institution = param_alphanum('institution', null);
$params->requested = param_integer('requested', null);
$params->invited = param_integer('invited', null);
$params->member = param_integer('member', null);
$limit = param_integer('limit', 100);
json_headers();
$data = get_institutional_admin_search_results($params, $limit);
$data['error'] = false;
$data['message'] = null;
echo json_encode($data);
exit;
?>
......@@ -347,13 +347,8 @@ class User {
public function join_institution($institution) {
if ($institution != 'mahara' && !$this->in_institution($institution)) {
// @todo: set expiry, studentid, ctime
insert_record('usr_institution', (object) array(
'usr' => $this->get('id'),
'institution' => $institution
));
delete_records('usr_institution_request', 'usr', $this->get('id'), 'institution', $institution);
// Send confirmation
require_once('institution.php');
add_user_to_institution($this->id, $institution);
}
}
......
......@@ -289,7 +289,26 @@ $string['settingsfor'] = 'Settings for:';
$string['institutionadministration'] = 'Institution Administration';
$string['institutionmembers'] = 'Institution Members';
$string['notadminforinstitution'] = 'You are not an administrator for that institution';
$string['institutionmemberspagedescription'] = 'On this page you can see users who have requested membership of your institution and add them as members. You can also remove users from your institution, and invite users to join.';
$string['userstodisplay'] = 'Users to display:';
$string['institutionusersrequesters'] = 'People who have requested institution membership';
$string['institutionusersnonmembers'] = 'People who have not requested membership yet';
$string['institutionusersmembers'] = 'People who are already institution members';
$string['addnewmembers'] = 'Add new members';
$string['addnewmembersdescription'] = '';
$string['usersrequested'] = 'Users who have requested membership';
$string['userstobeadded'] = 'Users to be added as members';
$string['addmembers'] = 'Add members';
$string['inviteuserstojoin'] = 'Invite users to join the institution';
$string['Non-members'] = 'Non-members';
$string['userstobeinvited'] = 'Users to be invited';
$string['inviteusers'] = 'Invite Users';
$string['removeusersfrominstitution'] = 'Remove users from the institution';
$string['currentmembers'] = 'Current Members';
$string['userstoberemoved'] = 'Users to be removed';
$string['removeusers'] = 'Remove Users';
// general stuff
$string['notificationssaved'] = 'Notification settings saved';
......
......@@ -238,17 +238,41 @@ function get_institution_selector() {
'type' => 'select',
'title' => get_string('institution'),
'defaultvalue' => $institution,
'options' => $options
'options' => $options,
'rules' => array('regex' => '/^[a-zA-Z0-9]+$/')
);
} else {
$institution = $institutions[0]->name;
$institutionelement = array(
'type' => 'hidden',
'value' => $institution,
'rules' => array('regex' => '/^[a-zA-Z0-9]+$/')
);
}
return $institutionelement;
}
function add_user_to_institution($id, $institution) {
// @todo: set expiry, studentid, ctime
db_begin();
insert_record('usr_institution', (object) array(
'usr' => $id,
'institution' => $institution
));
delete_records('usr_institution_request', 'usr', $id, 'institution', $institution);
// Send confirmation
db_commit();
}
function invite_user_to_institution($id, $institution) {
insert_record('usr_institution_request', (object) array(
'usr' => $id,
'institution' => $institution,
'confirmedinstitution' => 1,
'ctime' => db_format_timestamp(time())
));
// Send notification
}
?>
......@@ -117,6 +117,41 @@ function search_user($query_string, $limit, $offset = 0) {
}
/*
* Institutional admin queries:
*
* These are only used to populate user lists on the Institution
* Members page. They may return users who are not in the same
* institution as the logged in institutional admin, so they should
* return names only, not email addresses.
*/
function get_institutional_admin_search_results($search, $limit) {
$institution = new StdClass;
$institution->name = $search->institution;
foreach (array('member', 'requested', 'invited') as $p) {
$institution->{$p} = $search->{$p};
}
$results = institutional_admin_user_search($search->query, $institution, $limit);
if ($results['count']) {
foreach ($results['data'] as &$result) {
$result['name'] = display_name($result);
}
}
return $results;
}
function institutional_admin_user_search($query, $institution, $limit) {
$plugin = get_config('searchplugin');
safe_require('search', $plugin);
return call_static_method(generate_class_name('search', $plugin), 'institutional_admin_search_user',
$query, $institution, $limit);
}
function get_admin_user_search_results($search, $offset, $limit, $sortby, $sortdir) {
// In admin search, the search string is interpreted as either a
// name search or an email search depending on its contents
......@@ -151,11 +186,11 @@ function get_admin_user_search_results($search, $offset, $limit, $sortby, $sortd
if (!$USER->get('admin')) {
$allowed = $USER->get('admininstitutions');
foreach (array('institution', 'institution_requested') as $p) {
if (isset($search->{$p})) {
if ($search->{$p} == 'all' || !isset($allowed[$p])) {
if (!empty($search->{$p})) {
if ($search->{$p} == 'all' || !isset($allowed[$search->{$p}])) {
$constraints[] = array('field' => $p,
'type' => 'in',
'list' => $allowed);
'string' => $allowed);
} else {
$constraints[] = array('field' => $p,
'type' => 'equals',
......@@ -168,10 +203,12 @@ function get_admin_user_search_results($search, $offset, $limit, $sortby, $sortd
'type' => 'equals',
'string' => $search->institution);
}
$results = admin_user_search($queries, $constraints, $offset, $limit, $sortby, $sortdir);
foreach ($results['data'] as &$result) {
$result['name'] = display_name($result);
if ($results['count']) {
foreach ($results['data'] as &$result) {
$result['name'] = display_name($result);
}
}
return $results;
}
......
......@@ -1310,7 +1310,7 @@ function admin_nav() {
),
array(
'path' => 'configusers/institutionmembers',
'url' => 'admin/users/staff.php',
'url' => 'admin/users/institutionusers.php',
'title' => get_string('institutionmembers', 'admin'),
'weight' => 20,
),
......
......@@ -252,22 +252,35 @@ class PluginSearchInternal extends PluginSearch {
}
private static function field_match($type, $string, &$values) {
switch ($type) {
case 'starts':
$values[] = $string;
return ' ILIKE ? || \'%\'';
case 'equals':
$values[] = $string;
return ' = ? ';
case 'contains':
$values[] = $string;
return ' ILIKE \'%\' || ? || \'%\'';
case 'in':
return ' IN (' . join(',', array_map('db_quote',$string)) . ')';
}
}
public static function admin_search_user_pg($queries, $constraints, $offset, $limit, $sort) {
$where = 'WHERE u.id <> 0 AND u.deleted = 0';
$values = array();
// Only handle OR/AND expressions at the top level. Eventually we may need subexpressions.
$matchtypes = array('starts' => ' ILIKE ? || \'%\'',
'equals' => ' = ? ',
'contains' => ' ILIKE \'%\' || ? || \'%\'');
if (!empty($queries)) {
$where .= ' AND ( ';
$str = array();
foreach ($queries as $f) {
$str[] = 'u.' . $f['field'] . $matchtypes[$f['type']];
$values[] = $f['string'];
$str[] = 'u.' . $f['field']
. PluginSearchInternal::field_match($f['type'], $f['string'], $values);
}
$where .= join(' OR ', $str) . ') ';
}
......@@ -278,28 +291,29 @@ class PluginSearchInternal extends PluginSearch {
$institutionsearch = '';
if (!empty($constraints)) {
foreach ($constraints as $f) {
if ($f['field'] == 'institution') {
$institutionsearch .= ' LEFT OUTER JOIN {usr_institution} i ON i.usr = u.id ';
if ($f['string'] == 'mahara') {
$where .= ' AND i.institution IS NULL';
} else {
$where .= ' AND i.institution' . $matchtypes[$f['type']];
$values[] = $f['string'];
if (strpos($f['field'], 'institution') === 0) {
$institutionsearch .= '
LEFT OUTER JOIN {usr_institution} i ON i.usr = u.id ';
if (strpos($f['field'], 'requested') > 0) {
$institutionsearch .= '
LEFT OUTER JOIN {usr_institution_request} ir ON ir.usr = u.id ';
}
} else if ($f['field'] == 'institution_requested') {
$institutionsearch .= ' LEFT OUTER JOIN {usr_institution} i ON i.usr = u.id ';
$institutionsearch .= ' LEFT OUTER JOIN {usr_institution_request} ir ON ir.usr = u.id ';
if ($f['type'] == 'in') {
$institutions = "('" . join("','", $f['list']) . "')";
$where .= ' AND (i.institution IN ' . $institutions . 'OR ir.institution IN ' . $institutions . ')';
} else if ($f['type'] == 'equals') {
$where .= ' AND (i.institution = ? OR ir.institution = ?)';
$values[] = $f['string'];
$values[] = $f['string'];
if ($f['field'] == 'institution_requested') {
$where .= ' AND ( i.institution ' .
PluginSearchInternal::field_match($f['type'], $f['string'], $values) .
' OR ir.institution ' .
PluginSearchInternal::field_match($f['type'], $f['string'], $values) . ')';
} else {
if ($f['string'] == 'mahara') {
$where .= ' AND i.institution IS NULL';
} else {
$where .= ' AND i.institution'
. PluginSearchInternal::field_match($f['type'], $f['string'], $values);
}
}
} else {
$where .= ' AND u.' . $f['field'] . $matchtypes[$f['type']];
$values[] = $f['string'];
$where .= ' AND u.' . $f['field']
. PluginSearchInternal::field_match($f['type'], $f['string'], $values);
}
}
}
......@@ -336,6 +350,7 @@ class PluginSearchInternal extends PluginSearch {
foreach ($data as &$item) {
$item = (array)$item;
}
$data = array_values($data);
}
}
else {
......@@ -350,6 +365,91 @@ class PluginSearchInternal extends PluginSearch {
);
}
public static function institutional_admin_search_user($query, $institution, $limit) {
if (is_postgres()) {
return self::institutional_admin_search_user_pg($query, $institution, $limit);
}
else {
throw new SQLException('institutional_admin_search_user() is not implemented for your database engine (' . get_config('dbtype') . ')');
}
}
public static function institutional_admin_search_user_pg($query, $institution, $limit) {
$sql = '
FROM {usr} u ';
$where = '
WHERE u.id <> 0 AND u.deleted = 0 ';
$values = array();
if (!empty($query)) {
$where .= '
AND (u.firstname ILIKE \'%\' || ? || \'%\'
OR u.lastname ILIKE \'%\' || ? || \'%\') ';
$values = array($query,$query);
}
if (!is_null($institution->member)) {
$sql .= '
LEFT OUTER JOIN {usr_institution} member ON (member.usr = u.id
AND member.institution = ' . db_quote($institution->name) . ')';
$where .= '
AND ' . ($institution->member ? ' NOT ' : '') . ' member.usr IS NULL';
}
if (!is_null($institution->requested) || !is_null($institution->invited)) {
$sql .= '
LEFT OUTER JOIN {usr_institution_request} req ON (req.usr = u.id
AND req.institution = ' . db_quote($institution->name) . ')';
if (!is_null($institution->requested)) {
if ($institution->requested == 1) {
$where .= ' AND req.confirmedusr = 1';
} else {
$where .= ' AND (req.confirmedusr = 0 OR req.confirmedusr IS NULL)';
}
}
if (!is_null($institution->invited)) {
if ($institution->requested == 1) {
$where .= ' AND req.confirmedinstitution = 1';
} else {
$where .= ' AND (req.confirmedinstitution = 0 OR req.confirmedinstitution IS NULL)';
}
}
}
$count = get_field_sql('SELECT COUNT(*) ' . $sql . $where, $values);
if ($count > 0) {
$data = get_records_sql_array('
SELECT
u.id, u.firstname, u.lastname, u.username, u.preferredname,
u.admin, u.staff ' . $sql . $where . '
ORDER BY u.firstname ASC',
$values,
0,
$limit);
foreach ($data as &$item) {
$item = (array)$item;
}
}
else {
$data = false;
}
return array(
'count' => $count,
'limit' => $limit,
'offset' => 0,
'data' => $data,
);
}
/**
* Implement group searching with SQL
*
......
{include file="header.tpl"}
{include file="columnfullstart.tpl"}
<h2>{str tag="institutionmembers" section="admin"}</h2>
<p>{str tag="institutionmemberspagedescription" section="admin"}</p>
{$usertypeselector}
{$institutionusersform}