config = $config; $this->container = $container; $this->userManager = $userManager; $this->groupManager = $groupManager; $this->logger = $logger; } private function getSubscription(): ?ISubscription { if ($this->subscription === null && $this->subscriptionService !== null) { try { $this->subscription = $this->container->query($this->subscriptionService); } catch (QueryException $e) { // Ignore this } } return $this->subscription; } /** * Register a subscription instance. In case it is called multiple times the * first one is used. * * @param ISubscription $subscription * @throws AlreadyRegisteredException * * @since 17.0.0 */ public function register(ISubscription $subscription): void { if ($this->subscription !== null || $this->subscriptionService !== null) { throw new AlreadyRegisteredException(); } $this->subscription = $subscription; } public function registerService(string $subscriptionService): void { if ($this->subscription !== null || $this->subscriptionService !== null) { throw new AlreadyRegisteredException(); } $this->subscriptionService = $subscriptionService; } /** * Fetches the list of app IDs that are supported by the subscription * * @since 17.0.0 */ public function delegateGetSupportedApps(): array { if ($this->getSubscription() instanceof ISupportedApps) { return $this->getSubscription()->getSupportedApps(); } return []; } /** * Indicates if a valid subscription is available * * @since 17.0.0 */ public function delegateHasValidSubscription(): bool { // Allow overwriting this manually for environments where the subscription information cannot be fetched if ($this->config->getSystemValueBool('has_valid_subscription')) { return true; } if ($this->getSubscription() instanceof ISubscription) { return $this->getSubscription()->hasValidSubscription(); } return false; } /** * Indicates if the subscription has extended support * * @since 17.0.0 */ public function delegateHasExtendedSupport(): bool { 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 * * @param IManager|null $notificationManager * @since 21.0.0 */ public function delegateIsHardUserLimitReached(?IManager $notificationManager = null): bool { $subscription = $this->getSubscription(); if ($subscription instanceof ISubscription && $subscription->hasValidSubscription()) { $userLimitReached = $subscription->isHardUserLimitReached(); if ($userLimitReached && $notificationManager instanceof IManager) { $this->notifyAboutReachedUserLimit($notificationManager); } return $userLimitReached; } $isOneClickInstance = $this->config->getSystemValueBool('one-click-instance', false); if (!$isOneClickInstance) { return false; } $userCount = $this->getUserCount(); $hardUserLimit = $this->config->getSystemValueInt('one-click-instance.user-limit', 50); $userLimitReached = $userCount >= $hardUserLimit; if ($userLimitReached && $notificationManager instanceof IManager) { $this->notifyAboutReachedUserLimit($notificationManager); } return $userLimitReached; } 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']); } } } $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(IManager $notificationManager): void { $admins = $this->groupManager->get('admin')->getUsers(); $notification = $notificationManager->createNotification(); $notification->setApp('core') ->setObject('user_limit_reached', '1') ->setSubject('user_limit_reached'); if ($notificationManager->getCount($notification) > 0 && !$this->reIssue() ) { return; } $notificationManager->markProcessed($notification); $notification->setDateTime(new \DateTime()); foreach ($admins as $admin) { $notification->setUser($admin->getUID()); $notificationManager->notify($notification); } $this->logger->warning('The account limit was reached and the new account was not created', ['app' => 'lib']); } protected function reIssue(): bool { $lastNotification = (int)$this->config->getAppValue('lib', 'last_subscription_reminder', '0'); if ((time() - $lastNotification) >= 86400) { $this->config->setAppValue('lib', 'last_subscription_reminder', (string)time()); return true; } return false; } }