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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @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_REMOVE_FROM_GOUP', 0x00001000);
|
||||
define('OC_GROUP_BACKEND_GET_DISPLAYNAME', 0x00010000);
|
||||
define('OC_GROUP_BACKEND_COUNT_USERS', 0x00100000);
|
||||
|
||||
/**
|
||||
* 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_REMOVE_FROM_GOUP => 'removeFromGroup',
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
|
|
@ -299,6 +299,68 @@ class Group extends \PHPUnit_Framework_TestCase {
|
|||
$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() {
|
||||
$backend = $this->getMock('OC_Group_Database');
|
||||
$userManager = $this->getUserManager();
|
||||
|
|
Loading…
Reference in New Issue