Merge pull request #7151 from owncloud/user-jquery

Continuing the New User management
This commit is contained in:
Thomas Müller 2014-06-03 15:04:30 +02:00
commit 79b3558c6d
22 changed files with 1786 additions and 758 deletions

View File

@ -309,7 +309,7 @@ input[type="submit"].enabled {
position: fixed;
top:45px;
right: 0;
left: 0;
left:0;
height: 44px;
width: 100%;
padding: 0;

View File

@ -1092,6 +1092,7 @@ function initCore() {
$('a.action.delete').tipsy({gravity:'e', fade:true, live:true});
$('a.action').tipsy({gravity:'s', fade:true, live:true});
$('td .modified').tipsy({gravity:'s', fade:true, live:true});
$('td.lastLogin').tipsy({gravity:'s', fade:true, html:true});
$('input').tipsy({gravity:'w', fade:true});
// toggle for menus

View File

@ -186,7 +186,7 @@ class Group {
* @param string $search
* @return int|bool
*/
public function count($search) {
public function count($search = '') {
$users = false;
foreach ($this->backends as $backend) {
if($backend->implementsActions(OC_GROUP_BACKEND_COUNT_USERS)) {

View File

@ -0,0 +1,188 @@
<?php
/**
* Copyright (c) 2014 Arthur Schiwon <blizzz@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Group;
class MetaData {
const SORT_NONE = 0;
const SORT_USERCOUNT = 1;
/**
* @var string $user
*/
protected $user;
/**
* @var bool $isAdmin
*/
protected $isAdmin;
/**
* @var string[] $groups
*/
protected $groups = array();
/**
* @var \OC\Group\Manager $groupManager
*/
protected $groupManager;
/**
* @var int $sorting
*/
protected $sorting = false;
/**
* @var string $lastSearch
*/
protected $lastSearch;
/**
* @param string the uid of the current user
* @param bool whether the current users is an admin
* @param \OC\Group\Manager
*/
public function __construct(
$user,
$isAdmin,
\OC\Group\Manager $groupManager
) {
$this->user = $user;
$this->isAdmin = (bool)$isAdmin;
$this->groupManager = $groupManager;
}
/**
* returns an array with meta data about all available groups
* the array is structured as follows:
* [0] array containing meta data about admin groups
* [1] array containing meta data about unprivileged groups
* @param string only effective when instance was created with isAdmin being
* true
* @return array
*/
public function get($search = '') {
if($this->lastSearch !== $search) {
$this->lastSearch = $search;
$this->groups = array();
}
$adminGroups = array();
$groups = array();
$sortGroupsIndex = 0;
$sortGroupsKeys = array();
$sortAdminGroupsIndex = 0;
$sortAdminGroupsKeys = array();
foreach($this->getGroups($search) as $group) {
$groupMetaData = $this->generateGroupMetaData($group);
if (strtolower($group->getGID()) !== 'admin') {
$this->addEntry(
$groups,
$sortGroupsKeys,
$sortGroupsIndex,
$groupMetaData);
} else {
//admin group is hard coded to 'admin' for now. In future,
//backends may define admin groups too. Then the if statement
//has to be adjusted accordingly.
$this->addEntry(
$adminGroups,
$sortAdminGroupsKeys,
$sortAdminGroupsIndex,
$groupMetaData);
}
}
//whether sorting is necessary is will be checked in sort()
$this->sort($groups, $sortGroupsKeys);
$this->sort($adminGroups, $sortAdminGroupsKeys);
return array($adminGroups, $groups);
}
/**
* @brief sets the sort mode, currently 0 (none) and 1 (user entries,
* descending) are supported
* @param int the sortMode (SORT_NONE, SORT_USERCOUNT)
*/
public function setSorting($sortMode) {
if($sortMode >= 0 && $sortMode <= 1) {
$this->sorting = $sortMode;
} else {
$this->sorting = 0;
}
}
/**
* @brief adds an group entry to the resulting array
* @param array the resulting array, by reference
* @param array the sort key array, by reference
* @param array the sort key index, by reference
* @param array the group's meta data as returned by generateGroupMetaData()
* @return null
*/
private function addEntry(&$entries, &$sortKeys, &$sortIndex, $data) {
$entries[] = $data;
if($this->sorting === 1) {
$sortKeys[$sortIndex] = $data['usercount'];
$sortIndex++;
}
}
/**
* @brief creates an array containing the group meta data
* @param \OC\Group\Group
* @return array with the keys 'id', 'name' and 'usercount'
*/
private function generateGroupMetaData(\OC\Group\Group $group) {
return array(
'id' => str_replace(' ','', $group->getGID()),
'name' => $group->getGID(),
'usercount' => $group->count()
);
}
/**
* @brief sorts the result array, if applicable
* @param array the result array, by reference
* @param array the array containing the sort keys
* @param return null
*/
private function sort(&$entries, $sortKeys) {
if($this->sorting > 0) {
array_multisort($sortKeys, SORT_DESC, $entries);
}
}
/**
* @brief returns the available groups
* @param string a search string
* @return \OC\Group\Group[]
*/
private function getGroups($search = '') {
if(count($this->groups) === 0) {
$this->fetchGroups($search);
}
return $this->groups;
}
/**
* @brief fetches the group using the group manager or the subAdmin API
* @param string a search string
* @return null
*/
private function fetchGroups($search = '') {
if($this->isAdmin) {
$this->groups = $this->groupManager->search($search);
} else {
$this->groups = \OC_SubAdmin::getSubAdminsGroups($this->user);
}
}
}

View File

@ -4,6 +4,7 @@ OCP\JSON::callCheck();
OC_JSON::checkAdminUser();
$groupname = $_POST["groupname"];
$l = OC_L10N::get('settings');
// Does the group exist?
if( in_array( $groupname, OC_Group::getGroups())) {

View File

@ -43,12 +43,15 @@ try {
OC_Group::addToGroup( $username, $i );
}
OC_JSON::success(array("data" =>
$userManager = \OC_User::getManager();
$user = $userManager->get($username);
OCP\JSON::success(array("data" =>
array(
// returns whether the home already existed
"homeExists" => $homeExists,
"username" => $username,
"groups" => OC_Group::getUserGroups( $username ))));
"groups" => OC_Group::getUserGroups( $username ),
'storageLocation' => $user->getHome())));
} catch (Exception $exception) {
OC_JSON::error(array("data" => array( "message" => $exception->getMessage())));
OCP\JSON::error(array("data" => array( "message" => $exception->getMessage())));
}

View File

@ -0,0 +1,48 @@
<?php
/**
* ownCloud
*
* @author Arthur Schiwon
* @copyright 2014 Arthur Schiwon <blizzz@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library 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 AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
OC_JSON::callCheck();
OC_JSON::checkSubAdminUser();
if (isset($_GET['pattern']) && !empty($_GET['pattern'])) {
$pattern = $_GET['pattern'];
} else {
$pattern = '';
}
$groups = array();
$adminGroups = array();
$groupManager = \OC_Group::getManager();
$isAdmin = OC_User::isAdminUser(OC_User::getUser());
//we pass isAdmin as true, because OC_SubAdmin has no search feature,
//groups will be filtered out later
$groupsInfo = new \OC\Group\MetaData(OC_User::getUser(), true, $groupManager);
$groupsInfo->setSorting($groupsInfo::SORT_USERCOUNT);
list($adminGroups, $groups) = $groupsInfo->get($pattern);
$accessibleGroups = $groupManager->search($pattern);
if(!$isAdmin) {
$subadminGroups = OC_SubAdmin::getSubAdminsGroups(OC_User::getUser());
$accessibleGroups = array_intersect($groups, $subadminGroups);
}
OC_JSON::success(
array('data' => array('adminGroups' => $adminGroups, 'groups' => $groups)));

View File

@ -32,26 +32,55 @@ if (isset($_GET['limit'])) {
} else {
$limit = 10;
}
if (isset($_GET['gid']) && !empty($_GET['gid'])) {
$gid = $_GET['gid'];
} else {
$gid = false;
}
if (isset($_GET['pattern']) && !empty($_GET['pattern'])) {
$pattern = $_GET['pattern'];
} else {
$pattern = '';
}
$users = array();
$userManager = \OC_User::getManager();
if (OC_User::isAdminUser(OC_User::getUser())) {
$batch = OC_User::getDisplayNames('', $limit, $offset);
foreach ($batch as $user => $displayname) {
if($gid !== false) {
$batch = OC_Group::displayNamesInGroup($gid, $pattern, $limit, $offset);
} else {
$batch = OC_User::getDisplayNames($pattern, $limit, $offset);
}
foreach ($batch as $uid => $displayname) {
$user = $userManager->get($uid);
$users[] = array(
'name' => $user,
'name' => $uid,
'displayname' => $displayname,
'groups' => join(', ', OC_Group::getUserGroups($user)),
'subadmin' => join(', ', OC_SubAdmin::getSubAdminsGroups($user)),
'quota' => OC_Preferences::getValue($user, 'files', 'quota', 'default'));
'groups' => join(', ', OC_Group::getUserGroups($uid)),
'subadmin' => join(', ', OC_SubAdmin::getSubAdminsGroups($uid)),
'quota' => OC_Preferences::getValue($uid, 'files', 'quota', 'default'),
'storageLocation' => $user->getHome(),
'lastLogin' => $user->getLastLogin(),
);
}
} else {
$groups = OC_SubAdmin::getSubAdminsGroups(OC_User::getUser());
$batch = OC_Group::usersInGroups($groups, '', $limit, $offset);
foreach ($batch as $user) {
if($gid !== false && in_array($gid, $groups)) {
$groups = array($gid);
} elseif($gid !== false) {
//don't you try to investigate loops you must not know about
$groups = array();
}
$batch = OC_Group::usersInGroups($groups, $pattern, $limit, $offset);
foreach ($batch as $uid) {
$user = $userManager->get($uid);
$users[] = array(
'name' => $user,
'displayname' => OC_User::getDisplayName($user),
'groups' => join(', ', OC_Group::getUserGroups($user)),
'quota' => OC_Preferences::getValue($user, 'files', 'quota', 'default'));
'displayname' => $user->getDisplayName(),
'groups' => join(', ', OC_Group::getUserGroups($uid)),
'quota' => OC_Preferences::getValue($uid, 'files', 'quota', 'default'),
'storageLocation' => $user->getHome(),
'lastLogin' => $user->getLastLogin(),
);
}
}
OC_JSON::success(array('data' => $users));

View File

@ -5,6 +5,13 @@
select#languageinput, select#timezone { width:15em; }
input#openid, input#webdav { width:20em; }
#user-controls {
-moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
position: fixed; right: 0; left:380px; height: 44px;
padding: 0; margin: 0;
background: #eee; border-bottom: 1px solid #e7e7e7;
z-index: 50;
}
/* PERSONAL */
#rootcert_import {
@ -44,7 +51,37 @@ table.nostyle label { margin-right: 2em; }
table.nostyle td { padding: 0.2em 0; }
/* USERS */
#newgroup-init a span { margin-left: 20px; }
#newgroup-init a span:before {
position: absolute; left: 12px; top:-2px;
content: '+'; font-weight: bold; font-size: 150%;
}
.usercount { float: left; margin: 5px; }
li.active span.utils .delete {
float: left; position: relative; opacity: 0.5;
top: -7px; left: 7px; width: 44px; height: 44px;
}
li.active .rename {
padding: 8px 14px 20px 14px;
top: 0px; position: absolute; width: 16px; height: 16px;
opacity: 0.5;
display: inline-block !important;
}
li.active span.utils .delete img { margin: 14px; }
li.active .rename { opacity: 0.5; }
li.active span.utils .delete:hover, li.active .rename:hover { opacity: 1; }
span.utils .delete, .rename { display: none; }
#app-navigation ul li.active > span.utils .delete,
#app-navigation ul li.active > span.utils .rename { display: block; }
#usersearchform { position: absolute; top: 4px; right: 10px; }
#usersearchform label { font-weight: 700; }
form { display:inline; }
/* display table at full width */
table.grid {
width: 100%;
}
table.grid th { height:2em; color:#999; }
table.grid th, table.grid td { border-bottom:1px solid #ddd; padding:0 .5em; padding-left:.8em; text-align:left; font-weight:normal; }
td.name, td.password { padding-left:.8em; }
@ -57,9 +94,8 @@ tr:hover>td.password>span, tr:hover>td.displayName>span { margin:0; cursor:point
tr:hover>td.remove>a, tr:hover>td.password>img,tr:hover>td.displayName>img, tr:hover>td.quota>img { visibility:visible; cursor:pointer; }
tr:hover>td.remove>a { float:right; }
table.grid { width:100%; }
div.quota {
float: right;
margin: 10px;
display: block;
}
div.quota-select-wrapper { position: relative; }
@ -78,6 +114,8 @@ div.quota>span {
}
select.quota.active { background: #fff; }
input.userFilter {width: 200px;}
/* positioning fixes */
#newuser .multiselect {
min-width: 150px !important;

View File

@ -1,546 +0,0 @@
/**
* Copyright (c) 2011, Robin Appelman <icewind1991@gmail.com>
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
*/
function setQuota (uid, quota, ready) {
$.post(
OC.filePath('settings', 'ajax', 'setquota.php'),
{username: uid, quota: quota},
function (result) {
if (ready) {
ready(result.data.quota);
}
}
);
}
var UserList = {
useUndo: true,
availableGroups: [],
offset: 30, //The first 30 users are there. No prob, if less in total.
//hardcoded in settings/users.php
usersToLoad: 10, //So many users will be loaded when user scrolls down
/**
* @brief Initiate user deletion process in UI
* @param string uid the user ID to be deleted
*
* Does not actually delete the user; it sets them for
* deletion when the current page is unloaded, at which point
* finishDelete() completes the process. This allows for 'undo'.
*/
do_delete: function (uid) {
if (typeof UserList.deleteUid !== 'undefined') {
//Already a user in the undo queue
UserList.finishDelete(null);
}
UserList.deleteUid = uid;
// Set undo flag
UserList.deleteCanceled = false;
// Provide user with option to undo
$('#notification').data('deleteuser', true);
OC.Notification.showHtml(t('settings', 'deleted') + ' ' + escapeHTML(uid) + '<span class="undo">' + t('settings', 'undo') + '</span>');
},
/**
* @brief Delete a user via ajax
* @param bool ready whether to use ready() upon completion
*
* Executes deletion via ajax of user identified by property deleteUid
* if 'undo' has not been used. Completes the user deletion procedure
* and reflects success in UI.
*/
finishDelete: function (ready) {
// Check deletion has not been undone
if (!UserList.deleteCanceled && UserList.deleteUid) {
// Delete user via ajax
$.ajax({
type: 'POST',
url: OC.filePath('settings', 'ajax', 'removeuser.php'),
async: false,
data: { username: UserList.deleteUid },
success: function (result) {
if (result.status === 'success') {
// Remove undo option, & remove user from table
OC.Notification.hide();
$('tr').filterAttr('data-uid', UserList.deleteUid).remove();
UserList.deleteCanceled = true;
if (ready) {
ready();
}
} else {
OC.dialogs.alert(result.data.message, t('settings', 'Unable to remove user'));
}
}
});
}
},
add: function (username, displayname, groups, subadmin, quota, sort) {
var tr = $('tbody tr').first().clone();
var subadminsEl;
var subadminSelect;
var groupsSelect;
if (tr.find('div.avatardiv').length){
$('div.avatardiv', tr).avatar(username, 32);
}
tr.attr('data-uid', username);
tr.attr('data-displayName', displayname);
tr.find('td.name').text(username);
tr.find('td.displayName > span').text(displayname);
// make them look like the multiselect buttons
// until they get time to really get initialized
groupsSelect = $('<select multiple="multiple" class="groupsselect multiselect button" data-placehoder="Groups" title="' + t('settings', 'Groups') + '"></select>')
.attr('data-username', username)
.data('user-groups', groups);
if (tr.find('td.subadmins').length > 0) {
subadminSelect = $('<select multiple="multiple" class="subadminsselect multiselect button" data-placehoder="subadmins" title="' + t('settings', 'Group Admin') + '">')
.attr('data-username', username)
.data('user-groups', groups)
.data('subadmin', subadmin);
tr.find('td.subadmins').empty();
}
$.each(this.availableGroups, function (i, group) {
groupsSelect.append($('<option value="' + escapeHTML(group) + '">' + escapeHTML(group) + '</option>'));
if (typeof subadminSelect !== 'undefined' && group !== 'admin') {
subadminSelect.append($('<option value="' + escapeHTML(group) + '">' + escapeHTML(group) + '</option>'));
}
});
tr.find('td.groups').empty().append(groupsSelect);
subadminsEl = tr.find('td.subadmins');
if (subadminsEl.length > 0) {
subadminsEl.append(subadminSelect);
}
if (tr.find('td.remove img').length === 0 && OC.currentUser !== username) {
var rm_img = $('<img class="svg action">').attr({
src: OC.imagePath('core', 'actions/delete')
});
var rm_link = $('<a class="action delete">')
.attr({ href: '#', 'original-title': t('settings', 'Delete')})
.append(rm_img);
tr.find('td.remove').append(rm_link);
} else if (OC.currentUser === username) {
tr.find('td.remove a').remove();
}
var quotaSelect = tr.find('select.quota-user');
if (quota === 'default') {
quotaSelect.find('option').attr('selected', null);
quotaSelect.find('option').first().attr('selected', 'selected');
quotaSelect.data('previous', 'default');
} else {
if (quotaSelect.find('option[value="' + quota + '"]').length > 0) {
quotaSelect.find('option[value="' + quota + '"]').attr('selected', 'selected');
} else {
quotaSelect.append('<option value="' + escapeHTML(quota) + '" selected="selected">' + escapeHTML(quota) + '</option>');
}
}
$(tr).appendTo('tbody');
if (sort) {
UserList.doSort();
}
quotaSelect.on('change', function () {
var uid = $(this).parent().parent().attr('data-uid');
var quota = $(this).val();
setQuota(uid, quota, function(returnedQuota){
if (quota !== returnedQuota) {
$(quotaSelect).find(':selected').text(returnedQuota);
}
});
});
// defer init so the user first sees the list appear more quickly
window.setTimeout(function(){
quotaSelect.singleSelect();
UserList.applyMultiplySelect(groupsSelect);
if (subadminSelect) {
UserList.applyMultiplySelect(subadminSelect);
}
}, 0);
return tr;
},
// From http://my.opera.com/GreyWyvern/blog/show.dml/1671288
alphanum: function(a, b) {
function chunkify(t) {
var tz = [], x = 0, y = -1, n = 0, i, j;
while (i = (j = t.charAt(x++)).charCodeAt(0)) {
var m = (i === 46 || (i >=48 && i <= 57));
if (m !== n) {
tz[++y] = "";
n = m;
}
tz[y] += j;
}
return tz;
}
var aa = chunkify(a.toLowerCase());
var bb = chunkify(b.toLowerCase());
for (x = 0; aa[x] && bb[x]; x++) {
if (aa[x] !== bb[x]) {
var c = Number(aa[x]), d = Number(bb[x]);
if (c === aa[x] && d === bb[x]) {
return c - d;
} else {
return (aa[x] > bb[x]) ? 1 : -1;
}
}
}
return aa.length - bb.length;
},
doSort: function() {
var self = this;
var rows = $('tbody tr').get();
rows.sort(function(a, b) {
return UserList.alphanum($(a).find('td.name').text(), $(b).find('td.name').text());
});
var items = [];
$.each(rows, function(index, row) {
items.push(row);
if(items.length === 100) {
$('tbody').append(items);
items = [];
}
});
if(items.length > 0) {
$('tbody').append(items);
}
},
update: function () {
if (UserList.updating) {
return;
}
$('table+.loading').css('visibility', 'visible');
UserList.updating = true;
var query = $.param({ offset: UserList.offset, limit: UserList.usersToLoad });
$.get(OC.generateUrl('/settings/ajax/userlist') + '?' + query, function (result) {
var loadedUsers = 0;
var trs = [];
if (result.status === 'success') {
//The offset does not mirror the amount of users available,
//because it is backend-dependent. For correct retrieval,
//always the limit(requested amount of users) needs to be added.
$.each(result.data, function (index, user) {
if($('tr[data-uid="' + user.name + '"]').length > 0) {
return true;
}
var tr = UserList.add(user.name, user.displayname, user.groups, user.subadmin, user.quota, false);
tr.addClass('appear transparent');
trs.push(tr);
loadedUsers++;
});
if (result.data.length > 0) {
UserList.doSort();
$('table+.loading').css('visibility', 'hidden');
}
else {
UserList.noMoreEntries = true;
$('table+.loading').remove();
}
UserList.offset += loadedUsers;
// animate
setTimeout(function() {
for (var i = 0; i < trs.length; i++) {
trs[i].removeClass('transparent');
}
}, 0);
}
UserList.updating = false;
});
},
applyMultiplySelect: function (element) {
var checked = [];
var user = element.attr('data-username');
if ($(element).hasClass('groupsselect')) {
if (element.data('userGroups')) {
checked = element.data('userGroups');
}
if (user) {
var checkHandeler = function (group) {
if (user === OC.currentUser && group === 'admin') {
return false;
}
if (!oc_isadmin && checked.length === 1 && checked[0] === group) {
return false;
}
$.post(
OC.filePath('settings', 'ajax', 'togglegroups.php'),
{
username: user,
group: group
},
function (response) {
if(response.status === 'success'
&& UserList.availableGroups.indexOf(response.data.groupname) === -1
&& response.data.action === 'add') {
UserList.availableGroups.push(response.data.groupname);
}
if(response.data.message) {
OC.Notification.show(response.data.message);
}
}
);
};
} else {
checkHandeler = false;
}
var addGroup = function (select, group) {
$('select[multiple]').each(function (index, element) {
if ($(element).find('option[value="' + group + '"]').length === 0 && select.data('msid') !== $(element).data('msid')) {
$(element).append('<option value="' + escapeHTML(group) + '">' + escapeHTML(group) + '</option>');
}
});
};
var label;
if (oc_isadmin) {
label = t('settings', 'add group');
} else {
label = null;
}
element.multiSelect({
createCallback: addGroup,
createText: label,
selectedFirst: true,
checked: checked,
oncheck: checkHandeler,
onuncheck: checkHandeler,
minWidth: 100
});
}
if ($(element).hasClass('subadminsselect')) {
if (element.data('subadmin')) {
checked = element.data('subadmin');
}
var checkHandeler = function (group) {
if (group === 'admin') {
return false;
}
$.post(
OC.filePath('settings', 'ajax', 'togglesubadmins.php'),
{
username: user,
group: group
},
function () {
}
);
};
var addSubAdmin = function (group) {
$('select[multiple]').each(function (index, element) {
if ($(element).find('option[value="' + group + '"]').length === 0) {
$(element).append('<option value="' + escapeHTML(group) + '">' + escapeHTML(group) + '</option>');
}
});
};
element.multiSelect({
createCallback: addSubAdmin,
createText: null,
checked: checked,
oncheck: checkHandeler,
onuncheck: checkHandeler,
minWidth: 100
});
}
},
_onScroll: function(e) {
if (!!UserList.noMoreEntries) {
return;
}
if ($(window).scrollTop() + $(window).height() > $(document).height() - 500) {
UserList.update(true);
}
},
};
$(document).ready(function () {
UserList.doSort();
UserList.availableGroups = $('#content table').data('groups');
$(window).scroll(function(e) {UserList._onScroll(e);});
$('table').after($('<div class="loading" style="height: 200px; visibility: hidden;"></div>'));
$('select[multiple]').each(function (index, element) {
UserList.applyMultiplySelect($(element));
});
$('table').on('click', 'td.remove>a', function (event) {
var row = $(this).parent().parent();
var uid = $(row).attr('data-uid');
$(row).hide();
// Call function for handling delete/undo
UserList.do_delete(uid);
});
$('table').on('click', 'td.password>img', function (event) {
event.stopPropagation();
var img = $(this);
var uid = img.parent().parent().attr('data-uid');
var input = $('<input type="password">');
img.css('display', 'none');
img.parent().children('span').replaceWith(input);
input.focus();
input.keypress(function (event) {
if (event.keyCode === 13) {
if ($(this).val().length > 0) {
var recoveryPasswordVal = $('input:password[id="recoveryPassword"]').val();
$.post(
OC.generateUrl('/settings/users/changepassword'),
{username: uid, password: $(this).val(), recoveryPassword: recoveryPasswordVal},
function (result) {
if (result.status != 'success') {
OC.Notification.show(t('admin', result.data.message));
}
}
);
input.blur();
} else {
input.blur();
}
}
});
input.blur(function () {
$(this).replaceWith($('<span>●●●●●●●</span>'));
img.css('display', '');
});
});
$('input:password[id="recoveryPassword"]').keyup(function(event) {
OC.Notification.hide();
});
$('table').on('click', 'td.password', function (event) {
$(this).children('img').click();
});
$('table').on('click', 'td.displayName>img', function (event) {
event.stopPropagation();
var img = $(this);
var uid = img.parent().parent().attr('data-uid');
var displayName = escapeHTML(img.parent().parent().attr('data-displayName'));
var input = $('<input type="text" value="' + displayName + '">');
img.css('display', 'none');
img.parent().children('span').replaceWith(input);
input.focus();
input.keypress(function (event) {
if (event.keyCode === 13) {
if ($(this).val().length > 0) {
$.post(
OC.filePath('settings', 'ajax', 'changedisplayname.php'),
{username: uid, displayName: $(this).val()},
function (result) {
if (result && result.status==='success'){
img.parent().parent().find('div.avatardiv').avatar(result.data.username, 32);
}
}
);
input.blur();
} else {
input.blur();
}
}
});
input.blur(function () {
var input = $(this),
displayName = input.val();
input.closest('tr').attr('data-displayName', displayName);
input.replaceWith('<span>' + escapeHTML(displayName) + '</span>');
img.css('display', '');
});
});
$('table').on('click', 'td.displayName', function (event) {
$(this).children('img').click();
});
$('select.quota, select.quota-user').singleSelect().on('change', function () {
var select = $(this);
var uid = $(this).parent().parent().attr('data-uid');
var quota = $(this).val();
setQuota(uid, quota, function(returnedQuota){
if (quota !== returnedQuota) {
select.find(':selected').text(returnedQuota);
}
});
});
$('#newuser').submit(function (event) {
event.preventDefault();
var username = $('#newusername').val();
var password = $('#newuserpassword').val();
if ($.trim(username) === '') {
OC.dialogs.alert(
t('settings', 'A valid username must be provided'),
t('settings', 'Error creating user'));
return false;
}
if ($.trim(password) === '') {
OC.dialogs.alert(
t('settings', 'A valid password must be provided'),
t('settings', 'Error creating user'));
return false;
}
var groups = $('#newusergroups').prev().children('div').data('settings').checked;
$('#newuser').get(0).reset();
$.post(
OC.filePath('settings', 'ajax', 'createuser.php'),
{
username: username,
password: password,
groups: groups
},
function (result) {
if (result.status !== 'success') {
OC.dialogs.alert(result.data.message,
t('settings', 'Error creating user'));
} else {
if (result.data.groups) {
var addedGroups = result.data.groups;
UserList.availableGroups = $.unique($.merge(UserList.availableGroups, addedGroups));
}
if (result.data.homeExists){
OC.Notification.hide();
OC.Notification.show(t('settings', 'Warning: Home directory for user "{user}" already exists', {user: result.data.username}));
if (UserList.notificationTimeout){
window.clearTimeout(UserList.notificationTimeout);
}
UserList.notificationTimeout = window.setTimeout(
function(){
OC.Notification.hide();
UserList.notificationTimeout = null;
}, 10000);
}
if($('tr[data-uid="' + username + '"]').length === 0) {
UserList.add(username, username, result.data.groups, null, 'default', true);
}
}
}
);
});
// Handle undo notifications
OC.Notification.hide();
$('#notification').on('click', '.undo', function () {
if ($('#notification').data('deleteuser')) {
$('tbody tr').filterAttr('data-uid', UserList.deleteUid).show();
UserList.deleteCanceled = true;
}
OC.Notification.hide();
});
UserList.useUndo = ('onbeforeunload' in window);
$(window).bind('beforeunload', function () {
UserList.finishDelete(null);
});
});

View File

@ -0,0 +1,171 @@
/**
* Copyright (c) 2014, Arthur Schiwon <blizzz@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
*/
/**
* takes care of deleting things represented by an ID
*
* @class
* @param {string} endpoint the corresponding ajax PHP script. Currently limited
* to settings - ajax path.
* @param {string} paramID the by the script expected parameter name holding the
* ID of the object to delete
* @param {markCallback} markCallback function to be called after successfully
* marking the object for deletion.
* @param {removeCallback} removeCallback the function to be called after
* successful delete.
*/
function DeleteHandler(endpoint, paramID, markCallback, removeCallback) {
this.oidToDelete = false;
this.canceled = false;
this.ajaxEndpoint = endpoint;
this.ajaxParamID = paramID;
this.markCallback = markCallback;
this.removeCallback = removeCallback;
this.undoCallback = false;
this.notifier = false;
this.notificationDataID = false;
this.notificationMessage = false;
this.notificationPlaceholder = '%oid';
}
/**
* The function to be called after successfully marking the object for deletion
* @callback markCallback
* @param {string} oid the ID of the specific user or group
*/
/**
* The function to be called after successful delete. The id of the object will
* be passed as argument. Unsuccessful operations will display an error using
* OC.dialogs, no callback is fired.
* @callback removeCallback
* @param {string} oid the ID of the specific user or group
*/
/**
* This callback is fired after "undo" was clicked so the consumer can update
* the web interface
* @callback undoCallback
* @param {string} oid the ID of the specific user or group
*/
/**
* enabled the notification system. Required for undo UI.
*
* @param {object} notifier Usually OC.Notification
* @param {string} dataID an identifier for the notifier, e.g. 'deleteuser'
* @param {string} message the message that should be shown upon delete. %oid
* will be replaced with the affected id of the item to be deleted
* @param {undoCallback} undoCallback called after "undo" was clicked
*/
DeleteHandler.prototype.setNotification = function(notifier, dataID, message, undoCallback) {
this.notifier = notifier;
this.notificationDataID = dataID;
this.notificationMessage = message;
this.undoCallback = undoCallback;
var dh = this;
$('#notification').on('click', '.undo', function () {
if ($('#notification').data(dh.notificationDataID)) {
var oid = dh.oidToDelete;
dh.cancel();
if(typeof dh.undoCallback !== 'undefined') {
dh.undoCallback(oid);
}
}
dh.notifier.hide();
});
};
/**
* shows the Undo Notification (if configured)
*/
DeleteHandler.prototype.showNotification = function() {
if(this.notifier !== false) {
if(!this.notifier.isHidden()) {
this.hideNotification();
}
$('#notification').data(this.notificationDataID, true);
var msg = this.notificationMessage.replace(this.notificationPlaceholder,
this.oidToDelete);
this.notifier.showHtml(msg);
}
};
/**
* hides the Undo Notification
*/
DeleteHandler.prototype.hideNotification = function() {
if(this.notifier !== false) {
$('#notification').removeData(this.notificationDataID);
this.notifier.hide();
}
};
/**
* initializes the delete operation for a given object id
*
* @param {string} oid the object id
*/
DeleteHandler.prototype.mark = function(oid) {
if(this.oidToDelete !== false) {
this.delete();
}
this.oidToDelete = oid;
this.canceled = false;
this.markCallback(oid);
this.showNotification();
};
/**
* cancels a delete operation
*/
DeleteHandler.prototype.cancel = function() {
this.canceled = true;
this.oidToDelete = false;
};
/**
* executes a delete operation. Requires that the operation has been
* initialized by mark(). On error, it will show a message via
* OC.dialogs.alert. On success, a callback is fired so that the client can
* update the web interface accordingly.
*/
DeleteHandler.prototype.delete = function() {
if(this.canceled || this.oidToDelete === false) {
return false;
}
var dh = this;
if($('#notification').data(this.notificationDataID) === true) {
dh.hideNotification();
}
var payload = {};
payload[dh.ajaxParamID] = dh.oidToDelete;
$.ajax({
type: 'POST',
url: OC.filePath('settings', 'ajax', dh.ajaxEndpoint),
async: false,
data: payload,
success: function (result) {
if (result.status === 'success') {
// Remove undo option, & remove user from table
//TODO: following line
dh.removeCallback(dh.oidToDelete);
dh.canceled = true;
} else {
OC.dialogs.alert(result.data.message, t('settings', 'Unable to delete ' + escapeHTML(dh.oidToDelete)));
dh.undoCallback(dh.oidToDelete);
}
}
});
};

View File

@ -0,0 +1,82 @@
/**
* Copyright (c) 2014, Arthur Schiwon <blizzz@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
*/
/**
* @brief this object takes care of the filter functionality on the user
* management page
* @param jQuery input element that works as the user text input field
* @param object the UserList object
*/
function UserManagementFilter(filterInput, userList, groupList) {
this.filterInput = filterInput;
this.userList = userList;
this.groupList = groupList;
this.thread = undefined;
this.oldval = this.filterInput.val();
this.init();
}
/**
* @brief sets up when the filter action shall be triggered
*/
UserManagementFilter.prototype.init = function() {
var umf = this;
this.filterInput.keyup(function(e) {
//we want to react on any printable letter, plus on modifying stuff like
//Backspace and Delete. extended https://stackoverflow.com/a/12467610
var valid =
e.keyCode === 0 || e.keyCode === 8 || // like ö or ж; backspace
e.keyCode === 9 || e.keyCode === 46 || // tab; delete
e.keyCode === 32 || // space
(e.keyCode > 47 && e.keyCode < 58) || // number keys
(e.keyCode > 64 && e.keyCode < 91) || // letter keys
(e.keyCode > 95 && e.keyCode < 112) || // numpad keys
(e.keyCode > 185 && e.keyCode < 193) || // ;=,-./` (in order)
(e.keyCode > 218 && e.keyCode < 223); // [\]' (in order)
//besides the keys, the value must have been changed compared to last
//time
if(valid && umf.oldVal !== umf.getPattern()) {
umf.run();
}
umf.oldVal = umf.getPattern();
});
};
/**
* @brief the filter action needs to be done, here the accurate steps are being
* taken care of
*/
UserManagementFilter.prototype.run = _.debounce(function() {
this.userList.empty();
this.userList.update(GroupList.getCurrentGID());
this.groupList.empty();
this.groupList.update();
},
300
);
/**
* @brief returns the filter String
* @returns string
*/
UserManagementFilter.prototype.getPattern = function() {
return this.filterInput.val();
};
/**
* @brief adds reset functionality to an HTML element
* @param jQuery the jQuery representation of that element
*/
UserManagementFilter.prototype.addResetButton = function(button) {
var umf = this;
button.click(function(){
umf.filterInput.val('');
umf.run();
});
};

292
settings/js/users/groups.js Normal file
View File

@ -0,0 +1,292 @@
/**
* Copyright (c) 2014, Raghu Nayyar <beingminimal@gmail.com>
* Copyright (c) 2014, Arthur Schiwon <blizzz@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
*/
var $userGroupList;
var GroupList;
GroupList = {
activeGID: '',
addGroup: function (gid, usercount) {
var $li = $userGroupList.find('.isgroup:last-child').clone();
$li
.data('gid', gid)
.find('.groupname').text(gid);
GroupList.setUserCount($li, usercount);
$li.appendTo($userGroupList);
GroupList.sortGroups();
return $li;
},
setUserCount: function (groupLiElement, usercount) {
var $groupLiElement = $(groupLiElement);
if (usercount === undefined || usercount === 0) {
usercount = '';
}
$groupLiElement.data('usercount', usercount);
$groupLiElement.find('.usercount').text(usercount);
},
getCurrentGID: function () {
return GroupList.activeGID;
},
sortGroups: function () {
var lis = $('.isgroup').get();
lis.sort(function (a, b) {
return UserList.alphanum(
$(a).find('a span').text(),
$(b).find('a span').text()
);
});
var items = [];
$.each(lis, function (index, li) {
items.push(li);
if (items.length === 100) {
$userGroupList.append(items);
items = [];
}
});
if (items.length > 0) {
$userGroupList.append(items);
}
},
createGroup: function (groupname) {
$.post(
OC.filePath('settings', 'ajax', 'creategroup.php'),
{
groupname: groupname
},
function (result) {
if (result.status !== 'success') {
OC.dialogs.alert(result.data.message,
t('settings', 'Error creating group'));
}
else {
if (result.data.groupname) {
var addedGroup = result.data.groupname;
UserList.availableGroups = $.unique($.merge(UserList.availableGroups, [addedGroup]));
GroupList.addGroup(result.data.groupname);
$('.groupsselect, .subadminsselect')
.append($('<option>', { value: result.data.groupname })
.text(result.data.groupname));
}
GroupList.toggleAddGroup();
}
}
);
},
update: function () {
if (GroupList.updating) {
return;
}
GroupList.updating = true;
$.get(
OC.generateUrl('/settings/ajax/grouplist'),
{pattern: filter.getPattern()},
function (result) {
var lis = [];
if (result.status === 'success') {
$.each(result.data, function (i, subset) {
$.each(subset, function (index, group) {
if (GroupList.getGroupLI(group.name).length > 0) {
GroupList.setUserCount(GroupList.getGroupLI(group.name).first(), group.usercount);
}
else {
var $li = GroupList.addGroup(group.name, group.usercount);
$li.addClass('appear transparent');
lis.push($li);
}
});
});
if (result.data.length > 0) {
GroupList.doSort();
}
else {
GroupList.noMoreEntries = true;
}
_.defer(function () {
$(lis).each(function () {
this.removeClass('transparent')
});
});
}
GroupList.updating = false;
}
);
},
elementBelongsToAddGroup: function (el) {
return !(el !== $('#newgroup-form').get(0) &&
$('#newgroup-form').find($(el)).length === 0);
},
hasAddGroupNameText: function () {
var name = $('#newgroupname').val();
return $.trim(name) !== '';
},
showGroup: function (gid) {
GroupList.activeGID = gid;
UserList.empty();
UserList.update(gid);
$userGroupList.find('li').removeClass('active');
if (gid !== undefined) {
//TODO: treat Everyone properly
GroupList.getGroupLI(gid).addClass('active');
}
},
isAddGroupButtonVisible: function () {
return $('#newgroup-init').is(":visible");
},
toggleAddGroup: function (event) {
if (GroupList.isAddGroupButtonVisible()) {
event.stopPropagation();
$('#newgroup-form').show();
$('#newgroup-init').hide();
$('#newgroupname').focus();
}
else {
$('#newgroup-form').hide();
$('#newgroup-init').show();
$('#newgroupname').val('');
}
},
isGroupNameValid: function (groupname) {
if ($.trim(groupname) === '') {
OC.dialogs.alert(
t('settings', 'A valid group name must be provided'),
t('settings', 'Error creating group'));
return false;
}
return true;
},
hide: function (gid) {
GroupList.getGroupLI(gid).hide();
},
show: function (gid) {
GroupList.getGroupLI(gid).show();
},
remove: function (gid) {
GroupList.getGroupLI(gid).remove();
},
empty: function () {
$userGroupList.find('.isgroup').filter(function(index, item){
return $(item).data('gid') !== '';
}).remove();
},
initDeleteHandling: function () {
//set up handler
GroupDeleteHandler = new DeleteHandler('removegroup.php', 'groupname',
GroupList.hide, GroupList.remove);
//configure undo
OC.Notification.hide();
var msg = t('settings', 'deleted') + ' %oid <span class="undo">' +
t('settings', 'undo') + '</span>';
GroupDeleteHandler.setNotification(OC.Notification, 'deletegroup', msg,
GroupList.show);
//when to mark user for delete
$userGroupList.on('click', '.delete', function () {
// Call function for handling delete/undo
GroupDeleteHandler.mark(GroupList.getElementGID(this));
});
//delete a marked user when leaving the page
$(window).on('beforeunload', function () {
GroupDeleteHandler.delete();
});
},
getGroupLI: function (gid) {
return $userGroupList.find('li.isgroup').filter(function () {
return GroupList.getElementGID(this) === gid;
});
},
getElementGID: function (element) {
return ($(element).closest('li').data('gid') || '').toString();
}
};
$(document).ready( function () {
$userGroupList = $('#usergrouplist');
GroupList.initDeleteHandling();
// Display or hide of Create Group List Element
$('#newgroup-form').hide();
$('#newgroup-init').on('click', function (e) {
GroupList.toggleAddGroup(e);
});
$(document).on('click keydown keyup', function(event) {
if(!GroupList.isAddGroupButtonVisible() &&
!GroupList.elementBelongsToAddGroup(event.target) &&
!GroupList.hasAddGroupNameText()) {
GroupList.toggleAddGroup();
}
// Escape
if(!GroupList.isAddGroupButtonVisible() && event.keyCode && event.keyCode === 27) {
GroupList.toggleAddGroup();
}
});
// Responsible for Creating Groups.
$('#newgroup-form form').submit(function (event) {
event.preventDefault();
if(GroupList.isGroupNameValid($('#newgroupname').val())) {
GroupList.createGroup($('#newgroupname').val());
}
});
// click on group name
$userGroupList.on('click', '.isgroup', function () {
GroupList.showGroup(GroupList.getElementGID(this));
});
// Implements Quota Settings Toggle.
var $appSettings = $('#app-settings');
$('#app-settings-header').on('click keydown',function(event) {
if(wrongKey(event)) {
return;
}
if($appSettings.hasClass('open')) {
$appSettings.switchClass('open', '');
} else {
$appSettings.switchClass('', 'open');
}
});
$('body').on('click', function(event){
if($appSettings.find(event.target).length === 0) {
$appSettings.switchClass('open', '');
}
});
});
var wrongKey = function(event) {
return ((event.type === 'keydown' || event.type === 'keypress') &&
(event.keyCode !== 32 && event.keyCode !== 13));
};

616
settings/js/users/users.js Normal file
View File

@ -0,0 +1,616 @@
/**
* Copyright (c) 2014, Arthur Schiwon <blizzz@owncloud.com>
* Copyright (c) 2014, Raghu Nayyar <beingminimal@gmail.com>
* Copyright (c) 2011, Robin Appelman <icewind1991@gmail.com>
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
*/
var $userList;
var $userListBody;
var filter;
var UserList = {
availableGroups: [],
offset: 30, //The first 30 users are there. No prob, if less in total.
//hardcoded in settings/users.php
usersToLoad: 10, //So many users will be loaded when user scrolls down
currentGid: '',
add: function (username, displayname, groups, subadmin, quota, storageLocation, lastLogin, sort) {
var $tr = $userListBody.find('tr:first-child').clone();
var subadminsEl;
var subadminSelect;
var groupsSelect;
if ($tr.find('div.avatardiv').length){
$tr.find('.avatardiv').imageplaceholder(username, displayname);
$('div.avatardiv', $tr).avatar(username, 32);
}
$tr.data('uid', username);
$tr.data('displayname', displayname);
$tr.find('td.name').text(username);
$tr.find('td.displayName > span').text(displayname);
// make them look like the multiselect buttons
// until they get time to really get initialized
groupsSelect = $('<select multiple="multiple" class="groupsselect multiselect button" data-placehoder="Groups" title="' + t('settings', 'Groups') + '"></select>')
.data('username', username)
.data('user-groups', groups);
if ($tr.find('td.subadmins').length > 0) {
subadminSelect = $('<select multiple="multiple" class="subadminsselect multiselect button" data-placehoder="subadmins" title="' + t('settings', 'Group Admin') + '">')
.data('username', username)
.data('user-groups', groups)
.data('subadmin', subadmin);
$tr.find('td.subadmins').empty();
}
$.each(this.availableGroups, function (i, group) {
groupsSelect.append($('<option value="' + escapeHTML(group) + '">' + escapeHTML(group) + '</option>'));
if (typeof subadminSelect !== 'undefined' && group !== 'admin') {
subadminSelect.append($('<option value="' + escapeHTML(group) + '">' + escapeHTML(group) + '</option>'));
}
});
$tr.find('td.groups').empty().append(groupsSelect);
subadminsEl = $tr.find('td.subadmins');
if (subadminsEl.length > 0) {
subadminsEl.append(subadminSelect);
}
if ($tr.find('td.remove img').length === 0 && OC.currentUser !== username) {
var deleteImage = $('<img class="svg action">').attr({
src: OC.imagePath('core', 'actions/delete')
});
var deleteLink = $('<a class="action delete">')
.attr({ href: '#', 'original-title': t('settings', 'Delete')})
.append(deleteImage);
$tr.find('td.remove').append(deleteLink);
} else if (OC.currentUser === username) {
$tr.find('td.remove a').remove();
}
var $quotaSelect = $tr.find('.quota-user');
if (quota === 'default') {
$quotaSelect
.data('previous', 'default')
.find('option').attr('selected', null)
.first().attr('selected', 'selected');
} else {
if ($quotaSelect.find('option[value="' + quota + '"]').length > 0) {
$quotaSelect.find('option[value="' + quota + '"]').attr('selected', 'selected');
} else {
$quotaSelect.append('<option value="' + escapeHTML(quota) + '" selected="selected">' + escapeHTML(quota) + '</option>');
}
}
$tr.find('td.storageLocation').text(storageLocation);
if(lastLogin === 0) {
lastLogin = t('settings', 'never');
} else {
lastLogin = new Date(lastLogin * 1000);
lastLogin = relative_modified_date(lastLogin.getTime() / 1000);
}
$tr.find('td.lastLogin').text(lastLogin);
$tr.appendTo($userList);
if(UserList.isEmpty === true) {
//when the list was emptied, one row was left, necessary to keep
//add working and the layout unbroken. We need to remove this item
$tr.show();
$userListBody.find('tr:first').remove();
UserList.isEmpty = false;
UserList.checkUsersToLoad();
}
if (sort) {
UserList.doSort();
}
$quotaSelect.on('change', function () {
var uid = UserList.getUID(this);
var quota = $(this).val();
setQuota(uid, quota, function(returnedQuota){
if (quota !== returnedQuota) {
$($quotaSelect).find(':selected').text(returnedQuota);
}
});
});
// defer init so the user first sees the list appear more quickly
window.setTimeout(function(){
$quotaSelect.singleSelect();
UserList.applyGroupSelect(groupsSelect);
if (subadminSelect) {
UserList.applySubadminSelect(subadminSelect);
}
}, 0);
return $tr;
},
// From http://my.opera.com/GreyWyvern/blog/show.dml/1671288
alphanum: function(a, b) {
function chunkify(t) {
var tz = [], x = 0, y = -1, n = 0, i, j;
while (i = (j = t.charAt(x++)).charCodeAt(0)) {
var m = (i === 46 || (i >=48 && i <= 57));
if (m !== n) {
tz[++y] = "";
n = m;
}
tz[y] += j;
}
return tz;
}
var aa = chunkify(a.toLowerCase());
var bb = chunkify(b.toLowerCase());
for (var x = 0; aa[x] && bb[x]; x++) {
if (aa[x] !== bb[x]) {
var c = Number(aa[x]), d = Number(bb[x]);
if (c === aa[x] && d === bb[x]) {
return c - d;
} else {
return (aa[x] > bb[x]) ? 1 : -1;
}
}
}
return aa.length - bb.length;
},
preSortSearchString: function(a, b) {
var pattern = filter.getPattern();
if(typeof pattern === 'undefined') {
return undefined;
}
pattern = pattern.toLowerCase();
var aMatches = false;
var bMatches = false;
if(typeof a === 'string' && a.toLowerCase().indexOf(pattern) === 0) {
aMatches = true;
}
if(typeof b === 'string' && b.toLowerCase().indexOf(pattern) === 0) {
bMatches = true;
}
if((aMatches && bMatches) || (!aMatches && !bMatches)) {
return undefined;
}
if(aMatches) {
return -1;
} else {
return 1;
}
},
doSort: function() {
var rows = $userListBody.find('tr').get();
rows.sort(function(a, b) {
a = $(a).find('td.name').text();
b = $(b).find('td.name').text();
var firstSort = UserList.preSortSearchString(a, b);
if(typeof firstSort !== 'undefined') {
return firstSort;
}
return UserList.alphanum(a, b);
});
var items = [];
$.each(rows, function(index, row) {
items.push(row);
if(items.length === 100) {
$userListBody.append(items);
items = [];
}
});
if(items.length > 0) {
$userListBody.append(items);
}
},
checkUsersToLoad: function() {
//30 shall be loaded initially, from then on always 10 upon scrolling
if(UserList.isEmpty === false) {
UserList.usersToLoad = 10;
} else {
UserList.usersToLoad = 30;
}
},
empty: function() {
//one row needs to be kept, because it is cloned to add new rows
$userListBody.find('tr:not(:first)').remove();
var $tr = $userListBody.find('tr:first');
$tr.hide();
//on an update a user may be missing when the username matches with that
//of the hidden row. So change this to a random string.
$tr.data('uid', Math.random().toString(36).substring(2));
UserList.isEmpty = true;
UserList.offset = 0;
UserList.checkUsersToLoad();
},
hide: function(uid) {
UserList.getRow(uid).hide();
},
show: function(uid) {
UserList.getRow(uid).show();
},
remove: function(uid) {
UserList.getRow(uid).remove();
},
has: function(uid) {
return UserList.getRow(uid).length > 0;
},
getRow: function(uid) {
return $userListBody.find('tr').filter(function(){
return UserList.getUID(this) === uid;
});
},
getUID: function(element) {
return ($(element).closest('tr').data('uid') || '').toString();
},
getDisplayName: function(element) {
return ($(element).closest('tr').data('displayname') || '').toString();
},
initDeleteHandling: function() {
//set up handler
UserDeleteHandler = new DeleteHandler('removeuser.php', 'username',
UserList.hide, UserList.remove);
//configure undo
OC.Notification.hide();
var msg = t('settings', 'deleted') + ' %oid <span class="undo">' +
t('settings', 'undo') + '</span>';
UserDeleteHandler.setNotification(OC.Notification, 'deleteuser', msg,
UserList.show);
//when to mark user for delete
$userListBody.on('click', '.delete', function () {
// Call function for handling delete/undo
var uid = UserList.getUID(this);
UserDeleteHandler.mark(uid);
});
//delete a marked user when leaving the page
$(window).on('beforeunload', function () {
UserDeleteHandler.delete();
});
},
update: function (gid) {
if (UserList.updating) {
return;
}
$userList.siblings('.loading').css('visibility', 'visible');
UserList.updating = true;
if(gid === undefined) {
gid = '';
}
UserList.currentGid = gid;
var pattern = filter.getPattern();
$.get(
OC.generateUrl('/settings/ajax/userlist'),
{ offset: UserList.offset, limit: UserList.usersToLoad, gid: gid, pattern: pattern },
function (result) {
var loadedUsers = 0;
var trs = [];
if (result.status === 'success') {
//The offset does not mirror the amount of users available,
//because it is backend-dependent. For correct retrieval,
//always the limit(requested amount of users) needs to be added.
$.each(result.data, function (index, user) {
if(UserList.has(user.name)) {
return true;
}
var $tr = UserList.add(user.name, user.displayname, user.groups, user.subadmin, user.quota, user.storageLocation, user.lastLogin, false);
$tr.addClass('appear transparent');
trs.push($tr);
loadedUsers++;
});
if (result.data.length > 0) {
UserList.doSort();
$userList.siblings('.loading').css('visibility', 'hidden');
}
else {
UserList.noMoreEntries = true;
$userList.siblings('.loading').remove();
}
UserList.offset += loadedUsers;
// animate
setTimeout(function() {
for (var i = 0; i < trs.length; i++) {
trs[i].removeClass('transparent');
}
}, 0);
}
UserList.updating = false;
});
},
applyGroupSelect: function (element) {
var checked = [];
var $element = $(element);
var user = UserList.getUID($element);
if ($element.data('user-groups')) {
checked = $element.data('user-groups');
}
var checkHandler = null;
if(user) { // Only if in a user row, and not the #newusergroups select
checkHandler = function (group) {
if (user === OC.currentUser && group === 'admin') {
return false;
}
if (!oc_isadmin && checked.length === 1 && checked[0] === group) {
return false;
}
$.post(
OC.filePath('settings', 'ajax', 'togglegroups.php'),
{
username: user,
group: group
},
function (response) {
if (response.status === 'success') {
GroupList.update();
if (UserList.availableGroups.indexOf(response.data.groupname) === -1 &&
response.data.action === 'add'
) {
UserList.availableGroups.push(response.data.groupname);
}
}
if (response.data.message) {
OC.Notification.show(response.data.message);
}
}
);
}
};
var addGroup = function (select, group) {
$('select[multiple]').each(function (index, element) {
$element = $(element);
if ($element.find('option[value="' + group + '"]').length === 0 && select.data('msid') !== $element.data('msid')) {
$element.append('<option value="' + escapeHTML(group) + '">' + escapeHTML(group) + '</option>');
}
});
GroupList.addGroup(escapeHTML(group));
};
var label;
if (oc_isadmin) {
label = t('settings', 'add group');
}
else {
label = null;
}
$element.multiSelect({
createCallback: addGroup,
createText: label,
selectedFirst: true,
checked: checked,
oncheck: checkHandler,
onuncheck: checkHandler,
minWidth: 100
});
},
applySubadminSelect: function (element) {
var checked = [];
var $element = $(element);
var user = UserList.getUID($element);
if ($element.data('subadmin')) {
checked = $element.data('subadmin');
}
var checkHandler = function (group) {
if (group === 'admin') {
return false;
}
$.post(
OC.filePath('settings', 'ajax', 'togglesubadmins.php'),
{
username: user,
group: group
},
function () {
}
);
};
var addSubAdmin = function (group) {
$('select[multiple]').each(function (index, element) {
if ($(element).find('option[value="' + group + '"]').length === 0) {
$(element).append('<option value="' + escapeHTML(group) + '">' + escapeHTML(group) + '</option>');
}
});
};
$element.multiSelect({
createCallback: addSubAdmin,
createText: null,
checked: checked,
oncheck: checkHandler,
onuncheck: checkHandler,
minWidth: 100
});
},
_onScroll: function() {
if (!!UserList.noMoreEntries) {
return;
}
if (UserList.scrollArea.scrollTop() + UserList.scrollArea.height() > UserList.scrollArea.get(0).scrollHeight - 500) {
UserList.update(UserList.currentGid, true);
}
}
};
function setQuota (uid, quota, ready) {
$.post(
OC.filePath('settings', 'ajax', 'setquota.php'),
{username: uid, quota: quota},
function (result) {
if (ready) {
ready(result.data.quota);
}
}
);
}
$(document).ready(function () {
$userList = $('#userlist');
$userListBody = $userList.find('tbody');
UserList.initDeleteHandling();
// Implements User Search
filter = new UserManagementFilter($('#usersearchform input'), UserList, GroupList);
UserList.doSort();
UserList.availableGroups = $userList.data('groups');
UserList.scrollArea = $('#app-content');
UserList.scrollArea.scroll(function(e) {UserList._onScroll(e);});
$userList.after($('<div class="loading" style="height: 200px; visibility: hidden;"></div>'));
$('.groupsselect').each(function (index, element) {
UserList.applyGroupSelect(element);
});
$('.subadminsselect').each(function (index, element) {
UserList.applySubadminSelect(element);
});
$userListBody.on('click', '.password', function (event) {
event.stopPropagation();
var $td = $(this).closest('td');
var uid = UserList.getUID($td);
var $input = $('<input type="password">');
$td.find('img').hide();
$td.children('span').replaceWith($input);
$input
.focus()
.keypress(function (event) {
if (event.keyCode === 13) {
if ($(this).val().length > 0) {
var recoveryPasswordVal = $('input:password[id="recoveryPassword"]').val();
$.post(
OC.generateUrl('/settings/users/changepassword'),
{username: uid, password: $(this).val(), recoveryPassword: recoveryPasswordVal},
function (result) {
if (result.status != 'success') {
OC.Notification.show(t('admin', result.data.message));
}
}
);
$input.blur();
} else {
$input.blur();
}
}
})
.blur(function () {
$(this).replaceWith($('<span>●●●●●●●</span>'));
$td.find('img').show();
});
});
$('input:password[id="recoveryPassword"]').keyup(function() {
OC.Notification.hide();
});
$userListBody.on('click', '.displayName', function (event) {
event.stopPropagation();
var $td = $(this).closest('td');
var $tr = $td.closest('tr');
var uid = UserList.getUID($td);
var displayName = escapeHTML(UserList.getDisplayName($td));
var $input = $('<input type="text" value="' + displayName + '">');
$td.find('img').hide();
$td.children('span').replaceWith($input);
$input
.focus()
.keypress(function (event) {
if (event.keyCode === 13) {
if ($(this).val().length > 0) {
$tr.find('.avatardiv').imageplaceholder(uid, displayName);
$.post(
OC.filePath('settings', 'ajax', 'changedisplayname.php'),
{username: uid, displayName: $(this).val()},
function (result) {
if (result && result.status==='success'){
$tr.find('.avatardiv').avatar(result.data.username, 32);
}
}
);
$input.blur();
} else {
$input.blur();
}
}
})
.blur(function () {
var displayName = $input.val();
$tr.data('displayname', displayName);
$input.replaceWith('<span>' + escapeHTML(displayName) + '</span>');
$td.find('img').show();
});
});
$('#default_quota, .quota-user').singleSelect().on('change', function () {
var $select = $(this);
var uid = UserList.getUID($select);
var quota = $select.val();
setQuota(uid, quota, function(returnedQuota){
if (quota !== returnedQuota) {
$select.find(':selected').text(returnedQuota);
}
});
});
$('#newuser').submit(function (event) {
event.preventDefault();
var username = $('#newusername').val();
var password = $('#newuserpassword').val();
if ($.trim(username) === '') {
OC.dialogs.alert(
t('settings', 'A valid username must be provided'),
t('settings', 'Error creating user'));
return false;
}
if ($.trim(password) === '') {
OC.dialogs.alert(
t('settings', 'A valid password must be provided'),
t('settings', 'Error creating user'));
return false;
}
var groups = $('#newusergroups').val();
$('#newuser').get(0).reset();
$.post(
OC.filePath('settings', 'ajax', 'createuser.php'),
{
username: username,
password: password,
groups: groups
},
function (result) {
if (result.status !== 'success') {
OC.dialogs.alert(result.data.message,
t('settings', 'Error creating user'));
} else {
if (result.data.groups) {
var addedGroups = result.data.groups;
UserList.availableGroups = $.unique($.merge(UserList.availableGroups, addedGroups));
}
if (result.data.homeExists){
OC.Notification.hide();
OC.Notification.show(t('settings', 'Warning: Home directory for user "{user}" already exists', {user: result.data.username}));
if (UserList.notificationTimeout){
window.clearTimeout(UserList.notificationTimeout);
}
UserList.notificationTimeout = window.setTimeout(
function(){
OC.Notification.hide();
UserList.notificationTimeout = null;
}, 10000);
}
if(!UserList.has(username)) {
UserList.add(username, username, result.data.groups, null, 'default', result.data.storageLocation, 0, true);
}
}
}
);
});
});

View File

@ -25,6 +25,8 @@ $this->create('settings_admin', '/settings/admin')
// users
$this->create('settings_ajax_userlist', '/settings/ajax/userlist')
->actionInclude('settings/ajax/userlist.php');
$this->create('settings_ajax_grouplist', '/settings/ajax/grouplist')
->actionInclude('settings/ajax/grouplist.php');
$this->create('settings_ajax_createuser', '/settings/ajax/createuser.php')
->actionInclude('settings/ajax/createuser.php');
$this->create('settings_ajax_removeuser', '/settings/ajax/removeuser.php')
@ -44,6 +46,8 @@ $this->create('settings_users_changepassword', '/settings/users/changepassword')
->action('OC\Settings\ChangePassword\Controller', 'changeUserPassword');
$this->create('settings_ajax_changedisplayname', '/settings/ajax/changedisplayname.php')
->actionInclude('settings/ajax/changedisplayname.php');
$this->create('settings_ajax_changegorupname', '/settings/ajax/changegroupname.php')
->actionInclude('settings/ajax/changegroupname.php');
// personal
$this->create('settings_personal_changepassword', '/settings/personal/changepassword')
->post()

View File

@ -1,176 +0,0 @@
<?php
/**
* Copyright (c) 2011, Robin Appelman <icewind1991@gmail.com>
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
*/
$allGroups=array();
foreach($_["groups"] as $group) {
$allGroups[] = $group['name'];
}
$_['subadmingroups'] = $allGroups;
$items = array_flip($_['subadmingroups']);
unset($items['admin']);
$_['subadmingroups'] = array_flip($items);
?>
<div id="controls">
<form id="newuser" autocomplete="off">
<input id="newusername" type="text" placeholder="<?php p($l->t('Login Name'))?>" /> <input
type="password" id="newuserpassword"
placeholder="<?php p($l->t('Password'))?>" /> <select
class="groupsselect"
id="newusergroups" data-placeholder="groups"
title="<?php p($l->t('Groups'))?>" multiple="multiple">
<?php foreach($_["groups"] as $group): ?>
<option value="<?php p($group['name']);?>"><?php p($group['name']);?></option>
<?php endforeach;?>
</select> <input type="submit" value="<?php p($l->t('Create'))?>" />
</form>
<?php if((bool)$_['recoveryAdminEnabled']): ?>
<div class="recoveryPassword">
<input id="recoveryPassword"
type="password"
placeholder="<?php p($l->t('Admin Recovery Password'))?>"
title="<?php p($l->t('Enter the recovery password in order to recover the users files during password change'))?>"
alt="<?php p($l->t('Enter the recovery password in order to recover the users files during password change'))?>"/>
</div>
<?php endif; ?>
<div class="quota">
<span><?php p($l->t('Default Storage'));?></span>
<?php if((bool) $_['isadmin']): ?>
<select class='quota' data-inputtitle="<?php p($l->t('Please enter storage quota (ex: "512 MB" or "12 GB")')) ?>">
<option
<?php if($_['default_quota'] === 'none') print_unescaped('selected="selected"');?>
value='none'>
<?php p($l->t('Unlimited'));?>
</option>
<?php foreach($_['quota_preset'] as $preset):?>
<?php if($preset !== 'default'):?>
<option
<?php if($_['default_quota']==$preset) print_unescaped('selected="selected"');?>
value='<?php p($preset);?>'>
<?php p($preset);?>
</option>
<?php endif;?>
<?php endforeach;?>
<?php if($_['defaultQuotaIsUserDefined']):?>
<option selected="selected"
value='<?php p($_['default_quota']);?>'>
<?php p($_['default_quota']);?>
</option>
<?php endif;?>
<option data-new value='other'>
<?php p($l->t('Other'));?>
...
</option>
</select>
<?php endif; ?>
<?php if((bool) !$_['isadmin']): ?>
<select class='quota' disabled="disabled">
<option selected="selected">
<?php p($_['default_quota']);?>
</option>
</select>
<?php endif; ?>
</div>
</div>
<table class="hascontrols grid" data-groups="<?php p(json_encode($allGroups));?>">
<thead>
<tr>
<?php if ($_['enableAvatars']): ?>
<th id='headerAvatar'></th>
<?php endif; ?>
<th id='headerName'><?php p($l->t('Username'))?></th>
<th id="headerDisplayName"><?php p($l->t( 'Full Name' )); ?></th>
<th id="headerPassword"><?php p($l->t( 'Password' )); ?></th>
<th id="headerGroups"><?php p($l->t( 'Groups' )); ?></th>
<?php if(is_array($_['subadmins']) || $_['subadmins']): ?>
<th id="headerSubAdmins"><?php p($l->t('Group Admin')); ?></th>
<?php endif;?>
<th id="headerQuota"><?php p($l->t('Storage')); ?></th>
<th id="headerRemove">&nbsp;</th>
</tr>
</thead>
<tbody>
<?php foreach($_["users"] as $user): ?>
<tr data-uid="<?php p($user["name"]) ?>"
data-displayName="<?php p($user["displayName"]) ?>">
<?php if ($_['enableAvatars']): ?>
<td class="avatar"><div class="avatardiv"></div></td>
<?php endif; ?>
<td class="name"><?php p($user["name"]); ?></td>
<td class="displayName"><span><?php p($user["displayName"]); ?></span> <img class="svg action"
src="<?php p(image_path('core', 'actions/rename.svg'))?>"
alt="<?php p($l->t("change full name"))?>" title="<?php p($l->t("change full name"))?>"/>
</td>
<td class="password"><span>●●●●●●●</span> <img class="svg action"
src="<?php print_unescaped(image_path('core', 'actions/rename.svg'))?>"
alt="<?php p($l->t("set new password"))?>" title="<?php p($l->t("set new password"))?>"/>
</td>
<td class="groups"><select
class="groupsselect"
data-username="<?php p($user['name']) ;?>"
data-user-groups="<?php p(json_encode($user['groups'])) ;?>"
data-placeholder="groups" title="<?php p($l->t('Groups'))?>"
multiple="multiple">
<?php foreach($_["groups"] as $group): ?>
<option value="<?php p($group['name']);?>"><?php p($group['name']);?></option>
<?php endforeach;?>
</select>
</td>
<?php if(is_array($_['subadmins']) || $_['subadmins']): ?>
<td class="subadmins"><select
class="subadminsselect"
data-username="<?php p($user['name']) ;?>"
data-subadmin="<?php p(json_encode($user['subadmin']));?>"
data-placeholder="subadmins" title="<?php p($l->t('Group Admin'))?>"
multiple="multiple">
<?php foreach($_["subadmingroups"] as $group): ?>
<option value="<?php p($group);?>"><?php p($group);?></option>
<?php endforeach;?>
</select>
</td>
<?php endif;?>
<td class="quota">
<select class='quota-user' data-inputtitle="<?php p($l->t('Please enter storage quota (ex: "512 MB" or "12 GB")')) ?>">
<option
<?php if($user['quota'] === 'default') print_unescaped('selected="selected"');?>
value='default'>
<?php p($l->t('Default'));?>
</option>
<option
<?php if($user['quota'] === 'none') print_unescaped('selected="selected"');?>
value='none'>
<?php p($l->t('Unlimited'));?>
</option>
<?php foreach($_['quota_preset'] as $preset):?>
<option
<?php if($user['quota']==$preset) print_unescaped('selected="selected"');?>
value='<?php p($preset);?>'>
<?php p($preset);?>
</option>
<?php endforeach;?>
<?php if($user['isQuotaUserDefined']):?>
<option selected="selected" value='<?php p($user['quota']);?>'>
<?php p($user['quota']);?>
</option>
<?php endif;?>
<option value='other' data-new>
<?php p($l->t('Other'));?>
...
</option>
</select>
</td>
<td class="remove">
<?php if($user['name']!=OC_User::getUser()):?>
<a href="#" class="action delete" original-title="<?php p($l->t('Delete'))?>">
<img src="<?php print_unescaped(image_path('core', 'actions/delete.svg')) ?>" class="svg" />
</a>
<?php endif;?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>

View File

@ -0,0 +1,32 @@
<?php
/**
* Copyright (c) 2011, Robin Appelman <icewind1991@gmail.com>
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
*/
$userlistParams = array();
$allGroups=array();
foreach($_["groups"] as $group) {
$allGroups[] = $group['name'];
}
foreach($_["adminGroup"] as $group) {
$allGroups[] = $group['name'];
}
$userlistParams['subadmingroups'] = $allGroups;
$userlistParams['allGroups'] = json_encode($allGroups);
$items = array_flip($userlistParams['subadmingroups']);
unset($items['admin']);
$userlistParams['subadmingroups'] = array_flip($items);
?>
<div id="app-navigation">
<?php print_unescaped($this->inc('users/part.grouplist')); ?>
<div id="app-settings">
<?php print_unescaped($this->inc('users/part.setquota')); ?>
</div>
</div>
<div id="app-content">
<?php print_unescaped($this->inc('users/part.createuser')); ?>
<?php print_unescaped($this->inc('users/part.userlist', $userlistParams)); ?>
</div>

View File

@ -0,0 +1,34 @@
<div id="user-controls">
<form id="newuser" autocomplete="off">
<input id="newusername" type="text"
placeholder="<?php p($l->t('Login Name'))?>"
autocomplete="off" autocapitalize="off" autocorrect="off" />
<input
type="password" id="newuserpassword"
placeholder="<?php p($l->t('Password'))?>"
autocomplete="off" autocapitalize="off" autocorrect="off" />
<select
class="groupsselect" id="newusergroups" data-placeholder="groups"
title="<?php p($l->t('Groups'))?>" multiple="multiple">
<?php foreach($_["adminGroup"] as $adminGroup): ?>
<option value="<?php p($adminGroup['name']);?>"><?php p($adminGroup['name']); ?></option>
<?php endforeach; ?>
<?php foreach($_["groups"] as $group): ?>
<option value="<?php p($group['name']);?>"><?php p($group['name']);?></option>
<?php endforeach;?>
</select>
<input type="submit" class="button" value="<?php p($l->t('Create'))?>" />
</form>
<?php if((bool)$_['recoveryAdminEnabled']): ?>
<div class="recoveryPassword">
<input id="recoveryPassword"
type="password"
placeholder="<?php p($l->t('Admin Recovery Password'))?>"
title="<?php p($l->t('Enter the recovery password in order to recover the users files during password change'))?>"
alt="<?php p($l->t('Enter the recovery password in order to recover the users files during password change'))?>"/>
</div>
<?php endif; ?>
<form autocomplete="off" id="usersearchform">
<input type="text" class="input userFilter" placeholder="<?php p($l->t('Search Users and Groups')); ?>" />
</form>
</div>

View File

@ -0,0 +1,50 @@
<ul id="usergrouplist">
<!-- Add new group -->
<li id="newgroup-init">
<a href="#">
<span><?php p($l->t('Add Group'))?></span>
</a>
</li>
<li id="newgroup-form">
<form>
<input type="text" id="newgroupname" placeholder="<?php p($l->t('Group')); ?>..." />
<input type="submit" class="button" value="<?php p($l->t('Add Group'))?>" />
</form>
</li>
<!-- Everyone -->
<li data-gid="" class="isgroup">
<a href="#">
<span class="groupname">
<?php p($l->t('Everyone')); ?>
</span>
</a>
<span class="utils">
<span class="usercount"></span>
</span>
</li>
<!-- The Admin Group -->
<?php foreach($_["adminGroup"] as $adminGroup): ?>
<li data-gid="admin" class="isgroup">
<a href="#"><span class="groupname"><?php p($l->t('Admins')); ?></span></a>
<span class="utils">
<span class="usercount"><?php if($adminGroup['usercount'] > 0) { p($adminGroup['usercount']); } ?></span>
</span>
</li>
<?php endforeach; ?>
<!--List of Groups-->
<?php foreach($_["groups"] as $group): ?>
<li data-gid="<?php p($group['name']) ?>" data-usercount="<?php p($group['usercount']) ?>" class="isgroup">
<a href="#" class="dorename">
<span class="groupname"><?php p($group['name']); ?></span>
</a>
<span class="utils">
<span class="usercount"><?php if($group['usercount'] > 0) { p($group['usercount']); } ?></span>
<a href="#" class="action delete" original-title="<?php p($l->t('Delete'))?>">
<img src="<?php print_unescaped(image_path('core', 'actions/delete.svg')) ?>" class="svg" />
</a>
</span>
</li>
<?php endforeach; ?>
</ul>

View File

@ -0,0 +1,39 @@
<div id="app-settings-header">
<button class="settings-button" tabindex="0"></button>
</div>
<div id="app-settings-content">
<div class="quota">
<!-- Default storage -->
<span><?php p($l->t('Default Quota'));?></span>
<?php if((bool) $_['isAdmin']): ?>
<select id='default_quota' data-inputtitle="<?php p($l->t('Please enter storage quota (ex: "512 MB" or "12 GB")')) ?>">
<option <?php if($_['default_quota'] === 'none') print_unescaped('selected="selected"');?> value='none'>
<?php p($l->t('Unlimited'));?>
</option>
<?php foreach($_['quota_preset'] as $preset):?>
<?php if($preset !== 'default'):?>
<option <?php if($_['default_quota']==$preset) print_unescaped('selected="selected"');?> value='<?php p($preset);?>'>
<?php p($preset);?>
</option>
<?php endif;?>
<?php endforeach;?>
<?php if($_['defaultQuotaIsUserDefined']):?>
<option selected="selected" value='<?php p($_['default_quota']);?>'>
<?php p($_['default_quota']);?>
</option>
<?php endif;?>
<option data-new value='other'>
<?php p($l->t('Other'));?>
...
</option>
</select>
<?php endif; ?>
<?php if((bool) !$_['isAdmin']): ?>
<select class='quota' disabled="disabled">
<option selected="selected">
<?php p($_['default_quota']);?>
</option>
</select>
<?php endif; ?>
</div>
</div>

View File

@ -0,0 +1,116 @@
<table id="userlist" class="hascontrols grid" data-groups="<?php p($_['allGroups']);?>">
<thead>
<tr>
<?php if ($_['enableAvatars']): ?>
<th id='headerAvatar'></th>
<?php endif; ?>
<th id='headerName'><?php p($l->t('Username'))?></th>
<th id="headerDisplayName"><?php p($l->t( 'Full Name' )); ?></th>
<th id="headerPassword"><?php p($l->t( 'Password' )); ?></th>
<th id="headerGroups"><?php p($l->t( 'Groups' )); ?></th>
<?php if(is_array($_['subadmins']) || $_['subadmins']): ?>
<th id="headerSubAdmins"><?php p($l->t('Group Admin')); ?></th>
<?php endif;?>
<th id="headerQuota"><?php p($l->t('Quota')); ?></th>
<th id="headerStorageLocation"><?php p($l->t('Storage Location')); ?></th>
<th id="headerLastLogin"><?php p($l->t('Last Login')); ?></th>
<th id="headerRemove">&nbsp;</th>
</tr>
</thead>
<tbody>
<?php foreach($_["users"] as $user): ?>
<tr data-uid="<?php p($user["name"]) ?>"
data-displayname="<?php p($user["displayName"]) ?>">
<?php if ($_['enableAvatars']): ?>
<td class="avatar"><div class="avatardiv"></div></td>
<?php endif; ?>
<td class="name"><?php p($user["name"]); ?></td>
<td class="displayName"><span><?php p($user["displayName"]); ?></span> <img class="svg action"
src="<?php p(image_path('core', 'actions/rename.svg'))?>"
alt="<?php p($l->t("change full name"))?>" title="<?php p($l->t("change full name"))?>"/>
</td>
<td class="password"><span>●●●●●●●</span> <img class="svg action"
src="<?php print_unescaped(image_path('core', 'actions/rename.svg'))?>"
alt="<?php p($l->t("set new password"))?>" title="<?php p($l->t("set new password"))?>"/>
</td>
<td class="groups">
<select
class="groupsselect"
data-username="<?php p($user['name']) ;?>"
data-user-groups="<?php p(json_encode($user['groups'])) ;?>"
data-placeholder="groups" title="<?php p($l->t('Groups'))?>"
multiple="multiple">
<?php foreach($_["adminGroup"] as $adminGroup): ?>
<option value="<?php p($adminGroup['name']);?>"><?php p($adminGroup['name']); ?></option>
<?php endforeach; ?>
<?php foreach($_["groups"] as $group): ?>
<option value="<?php p($group['name']);?>"><?php p($group['name']);?></option>
<?php endforeach;?>
</select>
</td>
<?php if(is_array($_['subadmins']) || $_['subadmins']): ?>
<td class="subadmins">
<select
class="subadminsselect"
data-username="<?php p($user['name']) ;?>"
data-subadmin="<?php p(json_encode($user['subadmin']));?>"
data-placeholder="subadmins" title="<?php p($l->t('Group Admin'))?>"
multiple="multiple">
<?php foreach($_["subadmingroups"] as $group): ?>
<option value="<?php p($group);?>"><?php p($group);?></option>
<?php endforeach;?>
</select>
</td>
<?php endif;?>
<td class="quota">
<select class='quota-user' data-inputtitle="<?php p($l->t('Please enter storage quota (ex: "512 MB" or "12 GB")')) ?>">
<option
<?php if($user['quota'] === 'default') print_unescaped('selected="selected"');?>
value='default'>
<?php p($l->t('Default'));?>
</option>
<option
<?php if($user['quota'] === 'none') print_unescaped('selected="selected"');?>
value='none'>
<?php p($l->t('Unlimited'));?>
</option>
<?php foreach($_['quota_preset'] as $preset):?>
<option
<?php if($user['quota']==$preset) print_unescaped('selected="selected"');?>
value='<?php p($preset);?>'>
<?php p($preset);?>
</option>
<?php endforeach;?>
<?php if($user['isQuotaUserDefined']):?>
<option selected="selected" value='<?php p($user['quota']);?>'>
<?php p($user['quota']);?>
</option>
<?php endif;?>
<option value='other' data-new>
<?php p($l->t('Other'));?>
...
</option>
</select>
</td>
<td class="storageLocation"><?php p($user["storageLocation"]); ?></td>
<?php
if($user["lastLogin"] === 0) {
$lastLogin = $l->t('never');
$lastLoginDate = '';
} else {
$lastLogin = relative_modified_date($user["lastLogin"]);
$lastLoginDate = \OC_Util::formatDate($user["lastLogin"]);
}
?>
<td class="lastLogin" title="<?php p('<span style="white-space: nowrap;">'.$lastLoginDate.'</span>'); ?>"><?php p($lastLogin); ?></td>
<td class="remove">
<?php if($user['name']!=OC_User::getUser()):?>
<a href="#" class="action delete" original-title="<?php p($l->t('Delete'))?>">
<img src="<?php print_unescaped(image_path('core', 'actions/delete.svg')) ?>" class="svg" />
</a>
<?php endif;?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>

View File

@ -8,7 +8,10 @@
OC_Util::checkSubAdminUser();
// We have some javascript foo!
OC_Util::addScript( 'settings', 'users' );
OC_Util::addScript('settings', 'users/deleteHandler');
OC_Util::addScript('settings', 'users/filter');
OC_Util::addScript( 'settings', 'users/users' );
OC_Util::addScript( 'settings', 'users/groups' );
OC_Util::addScript( 'core', 'multiselect' );
OC_Util::addScript( 'core', 'singleselect' );
OC_Util::addScript('core', 'jquery.inview');
@ -16,19 +19,23 @@ OC_Util::addStyle( 'settings', 'settings' );
OC_App::setActiveNavigationEntry( 'core_users' );
$users = array();
$groups = array();
$userManager = \OC_User::getManager();
$groupManager = \OC_Group::getManager();
$isAdmin = OC_User::isAdminUser(OC_User::getUser());
$groupsInfo = new \OC\Group\MetaData(OC_User::getUser(), $isAdmin, $groupManager);
$groupsInfo->setSorting($groupsInfo::SORT_USERCOUNT);
list($adminGroup, $groups) = $groupsInfo->get();
$isadmin = OC_User::isAdminUser(OC_User::getUser());
$recoveryAdminEnabled = OC_App::isEnabled('files_encryption') &&
OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' );
if($isadmin) {
$accessiblegroups = OC_Group::getGroups();
$accessibleusers = OC_User::getDisplayNames('', 30);
if($isAdmin) {
$accessibleUsers = OC_User::getDisplayNames('', 30);
$subadmins = OC_SubAdmin::getAllSubAdmins();
}else{
$accessiblegroups = OC_SubAdmin::getSubAdminsGroups(OC_User::getUser());
$accessibleusers = OC_Group::displayNamesInGroups($accessiblegroups, '', 30);
$accessibleUsers = OC_Group::displayNamesInGroups($groups, '', 30);
$subadmins = false;
}
@ -45,7 +52,7 @@ $defaultQuotaIsUserDefined=array_search($defaultQuota, $quotaPreset)===false
&& array_search($defaultQuota, array('none', 'default'))===false;
// load users and quota
foreach($accessibleusers as $uid => $displayName) {
foreach($accessibleUsers as $uid => $displayName) {
$quota=OC_Preferences::getValue($uid, 'files', 'quota', 'default');
$isQuotaUserDefined=array_search($quota, $quotaPreset)===false
&& array_search($quota, array('none', 'default'))===false;
@ -55,6 +62,7 @@ foreach($accessibleusers as $uid => $displayName) {
$name = $name . ' ('.$uid.')';
}
$user = $userManager->get($uid);
$users[] = array(
"name" => $uid,
"displayName" => $displayName,
@ -62,23 +70,21 @@ foreach($accessibleusers as $uid => $displayName) {
'quota' => $quota,
'isQuotaUserDefined' => $isQuotaUserDefined,
'subadmin' => OC_SubAdmin::getSubAdminsGroups($uid),
'storageLocation' => $user->getHome(),
'lastLogin' => $user->getLastLogin(),
);
}
foreach( $accessiblegroups as $i ) {
// Do some more work here soon
$groups[] = array( "name" => $i );
}
$tmpl = new OC_Template( "settings", "users", "user" );
$tmpl = new OC_Template( "settings", "users/main", "user" );
$tmpl->assign( 'users', $users );
$tmpl->assign( 'groups', $groups );
$tmpl->assign( 'isadmin', (int) $isadmin);
$tmpl->assign( 'adminGroup', $adminGroup );
$tmpl->assign( 'isAdmin', (int) $isAdmin);
$tmpl->assign( 'subadmins', $subadmins);
$tmpl->assign( 'numofgroups', count($accessiblegroups));
$tmpl->assign( 'numofgroups', count($groups) + count($adminGroup));
$tmpl->assign( 'quota_preset', $quotaPreset);
$tmpl->assign( 'default_quota', $defaultQuota);
$tmpl->assign( 'defaultQuotaIsUserDefined', $defaultQuotaIsUserDefined);
$tmpl->assign( 'recoveryAdminEnabled', $recoveryAdminEnabled);
$tmpl->assign('enableAvatars', \OC_Config::getValue('enable_avatars', true));
$tmpl->assign( 'enableAvatars', \OC_Config::getValue('enable_avatars', true));
$tmpl->printPage();