Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat(updatenotification): Add a limit to user count from LDAP so save…
… performances

Signed-off-by: Côme Chilliet <[email protected]>
  • Loading branch information
come-nc committed Jan 14, 2025
commit e187e4e87f73b6b17e40248d8779b8defe139a90
24 changes: 1 addition & 23 deletions apps/updatenotification/lib/Settings/Admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
*/
namespace OCA\UpdateNotification\Settings;

use OC\User\Backend;
use OCA\UpdateNotification\UpdateChecker;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState;
Expand All @@ -20,7 +19,6 @@
use OCP\L10N\IFactory;
use OCP\Settings\ISettings;
use OCP\Support\Subscription\IRegistry;
use OCP\User\Backend\ICountUsersBackend;
use OCP\Util;
use Psr\Log\LoggerInterface;

Expand Down Expand Up @@ -141,26 +139,6 @@ public function getPriority(): int {
}

private function isWebUpdaterRecommended(): bool {
return $this->getUserCount() < 100;
}

/**
* @see https://github.com/nextcloud/server/blob/39494fbf794d982f6f6551c984e6ca4c4e947d01/lib/private/Support/Subscription/Registry.php#L188-L216 implementation reference
*/
private function getUserCount(): int {
$userCount = 0;
$backends = $this->userManager->getBackends();
foreach ($backends as $backend) {
// TODO: change below to 'if ($backend instanceof ICountUsersBackend) {'
if ($backend->implementsActions(Backend::COUNT_USERS)) {
/** @var ICountUsersBackend $backend */
$backendUsers = $backend->countUsers();
if ($backendUsers !== false) {
$userCount += $backendUsers;
}
}
}

return $userCount;
return (int)$this->userManager->countUsersTotal(100) < 100;
}
}
12 changes: 5 additions & 7 deletions apps/user_ldap/lib/User_LDAP.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
use OCP\IUserBackend;
use OCP\Notification\IManager as INotificationManager;
use OCP\User\Backend\ICountMappedUsersBackend;
use OCP\User\Backend\ICountUsersBackend;
use OCP\User\Backend\ILimitAwareCountUsersBackend;
use OCP\User\Backend\IProvideEnabledStateBackend;
use OCP\UserInterface;
use Psr\Log\LoggerInterface;

