diff options
-rw-r--r-- | core/img/actions/user-plus.svg | 12 | ||||
-rw-r--r-- | core/img/actions/user-times.svg | 12 | ||||
-rw-r--r-- | settings/Controller/UsersController.php | 154 | ||||
-rw-r--r-- | settings/css/settings.css | 43 | ||||
-rw-r--r-- | settings/js/users/groups.js | 17 | ||||
-rw-r--r-- | settings/js/users/users.js | 84 | ||||
-rw-r--r-- | settings/routes.php | 1 | ||||
-rw-r--r-- | settings/templates/users/part.grouplist.php | 9 | ||||
-rw-r--r-- | settings/templates/users/part.userlist.php | 18 | ||||
-rw-r--r-- | settings/users.php | 15 |
10 files changed, 324 insertions, 41 deletions
diff --git a/core/img/actions/user-plus.svg b/core/img/actions/user-plus.svg new file mode 100644 index 00000000000..c236d9fc1df --- /dev/null +++ b/core/img/actions/user-plus.svg @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns:dc="http://purl.org/dc/elements/1.1/" version="1.1" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#"> +<metadata> +<rdf:RDF> +<cc:Work rdf:about=""> +<dc:format>image/svg+xml</dc:format> +<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> +</cc:Work> +</rdf:RDF> +</metadata> +<path d="m576 896q-159 0-271.5-112.5t-112.5-271.5 112.5-271.5 271.5-112.5 271.5 112.5 112.5 271.5-112.5 271.5-271.5 112.5zm960 128h352q13 0 22.5 9.5t9.5 22.5v192q0 13-9.5 22.5t-22.5 9.5h-352v352q0 13-9.5 22.5t-22.5 9.5h-192q-13 0-22.5-9.5t-9.5-22.5v-352h-352q-13 0-22.5-9.5t-9.5-22.5v-192q0-13 9.5-22.5t22.5-9.5h352v-352q0-13 9.5-22.5t22.5-9.5h192q13 0 22.5 9.5t9.5 22.5v352zm-736 224q0 52 38 90t90 38h256v238q-68 50-171 50h-874q-121 0-194-69t-73-190q0-53 3.5-103.5t14-109 26.5-108.5 43-97.5 62-81 85.5-53.5 111.5-20q19 0 39 17 79 61 154.5 91.5t164.5 30.5 164.5-30.5 154.5-91.5q20-17 39-17 132 0 217 96h-223q-52 0-90 38t-38 90v192z"/> +</svg> diff --git a/core/img/actions/user-times.svg b/core/img/actions/user-times.svg new file mode 100644 index 00000000000..d99463b55c4 --- /dev/null +++ b/core/img/actions/user-times.svg @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg version="1.1" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" viewBox="0 0 1792 1792"> +<metadata> +<rdf:RDF> +<cc:Work rdf:about=""> +<dc:format>image/svg+xml</dc:format> +<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> +</cc:Work> +</rdf:RDF> +</metadata> +<path d="m576 896q-159 0-271.5-112.5t-112.5-271.5 112.5-271.5 271.5-112.5 271.5 112.5 112.5 271.5-112.5 271.5-271.5 112.5zm1077 320l249 249q9 9 9 23 0 13-9 22l-136 136q-9 9-22 9-14 0-23-9l-249-249-249 249q-9 9-23 9-13 0-22-9l-136-136q-9-9-9-22 0-14 9-23l249-249-249-249q-9-9-9-23 0-13 9-22l136-136q9-9 22-9 14 0 23 9l249 249 249-249q9-9 23-9 13 0 22 9l136 136q9 9 9 22 0 14-9 23zm-498 0l-181 181q-37 37-37 91 0 53 37 90l83 83q-21 3-44 3h-874q-121 0-194-69t-73-190q0-53 3.5-103.5t14-109 26.5-108.5 43-97.5 62-81 85.5-53.5 111.5-20q19 0 39 17 154 122 319 122t319-122q20-17 39-17 28 0 57 6-28 27-41 50t-13 56q0 54 37 91z"/> +</svg> diff --git a/settings/Controller/UsersController.php b/settings/Controller/UsersController.php index 7f6602a510c..5949d9c9746 100644 --- a/settings/Controller/UsersController.php +++ b/settings/Controller/UsersController.php @@ -225,6 +225,7 @@ class UsersController extends Controller { 'email' => $displayName, 'isRestoreDisabled' => !$restorePossible, 'isAvatarAvailable' => $avatarAvailable, + 'isEnabled' => $user->isEnabled(), ]; } @@ -253,11 +254,6 @@ class UsersController extends Controller { * TODO: Tidy up and write unit tests - code is mainly static method calls */ public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') { - // FIXME: The JS sends the group '_everyone' instead of no GID for the "all users" group. - if($gid === '_everyone') { - $gid = ''; - } - // Remove backends if(!empty($backend)) { $activeBackends = $this->userManager->getBackends(); @@ -272,15 +268,18 @@ class UsersController extends Controller { $users = []; if ($this->isAdmin) { - - if($gid !== '') { + if($gid !== '' && $gid !== 'disabledUsers') { $batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset)); } else { $batch = $this->userManager->search($pattern, $limit, $offset); } foreach ($batch as $user) { - $users[] = $this->formatUserForIndex($user); + if( ($gid !== 'disabledUsers' && $user->isEnabled()) || + ($gid === 'disabledUsers' && !$user->isEnabled()) + ) { + $users[] = $this->formatUserForIndex($user); + } } } else { @@ -293,7 +292,7 @@ class UsersController extends Controller { $subAdminOfGroups = $gids; // Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group - if($gid !== '' && !in_array($gid, $subAdminOfGroups)) { + if($gid !== '' && $gid !== 'disabledUsers' && !in_array($gid, $subAdminOfGroups)) { $gid = ''; } @@ -318,7 +317,11 @@ class UsersController extends Controller { $this->groupManager->getUserGroupIds($user), $subAdminOfGroups )); - $users[] = $this->formatUserForIndex($user, $userGroups); + if( ($gid !== 'disabledUsers' && $user->isEnabled()) || + ($gid === 'disabledUsers' && !$user->isEnabled()) + ) { + $users[] = $this->formatUserForIndex($user, $userGroups); + } } } @@ -514,6 +517,137 @@ class UsersController extends Controller { /** * @NoAdminRequired + * + * @param string $id + * @return DataResponse + */ + public function disable($id) { + $userId = $this->userSession->getUser()->getUID(); + $user = $this->userManager->get($id); + + if($userId === $id) { + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Unable to disable user.') + ) + ), + Http::STATUS_FORBIDDEN + ); + } + + if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) { + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Authentication error') + ) + ), + Http::STATUS_FORBIDDEN + ); + } + + if($user) { + $user->setEnabled(false); + return new DataResponse( + array( + 'status' => 'success', + 'data' => array( + 'username' => $id, + 'enabled' => 0 + ) + ) + ); + } else { + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Unable to disable user.') + ) + ) + ); + } + } + + /** + * @NoAdminRequired + * + * @param string $id + * @return DataResponse + */ + public function enable($id) { + $userId = $this->userSession->getUser()->getUID(); + $user = $this->userManager->get($id); + + if($userId === $id) { + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Unable to enable user.') + ) + ), + Http::STATUS_FORBIDDEN + ); + } + + if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) { + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Authentication error') + ) + ), + Http::STATUS_FORBIDDEN + ); + } + + if($user) { + $user->setEnabled(true); + return new DataResponse( + array( + 'status' => 'success', + 'data' => array( + 'username' => $id, + 'enabled' => 1 + ) + ) + ); + } else { + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Unable to enable user.') + ) + ) + ); + } + } + + /** + * @NoAdminRequired + * + * @param string $id + * @param int $enabled + * @return DataResponse + */ + public function setEnabled($id, $enabled) { + if((bool)$enabled) { + return $this->enable($id); + } else { + return $this->disable($id); + } + } + + /** + * Set the mail address of a user + * + * @NoAdminRequired * @NoSubadminRequired * @PasswordConfirmationRequired * diff --git a/settings/css/settings.css b/settings/css/settings.css index 5693224b94c..4a245fcf52e 100644 --- a/settings/css/settings.css +++ b/settings/css/settings.css @@ -458,15 +458,16 @@ table.grid th, table.grid td { font-weight: normal; } td.name, td.password { padding-left:.8em; } -td.password>img,td.displayName>img, td.remove>a, td.quota>img { visibility:hidden; vertical-align: middle;} +td.password>img,td.displayName>img, td.quota>img { visibility:hidden; } td.password, td.quota, td.displayName { width:12em; cursor:pointer; } -td.password>span, td.quota>span, rd.displayName>span { margin-right: 1.2em; color: #C7C7C7; } +td.password>span, td.quota>span, td.displayName>span { margin-right: 1.2em; color: #C7C7C7; } span.usersLastLoginTooltip { white-space: nowrap; } /* dropdowns will be relative to this element */ #userlist { position: relative; } + #userlist .mailAddress, #userlist .storageLocation, #userlist .userBackend, @@ -501,14 +502,42 @@ span.usersLastLoginTooltip { white-space: nowrap; } display: none; } +.bubble { + z-index:1; + right: -5px; +} +.bubble:after { + right: 5px; +} + +.popovermenu a.menuitem { + padding: 10px; + margin: -5px -10px -5px -15px; + height: 20px; +} + +#userlist .popovermenu { + margin-top: 1px; +} + +#userlist .popovermenu>ul.userActionsMenu { + right: 10px; + padding: 0 10px 10px; +} + +#userlist .popovermenu>ul.userActionsMenu a span { + margin-left: 5px; +} + +#userlist .popovermenu { + display:none; +} + tr:hover>td.password>span, tr:hover>td.displayName>span { margin:0; cursor:pointer; } -tr:hover>td.remove>a, tr:hover>td.password>img,tr:hover>td.displayName>img, tr:hover>td.quota>img { visibility:visible; cursor:pointer; } -td.remove { +tr:hover>td.password>img,tr:hover>td.displayName>img, tr:hover>td.quota>img { visibility:visible; cursor:pointer; } +td.userActions { width: 25px; } -tr:hover>td.remove>a { - float: left; -} div.recoveryPassword { left:50em; display:block; position:absolute; top:-1px; } input#recoveryPassword {width:15em;} diff --git a/settings/js/users/groups.js b/settings/js/users/groups.js index aac1609bce7..b54f26b4ccb 100644 --- a/settings/js/users/groups.js +++ b/settings/js/users/groups.js @@ -48,7 +48,8 @@ GroupList = { }, getUserCount: function ($groupLiElement) { - return parseInt($groupLiElement.data('usercount'), 10); + var count = parseInt($groupLiElement.data('usercount'), 10); + return isNaN(count) ? 0 : count; }, modGroupCount: function(gid, diff) { @@ -208,10 +209,17 @@ GroupList = { }, + showDisabledUsers: function () { + UserList.empty(); + UserList.update('disabledUsers'); + $userGroupList.find('li').removeClass('active'); + GroupList.getGroupLI('disabledUsers').addClass('active'); + }, + showGroup: function (gid) { GroupList.activeGID = gid; UserList.empty(); - UserList.update(gid); + UserList.update(gid === '_everyone' ? '' : gid); $userGroupList.find('li').removeClass('active'); if (gid !== undefined) { //TODO: treat Everyone properly @@ -364,6 +372,11 @@ $(document).ready( function () { GroupList.showGroup(GroupList.getElementGID(this)); }); + // show disabled users + $userGroupList.on('click', '.disabledusers', function () { + GroupList.showDisabledUsers(); + }); + $('#newgroupname').on('input', function(){ GroupList.handleAddGroupInput(this.value); }); diff --git a/settings/js/users/users.js b/settings/js/users/users.js index 46f4e5977be..552d28ad505 100644 --- a/settings/js/users/users.js +++ b/settings/js/users/users.js @@ -48,11 +48,12 @@ var UserList = { * 'backend': 'LDAP', * 'email': 'username@example.org' * 'isRestoreDisabled':false + * 'isEnabled': true * } */ add: function (user) { - if (this.currentGid && this.currentGid !== '_everyone' && _.indexOf(user.groups, this.currentGid) < 0) { - return; + if (this.currentGid && this.currentGid !== '_everyone' && this.currentGid !== 'disabledUsers' && _.indexOf(user.groups, this.currentGid) < 0) { + return false; } var $tr = $userListBody.find('tr:first-child').clone(); @@ -77,6 +78,7 @@ var UserList = { $tr.data('displayname', user.displayname); $tr.data('mailAddress', user.email); $tr.data('restoreDisabled', user.isRestoreDisabled); + $tr.data('userEnabled', user.isEnabled); $tr.find('.name').text(user.name); $tr.find('td.displayName > span').text(user.displayname); $tr.find('td.mailAddress > span').text(user.email); @@ -97,18 +99,17 @@ var UserList = { $tdSubadmins.find('.action').tooltip({placement: 'top'}); /** - * remove action + * user actions menu */ - if ($tr.find('td.remove img').length === 0 && OC.currentUser !== user.name) { - var deleteImage = $('<img class="action">').attr({ - src: OC.imagePath('core', 'actions/delete') + if ($tr.find('td.userActions > span > img').length === 0 && OC.currentUser !== user.name) { + var menuImage = $('<img class="svg action">').attr({ + src: OC.imagePath('core', 'actions/more') }); - var deleteLink = $('<a class="action delete">') - .attr({ href: '#', 'original-title': t('settings', 'Delete')}) - .append(deleteImage); - $tr.find('td.remove').append(deleteLink); + var menuLink = $('<span class="toggleUserActions"></span>') + .append(menuImage); + $tr.find('td.userActions > span').replaceWith(menuLink); } else if (OC.currentUser === user.name) { - $tr.find('td.remove a').remove(); + $tr.find('td.userActions').empty(); } /** @@ -160,14 +161,6 @@ var UserList = { * append generated row to user list */ $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(); - } $quotaSelect.on('change', UserList.onQuotaSelect); @@ -338,6 +331,9 @@ var UserList = { getRestoreDisabled: function(element) { return ($(element).closest('tr').data('restoreDisabled') || ''); }, + getUserEnabled: function(element) { + return ($(element).closest('tr').data('userEnabled') || ''); + }, initDeleteHandling: function() { //set up handler UserDeleteHandler = new DeleteHandler('/settings/users/users', 'username', @@ -351,7 +347,7 @@ var UserList = { UserList.undoRemove); //when to mark user for delete - $userListBody.on('click', '.delete', function () { + $userListBody.on('click', '.action-remove', function () { // Call function for handling delete/undo var uid = UserList.getUID(this); @@ -908,6 +904,54 @@ $(document).ready(function () { UserList._triggerGroupEdit($td, isSubadminSelect); }); + $userListBody.on('click', '.toggleUserActions', function (event) { + event.stopPropagation(); + var $td = $(this).closest('td'); + var $tr = $($td).closest('tr'); + var menudiv = $td.find('.popovermenu'); + + if(menudiv.is(':visible')) { + menudiv.fadeOut(100); + return; + } + menudiv.find('.action-togglestate').empty(); + if($tr.data('userEnabled')) { + $('.action-togglestate', $td).html('<span class="icon icon-close"></span><span>'+t('settings', 'Disable')+'</span>'); + } else { + $('.action-togglestate', $td).html('<span class="icon icon-add"></span><span>'+t('settings', 'Enable')+'</span>'); + } + menudiv.click(function() { menudiv.fadeOut(100); }); + menudiv.hover('', function() { menudiv.fadeOut(100); }); + menudiv.fadeIn(100); + }); + + $userListBody.on('click', '.action-togglestate', function (event) { + event.stopPropagation(); + var $td = $(this).closest('td'); + var $tr = $td.closest('tr'); + var uid = UserList.getUID($td); + var setEnabled = UserList.getUserEnabled($td) ? 0 : 1; + $.post( + OC.generateUrl('/settings/users/{id}/setEnabled', {id: uid}), + {username: uid, enabled: setEnabled}, + function (result) { + if (result && result.status==='success'){ + var count = GroupList.getUserCount(GroupList.getGroupLI('disabledUsers')); + $tr.remove(); + if(result.data.enabled == 1) { + $tr.data('userEnabled', true); + GroupList.setUserCount(GroupList.getGroupLI('disabledUsers'), count-1); + } else { + $tr.data('userEnabled', false); + GroupList.setUserCount(GroupList.getGroupLI('disabledUsers'), count+1); + } + } else { + OC.dialogs.alert(result.data.message, t('settings', 'Unable to change status of {user}', {user: uid})); + } + } + ); + }); + // init the quota field select box after it is shown the first time $('#app-settings').one('show', function() { $(this).find('#default_quota').singleSelect().on('change', UserList.onQuotaSelect); diff --git a/settings/routes.php b/settings/routes.php index ba0761856d4..fb85b11f390 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -53,6 +53,7 @@ $application->registerRoutes($this, [ ['name' => 'Users#setEMailAddress', 'url' => '/settings/users/{id}/mailAddress', 'verb' => 'PUT'], ['name' => 'Users#setUserSettings', 'url' => '/settings/users/{username}/settings', 'verb' => 'PUT'], ['name' => 'Users#getVerificationCode', 'url' => '/settings/users/{account}/verify', 'verb' => 'GET'], + ['name' => 'Users#setEnabled', 'url' => '/settings/users/{id}/setEnabled', 'verb' => 'POST'], ['name' => 'Users#stats', 'url' => '/settings/users/stats', 'verb' => 'GET'], ['name' => 'LogSettings#setLogLevel', 'url' => '/settings/admin/log/level', 'verb' => 'POST'], ['name' => 'LogSettings#getEntries', 'url' => '/settings/admin/log/entries', 'verb' => 'GET'], diff --git a/settings/templates/users/part.grouplist.php b/settings/templates/users/part.grouplist.php index beb0f275a33..0b953c0298f 100644 --- a/settings/templates/users/part.grouplist.php +++ b/settings/templates/users/part.grouplist.php @@ -37,6 +37,15 @@ </li> <?php endforeach; ?> + <!-- Disabled Users --> + <?php $disabledUsersGroup = $_["disabledUsersGroup"] ?> + <li data-gid="disabledUsers" data-usercount="<?php if($disabledUsersGroup['usercount'] > 0) { p($disabledUsersGroup['usercount']); } ?>" class="isgroup"> + <a href="#"><span class="groupname"><?php p($l->t('Disabled')); ?></span></a> + <span class="utils"> + <span class="usercount"><?php if($disabledUsersGroup['usercount'] > 0) { p($disabledUsersGroup['usercount']); } ?></span> + </span> + </li> + <!--List of Groups--> <?php foreach($_["groups"] as $group): ?> <li data-gid="<?php p($group['name']) ?>" data-usercount="<?php p($group['usercount']) ?>" class="isgroup"> diff --git a/settings/templates/users/part.userlist.php b/settings/templates/users/part.userlist.php index 7e7e1561e2f..b908109ad2d 100644 --- a/settings/templates/users/part.userlist.php +++ b/settings/templates/users/part.userlist.php @@ -14,7 +14,7 @@ <th class="storageLocation" scope="col"><?php p($l->t('Storage location')); ?></th> <th class="userBackend" scope="col"><?php p($l->t('User backend')); ?></th> <th class="lastLogin" scope="col"><?php p($l->t('Last login')); ?></th> - <th id="headerRemove"> </th> + <th class="userActions"></th> </tr> </thead> <tbody> @@ -63,7 +63,21 @@ <td class="storageLocation"></td> <td class="userBackend"></td> <td class="lastLogin"></td> - <td class="remove"></td> + <td class="userActions"><span></span> + <div class="popovermenu bubble open menu"> + <ul class="userActionsMenu"> + <li> + <a href="#" class="menuitem action-togglestate permanent" data-action="togglestate"></a> + </li> + <li> + <a href="#" class="menuitem action-remove permanent" data-action="remove"> + <span class="icon icon-delete"></span> + <span><?php p($l->t('Delete')); ?></span> + </a> + </li> + </ul> + </div> + </td> </tr> </tbody> </table> diff --git a/settings/users.php b/settings/users.php index 1986592af75..c3b32d0473e 100644 --- a/settings/users.php +++ b/settings/users.php @@ -59,12 +59,15 @@ $config = \OC::$server->getConfig(); $isAdmin = OC_User::isAdminUser(OC_User::getUser()); +$isDisabled = !OC_User::isEnabled(OC_User::getUser()); + $groupsInfo = new \OC\Group\MetaData( OC_User::getUser(), $isAdmin, $groupManager, \OC::$server->getUserSession() ); + $groupsInfo->setSorting($sortGroupsBy); list($adminGroup, $groups) = $groupsInfo->get(); @@ -92,6 +95,17 @@ if($isAdmin) { } $subAdmins = false; } +$disabledUsers = 0; +foreach (OC_User::getUsers() as $uid) { + if(!$userManager->get($uid)->isEnabled()) { + $disabledUsers++; + } +} +$disabledUsersGroup = array( + 'id' => 'disabledUsers', + 'name' => 'disabledUsers', + 'usercount' => $disabledUsers +); // load preset quotas $quotaPreset=$config->getAppValue('files', 'quota_preset', '1 GB, 5 GB, 10 GB'); @@ -111,6 +125,7 @@ $tmpl = new OC_Template("settings", "users/main", "user"); $tmpl->assign('groups', $groups); $tmpl->assign('sortGroups', $sortGroupsBy); $tmpl->assign('adminGroup', $adminGroup); +$tmpl->assign('disabledUsersGroup', $disabledUsersGroup); $tmpl->assign('isAdmin', (int)$isAdmin); $tmpl->assign('subadmins', $subAdmins); $tmpl->assign('numofgroups', count($groups) + count($adminGroup)); |