From d87705a8941511a4e3bf8f6c97d6e0f36a42799e Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Thu, 8 Oct 2020 11:41:16 +0200 Subject: Allow subscription to indicate that a userlimit is reached Signed-off-by: Morris Jobke --- lib/private/Support/Subscription/Registry.php | 85 ++++++++++++++++++++++- lib/private/User/Manager.php | 8 +++ lib/public/Support/Subscription/IRegistry.php | 7 ++ lib/public/Support/Subscription/ISubscription.php | 7 ++ 4 files changed, 104 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/private/Support/Subscription/Registry.php b/lib/private/Support/Subscription/Registry.php index 3d6a9b09d84..ba9c4099b9b 100644 --- a/lib/private/Support/Subscription/Registry.php +++ b/lib/private/Support/Subscription/Registry.php @@ -28,13 +28,16 @@ declare(strict_types=1); namespace OC\Support\Subscription; +use OC\User\Backend; use OCP\AppFramework\QueryException; use OCP\IConfig; use OCP\IServerContainer; +use OCP\IUserManager; use OCP\Support\Subscription\Exception\AlreadyRegisteredException; use OCP\Support\Subscription\IRegistry; use OCP\Support\Subscription\ISubscription; use OCP\Support\Subscription\ISupportedApps; +use Psr\Log\LoggerInterface; class Registry implements IRegistry { @@ -49,10 +52,19 @@ class Registry implements IRegistry { /** @var IServerContainer */ private $container; - - public function __construct(IConfig $config, IServerContainer $container) { + /** @var IUserManager */ + private $userManager; + /** @var LoggerInterface */ + private $logger; + + public function __construct(IConfig $config, + IServerContainer $container, + IUserManager $userManager, + LoggerInterface $logger) { $this->config = $config; $this->container = $container; + $this->userManager = $userManager; + $this->logger = $logger; } private function getSubscription(): ?ISubscription { @@ -127,9 +139,76 @@ class Registry implements IRegistry { * @since 17.0.0 */ public function delegateHasExtendedSupport(): bool { - if ($this->getSubscription() instanceof ISubscription && method_exists($this->subscription, 'hasExtendedSupport')) { + if ($this->getSubscription() instanceof ISubscription) { return $this->getSubscription()->hasExtendedSupport(); } return false; } + + + /** + * Indicates if a hard user limit is reached and no new users should be created + * + * @since 21.0.0 + */ + public function delegateIsHardUserLimitReached(): bool { + $subscription = $this->getSubscription(); + if ($subscription instanceof ISubscription && + $subscription->hasValidSubscription()) { + $userLimitReached = $subscription->isHardUserLimitReached(); + if ($userLimitReached) { + $this->notifyAboutReachedUserLimit(); + } + return $userLimitReached; + } + + $isOneClickInstance = $this->config->getSystemValueBool('one-click-instance', false); + + if (!$isOneClickInstance) { + return false; + } + + $userCount = $this->getUserCount(); + $hardUserLimit = $this->config->getSystemValue('one-click-instance.user-limit', 50); + + $userLimitReached = $userCount >= $hardUserLimit; + if ($userLimitReached) { + $this->notifyAboutReachedUserLimit(); + } + return $userLimitReached; + } + + private function getUserCount(): int { + $userCount = 0; + $backends = $this->userManager->getBackends(); + foreach ($backends as $backend) { + if ($backend->implementsActions(Backend::COUNT_USERS)) { + $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']); + } + } + } + + $disabledUsers = $this->config->getUsersForUserValue('core', 'enabled', 'false'); + $disabledUsersCount = count($disabledUsers); + $userCount = $userCount - $disabledUsersCount; + + if ($userCount < 0) { + $userCount = 0; + + // this should never happen + $this->logger->warning("Total user count was negative (users: $userCount, disabled: $disabledUsersCount)", ['app' => 'lib']); + } + + return $userCount; + } + + private function notifyAboutReachedUserLimit() { + // TODO notify admin about reached user limit + $this->logger->warning('The user limit was reached and the new user was not created', ['app' => 'lib']); + } } diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php index 1201a456ce2..1d58c68268c 100644 --- a/lib/private/User/Manager.php +++ b/lib/private/User/Manager.php @@ -34,6 +34,7 @@ namespace OC\User; +use OC\HintException; use OC\Hooks\PublicEmitter; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\EventDispatcher\IEventDispatcher; @@ -42,6 +43,7 @@ use OCP\IGroup; use OCP\IUser; use OCP\IUserBackend; use OCP\IUserManager; +use OCP\Support\Subscription\IRegistry; use OCP\User\Backend\IGetRealUIDBackend; use OCP\User\Events\BeforeUserCreatedEvent; use OCP\User\Events\UserCreatedEvent; @@ -297,6 +299,12 @@ class Manager extends PublicEmitter implements IUserManager { * @return bool|IUser the created user or false */ public function createUser($uid, $password) { + // DI injection is not used here as IRegistry needs the user manager itself for user count and thus it would create a cyclic dependency + if (\OC::$server->get(IRegistry::class)->delegateIsHardUserLimitReached()) { + $l = \OC::$server->getL10N('lib'); + throw new HintException($l->t('The user limit has been reached and the user was not created.')); + } + $localBackends = []; foreach ($this->backends as $backend) { if ($backend instanceof Database) { diff --git a/lib/public/Support/Subscription/IRegistry.php b/lib/public/Support/Subscription/IRegistry.php index f3d6cf2f92c..ab1d00fa823 100644 --- a/lib/public/Support/Subscription/IRegistry.php +++ b/lib/public/Support/Subscription/IRegistry.php @@ -78,4 +78,11 @@ interface IRegistry { * @since 17.0.0 */ public function delegateHasExtendedSupport(): bool; + + /** + * Indicates if a hard user limit is reached and no new users should be created + * + * @since 21.0.0 + */ + public function delegateIsHardUserLimitReached(): bool; } diff --git a/lib/public/Support/Subscription/ISubscription.php b/lib/public/Support/Subscription/ISubscription.php index 83b7509b9fe..9614c0ed77b 100644 --- a/lib/public/Support/Subscription/ISubscription.php +++ b/lib/public/Support/Subscription/ISubscription.php @@ -45,4 +45,11 @@ interface ISubscription { * @since 17.0.0 */ public function hasExtendedSupport(): bool; + + /** + * Indicates if a hard user limit is reached and no new users should be created + * + * @since 21.0.0 + */ + public function isHardUserLimitReached(): bool; } -- cgit v1.2.3