class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, IUserLDAP, ICountUsersBackend, ICountMappedUsersBackend, IProvideEnabledStateBackend {
class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, IUserLDAP, ILimitAwareCountUsersBackend, ICountMappedUsersBackend, IProvideEnabledStateBackend {
public function __construct(
Access $access,
protected INotificationManager $notificationManager,
Expand Down Expand Up @@ -528,20 +528,18 @@ public function hasUserListings() {

/**
* counts the users in LDAP
*
* @return int|false
*/
public function countUsers() {
public function countUsers(int $limit = 0): int|false {
if ($this->userPluginManager->implementsActions(Backend::COUNT_USERS)) {
return $this->userPluginManager->countUsers();
}

$filter = $this->access->getFilterForUserCount();
$cacheKey = 'countUsers-' . $filter;
$cacheKey = 'countUsers-' . $filter . '-' . $limit;
if (!is_null($entries = $this->access->connection->getFromCache($cacheKey))) {
return $entries;
}
$entries = $this->access->countUsers($filter);
$entries = $this->access->countUsers($filter, limit:$limit);
$this->access->connection->writeToCache($cacheKey, $entries);
return $entries;
}
Expand Down
16 changes: 10 additions & 6 deletions apps/user_ldap/lib/User_Proxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
use OCP\IUserBackend;
use OCP\Notification\IManager as INotificationManager;
use OCP\User\Backend\ICountMappedUsersBackend;
use OCP\User\Backend\ICountUsersBackend;
use OCP\User\Backend\ILimitAwareCountUsersBackend;
use OCP\User\Backend\IProvideEnabledStateBackend;
use OCP\UserInterface;
use Psr\Log\LoggerInterface;

class User_Proxy extends Proxy implements IUserBackend, UserInterface, IUserLDAP, ICountUsersBackend, ICountMappedUsersBackend, IProvideEnabledStateBackend {
class User_Proxy extends Proxy implements IUserBackend, UserInterface, IUserLDAP, ILimitAwareCountUsersBackend, ICountMappedUsersBackend, IProvideEnabledStateBackend {
/** @var User_LDAP[] */
private array $backends = [];
private ?User_LDAP $refBackend = null;
Expand Down Expand Up @@ -350,17 +350,21 @@ public function hasUserListings() {

/**
* Count the number of users
*
* @return int|false
*/
public function countUsers() {
public function countUsers(int $limit = 0): int|false {
$this->setup();

$users = false;
foreach ($this->backends as $backend) {
$backendUsers = $backend->countUsers();
$backendUsers = $backend->countUsers($limit);
if ($backendUsers !== false) {
$users = (int)$users + $backendUsers;
if ($limit > 0) {
if ($users >= $limit) {
break;
}
$limit -= $users;
}
}
}
return $users;
Expand Down
21 changes: 2 additions & 19 deletions lib/private/Support/Subscription/Registry.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
*/
namespace OC\Support\Subscription;

use OC\User\Backend;
use OCP\AppFramework\QueryException;
use OCP\IConfig;
use OCP\IGroupManager;
Expand All @@ -19,8 +18,6 @@
use OCP\Support\Subscription\IRegistry;
use OCP\Support\Subscription\ISubscription;
use OCP\Support\Subscription\ISupportedApps;
use OCP\User\Backend\ICountMappedUsersBackend;
use OCP\User\Backend\ICountUsersBackend;
use Psr\Log\LoggerInterface;

class Registry implements IRegistry {
Expand Down Expand Up @@ -167,22 +164,8 @@ public function delegateIsHardUserLimitReached(?IManager $notificationManager =
}

private function getUserCount(): int {
$userCount = 0;
$backends = $this->userManager->getBackends();
foreach ($backends as $backend) {
if ($backend instanceof ICountMappedUsersBackend) {
$userCount += $backend->countMappedUsers();
} elseif ($backend->implementsActions(Backend::COUNT_USERS)) {
/** @var ICountUsersBackend $backend */
$backendUsers = $backend->countUsers();
if ($backendUsers !== false) {
$userCount += $backendUsers;
} else {
// TODO what if the user count can't be determined?
$this->logger->warning('Can not determine user count for ' . get_class($backend), ['app' => 'lib']);
}
}
}
/* We cannot limit because we substract disabled users afterward. But we limit to mapped users so should be not too expensive. */
$userCount = (int)$this->userManager->countUsersTotal(0, true);

$disabledUsers = $this->config->getUsersForUserValue('core', 'enabled', 'false');
$disabledUsersCount = count($disabledUsers);
Expand Down
31 changes: 31 additions & 0 deletions lib/private/User/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
use OCP\Server;
use OCP\Support\Subscription\IAssertion;
use OCP\User\Backend\ICheckPasswordBackend;
use OCP\User\Backend\ICountMappedUsersBackend;
use OCP\User\Backend\ICountUsersBackend;
use OCP\User\Backend\IGetRealUIDBackend;
use OCP\User\Backend\ILimitAwareCountUsersBackend;
use OCP\User\Backend\IProvideEnabledStateBackend;
use OCP\User\Backend\ISearchKnownUsersBackend;
use OCP\User\Events\BeforeUserCreatedEvent;
Expand Down Expand Up @@ -488,6 +490,35 @@ public function countUsers() {
return $userCountStatistics;
}

public function countUsersTotal(int $limit = 0, bool $onlyMappedUsers = false): int|false {
$userCount = false;
foreach ($this->backends as $backend) {
if ($onlyMappedUsers && $backend instanceof ICountMappedUsersBackend) {
$backendUsers = $backend->countMappedUsers();
} elseif ($backend instanceof ILimitAwareCountUsersBackend) {
$backendUsers = $backend->countUsers($limit);
} elseif ($backend instanceof ICountUsersBackend || $backend->implementsActions(Backend::COUNT_USERS)) {
/** @var ICountUsersBackend $backend */
$backendUsers = $backend->countUsers();
} else {
$this->logger->debug('Skip backend for user count: ' . get_class($backend));
continue;
}
if ($backendUsers !== false) {
$userCount += $backendUsers;
if ($limit > 0) {
if ($userCount >= $limit) {
break;
}
$limit -= $userCount;
}
} else {
$this->logger->warning('Can not determine user count for ' . get_class($backend));
}
}
return $userCount;
}

/**
* returns how many users per backend exist in the requested groups (if supported by backend)
*
Expand Down
10 changes: 10 additions & 0 deletions lib/public/IUserManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,16 @@ public function createUserFromBackend($uid, $password, UserInterface $backend);
*/
public function countUsers();

/**
* Get how many users exists in total, whithin limit
*
* @param int $limit Limit the count to avoid resource waste. 0 to disable
* @param bool $onlyMappedUsers Count mapped users instead of all users for compatible backends
*
* @since 31.0.0
*/
public function countUsersTotal(int $limit = 0, bool $onlyMappedUsers = false): int|false;

/**
* @param \Closure $callback
* @psalm-param \Closure(\OCP\IUser):void $callback
Expand Down
1 change: 1 addition & 0 deletions lib/public/User/Backend/ICountUsersBackend.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

/**
* @since 14.0.0
* @deprecated 31.0.0 use and implement ILimitAwareCountUsersBackend instead.
*/
interface ICountUsersBackend {
/**
Expand Down