diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/private/Notification/Manager.php | 80 | ||||
-rw-r--r-- | lib/private/Support/Subscription/Registry.php | 23 | ||||
-rw-r--r-- | lib/private/User/Manager.php | 7 | ||||
-rw-r--r-- | lib/public/Notification/IManager.php | 12 | ||||
-rw-r--r-- | lib/public/Support/Subscription/IRegistry.php | 4 |
5 files changed, 93 insertions, 33 deletions
diff --git a/lib/private/Notification/Manager.php b/lib/private/Notification/Manager.php index fb3a46d5f5d..4e0992053f2 100644 --- a/lib/private/Notification/Manager.php +++ b/lib/private/Notification/Manager.php @@ -27,8 +27,10 @@ declare(strict_types=1); namespace OC\Notification; use OC\AppFramework\Bootstrap\Coordinator; -use OCP\AppFramework\QueryException; -use OCP\ILogger; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\ICache; +use OCP\ICacheFactory; +use OCP\IUserManager; use OCP\Notification\AlreadyProcessedException; use OCP\Notification\IApp; use OCP\Notification\IDeferrableApp; @@ -37,11 +39,22 @@ use OCP\Notification\IManager; use OCP\Notification\INotification; use OCP\Notification\INotifier; use OCP\RichObjectStrings\IValidator; +use OCP\Support\Subscription\IRegistry; +use Psr\Container\ContainerExceptionInterface; +use Psr\Log\LoggerInterface; class Manager implements IManager { /** @var IValidator */ protected $validator; - /** @var ILogger */ + /** @var IUserManager */ + private $userManager; + /** @var ICache */ + protected $cache; + /** @var ITimeFactory */ + protected $timeFactory; + /** @var IRegistry */ + protected $subscription; + /** @var LoggerInterface */ protected $logger; /** @var Coordinator */ private $coordinator; @@ -64,9 +77,17 @@ class Manager implements IManager { private $parsedRegistrationContext; public function __construct(IValidator $validator, - ILogger $logger, + IUserManager $userManager, + ICacheFactory $cacheFactory, + ITimeFactory $timeFactory, + IRegistry $subscription, + LoggerInterface $logger, Coordinator $coordinator) { $this->validator = $validator; + $this->userManager = $userManager; + $this->cache = $cacheFactory->createDistributed('notifications'); + $this->timeFactory = $timeFactory; + $this->subscription = $subscription; $this->logger = $logger; $this->coordinator = $coordinator; @@ -97,9 +118,10 @@ class Manager implements IManager { */ public function registerNotifier(\Closure $service, \Closure $info) { $infoData = $info(); - $this->logger->logException(new \InvalidArgumentException( + $exception = new \InvalidArgumentException( 'Notifier ' . $infoData['name'] . ' (id: ' . $infoData['id'] . ') is not considered because it is using the old way to register.' - )); + ); + $this->logger->error($exception->getMessage(), ['exception' => $exception]); } /** @@ -121,10 +143,10 @@ class Manager implements IManager { foreach ($this->appClasses as $appClass) { try { - $app = \OC::$server->query($appClass); - } catch (QueryException $e) { - $this->logger->logException($e, [ - 'message' => 'Failed to load notification app class: ' . $appClass, + $app = \OC::$server->get($appClass); + } catch (ContainerExceptionInterface $e) { + $this->logger->error('Failed to load notification app class: ' . $appClass, [ + 'exception' => $e, 'app' => 'notifications', ]); continue; @@ -153,10 +175,10 @@ class Manager implements IManager { $notifierServices = $this->coordinator->getRegistrationContext()->getNotifierServices(); foreach ($notifierServices as $notifierService) { try { - $notifier = \OC::$server->query($notifierService->getService()); - } catch (QueryException $e) { - $this->logger->logException($e, [ - 'message' => 'Failed to load notification notifier class: ' . $notifierService->getService(), + $notifier = \OC::$server->get($notifierService->getService()); + } catch (ContainerExceptionInterface $e) { + $this->logger->error('Failed to load notification notifier class: ' . $notifierService->getService(), [ + 'exception' => $e, 'app' => 'notifications', ]); continue; @@ -181,10 +203,10 @@ class Manager implements IManager { foreach ($this->notifierClasses as $notifierClass) { try { - $notifier = \OC::$server->query($notifierClass); - } catch (QueryException $e) { - $this->logger->logException($e, [ - 'message' => 'Failed to load notification notifier class: ' . $notifierClass, + $notifier = \OC::$server->get($notifierClass); + } catch (ContainerExceptionInterface $e) { + $this->logger->error('Failed to load notification notifier class: ' . $notifierClass, [ + 'exception' => $e, 'app' => 'notifications', ]); continue; @@ -278,6 +300,28 @@ class Manager implements IManager { } /** + * {@inheritDoc} + */ + public function isFairUseOfFreePushService(): bool { + $pushAllowed = $this->cache->get('push_fair_use'); + if ($pushAllowed === null) { + /** + * We want to keep offering our push notification service for free, but large + * users overload our infrastructure. For this reason we have to rate-limit the + * use of push notifications. If you need this feature, consider setting up your + * own push server or using Nextcloud Enterprise. + */ + // TODO Remove time check after 1st March 2022 + $isFairUse = $this->timeFactory->getTime() < 1646089200 + || $this->subscription->delegateHasValidSubscription() + || $this->userManager->countSeenUsers() < 5000; + $pushAllowed = $isFairUse ? 'yes' : 'no'; + $this->cache->set('push_fair_use', $pushAllowed, 3600); + } + return $pushAllowed === 'yes'; + } + + /** * @param INotification $notification * @throws \InvalidArgumentException When the notification is not valid * @since 8.2.0 diff --git a/lib/private/Support/Subscription/Registry.php b/lib/private/Support/Subscription/Registry.php index e64eaac1fa2..1298337acb2 100644 --- a/lib/private/Support/Subscription/Registry.php +++ b/lib/private/Support/Subscription/Registry.php @@ -59,21 +59,17 @@ class Registry implements IRegistry { 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) { + LoggerInterface $logger) { $this->config = $config; $this->container = $container; $this->userManager = $userManager; $this->groupManager = $groupManager; $this->logger = $logger; - $this->notificationManager = $notificationManager; } private function getSubscription(): ?ISubscription { @@ -158,15 +154,16 @@ class Registry implements IRegistry { /** * 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(): bool { + public function delegateIsHardUserLimitReached(?IManager $notificationManager = null): bool { $subscription = $this->getSubscription(); if ($subscription instanceof ISubscription && $subscription->hasValidSubscription()) { $userLimitReached = $subscription->isHardUserLimitReached(); - if ($userLimitReached) { - $this->notifyAboutReachedUserLimit(); + if ($userLimitReached && $notificationManager instanceof IManager) { + $this->notifyAboutReachedUserLimit($notificationManager); } return $userLimitReached; } @@ -181,8 +178,8 @@ class Registry implements IRegistry { $hardUserLimit = $this->config->getSystemValue('one-click-instance.user-limit', 50); $userLimitReached = $userCount >= $hardUserLimit; - if ($userLimitReached) { - $this->notifyAboutReachedUserLimit(); + if ($userLimitReached && $notificationManager instanceof IManager) { + $this->notifyAboutReachedUserLimit($notificationManager); } return $userLimitReached; } @@ -216,17 +213,17 @@ class Registry implements IRegistry { return $userCount; } - private function notifyAboutReachedUserLimit() { + private function notifyAboutReachedUserLimit(IManager $notificationManager) { $admins = $this->groupManager->get('admin')->getUsers(); foreach ($admins as $admin) { - $notification = $this->notificationManager->createNotification(); + $notification = $notificationManager->createNotification(); $notification->setApp('core') ->setUser($admin->getUID()) ->setDateTime(new \DateTime()) ->setObject('user_limit_reached', '1') ->setSubject('user_limit_reached'); - $this->notificationManager->notify($notification); + $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 dbbfc2b53a2..7ed80bc5bc2 100644 --- a/lib/private/User/Manager.php +++ b/lib/private/User/Manager.php @@ -44,6 +44,7 @@ use OCP\IGroup; use OCP\IUser; use OCP\IUserBackend; use OCP\IUserManager; +use OCP\Notification\IManager; use OCP\Support\Subscription\IRegistry; use OCP\User\Backend\IGetRealUIDBackend; use OCP\User\Backend\ISearchKnownUsersBackend; @@ -379,7 +380,11 @@ class Manager extends PublicEmitter implements IUserManager { */ 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()) { + /** @var IRegistry $registry */ + $registry = \OC::$server->get(IRegistry::class); + /** @var IManager $notificationManager */ + $notificationManager = \OC::$server->get(IManager::class); + if ($registry->delegateIsHardUserLimitReached($notificationManager)) { $l = \OC::$server->getL10N('lib'); throw new HintException($l->t('The user limit has been reached and the user was not created.')); } diff --git a/lib/public/Notification/IManager.php b/lib/public/Notification/IManager.php index 66fe78b723e..e2f37176850 100644 --- a/lib/public/Notification/IManager.php +++ b/lib/public/Notification/IManager.php @@ -107,4 +107,16 @@ interface IManager extends IApp, INotifier { * @since 20.0.0 */ public function flush(): void; + + /** + * Whether the server can use the hosted push notification service + * + * We want to keep offering our push notification service for free, but large + * users overload our infrastructure. For this reason we have to rate-limit the + * use of push notifications. If you need this feature, consider setting up your + * own push server or using Nextcloud Enterprise. + * + * @since 23.0.0 + */ + public function isFairUseOfFreePushService(): bool; } diff --git a/lib/public/Support/Subscription/IRegistry.php b/lib/public/Support/Subscription/IRegistry.php index 1082f12ab58..4a34cc91c5e 100644 --- a/lib/public/Support/Subscription/IRegistry.php +++ b/lib/public/Support/Subscription/IRegistry.php @@ -27,6 +27,7 @@ declare(strict_types=1); */ namespace OCP\Support\Subscription; +use OCP\Notification\IManager; use OCP\Support\Subscription\Exception\AlreadyRegisteredException; /** @@ -81,7 +82,8 @@ interface IRegistry { /** * 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(): bool; + public function delegateIsHardUserLimitReached(?IManager $notificationManager = null): bool; } |