Commit 0ce047c6 authored by Francois Marier's avatar Francois Marier Committed by Gerrit Code Review
Browse files

Merge changes I14dab961,Iad7195ff,I0c40f7d1,Ia65a960d

* changes:
  Let buttons disguised as links be used in navigation tabs
  Move bulk actions user list into a separate template
  Allow get_accesslists() to return views for >1 user
  Allow staff to access the admin user search page (bug #919009)
parents f15d037c 4c03ffb0
......@@ -58,6 +58,13 @@ $users = get_records_sql_assoc('
$ph
);
// Display the number of users filtered out due to institution permissions. This is not an
// exception, because the logged in user might be an admin in one institution, and staff in
// another.
if ($uneditableusers = count($userids) - count($users)) {
$SESSION->add_info_msg(get_string('uneditableusers', 'admin', $uneditableusers));
}
$userids = array_keys($users);
// Export CSV
......
......@@ -27,7 +27,7 @@
define('INTERNAL', 1);
define('JSON', 1);
define('INSTITUTIONALADMIN', 1);
define('INSTITUTIONALSTAFF', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
......
......@@ -26,7 +26,7 @@
*/
define('INTERNAL', 1);
define('INSTITUTIONALADMIN', 1);
define('INSTITUTIONALSTAFF', 1);
define('MENUITEM', 'configusers/usersearch');
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
define('TITLE', get_string('usersearch', 'admin'));
......@@ -46,11 +46,18 @@ $search = (object) array(
$offset = param_integer('offset', 0);
$limit = param_integer('limit', 10);
if ($USER->get('admin')) {
if ($USER->get('admin') || $USER->get('staff')) {
$institutions = get_records_array('institution', '', '', 'displayname');
$search->institution = param_alphanum('institution', 'all');
} else {
$institutions = get_records_select_array('institution', "name IN ('" . join("','", array_keys($USER->get('admininstitutions'))) . "')", null, 'displayname');
}
else {
$institutionnames = array_keys(array_merge($USER->get('admininstitutions'), $USER->get('staffinstitutions')));
$institutions = get_records_select_array(
'institution',
'name IN (' . join(',', array_fill(0, count($institutionnames), '?')) . ')',
$institutionnames,
'displayname'
);
}
$smarty = smarty(array('adminusersearch'));
......
......@@ -117,6 +117,7 @@ $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.';
$string['emailaddresshidden'] = 'Email address hidden';
$string['administergroups'] = 'Administer Groups';
$string['administergroupsdescription'] = 'Appoint group administrators and delete groups';
......@@ -869,6 +870,10 @@ $string['editselectedusers'] = 'Edit selected users';
// 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['uneditableusers'] = array(
0 => 'One of the users you selected is not editable by you, and has been removed from the list.',
1 => 'You selected %s users that are not editable by you. They have been removed from the list.',
);
$string['exportusersascsv'] = 'Export users in CSV format';
$string['Download'] = 'Download';
$string['suspendusers'] = 'Suspend users';
......
......@@ -225,8 +225,8 @@ function get_admin_user_search_results($search, $offset, $limit) {
// Filter by viewable institutions:
global $USER;
if (!$USER->get('admin')) {
$allowed = $USER->get('admininstitutions');
if (!$USER->get('admin') && !$USER->get('staff')) {
$allowed = array_merge($USER->get('admininstitutions'), $USER->get('staffinstitutions'));
if (empty($search->institution)) {
$search->institution = 'all';
}
......@@ -256,11 +256,26 @@ function get_admin_user_search_results($search, $offset, $limit) {
);
if ($results['count']) {
$isadmin = $USER->get('admin');
$admininstitutions = $USER->get('admininstitutions');
foreach ($results['data'] as &$result) {
$result['name'] = display_name($result);
if (!empty($result['institutions'])) {
$result['institutions'] = array_combine($result['institutions'],$result['institutions']);
}
if ($isadmin) {
continue;
}
// Remove email address when viewed by staff
if (!$hideemail = (empty($admininstitutions) || empty($result['institutions']))) {
$commoninstitutions = array_intersect($admininstitutions, $result['institutions']);
$hideemail |= empty($commoninstitutions);
}
if ($hideemail) {
unset($result['email']);
}
}
}
......@@ -337,6 +352,17 @@ function build_admin_user_search_results($search, $offset, $limit) {
'class' => 'center nojs-hidden-table-cell',
);
if (!$USER->get('admin') && !$USER->is_institutional_admin()) {
unset($cols['email']);
}
else if (!$USER->get('admin')) {
foreach ($results['data'] as &$r) {
if (!isset($r['email'])) {
$r['email'] = '- ' . get_string('emailaddresshidden', 'admin') . ' -';
}
}
}
$smarty = smarty_core();
$smarty->assign_by_ref('results', $results);
$smarty->assign_by_ref('institutions', $institutions);
......
......@@ -2761,7 +2761,27 @@ class View {
throw new SystemException("View::owner_sql: Passed object did not have an institution, group or owner field");
}
/**
* Returns an SQL snippet that can be used in a where clause to get views
* with the given set of owners.
*
* Only one of the owner, group, institution fields is used.
*
* @param object $ownerobj An object that has view ownership information -
* either the institution, group or owner fields set
* @return array containing an sql string and an array of placeholder values
*/
private static function multiple_owner_sql($ownerobj) {
foreach (get_object_vars($ownerobj) as $column => $values) {
if (is_array($values) && !empty($values)) {
return array(
'"' . $column . '" IN (' . join(',', array_fill(0, count($values), '?')) . ')',
$values,
);
}
}
return array(self::owner_sql($ownerobj), array());
}
/**
* Get all views visible to a user. Complicated because a view v
......@@ -3799,9 +3819,9 @@ class View {
* Get all views for a (user,group,institution), grouping views
* into their collections. Empty collections not returned.
*
* @param integer $owner
* @param integer $group
* @param string $institution
* @param mixed $owner integer userid or array of userids
* @param mixed $group integer groupid or array of groupids
* @param mixed $institution string institution name or array of institution names
* @param string $matchconfig record all matches with given config hash (see set_access)
* @param boolean $includeprofile include profile view
*
......@@ -3809,10 +3829,12 @@ class View {
*/
function get_views_and_collections($owner=null, $group=null, $institution=null, $matchconfig=null, $includeprofile=true) {
$excludelocked = $group && group_user_access($group) != 'admin';
$ownersql = self::owner_sql((object) array('owner' => $owner, 'group' => $group, 'institution' => $institution));
list($ownersql, $values) = self::multiple_owner_sql(
(object) array('owner' => $owner, 'group' => $group, 'institution' => $institution)
);
$sql = "
SELECT v.id AS vid, v.type AS vtype, v.title AS vname, v.accessconf,
v.startdate, v.stopdate, v.template,
v.startdate, v.stopdate, v.template, v.owner, v.group,
c.id AS cid, c.name AS cname
FROM {view} v
LEFT JOIN {collection_view} cv ON v.id = cv.view
......@@ -3821,7 +3843,7 @@ class View {
$sql .= $includeprofile ? ", 'profile') " : ') ';
$sql .= $excludelocked ? 'AND v.locked != 1 ' : '';
$sql .= 'ORDER BY c.name, v.title';
$records = get_records_sql_array($sql, array());
$records = get_records_sql_array($sql, $values);
$collections = array();
$views = array();
......@@ -3836,8 +3858,8 @@ class View {
'id' => $r->vid,
'title' => $r->vname,
'type' => $r->vtype,
'owner' => $owner,
'group' => $group,
'owner' => $r->owner,
'group' => $r->group,
));
$view->set('dirty', false);
$v = array(
......@@ -3848,10 +3870,16 @@ class View {
'startdate' => $r->startdate,
'stopdate' => $r->stopdate,
'template' => $r->template,
'owner' => $r->owner,
);
if ($r->cid) {
if (!isset($collections[$r->cid])) {
$collections[$r->cid] = array('id' => $r->cid, 'name' => $r->cname, 'views' => array());
$collections[$r->cid] = array(
'id' => $r->cid,
'name' => $r->cname,
'owner' => $r->owner,
'views' => array(),
);
if ($matchconfig && $matchconfig == $r->accessconf) {
$collections[$r->cid]['match'] = true;
}
......@@ -3906,7 +3934,7 @@ class View {
public static function get_accesslists($owner=null, $group=null, $institution=null) {
require_once('institution.php');
if (!is_null($owner) && $owner > 0) {
if (!is_null($owner) && !is_array($owner) && $owner > 0) {
$ownerobj = new User();
$ownerobj->find_by_id($owner);
}
......
......@@ -392,16 +392,17 @@ ul.edit-view-tabs {
height: 24px;
line-height: 26px;
}
ul.in-page-tabs li a, ul.in-page-tabs li a:link, ul.in-page-tabs li a:visited, ul.in-page-tabs li a:active,
ul.in-page-tabs li a, ul.in-page-tabs li a:link, ul.in-page-tabs li a:visited, ul.in-page-tabs li a:active, ul.in-page-tabs li input.linkbtn,
ul.edit-view-tabs li a, ul.edit-view-tabs li a:link, ul.edit-view-tabs li a:visited, ul.edit-view-tabs li a:active {
color: #FFF;
background: #00084F;
}
ul.in-page-tabs li input.linkbtn:hover,
ul.in-page-tabs li a:hover {
text-decoration: underline;
color: #1F97D5;
}
ul.in-page-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.in-page-tabs li a.current-tab:visited, ul.in-page-tabs li a.current-tab:active,
ul.in-page-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.in-page-tabs li a.current-tab:visited, ul.in-page-tabs li a.current-tab:active, ul.in-page-tabs li input.linkbtn.current-tab,
ul.edit-view-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.edit-view-tabs li a.current-tab:visited, ul.edit-view-tabs li a.current-tab:active {
color: #14336F;
}
......
......@@ -414,7 +414,7 @@ ul.in-page-tabs li,
ul.edit-view-tab li {
margin: 0 5px 0 0 !important;
}
ul.in-page-tabs li a, ul.in-page-tabs li a:link, ul.in-page-tabs li a:visited, ul.in-page-tabs li a:active,
ul.in-page-tabs li a, ul.in-page-tabs li a:link, ul.in-page-tabs li a:visited, ul.in-page-tabs li a:active, ul.in-page-tabs li input.linkbtn,
ul.edit-view-tabs li a, ul.edit-view-tabs li a:link, ul.edit-view-tabs li a:visited, ul.edit-view-tabs li a:active {
text-decoration: none;
background: none;
......@@ -422,11 +422,11 @@ ul.edit-view-tabs li a, ul.edit-view-tabs li a:link, ul.edit-view-tabs li a:visi
height: 28px;
line-height: 28px;
}
ul.in-page-tabs li a:hover,
ul.in-page-tabs li a:hover, ul.in-page-tabs li input.linkbtn:hover,
ul.edit-view-tabs li a:hover {
color: #d66800;
}
ul.in-page-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.in-page-tabs li a.current-tab:visited, ul.in-page-tabs li a.current-tab:active,
ul.in-page-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.in-page-tabs li a.current-tab:visited, ul.in-page-tabs li a.current-tab:active, ul.in-page-tabs li input.linkbtn.current-tab,
ul.edit-view-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.edit-view-tabs li a.current-tab:visited, ul.edit-view-tabs li a.current-tab:active {
color: #000000;
background: #eeeeee;
......
......@@ -358,7 +358,7 @@ ul.edit-view-tabs li {
background: none;
line-height: 25px;
}
ul.in-page-tabs li a, ul.in-page-tabs li a:link, ul.in-page-tabs li a:visited, ul.in-page-tabs li a:active,
ul.in-page-tabs li a, ul.in-page-tabs li a:link, ul.in-page-tabs li a:visited, ul.in-page-tabs li a:active, ul.in-page-tabs li input.linkbtn,
ul.edit-view-tabs li a, ul.edit-view-tabs li a:link, ul.edit-view-tabs li a:visited, ul.edit-view-tabs li a:active {
color: #1E6297;
padding: 0 12px 0 10px;
......@@ -367,11 +367,11 @@ ul.edit-view-tabs li a, ul.edit-view-tabs li a:link, ul.edit-view-tabs li a:visi
border-right: 1px solid #d1d1d1;
border-bottom: 1px solid #d1d1d1;
}
ul.in-page-tabs li a:hover,
ul.in-page-tabs li a:hover, ul.in-page-tabs li input.linkbtn:hover,
ul.edit-view-tabs li a:hover {
color: #7E7327;
}
ul.in-page-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.in-page-tabs li a.current-tab:visited, ul.in-page-tabs li a.current-tab:active,
ul.in-page-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.in-page-tabs li a.current-tab:visited, ul.in-page-tabs li a.current-tab:active, ul.in-page-tabs li input.linkbtn.current-tab,
ul.edit-view-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.edit-view-tabs li a.current-tab:visited, ul.edit-view-tabs li a.current-tab:active {
background: transparent url(../images/tabs-over-bg.gif) no-repeat right bottom;
color: #000;
......
......@@ -416,19 +416,19 @@ ul.edit-view-tabs li {
margin: 0 3px 0 0 !important;
background: none;
}
ul.in-page-tabs li a, ul.in-page-tabs li a:link, ul.in-page-tabs li a:visited, ul.in-page-tabs li a:active,
ul.in-page-tabs li a, ul.in-page-tabs li a:link, ul.in-page-tabs li a:visited, ul.in-page-tabs li a:active, ul.in-page-tabs li input.linkbtn,
ul.edit-view-tabs li a, ul.edit-view-tabs li a:link, ul.edit-view-tabs li a:visited, ul.edit-view-tabs li a:active {
color: #FFF;
font-weight: normal;
background: #1C3740 url(../images/mainnav-bg.gif) repeat-x center;
}
ul.in-page-tabs li a:hover,
ul.in-page-tabs li a:hover, ul.in-page-tabs li input.linkbtn:hover,
ul.edit-view-tabs li a:hover {
color: #FFF;
background: #1C3740 url(../images/mainnav-bg.gif) repeat-x center;
text-decoration: underline;
}
ul.in-page-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.in-page-tabs li a.current-tab:visited, ul.in-page-tabs li a.current-tab:active,
ul.in-page-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.in-page-tabs li a.current-tab:visited, ul.in-page-tabs li a.current-tab:active, ul.in-page-tabs li input.linkbtn.current-tab,
ul.edit-view-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.edit-view-tabs li a.current-tab:visited, ul.edit-view-tabs li a.current-tab:active {
color: #FFF;
font-weight: bold;
......
......@@ -1077,7 +1077,10 @@ ul.in-page-tabs li, ul.edit-view-tabs li {
padding: 0;
margin: 0 2px 0 0 !important;
}
ul.in-page-tabs li a, ul.in-page-tabs li a:link, ul.in-page-tabs li a:visited, ul.in-page-tabs li a:active, ul.edit-view-tabs li a, ul.edit-view-tabs li a:link, ul.edit-view-tabs li a:visited, ul.edit-view-tabs li a:active {
ul.in-page-tabs li input.linkbtn {
font-weight: bold;
}
ul.in-page-tabs li a, ul.in-page-tabs li a:link, ul.in-page-tabs li a:visited, ul.in-page-tabs li a:active, ul.edit-view-tabs li a, ul.edit-view-tabs li a:link, ul.edit-view-tabs li a:visited, ul.edit-view-tabs li a:active, ul.in-page-tabs li input.linkbtn {
background: #EEEEEE;
text-decoration: none;
height: 24px;
......@@ -1085,7 +1088,7 @@ ul.in-page-tabs li a, ul.in-page-tabs li a:link, ul.in-page-tabs li a:visited, u
display: block;
padding: 0 10px;
}
ul.in-page-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.in-page-tabs li a.current-tab:visited, ul.in-page-tabs li a.current-tab:active, ul.edit-view-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.edit-view-tabs li a.current-tab:visited, ul.edit-view-tabs li a.current-tab:active {
ul.in-page-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.in-page-tabs li a.current-tab:visited, ul.in-page-tabs li a.current-tab:active, ul.edit-view-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.edit-view-tabs li a.current-tab:visited, ul.edit-view-tabs li a.current-tab:active, ul.in-page-tabs li input.linkbtn.current-tab {
color: #333;
text-decoration: none;
background: #D1D1D1;
......
......@@ -18,32 +18,6 @@
<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="admin/users/userlist.tpl" users=$users}
{include file="footer.tpl"}
......@@ -22,11 +22,13 @@
</span>
{/foreach}
</div>
{if $USER->get('admin') || $USER->is_institutional_admin()}
<form class="fr nojs-hidden-block" id="bulkactions" action="{$WWWROOT}admin/users/bulk.php" method="post">
{str tag=editselectedusers section=admin}:
<input type="button" class="button" name="go" value="{str tag=go}">
<div id="nousersselected" class="hidden error">{str tag=nousersselected section=admin}</div>
</form>
{/if}
<form action="{$WWWROOT}admin/users/search.php" method="post">
<div class="searchform">
<label>{str tag='Search' section='admin'}:</label>
......
<a href="{$WWWROOT}admin/users/edit.php?id={$r.id}">{$r.username}</a>
{assign var=canedituser value=$USER->get('admin')}
{if !$canedituser && $USER->is_institutional_admin()}
{foreach from=$r.institutions item=i}
{if $USER->is_institutional_admin($i)}{assign var=canedituser value=1}{/if}
{/foreach}
{/if}
{if $canedituser}
<a href="{$WWWROOT}admin/users/edit.php?id={$r.id}">{$r.username}</a>
{else}
{$r.username}
{/if}
<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>
......@@ -380,12 +380,12 @@ span.btn a.icon, a span.icon {
}
/**************** IN PAGE TAB NAVIGATION ****************/
ul.in-page-tabs li a, ul.in-page-tabs li a:link, ul.in-page-tabs li a:visited, ul.in-page-tabs li a:active,
ul.in-page-tabs li a, ul.in-page-tabs li a:link, ul.in-page-tabs li a:visited, ul.in-page-tabs li a:active, ul.in-page-tabs li input.linkbtn,
ul.edit-view-tabs li a, ul.edit-view-tabs li a:link, ul.edit-view-tabs li a:visited, ul.edit-view-tabs li a:active {
color: #fadc8a;
background-color: #c66c14;
}
ul.in-page-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.in-page-tabs li a.current-tab:visited, ul.in-page-tabs li a.current-tab:active,
ul.in-page-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.in-page-tabs li a.current-tab:visited, ul.in-page-tabs li a.current-tab:active, ul.in-page-tabs li input.linkbtn.current-tab,
ul.edit-view-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.edit-view-tabs li a.current-tab:visited, ul.edit-view-tabs li a.current-tab:active {
color: #ffffff;
background-color: #8E1901;
......
......@@ -387,19 +387,19 @@ span.btn a.icon, a span.icon {
}
/**************** IN PAGE TAB NAVIGATION ****************/
ul.in-page-tabs li a, ul.in-page-tabs li a:link, ul.in-page-tabs li a:visited, ul.in-page-tabs li a:active,
ul.in-page-tabs li a, ul.in-page-tabs li a:link, ul.in-page-tabs li a:visited, ul.in-page-tabs li a:active, ul.in-page-tabs li input.linkbtn,
ul.edit-view-tabs li a, ul.edit-view-tabs li a:link, ul.edit-view-tabs li a:visited, ul.edit-view-tabs li a:active {
color: #ffffff;
font-weight: normal;
background-color: #5c0758;
}
ul.in-page-tabs li a:hover,
ul.in-page-tabs li a:hover, ul.in-page-tabs li input.linkbtn:hover,
ul.edit-view-tabs li a:hover {
color: #ffffff;
background-color: #5c0758;
text-decoration: underline;
}
ul.in-page-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.in-page-tabs li a.current-tab:visited, ul.in-page-tabs li a.current-tab:active,
ul.in-page-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.in-page-tabs li a.current-tab:visited, ul.in-page-tabs li a.current-tab:active, ul.in-page-tabs li input.linkbtn.current-tab,
ul.edit-view-tabs li a.current-tab, ul.in-page-tabs li a.current-tab:link, ul.edit-view-tabs li a.current-tab:visited, ul.edit-view-tabs li a.current-tab:active {
color: #ffffff;
font-weight: bold;
......
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