Merge pull request #8059 from owncloud/countUsersInGroup
add optional countUsersInGroup method to group backends
This commit is contained in:
commit
340089f270
|
@ -276,6 +276,84 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
|
||||||
return $groupUsers;
|
return $groupUsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief returns the number of users in a group, who match the search term
|
||||||
|
* @param string the internal group name
|
||||||
|
* @param string optional, a search string
|
||||||
|
* @returns int | bool
|
||||||
|
*/
|
||||||
|
public function countUsersInGroup($gid, $search = '') {
|
||||||
|
$cachekey = 'countUsersInGroup-'.$gid.'-'.$search;
|
||||||
|
if(!$this->enabled || !$this->groupExists($gid)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$groupUsers = $this->access->connection->getFromCache($cachekey);
|
||||||
|
if(!is_null($groupUsers)) {
|
||||||
|
return $groupUsers;
|
||||||
|
}
|
||||||
|
|
||||||
|
$groupDN = $this->access->groupname2dn($gid);
|
||||||
|
if(!$groupDN) {
|
||||||
|
// group couldn't be found, return empty resultset
|
||||||
|
$this->access->connection->writeToCache($cachekey, false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$members = array_keys($this->_groupMembers($groupDN));
|
||||||
|
if(!$members) {
|
||||||
|
//in case users could not be retrieved, return empty resultset
|
||||||
|
$this->access->connection->writeToCache($cachekey, false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(empty($search)) {
|
||||||
|
$groupUsers = count($members);
|
||||||
|
$this->access->connection->writeToCache($cachekey, $groupUsers);
|
||||||
|
return $groupUsers;
|
||||||
|
}
|
||||||
|
$isMemberUid =
|
||||||
|
(strtolower($this->access->connection->ldapGroupMemberAssocAttr)
|
||||||
|
=== 'memberuid');
|
||||||
|
|
||||||
|
//we need to apply the search filter
|
||||||
|
//alternatives that need to be checked:
|
||||||
|
//a) get all users by search filter and array_intersect them
|
||||||
|
//b) a, but only when less than 1k 10k ?k users like it is
|
||||||
|
//c) put all DNs|uids in a LDAP filter, combine with the search string
|
||||||
|
// and let it count.
|
||||||
|
//For now this is not important, because the only use of this method
|
||||||
|
//does not supply a search string
|
||||||
|
$groupUsers = array();
|
||||||
|
foreach($members as $member) {
|
||||||
|
if($isMemberUid) {
|
||||||
|
//we got uids, need to get their DNs to 'tranlsate' them to usernames
|
||||||
|
$filter = $this->access->combineFilterWithAnd(array(
|
||||||
|
\OCP\Util::mb_str_replace('%uid', $member,
|
||||||
|
$this->access->connection->ldapLoginFilter, 'UTF-8'),
|
||||||
|
$this->access->getFilterPartForUserSearch($search)
|
||||||
|
));
|
||||||
|
$ldap_users = $this->access->fetchListOfUsers($filter, 'dn');
|
||||||
|
if(count($ldap_users) < 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$groupUsers[] = $this->access->dn2username($ldap_users[0]);
|
||||||
|
} else {
|
||||||
|
//we need to apply the search filter now
|
||||||
|
if(!$this->access->readAttribute($member,
|
||||||
|
$this->access->connection->ldapUserDisplayName,
|
||||||
|
$this->access->getFilterPartForUserSearch($search))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// dn2username will also check if the users belong to the allowed base
|
||||||
|
if($ocname = $this->access->dn2username($member)) {
|
||||||
|
$groupUsers[] = $ocname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count($groupUsers);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief get a list of all display names in a group
|
* @brief get a list of all display names in a group
|
||||||
* @returns array with display names (value) and user ids(key)
|
* @returns array with display names (value) and user ids(key)
|
||||||
|
@ -418,6 +496,9 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
|
||||||
* compared with OC_USER_BACKEND_CREATE_USER etc.
|
* compared with OC_USER_BACKEND_CREATE_USER etc.
|
||||||
*/
|
*/
|
||||||
public function implementsActions($actions) {
|
public function implementsActions($actions) {
|
||||||
return (bool)(OC_GROUP_BACKEND_GET_DISPLAYNAME & $actions);
|
return (bool)((
|
||||||
|
OC_GROUP_BACKEND_GET_DISPLAYNAME
|
||||||
|
| OC_GROUP_BACKEND_COUNT_USERS
|
||||||
|
) & $actions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,6 +144,17 @@ class Group_Proxy extends lib\Proxy implements \OCP\GroupInterface {
|
||||||
return $users;
|
return $users;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief returns the number of users in a group, who match the search term
|
||||||
|
* @param string the internal group name
|
||||||
|
* @param string optional, a search string
|
||||||
|
* @returns int | bool
|
||||||
|
*/
|
||||||
|
public function countUsersInGroup($gid, $search = '') {
|
||||||
|
return $this->handleRequest(
|
||||||
|
$gid, 'countUsersInGroup', array($gid, $search));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief get a list of all display names in a group
|
* @brief get a list of all display names in a group
|
||||||
* @returns array with display names (value) and user ids(key)
|
* @returns array with display names (value) and user ids(key)
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
<?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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OCA\user_ldap\tests;
|
||||||
|
|
||||||
|
namespace OCA\user_ldap\tests;
|
||||||
|
|
||||||
|
use \OCA\user_ldap\GROUP_LDAP as GroupLDAP;
|
||||||
|
use \OCA\user_ldap\lib\Access;
|
||||||
|
use \OCA\user_ldap\lib\Connection;
|
||||||
|
use \OCA\user_ldap\lib\ILDAPWrapper;
|
||||||
|
|
||||||
|
class Test_Group_Ldap extends \PHPUnit_Framework_TestCase {
|
||||||
|
private function getAccessMock() {
|
||||||
|
static $conMethods;
|
||||||
|
static $accMethods;
|
||||||
|
|
||||||
|
if(is_null($conMethods) || is_null($accMethods)) {
|
||||||
|
$conMethods = get_class_methods('\OCA\user_ldap\lib\Connection');
|
||||||
|
$accMethods = get_class_methods('\OCA\user_ldap\lib\Access');
|
||||||
|
}
|
||||||
|
$lw = $this->getMock('\OCA\user_ldap\lib\ILDAPWrapper');
|
||||||
|
$connector = $this->getMock('\OCA\user_ldap\lib\Connection',
|
||||||
|
$conMethods,
|
||||||
|
array($lw, null, null));
|
||||||
|
$access = $this->getMock('\OCA\user_ldap\lib\Access',
|
||||||
|
$accMethods,
|
||||||
|
array($connector, $lw));
|
||||||
|
|
||||||
|
return $access;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function enableGroups($access) {
|
||||||
|
$access->connection->expects($this->any())
|
||||||
|
->method('__get')
|
||||||
|
->will($this->returnCallback(function($name) {
|
||||||
|
// if($name === 'ldapLoginFilter') {
|
||||||
|
// return '%uid';
|
||||||
|
// }
|
||||||
|
return 1;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCountEmptySearchString() {
|
||||||
|
$access = $this->getAccessMock();
|
||||||
|
|
||||||
|
$this->enableGroups($access);
|
||||||
|
|
||||||
|
$access->expects($this->any())
|
||||||
|
->method('groupname2dn')
|
||||||
|
->will($this->returnValue('cn=group,dc=foo,dc=bar'));
|
||||||
|
|
||||||
|
$access->expects($this->any())
|
||||||
|
->method('readAttribute')
|
||||||
|
->will($this->returnValue(array('u11', 'u22', 'u33', 'u34')));
|
||||||
|
|
||||||
|
$groupBackend = new GroupLDAP($access);
|
||||||
|
$users = $groupBackend->countUsersInGroup('group');
|
||||||
|
|
||||||
|
$this->assertSame(4, $users);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCountWithSearchString() {
|
||||||
|
$access = $this->getAccessMock();
|
||||||
|
|
||||||
|
$this->enableGroups($access);
|
||||||
|
|
||||||
|
$access->expects($this->any())
|
||||||
|
->method('groupname2dn')
|
||||||
|
->will($this->returnValue('cn=group,dc=foo,dc=bar'));
|
||||||
|
|
||||||
|
$access->expects($this->any())
|
||||||
|
->method('readAttribute')
|
||||||
|
->will($this->returnCallback(function($name) {
|
||||||
|
//the search operation will call readAttribute, thus we need
|
||||||
|
//to anaylze the "dn". All other times we just need to return
|
||||||
|
//something that is neither null or false, but once an array
|
||||||
|
//with the users in the group – so we do so all other times for
|
||||||
|
//simplicicity.
|
||||||
|
if(strpos($name, 'u') === 0) {
|
||||||
|
return strpos($name, '3');
|
||||||
|
}
|
||||||
|
return array('u11', 'u22', 'u33', 'u34');
|
||||||
|
}));
|
||||||
|
|
||||||
|
$access->expects($this->any())
|
||||||
|
->method('dn2username')
|
||||||
|
->will($this->returnValue('foobar'));
|
||||||
|
|
||||||
|
$groupBackend = new GroupLDAP($access);
|
||||||
|
$users = $groupBackend->countUsersInGroup('group', '3');
|
||||||
|
|
||||||
|
$this->assertSame(2, $users);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -34,6 +34,7 @@ define('OC_GROUP_BACKEND_DELETE_GROUP', 0x00000010);
|
||||||
define('OC_GROUP_BACKEND_ADD_TO_GROUP', 0x00000100);
|
define('OC_GROUP_BACKEND_ADD_TO_GROUP', 0x00000100);
|
||||||
define('OC_GROUP_BACKEND_REMOVE_FROM_GOUP', 0x00001000);
|
define('OC_GROUP_BACKEND_REMOVE_FROM_GOUP', 0x00001000);
|
||||||
define('OC_GROUP_BACKEND_GET_DISPLAYNAME', 0x00010000);
|
define('OC_GROUP_BACKEND_GET_DISPLAYNAME', 0x00010000);
|
||||||
|
define('OC_GROUP_BACKEND_COUNT_USERS', 0x00100000);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for user management
|
* Abstract base class for user management
|
||||||
|
@ -45,6 +46,7 @@ abstract class OC_Group_Backend implements OC_Group_Interface {
|
||||||
OC_GROUP_BACKEND_ADD_TO_GROUP => 'addToGroup',
|
OC_GROUP_BACKEND_ADD_TO_GROUP => 'addToGroup',
|
||||||
OC_GROUP_BACKEND_REMOVE_FROM_GOUP => 'removeFromGroup',
|
OC_GROUP_BACKEND_REMOVE_FROM_GOUP => 'removeFromGroup',
|
||||||
OC_GROUP_BACKEND_GET_DISPLAYNAME => 'displayNamesInGroup',
|
OC_GROUP_BACKEND_GET_DISPLAYNAME => 'displayNamesInGroup',
|
||||||
|
OC_GROUP_BACKEND_COUNT_USERS => 'countUsersInGroup',
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -211,6 +211,20 @@ class OC_Group_Database extends OC_Group_Backend {
|
||||||
return $users;
|
return $users;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the number of all users matching the search string in a group
|
||||||
|
* @param string $gid
|
||||||
|
* @param string $search
|
||||||
|
* @param int $limit
|
||||||
|
* @param int $offset
|
||||||
|
* @return int | false
|
||||||
|
*/
|
||||||
|
public function countUsersInGroup($gid, $search = '') {
|
||||||
|
$stmt = OC_DB::prepare('SELECT COUNT(`uid`) AS `count` FROM `*PREFIX*group_user` WHERE `gid` = ? AND `uid` LIKE ?');
|
||||||
|
$result = $stmt->execute(array($gid, $search.'%'));
|
||||||
|
return $result->fetchOne();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief get a list of all display names in a group
|
* @brief get a list of all display names in a group
|
||||||
* @param string $gid
|
* @param string $gid
|
||||||
|
|
|
@ -157,4 +157,14 @@ class OC_Group_Dummy extends OC_Group_Backend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the number of all users in a group
|
||||||
|
* @returns int | bool
|
||||||
|
*/
|
||||||
|
public function countUsersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
|
||||||
|
if(isset($this->groups[$gid])) {
|
||||||
|
return count($this->groups[$gid]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,6 +186,27 @@ class Group {
|
||||||
return array_values($users);
|
return array_values($users);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the number of users matching the search string
|
||||||
|
*
|
||||||
|
* @param string $search
|
||||||
|
* @return int | bool
|
||||||
|
*/
|
||||||
|
public function count($search) {
|
||||||
|
$users = false;
|
||||||
|
foreach ($this->backends as $backend) {
|
||||||
|
if($backend->implementsActions(OC_GROUP_BACKEND_COUNT_USERS)) {
|
||||||
|
if($users === false) {
|
||||||
|
//we could directly add to a bool variable, but this would
|
||||||
|
//be ugly
|
||||||
|
$users = 0;
|
||||||
|
}
|
||||||
|
$users += $backend->countUsersInGroup($this->gid, $search);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $users;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* search for users in the group by displayname
|
* search for users in the group by displayname
|
||||||
*
|
*
|
||||||
|
|
|
@ -299,6 +299,68 @@ class Group extends \PHPUnit_Framework_TestCase {
|
||||||
$this->assertEquals('user1', $user1->getUID());
|
$this->assertEquals('user1', $user1->getUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCountUsers() {
|
||||||
|
$backend1 = $this->getMock('OC_Group_Database');
|
||||||
|
$userManager = $this->getUserManager();
|
||||||
|
$group = new \OC\Group\Group('group1', array($backend1), $userManager);
|
||||||
|
|
||||||
|
$backend1->expects($this->once())
|
||||||
|
->method('countUsersInGroup')
|
||||||
|
->with('group1', '2')
|
||||||
|
->will($this->returnValue(3));
|
||||||
|
|
||||||
|
$backend1->expects($this->any())
|
||||||
|
->method('implementsActions')
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
|
$users = $group->count('2');
|
||||||
|
|
||||||
|
$this->assertSame(3, $users);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCountUsersMultipleBackends() {
|
||||||
|
$backend1 = $this->getMock('OC_Group_Database');
|
||||||
|
$backend2 = $this->getMock('OC_Group_Database');
|
||||||
|
$userManager = $this->getUserManager();
|
||||||
|
$group = new \OC\Group\Group('group1', array($backend1, $backend2), $userManager);
|
||||||
|
|
||||||
|
$backend1->expects($this->once())
|
||||||
|
->method('countUsersInGroup')
|
||||||
|
->with('group1', '2')
|
||||||
|
->will($this->returnValue(3));
|
||||||
|
$backend1->expects($this->any())
|
||||||
|
->method('implementsActions')
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
|
$backend2->expects($this->once())
|
||||||
|
->method('countUsersInGroup')
|
||||||
|
->with('group1', '2')
|
||||||
|
->will($this->returnValue(4));
|
||||||
|
$backend2->expects($this->any())
|
||||||
|
->method('implementsActions')
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
|
$users = $group->count('2');
|
||||||
|
|
||||||
|
$this->assertSame(7, $users);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCountUsersNoMethod() {
|
||||||
|
$backend1 = $this->getMock('OC_Group_Database');
|
||||||
|
$userManager = $this->getUserManager();
|
||||||
|
$group = new \OC\Group\Group('group1', array($backend1), $userManager);
|
||||||
|
|
||||||
|
$backend1->expects($this->never())
|
||||||
|
->method('countUsersInGroup');
|
||||||
|
$backend1->expects($this->any())
|
||||||
|
->method('implementsActions')
|
||||||
|
->will($this->returnValue(false));
|
||||||
|
|
||||||
|
$users = $group->count('2');
|
||||||
|
|
||||||
|
$this->assertSame(false, $users);
|
||||||
|
}
|
||||||
|
|
||||||
public function testDelete() {
|
public function testDelete() {
|
||||||
$backend = $this->getMock('OC_Group_Database');
|
$backend = $this->getMock('OC_Group_Database');
|
||||||
$userManager = $this->getUserManager();
|
$userManager = $this->getUserManager();
|
||||||
|
|
Loading…
Reference in New Issue