Merge pull request #6681 from owncloud/userreport
add command line option to get user number statistics
This commit is contained in:
commit
d8b8abb429
|
@ -634,6 +634,10 @@ class Access extends LDAPUtility {
|
||||||
return $this->search($filter, $this->connection->ldapBaseUsers, $attr, $limit, $offset);
|
return $this->search($filter, $this->connection->ldapBaseUsers, $attr, $limit, $offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function countUsers($filter, $attr = array('dn'), $limit = null, $offset = null) {
|
||||||
|
return $this->count($filter, $this->connection->ldapBaseGroups, $attr, $limit, $offset);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief executes an LDAP search, optimized for Groups
|
* @brief executes an LDAP search, optimized for Groups
|
||||||
* @param $filter the LDAP filter for the search
|
* @param $filter the LDAP filter for the search
|
||||||
|
@ -647,61 +651,68 @@ class Access extends LDAPUtility {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief executes an LDAP search
|
* @brief prepares and executes an LDAP search operation
|
||||||
* @param $filter the LDAP filter for the search
|
* @param $filter the LDAP filter for the search
|
||||||
* @param $base an array containing the LDAP subtree(s) that shall be searched
|
* @param $base an array containing the LDAP subtree(s) that shall be searched
|
||||||
* @param $attr optional, array, one or more attributes that shall be
|
* @param $attr optional, array, one or more attributes that shall be
|
||||||
* retrieved. Results will according to the order in the array.
|
* retrieved. Results will according to the order in the array.
|
||||||
* @returns array with the search result
|
* @param $limit optional, maximum results to be counted
|
||||||
*
|
* @param $offset optional, a starting point
|
||||||
* Executes an LDAP search
|
* @returns array with the search result as first value and pagedSearchOK as
|
||||||
|
* second | false if not successful
|
||||||
*/
|
*/
|
||||||
private function search($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) {
|
private function executeSearch($filter, $base, &$attr = null, $limit = null, $offset = null) {
|
||||||
if(!is_null($attr) && !is_array($attr)) {
|
if(!is_null($attr) && !is_array($attr)) {
|
||||||
$attr = array(mb_strtolower($attr, 'UTF-8'));
|
$attr = array(mb_strtolower($attr, 'UTF-8'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if we have a resource, in case not cancel with message
|
// See if we have a resource, in case not cancel with message
|
||||||
$link_resource = $this->connection->getConnectionResource();
|
$cr = $this->connection->getConnectionResource();
|
||||||
if(!$this->ldap->isResource($link_resource)) {
|
if(!$this->ldap->isResource($cr)) {
|
||||||
// Seems like we didn't find any resource.
|
// Seems like we didn't find any resource.
|
||||||
// Return an empty array just like before.
|
// Return an empty array just like before.
|
||||||
\OCP\Util::writeLog('user_ldap', 'Could not search, because resource is missing.', \OCP\Util::DEBUG);
|
\OCP\Util::writeLog('user_ldap', 'Could not search, because resource is missing.', \OCP\Util::DEBUG);
|
||||||
return array();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check wether paged search should be attempted
|
//check wether paged search should be attempted
|
||||||
$pagedSearchOK = $this->initPagedSearch($filter, $base, $attr, $limit, $offset);
|
$pagedSearchOK = $this->initPagedSearch($filter, $base, $attr, $limit, $offset);
|
||||||
|
|
||||||
$linkResources = array_pad(array(), count($base), $link_resource);
|
$linkResources = array_pad(array(), count($base), $cr);
|
||||||
$sr = $this->ldap->search($linkResources, $base, $filter, $attr);
|
$sr = $this->ldap->search($linkResources, $base, $filter, $attr);
|
||||||
$error = $this->ldap->errno($link_resource);
|
$error = $this->ldap->errno($cr);
|
||||||
if(!is_array($sr) || $error !== 0) {
|
if(!is_array($sr) || $error !== 0) {
|
||||||
\OCP\Util::writeLog('user_ldap',
|
\OCP\Util::writeLog('user_ldap',
|
||||||
'Error when searching: '.$this->ldap->error($link_resource).
|
'Error when searching: '.$this->ldap->error($cr).
|
||||||
' code '.$this->ldap->errno($link_resource),
|
' code '.$this->ldap->errno($cr),
|
||||||
\OCP\Util::ERROR);
|
\OCP\Util::ERROR);
|
||||||
\OCP\Util::writeLog('user_ldap', 'Attempt for Paging? '.print_r($pagedSearchOK, true), \OCP\Util::ERROR);
|
\OCP\Util::writeLog('user_ldap', 'Attempt for Paging? '.print_r($pagedSearchOK, true), \OCP\Util::ERROR);
|
||||||
return array();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do the server-side sorting
|
return array($sr, $pagedSearchOK);
|
||||||
foreach(array_reverse($attr) as $sortAttr){
|
}
|
||||||
foreach($sr as $searchResource) {
|
|
||||||
$this->ldap->sort($link_resource, $searchResource, $sortAttr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$findings = array();
|
/**
|
||||||
foreach($sr as $key => $res) {
|
* @brief processes an LDAP paged search operation
|
||||||
$findings = array_merge($findings, $this->ldap->getEntries($link_resource, $res ));
|
* @param $sr the array containing the LDAP search resources
|
||||||
}
|
* @param $filter the LDAP filter for the search
|
||||||
|
* @param $base an array containing the LDAP subtree(s) that shall be searched
|
||||||
|
* @param $iFoundItems number of results in the search operation
|
||||||
|
* @param $limit maximum results to be counted
|
||||||
|
* @param $offset a starting point
|
||||||
|
* @param $pagedSearchOK whether a paged search has been executed
|
||||||
|
* @param $skipHandling required for paged search when cookies to
|
||||||
|
* prior results need to be gained
|
||||||
|
* @returns array with the search result as first value and pagedSearchOK as
|
||||||
|
* second | false if not successful
|
||||||
|
*/
|
||||||
|
private function processPagedSearchStatus($sr, $filter, $base, $iFoundItems, $limit, $offset, $pagedSearchOK, $skipHandling) {
|
||||||
if($pagedSearchOK) {
|
if($pagedSearchOK) {
|
||||||
\OCP\Util::writeLog('user_ldap', 'Paged search successful', \OCP\Util::INFO);
|
$cr = $this->connection->getConnectionResource();
|
||||||
foreach($sr as $key => $res) {
|
foreach($sr as $key => $res) {
|
||||||
$cookie = null;
|
$cookie = null;
|
||||||
if($this->ldap->controlPagedResultResponse($link_resource, $res, $cookie)) {
|
if($this->ldap->controlPagedResultResponse($cr, $res, $cookie)) {
|
||||||
\OCP\Util::writeLog('user_ldap', 'Set paged search cookie', \OCP\Util::INFO);
|
|
||||||
$this->setPagedResultCookie($base[$key], $filter, $limit, $offset, $cookie);
|
$this->setPagedResultCookie($base[$key], $filter, $limit, $offset, $cookie);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -713,7 +724,7 @@ class Access extends LDAPUtility {
|
||||||
// if count is bigger, then the server does not support
|
// if count is bigger, then the server does not support
|
||||||
// paged search. Instead, he did a normal search. We set a
|
// paged search. Instead, he did a normal search. We set a
|
||||||
// flag here, so the callee knows how to deal with it.
|
// flag here, so the callee knows how to deal with it.
|
||||||
if($findings['count'] <= $limit) {
|
if($iFoundItems <= $limit) {
|
||||||
$this->pagedSearchedSuccessful = true;
|
$this->pagedSearchedSuccessful = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -721,6 +732,86 @@ class Access extends LDAPUtility {
|
||||||
\OCP\Util::writeLog('user_ldap', 'Paged search failed :(', \OCP\Util::INFO);
|
\OCP\Util::writeLog('user_ldap', 'Paged search failed :(', \OCP\Util::INFO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief executes an LDAP search, but counts the results only
|
||||||
|
* @param $filter the LDAP filter for the search
|
||||||
|
* @param $base an array containing the LDAP subtree(s) that shall be searched
|
||||||
|
* @param $attr optional, array, one or more attributes that shall be
|
||||||
|
* retrieved. Results will according to the order in the array.
|
||||||
|
* @param $limit optional, maximum results to be counted
|
||||||
|
* @param $offset optional, a starting point
|
||||||
|
* @param $skipHandling indicates whether the pages search operation is
|
||||||
|
* completed
|
||||||
|
* @returns int | false if the search could not be initialized
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function count($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) {
|
||||||
|
\OCP\Util::writeLog('user_ldap', 'Count filter: '.print_r($filter, true), \OCP\Util::DEBUG);
|
||||||
|
$search = $this->executeSearch($filter, $base, $attr, $limit, $offset);
|
||||||
|
if($search === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
list($sr, $pagedSearchOK) = $search;
|
||||||
|
$cr = $this->connection->getConnectionResource();
|
||||||
|
$counter = 0;
|
||||||
|
foreach($sr as $key => $res) {
|
||||||
|
$count = $this->ldap->countEntries($cr, $res);
|
||||||
|
if($count !== false) {
|
||||||
|
$counter += $count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->processPagedSearchStatus($sr, $filter, $base, $counter, $limit,
|
||||||
|
$offset, $pagedSearchOK, $skipHandling);
|
||||||
|
|
||||||
|
return $counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief executes an LDAP search
|
||||||
|
* @param $filter the LDAP filter for the search
|
||||||
|
* @param $base an array containing the LDAP subtree(s) that shall be searched
|
||||||
|
* @param $attr optional, array, one or more attributes that shall be
|
||||||
|
* retrieved. Results will according to the order in the array.
|
||||||
|
* @returns array with the search result
|
||||||
|
*
|
||||||
|
* Executes an LDAP search
|
||||||
|
*/
|
||||||
|
private function search($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) {
|
||||||
|
$search = $this->executeSearch($filter, $base, $attr, $limit, $offset);
|
||||||
|
if($search === false) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
list($sr, $pagedSearchOK) = $search;
|
||||||
|
$cr = $this->connection->getConnectionResource();
|
||||||
|
|
||||||
|
if($skipHandling) {
|
||||||
|
//i.e. result do not need to be fetched, we just need the cookie
|
||||||
|
//thus pass 1 or any other value as $iFoundItems because it is not
|
||||||
|
//used
|
||||||
|
$this->processPagedSearchStatus($sr, $filter, $base, 1, $limit,
|
||||||
|
$offset, $pagedSearchOK,
|
||||||
|
$skipHandling);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the server-side sorting
|
||||||
|
foreach(array_reverse($attr) as $sortAttr){
|
||||||
|
foreach($sr as $searchResource) {
|
||||||
|
$this->ldap->sort($cr, $searchResource, $sortAttr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$findings = array();
|
||||||
|
foreach($sr as $key => $res) {
|
||||||
|
$findings = array_merge($findings, $this->ldap->getEntries($cr , $res ));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->processPagedSearchStatus($sr, $filter, $base, $findings['count'],
|
||||||
|
$limit, $offset, $pagedSearchOK,
|
||||||
|
$skipHandling);
|
||||||
|
|
||||||
// if we're here, probably no connection resource is returned.
|
// if we're here, probably no connection resource is returned.
|
||||||
// to make ownCloud behave nicely, we simply give back an empty array.
|
// to make ownCloud behave nicely, we simply give back an empty array.
|
||||||
|
|
|
@ -408,4 +408,58 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
//no test for getDisplayNames, because it just invokes getUsers and
|
//no test for getDisplayNames, because it just invokes getUsers and
|
||||||
//getDisplayName
|
//getDisplayName
|
||||||
|
|
||||||
|
public function testCountUsers() {
|
||||||
|
$access = $this->getAccessMock();
|
||||||
|
|
||||||
|
$access->connection->expects($this->once())
|
||||||
|
->method('__get')
|
||||||
|
->will($this->returnCallback(function($name) {
|
||||||
|
if($name === 'ldapLoginFilter') {
|
||||||
|
return 'uid=%uid';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}));
|
||||||
|
|
||||||
|
$access->expects($this->once())
|
||||||
|
->method('countUsers')
|
||||||
|
->will($this->returnCallback(function($filter, $a, $b, $c) {
|
||||||
|
if($filter !== 'uid=*') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return 5;
|
||||||
|
}));
|
||||||
|
|
||||||
|
$backend = new UserLDAP($access);
|
||||||
|
|
||||||
|
$result = $backend->countUsers();
|
||||||
|
$this->assertEquals(5, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCountUsersFailing() {
|
||||||
|
$access = $this->getAccessMock();
|
||||||
|
|
||||||
|
$access->connection->expects($this->once())
|
||||||
|
->method('__get')
|
||||||
|
->will($this->returnCallback(function($name) {
|
||||||
|
if($name === 'ldapLoginFilter') {
|
||||||
|
return 'invalidFilter';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}));
|
||||||
|
|
||||||
|
$access->expects($this->once())
|
||||||
|
->method('countUsers')
|
||||||
|
->will($this->returnCallback(function($filter, $a, $b, $c) {
|
||||||
|
if($filter !== 'uid=*') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return 5;
|
||||||
|
}));
|
||||||
|
|
||||||
|
$backend = new UserLDAP($access);
|
||||||
|
|
||||||
|
$result = $backend->countUsers();
|
||||||
|
$this->assertFalse($result);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -363,7 +363,8 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
||||||
return (bool)((OC_USER_BACKEND_CHECK_PASSWORD
|
return (bool)((OC_USER_BACKEND_CHECK_PASSWORD
|
||||||
| OC_USER_BACKEND_GET_HOME
|
| OC_USER_BACKEND_GET_HOME
|
||||||
| OC_USER_BACKEND_GET_DISPLAYNAME
|
| OC_USER_BACKEND_GET_DISPLAYNAME
|
||||||
| OC_USER_BACKEND_PROVIDE_AVATAR)
|
| OC_USER_BACKEND_PROVIDE_AVATAR
|
||||||
|
| OC_USER_BACKEND_COUNT_USERS)
|
||||||
& $actions);
|
& $actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,4 +374,16 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
||||||
public function hasUserListings() {
|
public function hasUserListings() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* counts the users in LDAP
|
||||||
|
*
|
||||||
|
* @return int | bool
|
||||||
|
*/
|
||||||
|
public function countUsers() {
|
||||||
|
$filter = \OCP\Util::mb_str_replace(
|
||||||
|
'%uid', '*', $this->access->connection->ldapLoginFilter, 'UTF-8');
|
||||||
|
$entries = $this->access->countUsers($filter);
|
||||||
|
return $entries;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,4 +210,19 @@ class User_Proxy extends lib\Proxy implements \OCP\UserInterface {
|
||||||
return $this->refBackend->hasUserListings();
|
return $this->refBackend->hasUserListings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Count the number of users
|
||||||
|
* @returns int | bool
|
||||||
|
*/
|
||||||
|
public function countUsers() {
|
||||||
|
$users = false;
|
||||||
|
foreach($this->backends as $backend) {
|
||||||
|
$backendUsers = $backend->countUsers();
|
||||||
|
if ($backendUsers !== false) {
|
||||||
|
$users += $backendUsers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $users;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?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\Core\Command\User;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Helper\TableHelper;
|
||||||
|
|
||||||
|
class Report extends Command {
|
||||||
|
protected function configure() {
|
||||||
|
$this
|
||||||
|
->setName('user:report')
|
||||||
|
->setDescription('shows how many users have access');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||||
|
$table = $this->getHelperSet()->get('table');
|
||||||
|
$table->setHeaders(array('User Report', ''));
|
||||||
|
$userCountArray = $this->countUsers();
|
||||||
|
if(!empty($userCountArray)) {
|
||||||
|
$total = 0;
|
||||||
|
$rows = array();
|
||||||
|
foreach($userCountArray as $classname => $users) {
|
||||||
|
$total += $users;
|
||||||
|
$rows[] = array($classname, $users);
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows[] = array(' ');
|
||||||
|
$rows[] = array('total users', $total);
|
||||||
|
} else {
|
||||||
|
$rows[] = array('No backend enabled that supports user counting', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
$userDirectoryCount = $this->countUserDirectories();
|
||||||
|
$rows[] = array(' ');
|
||||||
|
$rows[] = array('user directories', $userDirectoryCount);
|
||||||
|
|
||||||
|
$table->setRows($rows);
|
||||||
|
$table->render($output);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function countUsers() {
|
||||||
|
\OC_App::loadApps(array('authentication'));
|
||||||
|
$userManager = \OC::$server->getUserManager();
|
||||||
|
return $userManager->countUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function countUserDirectories() {
|
||||||
|
$dataview = new \OC\Files\View('/');
|
||||||
|
$userDirectories = $dataview->getDirectoryContent('/', 'httpd/unix-directory');
|
||||||
|
return count($userDirectories);
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,3 +15,4 @@ $application->add(new OC\Core\Command\App\Disable());
|
||||||
$application->add(new OC\Core\Command\App\Enable());
|
$application->add(new OC\Core\Command\App\Enable());
|
||||||
$application->add(new OC\Core\Command\App\ListApps());
|
$application->add(new OC\Core\Command\App\ListApps());
|
||||||
$application->add(new OC\Core\Command\Maintenance\Repair(new \OC\Repair()));
|
$application->add(new OC\Core\Command\Maintenance\Repair(new \OC\Repair()));
|
||||||
|
$application->add(new OC\Core\Command\User\Report());
|
||||||
|
|
|
@ -31,13 +31,15 @@ define('OC_USER_BACKEND_NOT_IMPLEMENTED', -501);
|
||||||
/**
|
/**
|
||||||
* actions that user backends can define
|
* actions that user backends can define
|
||||||
*/
|
*/
|
||||||
define('OC_USER_BACKEND_CREATE_USER', 0x0000001);
|
define('OC_USER_BACKEND_CREATE_USER', 0x00000001);
|
||||||
define('OC_USER_BACKEND_SET_PASSWORD', 0x0000010);
|
define('OC_USER_BACKEND_SET_PASSWORD', 0x00000010);
|
||||||
define('OC_USER_BACKEND_CHECK_PASSWORD', 0x0000100);
|
define('OC_USER_BACKEND_CHECK_PASSWORD', 0x00000100);
|
||||||
define('OC_USER_BACKEND_GET_HOME', 0x0001000);
|
define('OC_USER_BACKEND_GET_HOME', 0x00001000);
|
||||||
define('OC_USER_BACKEND_GET_DISPLAYNAME', 0x0010000);
|
define('OC_USER_BACKEND_GET_DISPLAYNAME', 0x00010000);
|
||||||
define('OC_USER_BACKEND_SET_DISPLAYNAME', 0x0100000);
|
define('OC_USER_BACKEND_SET_DISPLAYNAME', 0x00100000);
|
||||||
define('OC_USER_BACKEND_PROVIDE_AVATAR', 0x1000000);
|
define('OC_USER_BACKEND_PROVIDE_AVATAR', 0x01000000);
|
||||||
|
define('OC_USER_BACKEND_COUNT_USERS', 0x10000000);
|
||||||
|
//more actions cannot be defined without breaking 32bit platforms!
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for user management. Provides methods for querying backend
|
* Abstract base class for user management. Provides methods for querying backend
|
||||||
|
@ -55,6 +57,7 @@ abstract class OC_User_Backend implements OC_User_Interface {
|
||||||
OC_USER_BACKEND_GET_DISPLAYNAME => 'getDisplayName',
|
OC_USER_BACKEND_GET_DISPLAYNAME => 'getDisplayName',
|
||||||
OC_USER_BACKEND_SET_DISPLAYNAME => 'setDisplayName',
|
OC_USER_BACKEND_SET_DISPLAYNAME => 'setDisplayName',
|
||||||
OC_USER_BACKEND_PROVIDE_AVATAR => 'canChangeAvatar',
|
OC_USER_BACKEND_PROVIDE_AVATAR => 'canChangeAvatar',
|
||||||
|
OC_USER_BACKEND_COUNT_USERS => 'countUsers',
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -253,4 +253,19 @@ class OC_User_Database extends OC_User_Backend {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* counts the users in the database
|
||||||
|
*
|
||||||
|
* @return int | bool
|
||||||
|
*/
|
||||||
|
public function countUsers() {
|
||||||
|
$query = OC_DB::prepare('SELECT COUNT(*) FROM `*PREFIX*users`');
|
||||||
|
$result = $query->execute();
|
||||||
|
if (OC_DB::isError($result)) {
|
||||||
|
OC_Log::write('core', OC_DB::getErrorMessage($result), OC_Log::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $result->fetchOne();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,4 +123,13 @@ class OC_User_Dummy extends OC_User_Backend {
|
||||||
public function hasUserListings() {
|
public function hasUserListings() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* counts the users in the database
|
||||||
|
*
|
||||||
|
* @return int | bool
|
||||||
|
*/
|
||||||
|
public function countUsers() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -270,4 +270,26 @@ class Manager extends PublicEmitter {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns how many users per backend exist (if supported by backend)
|
||||||
|
*
|
||||||
|
* @return array with backend class as key and count number as value
|
||||||
|
*/
|
||||||
|
public function countUsers() {
|
||||||
|
$userCountStatistics = array();
|
||||||
|
foreach ($this->backends as $backend) {
|
||||||
|
if ($backend->implementsActions(\OC_USER_BACKEND_COUNT_USERS)) {
|
||||||
|
$backendusers = $backend->countUsers();
|
||||||
|
if($backendusers !== false) {
|
||||||
|
if(isset($userCountStatistics[get_class($backend)])) {
|
||||||
|
$userCountStatistics[get_class($backend)] += $backendusers;
|
||||||
|
} else {
|
||||||
|
$userCountStatistics[get_class($backend)] = $backendusers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $userCountStatistics;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -346,4 +346,76 @@ class Manager extends \PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
$manager->createUser('foo', 'bar');
|
$manager->createUser('foo', 'bar');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCountUsersNoBackend() {
|
||||||
|
$manager = new \OC\User\Manager();
|
||||||
|
|
||||||
|
$result = $manager->countUsers();
|
||||||
|
$this->assertTrue(is_array($result));
|
||||||
|
$this->assertTrue(empty($result));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCountUsersOneBackend() {
|
||||||
|
/**
|
||||||
|
* @var \OC_User_Dummy | \PHPUnit_Framework_MockObject_MockObject $backend
|
||||||
|
*/
|
||||||
|
$backend = $this->getMock('\OC_User_Dummy');
|
||||||
|
$backend->expects($this->once())
|
||||||
|
->method('countUsers')
|
||||||
|
->will($this->returnValue(7));
|
||||||
|
|
||||||
|
$backend->expects($this->once())
|
||||||
|
->method('implementsActions')
|
||||||
|
->with(\OC_USER_BACKEND_COUNT_USERS)
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
|
$manager = new \OC\User\Manager();
|
||||||
|
$manager->registerBackend($backend);
|
||||||
|
|
||||||
|
$result = $manager->countUsers();
|
||||||
|
$keys = array_keys($result);
|
||||||
|
$this->assertTrue(strpos($keys[0], 'Mock_OC_User_Dummy') !== false);
|
||||||
|
|
||||||
|
$users = array_shift($result);
|
||||||
|
$this->assertEquals(7, $users);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCountUsersTwoBackends() {
|
||||||
|
/**
|
||||||
|
* @var \OC_User_Dummy | \PHPUnit_Framework_MockObject_MockObject $backend
|
||||||
|
*/
|
||||||
|
$backend1 = $this->getMock('\OC_User_Dummy');
|
||||||
|
$backend1->expects($this->once())
|
||||||
|
->method('countUsers')
|
||||||
|
->will($this->returnValue(7));
|
||||||
|
|
||||||
|
$backend1->expects($this->once())
|
||||||
|
->method('implementsActions')
|
||||||
|
->with(\OC_USER_BACKEND_COUNT_USERS)
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
|
$backend2 = $this->getMock('\OC_User_Dummy');
|
||||||
|
$backend2->expects($this->once())
|
||||||
|
->method('countUsers')
|
||||||
|
->will($this->returnValue(16));
|
||||||
|
|
||||||
|
$backend2->expects($this->once())
|
||||||
|
->method('implementsActions')
|
||||||
|
->with(\OC_USER_BACKEND_COUNT_USERS)
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
|
$manager = new \OC\User\Manager();
|
||||||
|
$manager->registerBackend($backend1);
|
||||||
|
$manager->registerBackend($backend2);
|
||||||
|
|
||||||
|
$result = $manager->countUsers();
|
||||||
|
//because the backends have the same class name, only one value expected
|
||||||
|
$this->assertEquals(1, count($result));
|
||||||
|
$keys = array_keys($result);
|
||||||
|
$this->assertTrue(strpos($keys[0], 'Mock_OC_User_Dummy') !== false);
|
||||||
|
|
||||||
|
$users = array_shift($result);
|
||||||
|
//users from backends shall be summed up
|
||||||
|
$this->assertEquals(7+16, $users);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue