diff --git a/apps/comments/lib/AppInfo/Application.php b/apps/comments/lib/AppInfo/Application.php index c152afddad..af12c7ac09 100644 --- a/apps/comments/lib/AppInfo/Application.php +++ b/apps/comments/lib/AppInfo/Application.php @@ -75,19 +75,16 @@ class Application extends App implements IBootstrap { $context->registerSearchProvider(CommentsSearchProvider::class); $context->registerInitialStateProvider(MaxAutoCompleteResultsInitialState::class); + + $context->registerNotifierService(Notifier::class); } public function boot(IBootContext $context): void { - $context->injectFn(Closure::fromCallable([$this, 'registerNotifier'])); $context->injectFn(Closure::fromCallable([$this, 'registerCommentsEventHandler'])); $context->getServerContainer()->get(ISearch::class)->registerProvider(LegacyProvider::class, ['apps' => ['files']]); } - protected function registerNotifier(IServerContainer $container) { - $container->getNotificationManager()->registerNotifierService(Notifier::class); - } - protected function registerCommentsEventHandler(IServerContainer $container) { $container->getCommentsManager()->registerEventHandler(function () { return $this->getContainer()->query(EventHandler::class); diff --git a/apps/dav/lib/AppInfo/Application.php b/apps/dav/lib/AppInfo/Application.php index dcca832439..7d5b98199d 100644 --- a/apps/dav/lib/AppInfo/Application.php +++ b/apps/dav/lib/AppInfo/Application.php @@ -72,7 +72,6 @@ use OCP\IConfig; use OCP\ILogger; use OCP\IServerContainer; use OCP\IUser; -use OCP\Notification\IManager as INotificationManager; use Psr\Container\ContainerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\GenericEvent; @@ -117,6 +116,8 @@ class Application extends App implements IBootstrap { $context->registerEventListener(CalendarObjectCreatedEvent::class, CalendarContactInteractionListener::class); $context->registerEventListener(CalendarObjectUpdatedEvent::class, CalendarContactInteractionListener::class); $context->registerEventListener(CalendarShareUpdatedEvent::class, CalendarContactInteractionListener::class); + + $context->registerNotifierService(Notifier::class); } public function boot(IBootContext $context): void { @@ -126,7 +127,6 @@ class Application extends App implements IBootstrap { $context->injectFn([$this, 'registerHooks']); $context->injectFn([$this, 'registerContactsManager']); $context->injectFn([$this, 'registerCalendarManager']); - $context->injectFn([$this, 'registerNotifier']); $context->injectFn([$this, 'registerCalendarReminders']); } @@ -396,10 +396,6 @@ class Application extends App implements IBootstrap { $cm->setupCalendarProvider($calendarManager, $userId); } - public function registerNotifier(INotificationManager $manager): void { - $manager->registerNotifierService(Notifier::class); - } - public function registerCalendarReminders(NotificationProviderManager $manager, ILogger $logger): void { try { diff --git a/apps/federatedfilesharing/lib/AppInfo/Application.php b/apps/federatedfilesharing/lib/AppInfo/Application.php index 1bb6e5d31b..30844750ca 100644 --- a/apps/federatedfilesharing/lib/AppInfo/Application.php +++ b/apps/federatedfilesharing/lib/AppInfo/Application.php @@ -38,7 +38,6 @@ use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\AppFramework\IAppContainer; use OCP\Federation\ICloudFederationProviderManager; -use OCP\Notification\IManager as INotifiactionManager; class Application extends App implements IBootstrap { public function __construct() { @@ -47,23 +46,19 @@ class Application extends App implements IBootstrap { public function register(IRegistrationContext $context): void { $context->registerEventListener(LoadAdditionalScriptsEvent::class, LoadAdditionalScriptsListener::class); + $context->registerNotifierService(Notifier::class); } public function boot(IBootContext $context): void { $context->injectFn(Closure::fromCallable([$this, 'registerCloudFederationProvider'])); - $context->injectFn(Closure::fromCallable([$this, 'registerNotificationManager'])); } private function registerCloudFederationProvider(ICloudFederationProviderManager $manager, IAppContainer $appContainer): void { $manager->addCloudFederationProvider('file', 'Federated Files Sharing', - function () use ($appContainer) { + function () use ($appContainer): CloudFederationProviderFiles { return $appContainer->get(CloudFederationProviderFiles::class); }); } - - private function registerNotificationManager(INotifiactionManager $manager): void { - $manager->registerNotifierService(Notifier::class); - } } diff --git a/apps/files/lib/AppInfo/Application.php b/apps/files/lib/AppInfo/Application.php index 92f29bfe41..025e6c42f2 100644 --- a/apps/files/lib/AppInfo/Application.php +++ b/apps/files/lib/AppInfo/Application.php @@ -61,7 +61,6 @@ use OCP\IRequest; use OCP\IServerContainer; use OCP\ITagManager; use OCP\IUserSession; -use OCP\Notification\IManager; use OCP\Share\IManager as IShareManager; use OCP\Util; use Psr\Container\ContainerInterface; @@ -118,12 +117,13 @@ class Application extends App implements IBootstrap { $context->registerEventListener(LoadSidebar::class, LoadSidebarListener::class); $context->registerSearchProvider(FilesSearchProvider::class); + + $context->registerNotifierService(Notifier::class); } public function boot(IBootContext $context): void { $context->injectFn(Closure::fromCallable([$this, 'registerCollaboration'])); $context->injectFn([Listener::class, 'register']); - $context->injectFn(Closure::fromCallable([$this, 'registerNotification'])); $context->injectFn(Closure::fromCallable([$this, 'registerSearchProvider'])); $this->registerTemplates(); $context->injectFn(Closure::fromCallable([$this, 'registerNavigation'])); @@ -134,10 +134,6 @@ class Application extends App implements IBootstrap { $providerManager->registerResourceProvider(ResourceProvider::class); } - private function registerNotification(IManager $notifications): void { - $notifications->registerNotifierService(Notifier::class); - } - private function registerSearchProvider(ISearch $search): void { $search->registerProvider(File::class, ['apps' => ['files']]); } diff --git a/apps/twofactor_backupcodes/lib/AppInfo/Application.php b/apps/twofactor_backupcodes/lib/AppInfo/Application.php index 4ac5016f92..67c09019d0 100644 --- a/apps/twofactor_backupcodes/lib/AppInfo/Application.php +++ b/apps/twofactor_backupcodes/lib/AppInfo/Application.php @@ -28,7 +28,6 @@ declare(strict_types=1); namespace OCA\TwoFactorBackupCodes\AppInfo; -use Closure; use OCA\TwoFactorBackupCodes\Db\BackupCodeMapper; use OCA\TwoFactorBackupCodes\Event\CodesGenerated; use OCA\TwoFactorBackupCodes\Listener\ActivityPublisher; @@ -42,7 +41,6 @@ use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\Authentication\TwoFactorAuth\IRegistry; -use OCP\Notification\IManager; use OCP\Util; class Application extends App implements IBootstrap { @@ -54,12 +52,12 @@ class Application extends App implements IBootstrap { public function register(IRegistrationContext $context): void { $this->registerHooksAndEvents($context); + + $context->registerNotifierService(Notifier::class); } public function boot(IBootContext $context): void { Util::connectHook('OC_User', 'post_deleteUser', $this, 'deleteUser'); - - $context->injectFn(Closure::fromCallable([$this, 'registerNotification'])); } /** @@ -73,10 +71,6 @@ class Application extends App implements IBootstrap { $context->registerEventListener(IRegistry::EVENT_PROVIDER_DISABLED, ProviderDisabled::class); } - private function registerNotification(IManager $manager) { - $manager->registerNotifierService(Notifier::class); - } - public function deleteUser($params) { /** @var BackupCodeMapper $mapper */ $mapper = $this->getContainer()->query(BackupCodeMapper::class); diff --git a/apps/updatenotification/lib/AppInfo/Application.php b/apps/updatenotification/lib/AppInfo/Application.php index 54d6444236..42c725caf8 100644 --- a/apps/updatenotification/lib/AppInfo/Application.php +++ b/apps/updatenotification/lib/AppInfo/Application.php @@ -43,7 +43,6 @@ use OCP\IGroupManager; use OCP\ILogger; use OCP\IUser; use OCP\IUserSession; -use OCP\Notification\IManager as INotificationManager; use OCP\Util; class Application extends App implements IBootstrap { @@ -52,11 +51,11 @@ class Application extends App implements IBootstrap { } public function register(IRegistrationContext $context): void { + $context->registerNotifierService(Notifier::class); } public function boot(IBootContext $context): void { $context->injectFn(function (IConfig $config, - INotificationManager $notificationsManager, IUserSession $userSession, IAppManager $appManager, IGroupManager $groupManager, @@ -67,9 +66,6 @@ class Application extends App implements IBootstrap { return; } - // Always register the notifier, so background jobs (without a user) can send push notifications - $notificationsManager->registerNotifierService(Notifier::class); - $user = $userSession->getUser(); if (!$user instanceof IUser) { // Nothing to do for guests diff --git a/apps/user_ldap/lib/AppInfo/Application.php b/apps/user_ldap/lib/AppInfo/Application.php index 8dad63fbaf..22bde27b72 100644 --- a/apps/user_ldap/lib/AppInfo/Application.php +++ b/apps/user_ldap/lib/AppInfo/Application.php @@ -81,6 +81,7 @@ class Application extends App implements IBootstrap { } public function register(IRegistrationContext $context): void { + $context->registerNotifierService(Notifier::class); } public function boot(IBootContext $context): void { @@ -96,8 +97,6 @@ class Application extends App implements IBootstrap { ) { $configPrefixes = $helper->getServerConfigurationPrefixes(true); if (count($configPrefixes) > 0) { - $notificationManager->registerNotifierService(Notifier::class); - $userPluginManager = $appContainer->get(UserPluginManager::class); $groupPluginManager = $appContainer->get(GroupPluginManager::class); diff --git a/lib/private/AppFramework/Bootstrap/RegistrationContext.php b/lib/private/AppFramework/Bootstrap/RegistrationContext.php index 4850de94ed..662296b8dd 100644 --- a/lib/private/AppFramework/Bootstrap/RegistrationContext.php +++ b/lib/private/AppFramework/Bootstrap/RegistrationContext.php @@ -44,6 +44,7 @@ use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Template\ICustomTemplateProvider; use OCP\Http\WellKnown\IHandler; use OCP\ILogger; +use OCP\Notification\INotifier; use OCP\Search\IProvider; use OCP\Support\CrashReport\IReporter; use Throwable; @@ -90,6 +91,9 @@ class RegistrationContext { /** @var ServiceRegistration[] */ private $templateProviders = []; + /** @var ServiceRegistration[] */ + private $notifierServices; + /** @var ILogger */ private $logger; @@ -206,6 +210,13 @@ class RegistrationContext { $providerClass ); } + + public function registerNotifierService(string $notifierClass): void { + $this->context->registerNotifierService( + $this->appId, + $notifierClass + ); + } }; } @@ -273,6 +284,10 @@ class RegistrationContext { $this->templateProviders[] = new ServiceRegistration($appId, $class); } + public function registerNotifierService(string $appId, string $class): void { + $this->notifierServices[] = new ServiceRegistration($appId, $class); + } + /** * @param App[] $apps */ @@ -457,4 +472,11 @@ class RegistrationContext { public function getTemplateProviders(): array { return $this->templateProviders; } + + /** + * @return ServiceRegistration[] + */ + public function getNotifierServices(): array { + return $this->notifierServices; + } } diff --git a/lib/private/Notification/Manager.php b/lib/private/Notification/Manager.php index f485b37cae..fd10a006e5 100644 --- a/lib/private/Notification/Manager.php +++ b/lib/private/Notification/Manager.php @@ -27,6 +27,7 @@ declare(strict_types=1); namespace OC\Notification; +use OC\AppFramework\Bootstrap\Coordinator; use OCP\AppFramework\QueryException; use OCP\ILogger; use OCP\Notification\AlreadyProcessedException; @@ -43,6 +44,8 @@ class Manager implements IManager { protected $validator; /** @var ILogger */ protected $logger; + /** @var Coordinator */ + private $coordinator; /** @var IApp[] */ protected $apps; @@ -58,17 +61,23 @@ class Manager implements IManager { protected $preparingPushNotification; /** @var bool */ protected $deferPushing; + /** @var bool */ + private $parsedRegistrationContext; public function __construct(IValidator $validator, - ILogger $logger) { + ILogger $logger, + Coordinator $coordinator) { $this->validator = $validator; $this->logger = $logger; + $this->coordinator = $coordinator; + $this->apps = []; $this->notifiers = []; $this->appClasses = []; $this->notifierClasses = []; $this->preparingPushNotification = false; $this->deferPushing = false; + $this->parsedRegistrationContext = false; } /** * @param string $appClass The service must implement IApp, otherwise a @@ -141,6 +150,32 @@ class Manager implements IManager { * @return INotifier[] */ public function getNotifiers(): array { + if (!$this->parsedRegistrationContext) { + $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(), + 'app' => 'notifications', + ]); + continue; + } + + if (!($notifier instanceof INotifier)) { + $this->logger->error('Notification notifier class ' . $notifierService->getService() . ' is not implementing ' . INotifier::class, [ + 'app' => 'notifications', + ]); + continue; + } + + $this->notifiers[] = $notifier; + } + + $this->parsedRegistrationContext = true; + } + if (empty($this->notifierClasses)) { return $this->notifiers; } diff --git a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php index a53a4d2a6e..870df9663e 100644 --- a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php +++ b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php @@ -34,6 +34,7 @@ use OCP\Capabilities\ICapability; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Template\ICustomTemplateProvider; use OCP\IContainer; +use OCP\Notification\INotifier; /** * The context object passed to IBootstrap::register @@ -209,4 +210,13 @@ interface IRegistrationContext { * @since 21.0.0 */ public function registerTemplateProvider(string $providerClass): void; + + /** + * Register an INotifier class + * + * @param string $notifierClass + * @psalm-param class-string $notifierClass + * @since 22.0.0 + */ + public function registerNotifierService(string $notifierClass): void; } diff --git a/lib/public/Notification/IManager.php b/lib/public/Notification/IManager.php index accebee61b..a98df30183 100644 --- a/lib/public/Notification/IManager.php +++ b/lib/public/Notification/IManager.php @@ -53,6 +53,7 @@ interface IManager extends IApp, INotifier { * @param string $notifierService The service must implement INotifier, otherwise a * \InvalidArgumentException is thrown later * @since 17.0.0 + * @depreacted 22.0.0 use the IBootStrap registration context */ public function registerNotifierService(string $notifierService): void; diff --git a/tests/lib/Notification/ManagerTest.php b/tests/lib/Notification/ManagerTest.php index cd0d4bd36c..b1201d31c4 100644 --- a/tests/lib/Notification/ManagerTest.php +++ b/tests/lib/Notification/ManagerTest.php @@ -21,6 +21,9 @@ namespace Test\Notification; +use OC\AppFramework\Bootstrap\Coordinator; +use OC\AppFramework\Bootstrap\RegistrationContext; +use OC\AppFramework\Bootstrap\ServiceRegistration; use OC\Notification\Manager; use OCP\ILogger; use OCP\Notification\IManager; @@ -37,12 +40,23 @@ class ManagerTest extends TestCase { protected $validator; /** @var ILogger|MockObject */ protected $logger; + /** @var Coordinator|MockObject */ + protected $coordinator; + /** @var RegistrationContext|MockObject */ + protected $registrationContext; protected function setUp(): void { parent::setUp(); + $this->validator = $this->createMock(IValidator::class); $this->logger = $this->createMock(ILogger::class); - $this->manager = new Manager($this->validator, $this->logger); + + $this->registrationContext = $this->createMock(RegistrationContext::class); + $this->coordinator = $this->createMock(Coordinator::class); + $this->coordinator->method('getRegistrationContext') + ->willReturn($this->registrationContext); + + $this->manager = new Manager($this->validator, $this->logger, $this->coordinator); } public function testRegisterApp() { @@ -79,6 +93,16 @@ class ManagerTest extends TestCase { $this->assertCount(2, self::invokePrivate($this->manager, 'getNotifiers')); } + public function testRegisterNotifierBootstrap() { + $this->registrationContext->method('getNotifierServices') + ->willReturn([ + new ServiceRegistration('app', DummyNotifier::class), + ]); + + $this->assertCount(1, self::invokePrivate($this->manager, 'getNotifiers')); + $this->assertCount(1, self::invokePrivate($this->manager, 'getNotifiers')); + } + public function testRegisterNotifierInvalid() { $this->manager->registerNotifierService(DummyApp::class); @@ -105,6 +129,7 @@ class ManagerTest extends TestCase { ->setConstructorArgs([ $this->validator, $this->logger, + $this->coordinator, ]) ->setMethods(['getApps']) ->getMock(); @@ -132,6 +157,7 @@ class ManagerTest extends TestCase { ->setConstructorArgs([ $this->validator, $this->logger, + $this->coordinator, ]) ->setMethods(['getApps']) ->getMock(); @@ -152,6 +178,7 @@ class ManagerTest extends TestCase { ->setConstructorArgs([ $this->validator, $this->logger, + $this->coordinator, ]) ->setMethods(['getApps']) ->getMock(); @@ -173,6 +200,7 @@ class ManagerTest extends TestCase { ->setConstructorArgs([ $this->validator, $this->logger, + $this->coordinator, ]) ->setMethods(['getApps']) ->getMock();