diff options
author | Christoph Wurst <ChristophWurst@users.noreply.github.com> | 2020-12-02 18:22:13 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-02 18:22:13 +0100 |
commit | 4deff37a3cd375a801d82b41663e2305c1d1c149 (patch) | |
tree | b7d6f8b38396fe0cb4aec0b5b7787efdb309e0ec /lib | |
parent | dc3e05b69a31ef0187dba140520ec053a96ce554 (diff) | |
parent | c0a05c0412e11fd80adc2059b28c8963ba4252dc (diff) | |
download | nextcloud-server-4deff37a3cd375a801d82b41663e2305c1d1c149.tar.gz nextcloud-server-4deff37a3cd375a801d82b41663e2305c1d1c149.zip |
Merge pull request #23278 from nextcloud/enh/noid/user-limits
Allow subscription to indicate that a userlimit is reached
Diffstat (limited to 'lib')
-rw-r--r-- | lib/composer/composer/autoload_classmap.php | 2 | ||||
-rw-r--r-- | lib/composer/composer/autoload_static.php | 2 | ||||
-rw-r--r-- | lib/private/Support/Subscription/Registry.php | 106 | ||||
-rw-r--r-- | lib/private/User/Manager.php | 8 | ||||
-rw-r--r-- | lib/public/Support/Subscription/IRegistry.php | 7 | ||||
-rw-r--r-- | lib/public/Support/Subscription/ISubscription.php | 7 |
6 files changed, 127 insertions, 5 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index f841ef0755d..fe5abfb4758 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -927,7 +927,7 @@ return array( 'OC\\Core\\Migrations\\Version20000Date20201109081918' => $baseDir . '/core/Migrations/Version20000Date20201109081918.php', 'OC\\Core\\Migrations\\Version20000Date20201109081919' => $baseDir . '/core/Migrations/Version20000Date20201109081919.php', 'OC\\Core\\Migrations\\Version20000Date20201111081915' => $baseDir . '/core/Migrations/Version20000Date20201111081915.php', - 'OC\\Core\\Notification\\RemoveLinkSharesNotifier' => $baseDir . '/core/Notification/RemoveLinkSharesNotifier.php', + 'OC\\Core\\Notification\\CoreNotifier' => $baseDir . '/core/Notification/CoreNotifier.php', 'OC\\Core\\Service\\LoginFlowV2Service' => $baseDir . '/core/Service/LoginFlowV2Service.php', 'OC\\DB\\Adapter' => $baseDir . '/lib/private/DB/Adapter.php', 'OC\\DB\\AdapterMySQL' => $baseDir . '/lib/private/DB/AdapterMySQL.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index c587a7505fe..664ab007a94 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -956,7 +956,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Core\\Migrations\\Version20000Date20201109081918' => __DIR__ . '/../../..' . '/core/Migrations/Version20000Date20201109081918.php', 'OC\\Core\\Migrations\\Version20000Date20201109081919' => __DIR__ . '/../../..' . '/core/Migrations/Version20000Date20201109081919.php', 'OC\\Core\\Migrations\\Version20000Date20201111081915' => __DIR__ . '/../../..' . '/core/Migrations/Version20000Date20201111081915.php', - 'OC\\Core\\Notification\\RemoveLinkSharesNotifier' => __DIR__ . '/../../..' . '/core/Notification/RemoveLinkSharesNotifier.php', + 'OC\\Core\\Notification\\CoreNotifier' => __DIR__ . '/../../..' . '/core/Notification/CoreNotifier.php', 'OC\\Core\\Service\\LoginFlowV2Service' => __DIR__ . '/../../..' . '/core/Service/LoginFlowV2Service.php', 'OC\\DB\\Adapter' => __DIR__ . '/../../..' . '/lib/private/DB/Adapter.php', 'OC\\DB\\AdapterMySQL' => __DIR__ . '/../../..' . '/lib/private/DB/AdapterMySQL.php', diff --git a/lib/private/Support/Subscription/Registry.php b/lib/private/Support/Subscription/Registry.php index 3d6a9b09d84..72bae2adc8e 100644 --- a/lib/private/Support/Subscription/Registry.php +++ b/lib/private/Support/Subscription/Registry.php @@ -28,13 +28,18 @@ declare(strict_types=1); namespace OC\Support\Subscription; +use OC\User\Backend; use OCP\AppFramework\QueryException; use OCP\IConfig; +use OCP\IGroupManager; use OCP\IServerContainer; +use OCP\IUserManager; +use OCP\Notification\IManager; 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 +54,27 @@ class Registry implements IRegistry { /** @var IServerContainer */ private $container; - - public function __construct(IConfig $config, IServerContainer $container) { + /** @var IUserManager */ + private $userManager; + /** @var IGroupManager */ + private $groupManager; + /** @var LoggerInterface */ + private $logger; + /** @var IManager */ + private $notificationManager; + + public function __construct(IConfig $config, + IServerContainer $container, + IUserManager $userManager, + IGroupManager $groupManager, + LoggerInterface $logger, + IManager $notificationManager) { $this->config = $config; $this->container = $container; + $this->userManager = $userManager; + $this->groupManager = $groupManager; + $this->logger = $logger; + $this->notificationManager = $notificationManager; } private function getSubscription(): ?ISubscription { @@ -127,9 +149,87 @@ 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() { + $admins = $this->groupManager->get('admin')->getUsers(); + foreach ($admins as $admin) { + $notification = $this->notificationManager->createNotification(); + + $notification->setApp('core') + ->setUser($admin->getUID()) + ->setDateTime(new \DateTime()) + ->setObject('user_limit_reached', '1') + ->setSubject('user_limit_reached'); + $this->notificationManager->notify($notification); + } + + $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; } |