Merge pull request #9488 from nextcloud/disabled-users-fix
Added disabled count per groups & fixed disabled users query
This commit is contained in:
commit
760b28ba4c
|
@ -90,12 +90,12 @@ abstract class AUserData extends OCSController {
|
|||
}
|
||||
|
||||
// Should be at least Admin Or SubAdmin!
|
||||
if( $this->groupManager->isAdmin($currentLoggedInUser->getUID())
|
||||
if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())
|
||||
|| $this->groupManager->getSubAdmin()->isUserAccessible($currentLoggedInUser, $targetUserObject)) {
|
||||
$data['enabled'] = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'enabled', 'true') === 'true';
|
||||
} else {
|
||||
// Check they are looking up themselves
|
||||
if($currentLoggedInUser->getUID() !== $targetUserObject->getUID()) {
|
||||
if ($currentLoggedInUser->getUID() !== $targetUserObject->getUID()) {
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,12 @@ class GroupsController extends AUserData {
|
|||
$groups = $this->groupManager->search($search, $limit, $offset);
|
||||
$groups = array_map(function($group) {
|
||||
/** @var IGroup $group */
|
||||
return ['id' => $group->getGID(), 'displayname' => $group->getDisplayName()];
|
||||
return [
|
||||
'id' => $group->getGID(),
|
||||
'displayname' => $group->getDisplayName(),
|
||||
'usercount' => $group->count(),
|
||||
'disabled' => $group->countDisabled()
|
||||
];
|
||||
}, $groups);
|
||||
|
||||
return new DataResponse(['groups' => $groups]);
|
||||
|
@ -202,6 +207,10 @@ class GroupsController extends AUserData {
|
|||
// Do not insert empty entry
|
||||
if(!empty($userData)) {
|
||||
$usersDetails[$userId] = $userData;
|
||||
} else {
|
||||
// Logged user does not have permissions to see this user
|
||||
// only showing its id
|
||||
$usersDetails[$userId] = ['id' => $userId];
|
||||
}
|
||||
}
|
||||
return new DataResponse(['users' => $usersDetails]);
|
||||
|
|
|
@ -180,6 +180,10 @@ class UsersController extends AUserData {
|
|||
// Do not insert empty entry
|
||||
if (!empty($userData)) {
|
||||
$usersDetails[$userId] = $userData;
|
||||
} else {
|
||||
// Logged user does not have permissions to see this user
|
||||
// only showing its id
|
||||
$usersDetails[$userId] = ['id' => $userId];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -101,6 +101,12 @@ class GroupsControllerTest extends \Test\TestCase {
|
|||
$group
|
||||
->method('getDisplayName')
|
||||
->willReturn($gid.'-name');
|
||||
$group
|
||||
->method('count')
|
||||
->willReturn(123);
|
||||
$group
|
||||
->method('countDisabled')
|
||||
->willReturn(11);
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
@ -205,8 +211,18 @@ class GroupsControllerTest extends \Test\TestCase {
|
|||
|
||||
$result = $this->api->getGroupsDetails($search, $limit, $offset);
|
||||
$this->assertEquals(['groups' => [
|
||||
Array('id' => 'group1', 'displayname' => 'group1-name'),
|
||||
Array('id' => 'group2', 'displayname' => 'group2-name')
|
||||
Array(
|
||||
'id' => 'group1',
|
||||
'displayname' => 'group1-name',
|
||||
'usercount' => 123,
|
||||
'disabled' => 11
|
||||
),
|
||||
Array(
|
||||
'id' => 'group2',
|
||||
'displayname' => 'group2-name',
|
||||
'usercount' => 123,
|
||||
'disabled' => 11
|
||||
)
|
||||
]], $result->getData());
|
||||
|
||||
}
|
||||
|
|
|
@ -188,6 +188,7 @@ return array(
|
|||
'OCP\\GroupInterface' => $baseDir . '/lib/public/GroupInterface.php',
|
||||
'OCP\\Group\\Backend\\ABackend' => $baseDir . '/lib/public/Group/Backend/ABackend.php',
|
||||
'OCP\\Group\\Backend\\IAddToGroupBackend' => $baseDir . '/lib/public/Group/Backend/IAddToGroupBackend.php',
|
||||
'OCP\\Group\\Backend\\ICountDisabledInGroup' => $baseDir . '/lib/public/Group/Backend/ICountDisabledInGroup.php',
|
||||
'OCP\\Group\\Backend\\ICountUsersBackend' => $baseDir . '/lib/public/Group/Backend/ICountUsersBackend.php',
|
||||
'OCP\\Group\\Backend\\ICreateGroupBackend' => $baseDir . '/lib/public/Group/Backend/ICreateGroupBackend.php',
|
||||
'OCP\\Group\\Backend\\IDeleteGroupBackend' => $baseDir . '/lib/public/Group/Backend/IDeleteGroupBackend.php',
|
||||
|
|
|
@ -218,6 +218,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
|||
'OCP\\GroupInterface' => __DIR__ . '/../../..' . '/lib/public/GroupInterface.php',
|
||||
'OCP\\Group\\Backend\\ABackend' => __DIR__ . '/../../..' . '/lib/public/Group/Backend/ABackend.php',
|
||||
'OCP\\Group\\Backend\\IAddToGroupBackend' => __DIR__ . '/../../..' . '/lib/public/Group/Backend/IAddToGroupBackend.php',
|
||||
'OCP\\Group\\Backend\\ICountDisabledInGroup' => __DIR__ . '/../../..' . '/lib/public/Group/Backend/ICountDisabledInGroup.php',
|
||||
'OCP\\Group\\Backend\\ICountUsersBackend' => __DIR__ . '/../../..' . '/lib/public/Group/Backend/ICountUsersBackend.php',
|
||||
'OCP\\Group\\Backend\\ICreateGroupBackend' => __DIR__ . '/../../..' . '/lib/public/Group/Backend/ICreateGroupBackend.php',
|
||||
'OCP\\Group\\Backend\\IDeleteGroupBackend' => __DIR__ . '/../../..' . '/lib/public/Group/Backend/IDeleteGroupBackend.php',
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* @author Aaron Wood <aaronjwood@gmail.com>
|
||||
* @author Loki3000 <github@labcms.ru>
|
||||
* @author Roeland Jago Douma <roeland@famdouma.nl>
|
||||
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
||||
*
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
|
@ -40,8 +41,10 @@
|
|||
|
||||
namespace OC\Group;
|
||||
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\Group\Backend\ABackend;
|
||||
use OCP\Group\Backend\IAddToGroupBackend;
|
||||
use OCP\Group\Backend\ICountDisabledInGroup;
|
||||
use OCP\Group\Backend\ICountUsersBackend;
|
||||
use OCP\Group\Backend\ICreateGroupBackend;
|
||||
use OCP\Group\Backend\IDeleteGroupBackend;
|
||||
|
@ -53,6 +56,7 @@ use OCP\IDBConnection;
|
|||
*/
|
||||
class Database extends ABackend
|
||||
implements IAddToGroupBackend,
|
||||
ICountDisabledInGroup,
|
||||
ICountUsersBackend,
|
||||
ICreateGroupBackend,
|
||||
IDeleteGroupBackend,
|
||||
|
@ -373,4 +377,35 @@ class Database extends ABackend
|
|||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the number of disabled users in a group
|
||||
*
|
||||
* @param string $search
|
||||
* @return int|bool
|
||||
*/
|
||||
public function countDisabledInGroup(string $gid): int {
|
||||
$this->fixDI();
|
||||
|
||||
$query = $this->dbConn->getQueryBuilder();
|
||||
$query->select($query->createFunction('COUNT(Distinct uid)'))
|
||||
->from('preferences', 'p')
|
||||
->innerJoin('p', 'group_user', 'g', 'p.userid = g.uid')
|
||||
->where($query->expr()->eq('appid', $query->createNamedParameter('core')))
|
||||
->andWhere($query->expr()->eq('configkey', $query->createNamedParameter('enabled')))
|
||||
->andWhere($query->expr()->eq('configvalue', $query->createNamedParameter('false'), IQueryBuilder::PARAM_STR))
|
||||
->andWhere($query->expr()->eq('gid', $query->createNamedParameter($gid), IQueryBuilder::PARAM_STR));
|
||||
|
||||
$result = $query->execute();
|
||||
$count = $result->fetchColumn();
|
||||
$result->closeCursor();
|
||||
|
||||
if ($count !== false) {
|
||||
$count = (int)$count;
|
||||
} else {
|
||||
$count = 0;
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* @author Robin McCorkell <robin@mccorkell.me.uk>
|
||||
* @author Roeland Jago Douma <roeland@famdouma.nl>
|
||||
* @author Vincent Petry <pvince81@owncloud.com>
|
||||
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
||||
*
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
|
@ -31,6 +32,7 @@ namespace OC\Group;
|
|||
|
||||
use OCP\IGroup;
|
||||
use OCP\IUser;
|
||||
use OCP\Group\Backend\ICountDisabledInGroup;
|
||||
|
||||
class Group implements IGroup {
|
||||
/** @var null|string */
|
||||
|
@ -236,6 +238,26 @@ class Group implements IGroup {
|
|||
return $users;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the number of disabled users
|
||||
*
|
||||
* @return int|bool
|
||||
*/
|
||||
public function countDisabled() {
|
||||
$users = false;
|
||||
foreach ($this->backends as $backend) {
|
||||
if($backend instanceOf ICountDisabledInGroup) {
|
||||
if($users === false) {
|
||||
//we could directly add to a bool variable, but this would
|
||||
//be ugly
|
||||
$users = 0;
|
||||
}
|
||||
$users += $backend->countDisabledInGroup($this->gid);
|
||||
}
|
||||
}
|
||||
return $users;
|
||||
}
|
||||
|
||||
/**
|
||||
* search for users in the group by displayname
|
||||
*
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
* @author Morris Jobke <hey@morrisjobke.de>
|
||||
* @author Stephan Peijnik <speijnik@anexia-it.com>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
||||
*
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
|
@ -28,6 +29,7 @@
|
|||
namespace OC\Group;
|
||||
|
||||
use OCP\IUserSession;
|
||||
use OCP\IGroupManager;
|
||||
|
||||
class MetaData {
|
||||
const SORT_NONE = 0;
|
||||
|
@ -40,7 +42,7 @@ class MetaData {
|
|||
protected $isAdmin;
|
||||
/** @var array */
|
||||
protected $metaData = array();
|
||||
/** @var \OCP\IGroupManager */
|
||||
/** @var IGroupManager */
|
||||
protected $groupManager;
|
||||
/** @var bool */
|
||||
protected $sorting = false;
|
||||
|
@ -50,13 +52,14 @@ class MetaData {
|
|||
/**
|
||||
* @param string $user the uid of the current user
|
||||
* @param bool $isAdmin whether the current users is an admin
|
||||
* @param \OCP\IGroupManager $groupManager
|
||||
* @param IGroupManager $groupManager
|
||||
* @param IUserManager $userManager
|
||||
* @param IUserSession $userSession
|
||||
*/
|
||||
public function __construct(
|
||||
$user,
|
||||
$isAdmin,
|
||||
\OCP\IGroupManager $groupManager,
|
||||
IGroupManager $groupManager,
|
||||
IUserSession $userSession
|
||||
) {
|
||||
$this->user = $user;
|
||||
|
@ -155,13 +158,14 @@ class MetaData {
|
|||
* creates an array containing the group meta data
|
||||
* @param \OCP\IGroup $group
|
||||
* @param string $userSearch
|
||||
* @return array with the keys 'id', 'name' and 'usercount'
|
||||
* @return array with the keys 'id', 'name', 'usercount' and 'disabled'
|
||||
*/
|
||||
private function generateGroupMetaData(\OCP\IGroup $group, $userSearch) {
|
||||
return array(
|
||||
'id' => $group->getGID(),
|
||||
'name' => $group->getDisplayName(),
|
||||
'usercount' => $this->sorting === self::SORT_USERCOUNT ? $group->count($userSearch) : 0,
|
||||
'disabled' => $group->countDisabled()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -184,7 +188,7 @@ class MetaData {
|
|||
* @param string $search a search string
|
||||
* @return \OCP\IGroup[]
|
||||
*/
|
||||
protected function getGroups($search = '') {
|
||||
public function getGroups($search = '') {
|
||||
if($this->isAdmin) {
|
||||
return $this->groupManager->search($search);
|
||||
} else {
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace OC\User;
|
|||
use OC\Hooks\PublicEmitter;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IUser;
|
||||
use OCP\IGroup;
|
||||
use OCP\IUserBackend;
|
||||
use OCP\IUserManager;
|
||||
use OCP\IConfig;
|
||||
|
@ -384,6 +385,24 @@ class Manager extends PublicEmitter implements IUserManager {
|
|||
return $userCountStatistics;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns how many users per backend exist in the requested groups (if supported by backend)
|
||||
*
|
||||
* @param IGroup[] $groups an array of gid to search in
|
||||
* @return array|int an array of backend class as key and count number as value
|
||||
* if $hasLoggedIn is true only an int is returned
|
||||
*/
|
||||
public function countUsersOfGroups(array $groups) {
|
||||
$users = [];
|
||||
foreach($groups as $group) {
|
||||
$usersIds = array_map(function($user) {
|
||||
return $user->getUID();
|
||||
}, $group->getUsers());
|
||||
$users = array_merge($users, $usersIds);
|
||||
}
|
||||
return count(array_unique($users));
|
||||
}
|
||||
|
||||
/**
|
||||
* The callback is executed for each user on each backend.
|
||||
* If the callback returns false no further users will be retrieved.
|
||||
|
@ -420,12 +439,12 @@ class Manager extends PublicEmitter implements IUserManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* returns how many users have logged in once
|
||||
* returns how many users are disabled
|
||||
*
|
||||
* @return int
|
||||
* @since 12.0.0
|
||||
*/
|
||||
public function countDisabledUsers() {
|
||||
public function countDisabledUsers(): int {
|
||||
$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
|
||||
$queryBuilder->select($queryBuilder->createFunction('COUNT(*)'))
|
||||
->from('preferences')
|
||||
|
@ -433,12 +452,48 @@ class Manager extends PublicEmitter implements IUserManager {
|
|||
->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('enabled')))
|
||||
->andWhere($queryBuilder->expr()->eq('configvalue', $queryBuilder->createNamedParameter('false'), IQueryBuilder::PARAM_STR));
|
||||
|
||||
$query = $queryBuilder->execute();
|
||||
|
||||
$result = $queryBuilder->execute();
|
||||
$count = $result->fetchColumn();
|
||||
$result->closeCursor();
|
||||
|
||||
if ($count !== false) {
|
||||
$count = (int)$count;
|
||||
} else {
|
||||
$count = 0;
|
||||
}
|
||||
|
||||
$result = (int)$query->fetchColumn();
|
||||
$query->closeCursor();
|
||||
return $count;
|
||||
}
|
||||
|
||||
return $result;
|
||||
/**
|
||||
* returns how many users are disabled in the requested groups
|
||||
*
|
||||
* @param array $groups groupids to search
|
||||
* @return int
|
||||
* @since 14.0.0
|
||||
*/
|
||||
public function countDisabledUsersOfGroups(array $groups): int {
|
||||
$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
|
||||
$queryBuilder->select($queryBuilder->createFunction('COUNT(Distinct uid)'))
|
||||
->from('preferences', 'p')
|
||||
->innerJoin('p', 'group_user', 'g', 'p.userid = g.uid')
|
||||
->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('core')))
|
||||
->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('enabled')))
|
||||
->andWhere($queryBuilder->expr()->eq('configvalue', $queryBuilder->createNamedParameter('false'), IQueryBuilder::PARAM_STR))
|
||||
->andWhere($queryBuilder->expr()->in('gid', $queryBuilder->createNamedParameter($groups, IQueryBuilder::PARAM_STR_ARRAY)));
|
||||
|
||||
$result = $queryBuilder->execute();
|
||||
$count = $result->fetchColumn();
|
||||
$result->closeCursor();
|
||||
|
||||
if ($count !== false) {
|
||||
$count = (int)$count;
|
||||
} else {
|
||||
$count = 0;
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
|
||||
*
|
||||
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCP\Group\Backend;
|
||||
|
||||
/**
|
||||
* @since 14.0.0
|
||||
*/
|
||||
interface ICountDisabledInGroup {
|
||||
|
||||
/**
|
||||
* @since 14.0.0
|
||||
*/
|
||||
public function countDisabledInGroup(string $gid): int;
|
||||
}
|
|
@ -100,6 +100,14 @@ interface IGroup {
|
|||
*/
|
||||
public function count($search = '');
|
||||
|
||||
/**
|
||||
* returns the number of disabled users
|
||||
*
|
||||
* @return int|bool
|
||||
* @since 14.0.0
|
||||
*/
|
||||
public function countDisabled();
|
||||
|
||||
/**
|
||||
* search for users in the group by displayname
|
||||
*
|
||||
|
|
|
@ -187,34 +187,35 @@ class UsersController extends Controller {
|
|||
list($adminGroup, $groups) = $groupsInfo->get();
|
||||
|
||||
if ($this->isAdmin) {
|
||||
$subAdmins = $this->groupManager->getSubAdmin()->getAllSubAdmins();
|
||||
// New class returns IUser[] so convert back
|
||||
$result = [];
|
||||
foreach ($subAdmins as $subAdmin) {
|
||||
$result[] = [
|
||||
'gid' => $subAdmin['group']->getGID(),
|
||||
'uid' => $subAdmin['user']->getUID(),
|
||||
];
|
||||
}
|
||||
$subAdmins = $result;
|
||||
$disabledUsers = $isLDAPUsed ? 0 : $this->userManager->countDisabledUsers();
|
||||
$userCount = array_reduce($this->userManager->countUsers(), function($v, $w) {
|
||||
return $v + (int)$w;
|
||||
}, 0);
|
||||
} else {
|
||||
/* Retrieve group IDs from $groups array, so we can pass that information into OC_Group::displayNamesInGroups() */
|
||||
$gids = array();
|
||||
foreach($groups as $group) {
|
||||
if (isset($group['id'])) {
|
||||
$gids[] = $group['id'];
|
||||
// User is subadmin !
|
||||
// Map group list to names to retrieve the countDisabledUsersOfGroups
|
||||
$userGroups = $this->groupManager->getUserGroups($user);
|
||||
$groupsNames = [];
|
||||
$userCount = 0;
|
||||
|
||||
foreach($groups as $key => $group) {
|
||||
// $userCount += (int)$group['usercount'];
|
||||
array_push($groupsNames, $group['name']);
|
||||
// we prevent subadmins from looking up themselves
|
||||
// so we lower the count of the groups he belongs to
|
||||
if (array_key_exists($group['id'], $userGroups)) {
|
||||
$groups[$key]['usercount']--;
|
||||
$userCount = -1; // we also lower from one the total count
|
||||
}
|
||||
}
|
||||
$subAdmins = false;
|
||||
};
|
||||
$userCount += $this->userManager->countUsersOfGroups($groupsInfo->getGroups());
|
||||
$disabledUsers = $isLDAPUsed ? 0 : $this->userManager->countDisabledUsersOfGroups($groupsNames);
|
||||
}
|
||||
|
||||
$disabledUsers = $isLDAPUsed ? 0 : $this->userManager->countDisabledUsers();
|
||||
$disabledUsersGroup = [
|
||||
'id' => 'disabled',
|
||||
'name' => 'Disabled users',
|
||||
'usercount' => $disabledUsers
|
||||
];
|
||||
$allGroups = array_merge_recursive($adminGroup, $groups);
|
||||
|
||||
/* QUOTAS PRESETS */
|
||||
$quotaPreset = $this->config->getAppValue('files', 'quota_preset', '1 GB, 5 GB, 10 GB');
|
||||
|
@ -227,11 +228,6 @@ class UsersController extends Controller {
|
|||
|
||||
\OC::$server->getEventDispatcher()->dispatch('OC\Settings\Users::loadAdditionalScripts');
|
||||
|
||||
/* TOTAL USERS COUNT */
|
||||
$userCount = array_reduce($this->userManager->countUsers(), function($v, $w) {
|
||||
return $v + (int)$w;
|
||||
}, 0);
|
||||
|
||||
/* LANGUAGES */
|
||||
$languages = $this->l10nFactory->getLanguages();
|
||||
|
||||
|
@ -241,10 +237,9 @@ class UsersController extends Controller {
|
|||
$serverData['groups'] = array_merge_recursive($adminGroup, [$disabledUsersGroup], $groups);
|
||||
// Various data
|
||||
$serverData['isAdmin'] = $this->isAdmin;
|
||||
$serverData['subadmins'] = $subAdmins;
|
||||
$serverData['sortGroups'] = $sortGroupsBy;
|
||||
$serverData['quotaPreset'] = $quotaPreset;
|
||||
$serverData['userCount'] = $userCount-$disabledUsers;
|
||||
$serverData['userCount'] = $userCount - $disabledUsers;
|
||||
$serverData['languages'] = $languages;
|
||||
$serverData['defaultLanguage'] = $this->config->getSystemValue('default_language', 'en');
|
||||
// Settings
|
||||
|
|
|
@ -1320,6 +1320,10 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
|
|||
.userActions {
|
||||
width: 100px;
|
||||
}
|
||||
.obfuscated {
|
||||
width: 400px;
|
||||
opacity: .7;
|
||||
}
|
||||
&#grid-header,
|
||||
&#new-user {
|
||||
position: sticky;
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -4,7 +4,7 @@
|
|||
<button type="button" :id="menu.new.id" :class="menu.new.icon" @click="menu.new.action">{{menu.new.text}}</button>
|
||||
</div>
|
||||
<ul :id="menu.id">
|
||||
<navigation-item v-for="(item, key) in menu.items" :item="item" :key="key" />
|
||||
<navigation-item v-for="item in menu.items" :item="item" :key="item.key" />
|
||||
</ul>
|
||||
<div id="app-settings">
|
||||
<div id="app-settings-header">
|
||||
|
|
|
@ -1,21 +1,16 @@
|
|||
<template>
|
||||
<li :id="item.id" :class="[{'icon-loading-small': item.loading, 'open': item.opened, 'collapsible': item.collapsible&&item.children&&item.children.length>0 }, item.classes]">
|
||||
<nav-element :id="item.id" v-bind="navElement(item)"
|
||||
:class="[{'icon-loading-small': item.loading, 'open': item.opened, 'collapsible': item.collapsible&&item.children&&item.children.length>0 }, item.classes]">
|
||||
|
||||
<!-- Bullet -->
|
||||
<div v-if="item.bullet" class="app-navigation-entry-bullet" :style="{ backgroundColor: item.bullet }"></div>
|
||||
|
||||
<!-- Main link -->
|
||||
<a v-if="item.href" :href="(item.href) ? item.href : '#' " @click="toggleCollapse" :class="item.icon" >
|
||||
<a :href="(item.href) ? item.href : '#' " @click="toggleCollapse" :class="item.icon">
|
||||
<img v-if="item.iconUrl" :alt="item.text" :src="item.iconUrl">
|
||||
{{item.text}}
|
||||
</a>
|
||||
|
||||
<!-- Router link if specified. href OR router -->
|
||||
<router-link :to="item.router" v-else-if="item.router" :class="item.icon" >
|
||||
<img v-if="item.iconUrl" :alt="item.text" :src="item.iconUrl">
|
||||
{{item.text}}
|
||||
</router-link>
|
||||
|
||||
<!-- Popover, counter and button(s) -->
|
||||
<div v-if="item.utils" class="app-navigation-entry-utils">
|
||||
<ul>
|
||||
|
@ -69,7 +64,7 @@
|
|||
<ul v-if="item.children">
|
||||
<navigation-item v-for="(item, key) in item.children" :item="item" :key="key" />
|
||||
</ul>
|
||||
</li>
|
||||
</nav-element>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -89,7 +84,7 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
openedMenu: false
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
showMenu() {
|
||||
|
@ -106,12 +101,29 @@ export default {
|
|||
cancelEdit() {
|
||||
// remove the editing class
|
||||
if (Array.isArray(this.item.classes))
|
||||
this.item.classes = this.item.classes.filter(item => item !== 'editing');
|
||||
this.item.classes = this.item.classes.filter(
|
||||
item => item !== 'editing'
|
||||
);
|
||||
},
|
||||
// This is used to decide which outter element type to use
|
||||
// li or router-link
|
||||
navElement(item) {
|
||||
if (item.href) {
|
||||
return {
|
||||
is: 'li'
|
||||
};
|
||||
}
|
||||
return {
|
||||
is: 'router-link',
|
||||
tag: 'li',
|
||||
to: item.router,
|
||||
exact: true
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// prevent click outside event with popupItem.
|
||||
this.popupItem = this.$el;
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -171,7 +171,7 @@ export default {
|
|||
},
|
||||
filteredUsers() {
|
||||
if (this.selectedGroup === 'disabled') {
|
||||
let disabledUsers = this.users.filter(user => user.enabled !== true);
|
||||
let disabledUsers = this.users.filter(user => user.enabled === false);
|
||||
if (disabledUsers.length===0 && this.$refs.infiniteLoading && this.$refs.infiniteLoading.isComplete) {
|
||||
// disabled group is empty, redirection to all users
|
||||
this.$router.push({name: 'users'});
|
||||
|
@ -179,7 +179,11 @@ export default {
|
|||
}
|
||||
return disabledUsers;
|
||||
}
|
||||
return this.users.filter(user => user.enabled === true);
|
||||
if (!settings.isAdmin) {
|
||||
// We don't want subadmins to edit themselves
|
||||
return this.users.filter(user => user.enabled !== false && user.id !== oc_current_user);
|
||||
}
|
||||
return this.users.filter(user => user.enabled !== false);
|
||||
},
|
||||
groups() {
|
||||
// data provided php side + remove the disabled group
|
||||
|
|
|
@ -1,5 +1,17 @@
|
|||
<template>
|
||||
<div class="row" :class="{'disabled': loading.delete || loading.disable}">
|
||||
<!-- Obfuscated user: Logged in user does not have permissions to see all of the data -->
|
||||
<div class="row" v-if="Object.keys(user).length ===1">
|
||||
<div class="avatar" :class="{'icon-loading-small': loading.delete || loading.disable}">
|
||||
<img alt="" width="32" height="32" :src="generateAvatar(user.id, 32)"
|
||||
:srcset="generateAvatar(user.id, 64)+' 2x, '+generateAvatar(user.id, 128)+' 4x'"
|
||||
v-if="!loading.delete && !loading.disable">
|
||||
</div>
|
||||
<div class="name">{{user.id}}</div>
|
||||
<div class="obfuscated">{{t('settings','You do not have permissions to see the details of this user')}}</div>
|
||||
</div>
|
||||
|
||||
<!-- User full data -->
|
||||
<div class="row" v-else :class="{'disabled': loading.delete || loading.disable}">
|
||||
<div class="avatar" :class="{'icon-loading-small': loading.delete || loading.disable}">
|
||||
<img alt="" width="32" height="32" :src="generateAvatar(user.id, 32)"
|
||||
:srcset="generateAvatar(user.id, 64)+' 2x, '+generateAvatar(user.id, 128)+' 4x'"
|
||||
|
@ -314,18 +326,22 @@ export default {
|
|||
},
|
||||
|
||||
/**
|
||||
* Create a new group
|
||||
* Create a new group and add user to it
|
||||
*
|
||||
* @param {string} groups Group id
|
||||
* @returns {Promise}
|
||||
*/
|
||||
createGroup(gid) {
|
||||
this.loading = {groups:true, subadmins:true}
|
||||
this.$store.dispatch('addGroup', gid).then(() => {
|
||||
this.loading = {groups:false, subadmins:false};
|
||||
let userid = this.user.id;
|
||||
this.$store.dispatch('addUserGroup', {userid, gid});
|
||||
});
|
||||
this.$store.dispatch('addGroup', gid)
|
||||
.then(() => {
|
||||
this.loading = {groups:false, subadmins:false};
|
||||
let userid = this.user.id;
|
||||
this.$store.dispatch('addUserGroup', {userid, gid});
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = {groups:false, subadmins:false};
|
||||
});
|
||||
return this.$store.getters.getGroups[this.groups.length];
|
||||
},
|
||||
|
||||
|
@ -360,6 +376,9 @@ export default {
|
|||
if (this.$route.params.selectedGroup === gid) {
|
||||
this.$store.commit('deleteUser', userid);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading.groups = false
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ sync(store, router);
|
|||
Vue.prototype.t = t;
|
||||
Vue.prototype.OC = OC;
|
||||
Vue.prototype.oc_userconfig = oc_userconfig;
|
||||
Vue.prototype.oc_current_user = oc_current_user;
|
||||
|
||||
const app = new Vue({
|
||||
router,
|
||||
|
|
|
@ -18,6 +18,7 @@ export default new Router({
|
|||
// if index.php is in the url AND we got this far, then it's working:
|
||||
// let's keep using index.php in the url
|
||||
base: OC.generateUrl(''),
|
||||
linkActiveClass: 'active',
|
||||
routes: [
|
||||
{
|
||||
path: '/:index(index.php/)?settings/users',
|
||||
|
|
|
@ -10,8 +10,12 @@ const debug = process.env.NODE_ENV !== 'production';
|
|||
|
||||
const mutations = {
|
||||
API_FAILURE(state, error) {
|
||||
let message = error.error.response.data.ocs.meta.message;
|
||||
OC.Notification.showHtml(t('settings','An error occured during the request. Unable to proceed.')+'<br>'+message, {timeout: 7});
|
||||
try {
|
||||
let message = error.error.response.data.ocs.meta.message;
|
||||
OC.Notification.showHtml(t('settings','An error occured during the request. Unable to proceed.')+'<br>'+message, {timeout: 7});
|
||||
} catch(e) {
|
||||
OC.Notification.showTemporary(t('settings','An error occured during the request. Unable to proceed.'));
|
||||
}
|
||||
console.log(state, error);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -6,12 +6,21 @@ const orderGroups = function(groups, orderBy) {
|
|||
* https://github.com/nextcloud/server/blob/208e38e84e1a07a49699aa90dc5b7272d24489f0/lib/private/Group/MetaData.php#L34
|
||||
*/
|
||||
if (orderBy === 1) {
|
||||
return groups.sort((a, b) => a.usercount < b.usercount);
|
||||
return groups.sort((a, b) => a.usercount-a.disabled < b.usercount - b.disabled);
|
||||
} else {
|
||||
return groups.sort((a, b) => a.name.localeCompare(b.name));
|
||||
}
|
||||
};
|
||||
|
||||
const defaults = {
|
||||
group: {
|
||||
id: '',
|
||||
name: '',
|
||||
usercount: 0,
|
||||
disabled: 0
|
||||
}
|
||||
}
|
||||
|
||||
const state = {
|
||||
users: [],
|
||||
groups: [],
|
||||
|
@ -33,18 +42,20 @@ const mutations = {
|
|||
state.minPasswordLength = length!=='' ? length : 0;
|
||||
},
|
||||
initGroups(state, {groups, orderBy, userCount}) {
|
||||
state.groups = groups;
|
||||
state.groups = groups.map(group => Object.assign({}, defaults.group, group));
|
||||
state.orderBy = orderBy;
|
||||
state.userCount = userCount;
|
||||
state.groups = orderGroups(state.groups, state.orderBy);
|
||||
|
||||
},
|
||||
addGroup(state, gid) {
|
||||
try {
|
||||
state.groups.push({
|
||||
// extend group to default values
|
||||
let group = Object.assign({}, defaults.group, {
|
||||
id: gid,
|
||||
name: gid,
|
||||
usercount: 0 // user will be added after the creation
|
||||
name: gid
|
||||
});
|
||||
state.groups.push(group);
|
||||
state.groups = orderGroups(state.groups, state.orderBy);
|
||||
} catch (e) {
|
||||
console.log('Can\'t create group', e);
|
||||
|
@ -58,19 +69,23 @@ const mutations = {
|
|||
},
|
||||
addUserGroup(state, { userid, gid }) {
|
||||
let group = state.groups.find(groupSearch => groupSearch.id == gid);
|
||||
if (group) {
|
||||
group.usercount++; // increase count
|
||||
let user = state.users.find(user => user.id == userid);
|
||||
// increase count if user is enabled
|
||||
if (group && user.enabled) {
|
||||
group.usercount++;
|
||||
}
|
||||
let groups = state.users.find(user => user.id == userid).groups;
|
||||
let groups = user.groups;
|
||||
groups.push(gid);
|
||||
state.groups = orderGroups(state.groups, state.orderBy);
|
||||
},
|
||||
removeUserGroup(state, { userid, gid }) {
|
||||
let group = state.groups.find(groupSearch => groupSearch.id == gid);
|
||||
if (group) {
|
||||
group.usercount--; // lower count
|
||||
let user = state.users.find(user => user.id == userid);
|
||||
// lower count if user is enabled
|
||||
if (group && user.enabled) {
|
||||
group.usercount--;
|
||||
}
|
||||
let groups = state.users.find(user => user.id == userid).groups;
|
||||
let groups = user.groups;
|
||||
groups.splice(groups.indexOf(gid),1);
|
||||
state.groups = orderGroups(state.groups, state.orderBy);
|
||||
},
|
||||
|
@ -90,11 +105,15 @@ const mutations = {
|
|||
state.users.push(response.data.ocs.data);
|
||||
},
|
||||
enableDisableUser(state, { userid, enabled }) {
|
||||
state.users.find(user => user.id == userid).enabled = enabled;
|
||||
let user = state.users.find(user => user.id == userid);
|
||||
user.enabled = enabled;
|
||||
// increment or not
|
||||
state.groups.find(group => group.id == 'disabled').usercount += enabled ? -1 : 1;
|
||||
state.userCount += enabled ? 1 : -1;
|
||||
console.log(enabled);
|
||||
user.groups.forEach(group => {
|
||||
// Increment disabled count
|
||||
state.groups.find(groupSearch => groupSearch.id == group).disabled += enabled ? -1 : 1;
|
||||
});
|
||||
},
|
||||
setUserData(state, { userid, key, value }) {
|
||||
if (key === 'quota') {
|
||||
|
@ -236,7 +255,12 @@ const actions = {
|
|||
return api.post(OC.linkToOCS(`cloud/groups`, 2), {groupid: gid})
|
||||
.then((response) => context.commit('addGroup', gid))
|
||||
.catch((error) => {throw error;});
|
||||
}).catch((error) => context.commit('API_FAILURE', { userid, error }));
|
||||
}).catch((error) => {
|
||||
context.commit('API_FAILURE', { gid, error });
|
||||
// let's throw one more time to prevent the view
|
||||
// from adding the user to a group that doesn't exists
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -285,7 +309,12 @@ const actions = {
|
|||
return api.delete(OC.linkToOCS(`cloud/users/${userid}/groups`, 2), { groupid: gid })
|
||||
.then((response) => context.commit('removeUserGroup', { userid, gid }))
|
||||
.catch((error) => {throw error;});
|
||||
}).catch((error) => context.commit('API_FAILURE', { userid, error }));
|
||||
}).catch((error) => {
|
||||
context.commit('API_FAILURE', { userid, error });
|
||||
// let's throw one more time to prevent
|
||||
// the view from removing the user row on failure
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -233,13 +233,22 @@ export default {
|
|||
groups = groups.map(group => {
|
||||
let item = {};
|
||||
item.id = group.id.replace(' ', '_');
|
||||
item.classes = []; // empty classes, active will be set later
|
||||
item.router = { // router link to
|
||||
item.key = item.id;
|
||||
item.utils = {}
|
||||
|
||||
// router link to
|
||||
item.router = {
|
||||
name: 'group',
|
||||
params: {selectedGroup: group.id}
|
||||
};
|
||||
item.text = group.name; // group name
|
||||
item.utils = {counter: group.usercount}; // users count
|
||||
|
||||
// group name
|
||||
item.text = group.name;
|
||||
|
||||
// users count
|
||||
if (group.usercount - group.disabled > 0) {
|
||||
item.utils.counter = group.usercount - group.disabled;
|
||||
}
|
||||
|
||||
if (item.id !== 'admin' && item.id !== 'disabled' && this.settings.isAdmin) {
|
||||
// add delete button on real groups
|
||||
|
@ -268,21 +277,17 @@ export default {
|
|||
}
|
||||
|
||||
// Add everyone group
|
||||
groups.unshift({
|
||||
let everyoneGroup = {
|
||||
id: 'everyone',
|
||||
classes: [],
|
||||
key: 'everyone',
|
||||
router: {name:'users'},
|
||||
text: t('settings', 'Everyone'),
|
||||
utils: {counter: this.userCount}
|
||||
});
|
||||
|
||||
// Set current group as active
|
||||
let activeGroup = groups.findIndex(group => group.id === this.selectedGroup);
|
||||
if (activeGroup >= 0) {
|
||||
groups[activeGroup].classes.push('active');
|
||||
} else {
|
||||
groups[0].classes.push('active');
|
||||
};
|
||||
// users count
|
||||
if (this.userCount > 0) {
|
||||
everyoneGroup.utils = {counter: this.userCount};
|
||||
}
|
||||
groups.unshift(everyoneGroup);
|
||||
|
||||
// Return
|
||||
return {
|
||||
|
|
Loading…
Reference in New Issue