Merge pull request #7151 from owncloud/user-jquery
Continuing the New User managementremotes/origin/ldap_group_count
commit
79b3558c6d
@ -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); |
||||
} |
||||
} |
||||
} |
||||
@ -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))); |
||||
@ -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); |
||||
}); |
||||
}); |
||||
@ -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); |
||||
} |
||||
} |
||||
}); |
||||
}; |
||||
@ -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(); |
||||
}); |
||||
}; |
||||
@ -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)); |
||||
}; |
||||
@ -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); |
||||
} |
||||
} |
||||
} |
||||
); |
||||
}); |
||||
|
||||
}); |
||||
@ -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"> </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> |
||||
@ -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> |
||||
@ -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> |
||||
@ -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> |
||||
@ -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> |
||||
@ -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"> </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> |
||||
Loading…
Reference in new issue