Merge pull request #26553 from nextcloud/enh/bootstrap/notifiers

Move NotifierService registration to IBootstrap
This commit is contained in:
Roeland Jago Douma 2021-04-16 14:27:19 +02:00 committed by GitHub
commit 874eff9aaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 110 additions and 41 deletions

View File

@ -75,19 +75,16 @@ class Application extends App implements IBootstrap {
$context->registerSearchProvider(CommentsSearchProvider::class); $context->registerSearchProvider(CommentsSearchProvider::class);
$context->registerInitialStateProvider(MaxAutoCompleteResultsInitialState::class); $context->registerInitialStateProvider(MaxAutoCompleteResultsInitialState::class);
$context->registerNotifierService(Notifier::class);
} }
public function boot(IBootContext $context): void { public function boot(IBootContext $context): void {
$context->injectFn(Closure::fromCallable([$this, 'registerNotifier']));
$context->injectFn(Closure::fromCallable([$this, 'registerCommentsEventHandler'])); $context->injectFn(Closure::fromCallable([$this, 'registerCommentsEventHandler']));
$context->getServerContainer()->get(ISearch::class)->registerProvider(LegacyProvider::class, ['apps' => ['files']]); $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) { protected function registerCommentsEventHandler(IServerContainer $container) {
$container->getCommentsManager()->registerEventHandler(function () { $container->getCommentsManager()->registerEventHandler(function () {
return $this->getContainer()->query(EventHandler::class); return $this->getContainer()->query(EventHandler::class);

View File

@ -72,7 +72,6 @@ use OCP\IConfig;
use OCP\ILogger; use OCP\ILogger;
use OCP\IServerContainer; use OCP\IServerContainer;
use OCP\IUser; use OCP\IUser;
use OCP\Notification\IManager as INotificationManager;
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent; use Symfony\Component\EventDispatcher\GenericEvent;
@ -117,6 +116,8 @@ class Application extends App implements IBootstrap {
$context->registerEventListener(CalendarObjectCreatedEvent::class, CalendarContactInteractionListener::class); $context->registerEventListener(CalendarObjectCreatedEvent::class, CalendarContactInteractionListener::class);
$context->registerEventListener(CalendarObjectUpdatedEvent::class, CalendarContactInteractionListener::class); $context->registerEventListener(CalendarObjectUpdatedEvent::class, CalendarContactInteractionListener::class);
$context->registerEventListener(CalendarShareUpdatedEvent::class, CalendarContactInteractionListener::class); $context->registerEventListener(CalendarShareUpdatedEvent::class, CalendarContactInteractionListener::class);
$context->registerNotifierService(Notifier::class);
} }
public function boot(IBootContext $context): void { public function boot(IBootContext $context): void {
@ -126,7 +127,6 @@ class Application extends App implements IBootstrap {
$context->injectFn([$this, 'registerHooks']); $context->injectFn([$this, 'registerHooks']);
$context->injectFn([$this, 'registerContactsManager']); $context->injectFn([$this, 'registerContactsManager']);
$context->injectFn([$this, 'registerCalendarManager']); $context->injectFn([$this, 'registerCalendarManager']);
$context->injectFn([$this, 'registerNotifier']);
$context->injectFn([$this, 'registerCalendarReminders']); $context->injectFn([$this, 'registerCalendarReminders']);
} }
@ -396,10 +396,6 @@ class Application extends App implements IBootstrap {
$cm->setupCalendarProvider($calendarManager, $userId); $cm->setupCalendarProvider($calendarManager, $userId);
} }
public function registerNotifier(INotificationManager $manager): void {
$manager->registerNotifierService(Notifier::class);
}
public function registerCalendarReminders(NotificationProviderManager $manager, public function registerCalendarReminders(NotificationProviderManager $manager,
ILogger $logger): void { ILogger $logger): void {
try { try {

View File

@ -38,7 +38,6 @@ use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\AppFramework\IAppContainer; use OCP\AppFramework\IAppContainer;
use OCP\Federation\ICloudFederationProviderManager; use OCP\Federation\ICloudFederationProviderManager;
use OCP\Notification\IManager as INotifiactionManager;
class Application extends App implements IBootstrap { class Application extends App implements IBootstrap {
public function __construct() { public function __construct() {
@ -47,23 +46,19 @@ class Application extends App implements IBootstrap {
public function register(IRegistrationContext $context): void { public function register(IRegistrationContext $context): void {
$context->registerEventListener(LoadAdditionalScriptsEvent::class, LoadAdditionalScriptsListener::class); $context->registerEventListener(LoadAdditionalScriptsEvent::class, LoadAdditionalScriptsListener::class);
$context->registerNotifierService(Notifier::class);
} }
public function boot(IBootContext $context): void { public function boot(IBootContext $context): void {
$context->injectFn(Closure::fromCallable([$this, 'registerCloudFederationProvider'])); $context->injectFn(Closure::fromCallable([$this, 'registerCloudFederationProvider']));
$context->injectFn(Closure::fromCallable([$this, 'registerNotificationManager']));
} }
private function registerCloudFederationProvider(ICloudFederationProviderManager $manager, private function registerCloudFederationProvider(ICloudFederationProviderManager $manager,
IAppContainer $appContainer): void { IAppContainer $appContainer): void {
$manager->addCloudFederationProvider('file', $manager->addCloudFederationProvider('file',
'Federated Files Sharing', 'Federated Files Sharing',
function () use ($appContainer) { function () use ($appContainer): CloudFederationProviderFiles {
return $appContainer->get(CloudFederationProviderFiles::class); return $appContainer->get(CloudFederationProviderFiles::class);
}); });
} }
private function registerNotificationManager(INotifiactionManager $manager): void {
$manager->registerNotifierService(Notifier::class);
}
} }

View File

@ -61,7 +61,6 @@ use OCP\IRequest;
use OCP\IServerContainer; use OCP\IServerContainer;
use OCP\ITagManager; use OCP\ITagManager;
use OCP\IUserSession; use OCP\IUserSession;
use OCP\Notification\IManager;
use OCP\Share\IManager as IShareManager; use OCP\Share\IManager as IShareManager;
use OCP\Util; use OCP\Util;
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
@ -118,12 +117,13 @@ class Application extends App implements IBootstrap {
$context->registerEventListener(LoadSidebar::class, LoadSidebarListener::class); $context->registerEventListener(LoadSidebar::class, LoadSidebarListener::class);
$context->registerSearchProvider(FilesSearchProvider::class); $context->registerSearchProvider(FilesSearchProvider::class);
$context->registerNotifierService(Notifier::class);
} }
public function boot(IBootContext $context): void { public function boot(IBootContext $context): void {
$context->injectFn(Closure::fromCallable([$this, 'registerCollaboration'])); $context->injectFn(Closure::fromCallable([$this, 'registerCollaboration']));
$context->injectFn([Listener::class, 'register']); $context->injectFn([Listener::class, 'register']);
$context->injectFn(Closure::fromCallable([$this, 'registerNotification']));
$context->injectFn(Closure::fromCallable([$this, 'registerSearchProvider'])); $context->injectFn(Closure::fromCallable([$this, 'registerSearchProvider']));
$this->registerTemplates(); $this->registerTemplates();
$context->injectFn(Closure::fromCallable([$this, 'registerNavigation'])); $context->injectFn(Closure::fromCallable([$this, 'registerNavigation']));
@ -134,10 +134,6 @@ class Application extends App implements IBootstrap {
$providerManager->registerResourceProvider(ResourceProvider::class); $providerManager->registerResourceProvider(ResourceProvider::class);
} }
private function registerNotification(IManager $notifications): void {
$notifications->registerNotifierService(Notifier::class);
}
private function registerSearchProvider(ISearch $search): void { private function registerSearchProvider(ISearch $search): void {
$search->registerProvider(File::class, ['apps' => ['files']]); $search->registerProvider(File::class, ['apps' => ['files']]);
} }

View File

@ -28,7 +28,6 @@ declare(strict_types=1);
namespace OCA\TwoFactorBackupCodes\AppInfo; namespace OCA\TwoFactorBackupCodes\AppInfo;
use Closure;
use OCA\TwoFactorBackupCodes\Db\BackupCodeMapper; use OCA\TwoFactorBackupCodes\Db\BackupCodeMapper;
use OCA\TwoFactorBackupCodes\Event\CodesGenerated; use OCA\TwoFactorBackupCodes\Event\CodesGenerated;
use OCA\TwoFactorBackupCodes\Listener\ActivityPublisher; use OCA\TwoFactorBackupCodes\Listener\ActivityPublisher;
@ -42,7 +41,6 @@ use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\Authentication\TwoFactorAuth\IRegistry; use OCP\Authentication\TwoFactorAuth\IRegistry;
use OCP\Notification\IManager;
use OCP\Util; use OCP\Util;
class Application extends App implements IBootstrap { class Application extends App implements IBootstrap {
@ -54,12 +52,12 @@ class Application extends App implements IBootstrap {
public function register(IRegistrationContext $context): void { public function register(IRegistrationContext $context): void {
$this->registerHooksAndEvents($context); $this->registerHooksAndEvents($context);
$context->registerNotifierService(Notifier::class);
} }
public function boot(IBootContext $context): void { public function boot(IBootContext $context): void {
Util::connectHook('OC_User', 'post_deleteUser', $this, 'deleteUser'); 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); $context->registerEventListener(IRegistry::EVENT_PROVIDER_DISABLED, ProviderDisabled::class);
} }
private function registerNotification(IManager $manager) {
$manager->registerNotifierService(Notifier::class);
}
public function deleteUser($params) { public function deleteUser($params) {
/** @var BackupCodeMapper $mapper */ /** @var BackupCodeMapper $mapper */
$mapper = $this->getContainer()->query(BackupCodeMapper::class); $mapper = $this->getContainer()->query(BackupCodeMapper::class);

View File

@ -43,7 +43,6 @@ use OCP\IGroupManager;
use OCP\ILogger; use OCP\ILogger;
use OCP\IUser; use OCP\IUser;
use OCP\IUserSession; use OCP\IUserSession;
use OCP\Notification\IManager as INotificationManager;
use OCP\Util; use OCP\Util;
class Application extends App implements IBootstrap { class Application extends App implements IBootstrap {
@ -52,11 +51,11 @@ class Application extends App implements IBootstrap {
} }
public function register(IRegistrationContext $context): void { public function register(IRegistrationContext $context): void {
$context->registerNotifierService(Notifier::class);
} }
public function boot(IBootContext $context): void { public function boot(IBootContext $context): void {
$context->injectFn(function (IConfig $config, $context->injectFn(function (IConfig $config,
INotificationManager $notificationsManager,
IUserSession $userSession, IUserSession $userSession,
IAppManager $appManager, IAppManager $appManager,
IGroupManager $groupManager, IGroupManager $groupManager,
@ -67,9 +66,6 @@ class Application extends App implements IBootstrap {
return; return;
} }
// Always register the notifier, so background jobs (without a user) can send push notifications
$notificationsManager->registerNotifierService(Notifier::class);
$user = $userSession->getUser(); $user = $userSession->getUser();
if (!$user instanceof IUser) { if (!$user instanceof IUser) {
// Nothing to do for guests // Nothing to do for guests

View File

@ -81,6 +81,7 @@ class Application extends App implements IBootstrap {
} }
public function register(IRegistrationContext $context): void { public function register(IRegistrationContext $context): void {
$context->registerNotifierService(Notifier::class);
} }
public function boot(IBootContext $context): void { public function boot(IBootContext $context): void {
@ -96,8 +97,6 @@ class Application extends App implements IBootstrap {
) { ) {
$configPrefixes = $helper->getServerConfigurationPrefixes(true); $configPrefixes = $helper->getServerConfigurationPrefixes(true);
if (count($configPrefixes) > 0) { if (count($configPrefixes) > 0) {
$notificationManager->registerNotifierService(Notifier::class);
$userPluginManager = $appContainer->get(UserPluginManager::class); $userPluginManager = $appContainer->get(UserPluginManager::class);
$groupPluginManager = $appContainer->get(GroupPluginManager::class); $groupPluginManager = $appContainer->get(GroupPluginManager::class);

View File

@ -44,6 +44,7 @@ use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Template\ICustomTemplateProvider; use OCP\Files\Template\ICustomTemplateProvider;
use OCP\Http\WellKnown\IHandler; use OCP\Http\WellKnown\IHandler;
use OCP\ILogger; use OCP\ILogger;
use OCP\Notification\INotifier;
use OCP\Search\IProvider; use OCP\Search\IProvider;
use OCP\Support\CrashReport\IReporter; use OCP\Support\CrashReport\IReporter;
use Throwable; use Throwable;
@ -90,6 +91,9 @@ class RegistrationContext {
/** @var ServiceRegistration<ICustomTemplateProvider>[] */ /** @var ServiceRegistration<ICustomTemplateProvider>[] */
private $templateProviders = []; private $templateProviders = [];
/** @var ServiceRegistration<INotifier>[] */
private $notifierServices;
/** @var ILogger */ /** @var ILogger */
private $logger; private $logger;
@ -206,6 +210,13 @@ class RegistrationContext {
$providerClass $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); $this->templateProviders[] = new ServiceRegistration($appId, $class);
} }
public function registerNotifierService(string $appId, string $class): void {
$this->notifierServices[] = new ServiceRegistration($appId, $class);
}
/** /**
* @param App[] $apps * @param App[] $apps
*/ */
@ -457,4 +472,11 @@ class RegistrationContext {
public function getTemplateProviders(): array { public function getTemplateProviders(): array {
return $this->templateProviders; return $this->templateProviders;
} }
/**
* @return ServiceRegistration<INotifier>[]
*/
public function getNotifierServices(): array {
return $this->notifierServices;
}
} }

View File

@ -27,6 +27,7 @@ declare(strict_types=1);
namespace OC\Notification; namespace OC\Notification;
use OC\AppFramework\Bootstrap\Coordinator;
use OCP\AppFramework\QueryException; use OCP\AppFramework\QueryException;
use OCP\ILogger; use OCP\ILogger;
use OCP\Notification\AlreadyProcessedException; use OCP\Notification\AlreadyProcessedException;
@ -43,6 +44,8 @@ class Manager implements IManager {
protected $validator; protected $validator;
/** @var ILogger */ /** @var ILogger */
protected $logger; protected $logger;
/** @var Coordinator */
private $coordinator;
/** @var IApp[] */ /** @var IApp[] */
protected $apps; protected $apps;
@ -58,17 +61,23 @@ class Manager implements IManager {
protected $preparingPushNotification; protected $preparingPushNotification;
/** @var bool */ /** @var bool */
protected $deferPushing; protected $deferPushing;
/** @var bool */
private $parsedRegistrationContext;
public function __construct(IValidator $validator, public function __construct(IValidator $validator,
ILogger $logger) { ILogger $logger,
Coordinator $coordinator) {
$this->validator = $validator; $this->validator = $validator;
$this->logger = $logger; $this->logger = $logger;
$this->coordinator = $coordinator;
$this->apps = []; $this->apps = [];
$this->notifiers = []; $this->notifiers = [];
$this->appClasses = []; $this->appClasses = [];
$this->notifierClasses = []; $this->notifierClasses = [];
$this->preparingPushNotification = false; $this->preparingPushNotification = false;
$this->deferPushing = false; $this->deferPushing = false;
$this->parsedRegistrationContext = false;
} }
/** /**
* @param string $appClass The service must implement IApp, otherwise a * @param string $appClass The service must implement IApp, otherwise a
@ -141,6 +150,32 @@ class Manager implements IManager {
* @return INotifier[] * @return INotifier[]
*/ */
public function getNotifiers(): array { 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)) { if (empty($this->notifierClasses)) {
return $this->notifiers; return $this->notifiers;
} }

View File

@ -34,6 +34,7 @@ use OCP\Capabilities\ICapability;
use OCP\EventDispatcher\IEventDispatcher; use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Template\ICustomTemplateProvider; use OCP\Files\Template\ICustomTemplateProvider;
use OCP\IContainer; use OCP\IContainer;
use OCP\Notification\INotifier;
/** /**
* The context object passed to IBootstrap::register * The context object passed to IBootstrap::register
@ -209,4 +210,13 @@ interface IRegistrationContext {
* @since 21.0.0 * @since 21.0.0
*/ */
public function registerTemplateProvider(string $providerClass): void; public function registerTemplateProvider(string $providerClass): void;
/**
* Register an INotifier class
*
* @param string $notifierClass
* @psalm-param class-string<INotifier> $notifierClass
* @since 22.0.0
*/
public function registerNotifierService(string $notifierClass): void;
} }

View File

@ -53,6 +53,7 @@ interface IManager extends IApp, INotifier {
* @param string $notifierService The service must implement INotifier, otherwise a * @param string $notifierService The service must implement INotifier, otherwise a
* \InvalidArgumentException is thrown later * \InvalidArgumentException is thrown later
* @since 17.0.0 * @since 17.0.0
* @depreacted 22.0.0 use the IBootStrap registration context
*/ */
public function registerNotifierService(string $notifierService): void; public function registerNotifierService(string $notifierService): void;

View File

@ -21,6 +21,9 @@
namespace Test\Notification; namespace Test\Notification;
use OC\AppFramework\Bootstrap\Coordinator;
use OC\AppFramework\Bootstrap\RegistrationContext;
use OC\AppFramework\Bootstrap\ServiceRegistration;
use OC\Notification\Manager; use OC\Notification\Manager;
use OCP\ILogger; use OCP\ILogger;
use OCP\Notification\IManager; use OCP\Notification\IManager;
@ -37,12 +40,23 @@ class ManagerTest extends TestCase {
protected $validator; protected $validator;
/** @var ILogger|MockObject */ /** @var ILogger|MockObject */
protected $logger; protected $logger;
/** @var Coordinator|MockObject */
protected $coordinator;
/** @var RegistrationContext|MockObject */
protected $registrationContext;
protected function setUp(): void { protected function setUp(): void {
parent::setUp(); parent::setUp();
$this->validator = $this->createMock(IValidator::class); $this->validator = $this->createMock(IValidator::class);
$this->logger = $this->createMock(ILogger::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() { public function testRegisterApp() {
@ -79,6 +93,16 @@ class ManagerTest extends TestCase {
$this->assertCount(2, self::invokePrivate($this->manager, 'getNotifiers')); $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() { public function testRegisterNotifierInvalid() {
$this->manager->registerNotifierService(DummyApp::class); $this->manager->registerNotifierService(DummyApp::class);
@ -105,6 +129,7 @@ class ManagerTest extends TestCase {
->setConstructorArgs([ ->setConstructorArgs([
$this->validator, $this->validator,
$this->logger, $this->logger,
$this->coordinator,
]) ])
->setMethods(['getApps']) ->setMethods(['getApps'])
->getMock(); ->getMock();
@ -132,6 +157,7 @@ class ManagerTest extends TestCase {
->setConstructorArgs([ ->setConstructorArgs([
$this->validator, $this->validator,
$this->logger, $this->logger,
$this->coordinator,
]) ])
->setMethods(['getApps']) ->setMethods(['getApps'])
->getMock(); ->getMock();
@ -152,6 +178,7 @@ class ManagerTest extends TestCase {
->setConstructorArgs([ ->setConstructorArgs([
$this->validator, $this->validator,
$this->logger, $this->logger,
$this->coordinator,
]) ])
->setMethods(['getApps']) ->setMethods(['getApps'])
->getMock(); ->getMock();
@ -173,6 +200,7 @@ class ManagerTest extends TestCase {
->setConstructorArgs([ ->setConstructorArgs([
$this->validator, $this->validator,
$this->logger, $this->logger,
$this->coordinator,
]) ])
->setMethods(['getApps']) ->setMethods(['getApps'])
->getMock(); ->getMock();