Merge pull request #15040 from nextcloud/feature/13980/push-for-deleted-notifications

Notifications overhaul
This commit is contained in:
Morris Jobke 2019-07-17 20:22:03 +02:00 committed by GitHub
commit 5b604eaeab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 719 additions and 742 deletions

View File

@ -76,15 +76,7 @@ class Application extends App {
} }
protected function registerNotifier() { protected function registerNotifier() {
$this->getContainer()->getServer()->getNotificationManager()->registerNotifier( $this->getContainer()->getServer()->getNotificationManager()->registerNotifierService(Notifier::class);
function() {
return $this->getContainer()->query(Notifier::class);
},
function () {
$l = $this->getContainer()->getServer()->getL10NFactory()->get('comments');
return ['id' => 'comments', 'name' => $l->t('Comments')];
}
);
} }
protected function registerCommentsEventHandler() { protected function registerCommentsEventHandler() {

View File

@ -32,6 +32,7 @@ use OCP\IURLGenerator;
use OCP\IUser; use OCP\IUser;
use OCP\IUserManager; use OCP\IUserManager;
use OCP\L10N\IFactory; use OCP\L10N\IFactory;
use OCP\Notification\AlreadyProcessedException;
use OCP\Notification\INotification; use OCP\Notification\INotification;
use OCP\Notification\INotifier; use OCP\Notification\INotifier;
@ -66,13 +67,35 @@ class Notifier implements INotifier {
$this->userManager = $userManager; $this->userManager = $userManager;
} }
/**
* Identifier of the notifier, only use [a-z0-9_]
*
* @return string
* @since 17.0.0
*/
public function getID(): string {
return 'comments';
}
/**
* Human readable name describing the notifier
*
* @return string
* @since 17.0.0
*/
public function getName(): string {
return $this->l10nFactory->get('comments')->t('Comments');
}
/** /**
* @param INotification $notification * @param INotification $notification
* @param string $languageCode The code of the language that should be used to prepare the notification * @param string $languageCode The code of the language that should be used to prepare the notification
* @return INotification * @return INotification
* @throws \InvalidArgumentException When the notification was not prepared by a notifier * @throws \InvalidArgumentException When the notification was not prepared by a notifier
* @throws AlreadyProcessedException When the notification is not needed anymore and should be deleted
* @since 9.0.0
*/ */
public function prepare(INotification $notification, $languageCode) { public function prepare(INotification $notification, string $languageCode): INotification {
if($notification->getApp() !== 'comments') { if($notification->getApp() !== 'comments') {
throw new \InvalidArgumentException(); throw new \InvalidArgumentException();
} }
@ -101,7 +124,7 @@ class Notifier implements INotifier {
$userFolder = $this->rootFolder->getUserFolder($notification->getUser()); $userFolder = $this->rootFolder->getUserFolder($notification->getUser());
$nodes = $userFolder->getById((int)$parameters[1]); $nodes = $userFolder->getById((int)$parameters[1]);
if(empty($nodes)) { if(empty($nodes)) {
throw new \InvalidArgumentException('Cannot resolve file ID to node instance'); throw new AlreadyProcessedException();
} }
$node = $nodes[0]; $node = $nodes[0];

View File

@ -117,6 +117,9 @@ class NotificationsTest extends TestCase {
$comment->expects($this->any()) $comment->expects($this->any())
->method('getObjectType') ->method('getObjectType')
->willReturn('files'); ->willReturn('files');
$comment->expects($this->any())
->method('getId')
->willReturn('1234');
$this->commentsManager->expects($this->any()) $this->commentsManager->expects($this->any())
->method('get') ->method('get')
@ -192,6 +195,9 @@ class NotificationsTest extends TestCase {
$comment->expects($this->any()) $comment->expects($this->any())
->method('getObjectType') ->method('getObjectType')
->willReturn('files'); ->willReturn('files');
$comment->expects($this->any())
->method('getId')
->willReturn('1234');
$this->commentsManager->expects($this->any()) $this->commentsManager->expects($this->any())
->method('get') ->method('get')

View File

@ -91,6 +91,9 @@ class ListenerTest extends TestCase {
[ 'type' => 'user', 'id' => '23452-4333-54353-2342'], [ 'type' => 'user', 'id' => '23452-4333-54353-2342'],
[ 'type' => 'user', 'id' => 'yolo'], [ 'type' => 'user', 'id' => 'yolo'],
]); ]);
$comment->expects($this->atLeastOnce())
->method('getId')
->willReturn('1234');
/** @var CommentsEvent|\PHPUnit_Framework_MockObject_MockObject $event */ /** @var CommentsEvent|\PHPUnit_Framework_MockObject_MockObject $event */
$event = $this->getMockBuilder(CommentsEvent::class) $event = $this->getMockBuilder(CommentsEvent::class)
@ -186,6 +189,9 @@ class ListenerTest extends TestCase {
$comment->expects($this->once()) $comment->expects($this->once())
->method('getMentions') ->method('getMentions')
->willReturn([[ 'type' => 'user', 'id' => 'foobar']]); ->willReturn([[ 'type' => 'user', 'id' => 'foobar']]);
$comment->expects($this->atLeastOnce())
->method('getId')
->willReturn('1234');
/** @var CommentsEvent|\PHPUnit_Framework_MockObject_MockObject $event */ /** @var CommentsEvent|\PHPUnit_Framework_MockObject_MockObject $event */
$event = $this->getMockBuilder(CommentsEvent::class) $event = $this->getMockBuilder(CommentsEvent::class)

View File

@ -195,6 +195,9 @@ class NotifierTest extends TestCase {
->expects($this->any()) ->expects($this->any())
->method('getMentions') ->method('getMentions')
->willReturn([['type' => 'user', 'id' => 'you']]); ->willReturn([['type' => 'user', 'id' => 'you']]);
$this->comment->expects($this->atLeastOnce())
->method('getId')
->willReturn('1234');
$this->commentsManager $this->commentsManager
->expects($this->once()) ->expects($this->once())
@ -539,7 +542,7 @@ class NotifierTest extends TestCase {
} }
/** /**
* @expectedException \InvalidArgumentException * @expectedException \OCP\Notification\AlreadyProcessedException
*/ */
public function testPrepareUnresolvableFileID() { public function testPrepareUnresolvableFileID() {
$displayName = 'Huraga'; $displayName = 'Huraga';

View File

@ -29,15 +29,7 @@ $app = new \OCA\FederatedFileSharing\AppInfo\Application();
$eventDispatcher = \OC::$server->getEventDispatcher(); $eventDispatcher = \OC::$server->getEventDispatcher();
$manager = \OC::$server->getNotificationManager(); $manager = \OC::$server->getNotificationManager();
$manager->registerNotifier(function() { $manager->registerNotifierService(Notifier::class);
return \OC::$server->query(Notifier::class);
}, function() {
$l = \OC::$server->getL10N('files_sharing');
return [
'id' => 'files_sharing',
'name' => $l->t('Federated sharing'),
];
});
$federatedShareProvider = $app->getFederatedShareProvider(); $federatedShareProvider = $app->getFederatedShareProvider();

View File

@ -59,13 +59,33 @@ class Notifier implements INotifier {
$this->cloudIdManager = $cloudIdManager; $this->cloudIdManager = $cloudIdManager;
} }
/**
* Identifier of the notifier, only use [a-z0-9_]
*
* @return string
* @since 17.0.0
*/
public function getID(): string {
return 'federatedfilesharing';
}
/**
* Human readable name describing the notifier
*
* @return string
* @since 17.0.0
*/
public function getName(): string {
return $this->factory->get('federatedfilesharing')->t('Federated sharing');
}
/** /**
* @param INotification $notification * @param INotification $notification
* @param string $languageCode The code of the language that should be used to prepare the notification * @param string $languageCode The code of the language that should be used to prepare the notification
* @return INotification * @return INotification
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*/ */
public function prepare(INotification $notification, $languageCode) { public function prepare(INotification $notification, string $languageCode): INotification {
if ($notification->getApp() !== 'files_sharing') { if ($notification->getApp() !== 'files_sharing') {
// Not my app => throw // Not my app => throw
throw new \InvalidArgumentException(); throw new \InvalidArgumentException();

View File

@ -74,15 +74,7 @@ class Application extends App {
$container = $this->getContainer(); $container = $this->getContainer();
/** @var IManager $manager */ /** @var IManager $manager */
$manager = $container->query(IManager::class); $manager = $container->query(IManager::class);
$manager->registerNotifier( $manager->registerNotifierService(Notifier::class);
function() use ($container) {
return $container->query(Notifier::class);
},
function () use ($container) {
$l = $container->query(IL10N::class);
return ['id' => 'twofactor_backupcodes', 'name' => $l->t('Second-factor backup codes')];
}
);
} }
public function deleteUser($params) { public function deleteUser($params) {

View File

@ -42,7 +42,27 @@ class Notifier implements INotifier {
$this->url = $url; $this->url = $url;
} }
public function prepare(INotification $notification, $languageCode) { /**
* Identifier of the notifier, only use [a-z0-9_]
*
* @return string
* @since 17.0.0
*/
public function getID(): string {
return 'twofactor_backupcodes';
}
/**
* Human readable name describing the notifier
*
* @return string
* @since 17.0.0
*/
public function getName(): string {
return $this->factory->get('twofactor_backupcodes')->t('Second-factor backup codes');
}
public function prepare(INotification $notification, string $languageCode): INotification {
if ($notification->getApp() !== 'twofactor_backupcodes') { if ($notification->getApp() !== 'twofactor_backupcodes') {
// Not my app => throw // Not my app => throw
throw new \InvalidArgumentException(); throw new \InvalidArgumentException();
@ -70,5 +90,4 @@ class Notifier implements INotifier {
throw new \InvalidArgumentException(); throw new \InvalidArgumentException();
} }
} }
} }

View File

@ -71,14 +71,6 @@ class Application extends App {
public function registerNotifier() { public function registerNotifier() {
$notificationsManager = $this->getContainer()->getServer()->getNotificationManager(); $notificationsManager = $this->getContainer()->getServer()->getNotificationManager();
$notificationsManager->registerNotifier(function() { $notificationsManager->registerNotifierService(Notifier::class);
return $this->getContainer()->query(Notifier::class);
}, function() {
$l = $this->getContainer()->getServer()->getL10N('updatenotification');
return [
'id' => 'updatenotification',
'name' => $l->t('Update notifications'),
];
});
} }
} }

View File

@ -31,6 +31,7 @@ use OCP\IURLGenerator;
use OCP\IUser; use OCP\IUser;
use OCP\IUserSession; use OCP\IUserSession;
use OCP\L10N\IFactory; use OCP\L10N\IFactory;
use OCP\Notification\AlreadyProcessedException;
use OCP\Notification\IManager; use OCP\Notification\IManager;
use OCP\Notification\INotification; use OCP\Notification\INotification;
use OCP\Notification\INotifier; use OCP\Notification\INotifier;
@ -79,14 +80,35 @@ class Notifier implements INotifier {
$this->appVersions = $this->getAppVersions(); $this->appVersions = $this->getAppVersions();
} }
/**
* Identifier of the notifier, only use [a-z0-9_]
*
* @return string
* @since 17.0.0
*/
public function getID(): string {
return 'updatenotification';
}
/**
* Human readable name describing the notifier
*
* @return string
* @since 17.0.0
*/
public function getName(): string {
return $this->l10NFactory->get('updatenotification')->t('Update notifications');
}
/** /**
* @param INotification $notification * @param INotification $notification
* @param string $languageCode The code of the language that should be used to prepare the notification * @param string $languageCode The code of the language that should be used to prepare the notification
* @return INotification * @return INotification
* @throws \InvalidArgumentException When the notification was not prepared by a notifier * @throws \InvalidArgumentException When the notification was not prepared by a notifier
* @throws AlreadyProcessedException When the notification is not needed anymore and should be deleted
* @since 9.0.0 * @since 9.0.0
*/ */
public function prepare(INotification $notification, $languageCode): INotification { public function prepare(INotification $notification, string $languageCode): INotification {
if ($notification->getApp() !== 'updatenotification') { if ($notification->getApp() !== 'updatenotification') {
throw new \InvalidArgumentException('Unknown app id'); throw new \InvalidArgumentException('Unknown app id');
} }
@ -142,12 +164,11 @@ class Notifier implements INotifier {
* *
* @param INotification $notification * @param INotification $notification
* @param string $installedVersion * @param string $installedVersion
* @throws \InvalidArgumentException When the update is already installed * @throws AlreadyProcessedException When the update is already installed
*/ */
protected function updateAlreadyInstalledCheck(INotification $notification, $installedVersion) { protected function updateAlreadyInstalledCheck(INotification $notification, $installedVersion) {
if (version_compare($notification->getObjectId(), $installedVersion, '<=')) { if (version_compare($notification->getObjectId(), $installedVersion, '<=')) {
$this->notificationManager->markProcessed($notification); throw new AlreadyProcessedException();
throw new \InvalidArgumentException('Update already installed');
} }
} }

View File

@ -30,6 +30,7 @@ use OCP\IGroupManager;
use OCP\IURLGenerator; use OCP\IURLGenerator;
use OCP\IUserSession; use OCP\IUserSession;
use OCP\L10N\IFactory; use OCP\L10N\IFactory;
use OCP\Notification\AlreadyProcessedException;
use OCP\Notification\IManager; use OCP\Notification\IManager;
use OCP\Notification\INotification; use OCP\Notification\INotification;
use Test\TestCase; use Test\TestCase;
@ -112,21 +113,12 @@ class NotifierTest extends TestCase {
->method('getObjectId') ->method('getObjectId')
->willReturn($versionNotification); ->willReturn($versionNotification);
if ($exception) {
$this->notificationManager->expects($this->once())
->method('markProcessed')
->with($notification);
} else {
$this->notificationManager->expects($this->never())
->method('markProcessed');
}
try { try {
self::invokePrivate($notifier, 'updateAlreadyInstalledCheck', [$notification, $versionInstalled]); self::invokePrivate($notifier, 'updateAlreadyInstalledCheck', [$notification, $versionInstalled]);
$this->assertFalse($exception); $this->assertFalse($exception);
} catch (\Exception $e) { } catch (\Exception $e) {
$this->assertTrue($exception); $this->assertTrue($exception);
$this->assertInstanceOf('InvalidArgumentException', $e); $this->assertInstanceOf(AlreadyProcessedException::class, $e);
} }
} }
} }

View File

@ -42,17 +42,7 @@ if(count($configPrefixes) > 0) {
$ldapWrapper = new OCA\User_LDAP\LDAP(); $ldapWrapper = new OCA\User_LDAP\LDAP();
$ocConfig = \OC::$server->getConfig(); $ocConfig = \OC::$server->getConfig();
$notificationManager = \OC::$server->getNotificationManager(); $notificationManager = \OC::$server->getNotificationManager();
$notificationManager->registerNotifier(function() { $notificationManager->registerNotifierService(\OCA\User_LDAP\Notification\Notifier::class);
return new \OCA\User_LDAP\Notification\Notifier(
\OC::$server->getL10NFactory()
);
}, function() {
$l = \OC::$server->getL10N('user_ldap');
return [
'id' => 'user_ldap',
'name' => $l->t('LDAP user and group backend'),
];
});
$userSession = \OC::$server->getUserSession(); $userSession = \OC::$server->getUserSession();
$userPluginManager = \OC::$server->query('LDAPUserPluginManager'); $userPluginManager = \OC::$server->query('LDAPUserPluginManager');

View File

@ -42,13 +42,33 @@ class Notifier implements INotifier {
$this->l10nFactory = $l10nFactory; $this->l10nFactory = $l10nFactory;
} }
/**
* Identifier of the notifier, only use [a-z0-9_]
*
* @return string
* @since 17.0.0
*/
public function getID(): string {
return 'user_ldap';
}
/**
* Human readable name describing the notifier
*
* @return string
* @since 17.0.0
*/
public function getName(): string {
return $this->l10nFactory->get('user_ldap')->t('LDAP User backend');
}
/** /**
* @param INotification $notification * @param INotification $notification
* @param string $languageCode The code of the language that should be used to prepare the notification * @param string $languageCode The code of the language that should be used to prepare the notification
* @return INotification * @return INotification
* @throws \InvalidArgumentException When the notification was not prepared by a notifier * @throws \InvalidArgumentException When the notification was not prepared by a notifier
*/ */
public function prepare(INotification $notification, $languageCode) { public function prepare(INotification $notification, string $languageCode): INotification {
if ($notification->getApp() !== 'user_ldap') { if ($notification->getApp() !== 'user_ldap') {
// Not my app => throw // Not my app => throw
throw new \InvalidArgumentException(); throw new \InvalidArgumentException();

View File

@ -65,24 +65,8 @@ class Application extends App {
$eventDispatcher = $server->query(IEventDispatcher::class); $eventDispatcher = $server->query(IEventDispatcher::class);
$notificationManager = $server->getNotificationManager(); $notificationManager = $server->getNotificationManager();
$notificationManager->registerNotifier(function () use ($server) { $notificationManager->registerNotifierService(RemoveLinkSharesNotifier::class);
return new RemoveLinkSharesNotifier( $notificationManager->registerNotifierService(AuthenticationNotifier::class);
$server->getL10NFactory()
);
}, function () {
return [
'id' => 'core',
'name' => 'core',
];
});
$notificationManager->registerNotifier(function () use ($server) {
return $server->query(AuthenticationNotifier::class);
}, function () {
return [
'id' => 'auth',
'name' => 'authentication notifier',
];
});
$eventDispatcher->addListener(IDBConnection::CHECK_MISSING_INDEXES_EVENT, $eventDispatcher->addListener(IDBConnection::CHECK_MISSING_INDEXES_EVENT,
function (GenericEvent $event) use ($container) { function (GenericEvent $event) use ($container) {

View File

@ -36,7 +36,27 @@ class RemoveLinkSharesNotifier implements INotifier {
$this->l10nFactory = $factory; $this->l10nFactory = $factory;
} }
public function prepare(INotification $notification, $languageCode): INotification { /**
* Identifier of the notifier, only use [a-z0-9_]
*
* @return string
* @since 17.0.0
*/
public function getID(): string {
return 'core';
}
/**
* Human readable name describing the notifier
*
* @return string
* @since 17.0.0
*/
public function getName(): string {
return $this->l10nFactory->get('core')->t('Nextcloud Server');
}
public function prepare(INotification $notification, string $languageCode): INotification {
if($notification->getApp() !== 'core') { if($notification->getApp() !== 'core') {
throw new \InvalidArgumentException(); throw new \InvalidArgumentException();
} }
@ -51,5 +71,4 @@ class RemoveLinkSharesNotifier implements INotifier {
throw new \InvalidArgumentException('Invalid subject'); throw new \InvalidArgumentException('Invalid subject');
} }
} }

View File

@ -347,6 +347,7 @@ return array(
'OCP\\Migration\\IOutput' => $baseDir . '/lib/public/Migration/IOutput.php', 'OCP\\Migration\\IOutput' => $baseDir . '/lib/public/Migration/IOutput.php',
'OCP\\Migration\\IRepairStep' => $baseDir . '/lib/public/Migration/IRepairStep.php', 'OCP\\Migration\\IRepairStep' => $baseDir . '/lib/public/Migration/IRepairStep.php',
'OCP\\Migration\\SimpleMigrationStep' => $baseDir . '/lib/public/Migration/SimpleMigrationStep.php', 'OCP\\Migration\\SimpleMigrationStep' => $baseDir . '/lib/public/Migration/SimpleMigrationStep.php',
'OCP\\Notification\\AlreadyProcessedException' => $baseDir . '/lib/public/Notification/AlreadyProcessedException.php',
'OCP\\Notification\\IAction' => $baseDir . '/lib/public/Notification/IAction.php', 'OCP\\Notification\\IAction' => $baseDir . '/lib/public/Notification/IAction.php',
'OCP\\Notification\\IApp' => $baseDir . '/lib/public/Notification/IApp.php', 'OCP\\Notification\\IApp' => $baseDir . '/lib/public/Notification/IApp.php',
'OCP\\Notification\\IManager' => $baseDir . '/lib/public/Notification/IManager.php', 'OCP\\Notification\\IManager' => $baseDir . '/lib/public/Notification/IManager.php',

View File

@ -381,6 +381,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OCP\\Migration\\IOutput' => __DIR__ . '/../../..' . '/lib/public/Migration/IOutput.php', 'OCP\\Migration\\IOutput' => __DIR__ . '/../../..' . '/lib/public/Migration/IOutput.php',
'OCP\\Migration\\IRepairStep' => __DIR__ . '/../../..' . '/lib/public/Migration/IRepairStep.php', 'OCP\\Migration\\IRepairStep' => __DIR__ . '/../../..' . '/lib/public/Migration/IRepairStep.php',
'OCP\\Migration\\SimpleMigrationStep' => __DIR__ . '/../../..' . '/lib/public/Migration/SimpleMigrationStep.php', 'OCP\\Migration\\SimpleMigrationStep' => __DIR__ . '/../../..' . '/lib/public/Migration/SimpleMigrationStep.php',
'OCP\\Notification\\AlreadyProcessedException' => __DIR__ . '/../../..' . '/lib/public/Notification/AlreadyProcessedException.php',
'OCP\\Notification\\IAction' => __DIR__ . '/../../..' . '/lib/public/Notification/IAction.php', 'OCP\\Notification\\IAction' => __DIR__ . '/../../..' . '/lib/public/Notification/IAction.php',
'OCP\\Notification\\IApp' => __DIR__ . '/../../..' . '/lib/public/Notification/IApp.php', 'OCP\\Notification\\IApp' => __DIR__ . '/../../..' . '/lib/public/Notification/IApp.php',
'OCP\\Notification\\IManager' => __DIR__ . '/../../..' . '/lib/public/Notification/IManager.php', 'OCP\\Notification\\IManager' => __DIR__ . '/../../..' . '/lib/public/Notification/IManager.php',

View File

@ -61,7 +61,7 @@ class RemoteWipeNotificationsListener implements IEventListener {
$notification->setApp('auth') $notification->setApp('auth')
->setUser($token->getUID()) ->setUser($token->getUID())
->setDateTime($this->timeFactory->getDateTime()) ->setDateTime($this->timeFactory->getDateTime())
->setObject('token', $token->getId()) ->setObject('token', (string) $token->getId())
->setSubject($event, [ ->setSubject($event, [
'name' => $token->getName(), 'name' => $token->getName(),
]); ]);

View File

@ -42,7 +42,7 @@ class Notifier implements INotifier {
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function prepare(INotification $notification, $languageCode) { public function prepare(INotification $notification, string $languageCode): INotification {
if ($notification->getApp() !== 'auth') { if ($notification->getApp() !== 'auth') {
// Not my app => throw // Not my app => throw
throw new InvalidArgumentException(); throw new InvalidArgumentException();
@ -74,4 +74,23 @@ class Notifier implements INotifier {
} }
} }
/**
* Identifier of the notifier, only use [a-z0-9_]
*
* @return string
* @since 17.0.0
*/
public function getID(): string {
return 'auth';
}
/**
* Human readable name describing the notifier
*
* @return string
* @since 17.0.0
*/
public function getName(): string {
return $this->factory->get('lib')->t('Authentication');
}
} }

View File

@ -1,4 +1,5 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2016, ownCloud, Inc. * @copyright Copyright (c) 2016, ownCloud, Inc.
* *
@ -45,9 +46,6 @@ class Action implements IAction {
/** @var bool */ /** @var bool */
protected $primary; protected $primary;
/**
* Constructor
*/
public function __construct() { public function __construct() {
$this->label = ''; $this->label = '';
$this->labelParsed = ''; $this->labelParsed = '';
@ -62,8 +60,8 @@ class Action implements IAction {
* @throws \InvalidArgumentException if the label is invalid * @throws \InvalidArgumentException if the label is invalid
* @since 8.2.0 * @since 8.2.0
*/ */
public function setLabel($label) { public function setLabel(string $label): IAction {
if (!is_string($label) || $label === '' || isset($label[32])) { if ($label === '' || isset($label[32])) {
throw new \InvalidArgumentException('The given label is invalid'); throw new \InvalidArgumentException('The given label is invalid');
} }
$this->label = $label; $this->label = $label;
@ -74,7 +72,7 @@ class Action implements IAction {
* @return string * @return string
* @since 8.2.0 * @since 8.2.0
*/ */
public function getLabel() { public function getLabel(): string {
return $this->label; return $this->label;
} }
@ -84,8 +82,8 @@ class Action implements IAction {
* @throws \InvalidArgumentException if the label is invalid * @throws \InvalidArgumentException if the label is invalid
* @since 8.2.0 * @since 8.2.0
*/ */
public function setParsedLabel($label) { public function setParsedLabel(string $label): IAction {
if (!is_string($label) || $label === '') { if ($label === '') {
throw new \InvalidArgumentException('The given parsed label is invalid'); throw new \InvalidArgumentException('The given parsed label is invalid');
} }
$this->labelParsed = $label; $this->labelParsed = $label;
@ -96,21 +94,16 @@ class Action implements IAction {
* @return string * @return string
* @since 8.2.0 * @since 8.2.0
*/ */
public function getParsedLabel() { public function getParsedLabel(): string {
return $this->labelParsed; return $this->labelParsed;
} }
/** /**
* @param $primary bool * @param $primary bool
* @return $this * @return $this
* @throws \InvalidArgumentException if $primary is invalid
* @since 9.0.0 * @since 9.0.0
*/ */
public function setPrimary($primary) { public function setPrimary(bool $primary): IAction {
if (!is_bool($primary)) {
throw new \InvalidArgumentException('The given primary option is invalid');
}
$this->primary = $primary; $this->primary = $primary;
return $this; return $this;
} }
@ -119,7 +112,7 @@ class Action implements IAction {
* @return bool * @return bool
* @since 9.0.0 * @since 9.0.0
*/ */
public function isPrimary() { public function isPrimary(): bool {
return $this->primary; return $this->primary;
} }
@ -130,11 +123,17 @@ class Action implements IAction {
* @throws \InvalidArgumentException if the link is invalid * @throws \InvalidArgumentException if the link is invalid
* @since 8.2.0 * @since 8.2.0
*/ */
public function setLink($link, $requestType) { public function setLink(string $link, string $requestType): IAction {
if (!is_string($link) || $link === '' || isset($link[256])) { if ($link === '' || isset($link[256])) {
throw new \InvalidArgumentException('The given link is invalid'); throw new \InvalidArgumentException('The given link is invalid');
} }
if (!in_array($requestType, ['GET', 'POST', 'PUT', 'DELETE'], true)) { if (!in_array($requestType, [
self::TYPE_GET,
self::TYPE_POST,
self::TYPE_PUT,
self::TYPE_DELETE,
self::TYPE_WEB,
], true)) {
throw new \InvalidArgumentException('The given request type is invalid'); throw new \InvalidArgumentException('The given request type is invalid');
} }
$this->link = $link; $this->link = $link;
@ -146,7 +145,7 @@ class Action implements IAction {
* @return string * @return string
* @since 8.2.0 * @since 8.2.0
*/ */
public function getLink() { public function getLink(): string {
return $this->link; return $this->link;
} }
@ -154,21 +153,21 @@ class Action implements IAction {
* @return string * @return string
* @since 8.2.0 * @since 8.2.0
*/ */
public function getRequestType() { public function getRequestType(): string {
return $this->requestType; return $this->requestType;
} }
/** /**
* @return bool * @return bool
*/ */
public function isValid() { public function isValid(): bool {
return $this->label !== '' && $this->link !== ''; return $this->label !== '' && $this->link !== '';
} }
/** /**
* @return bool * @return bool
*/ */
public function isValidParsed() { public function isValidParsed(): bool {
return $this->labelParsed !== '' && $this->link !== ''; return $this->labelParsed !== '' && $this->link !== '';
} }
} }

View File

@ -1,4 +1,5 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2016, ownCloud, Inc. * @copyright Copyright (c) 2016, ownCloud, Inc.
* *
@ -25,6 +26,9 @@
namespace OC\Notification; namespace OC\Notification;
use OCP\AppFramework\QueryException;
use OCP\ILogger;
use OCP\Notification\AlreadyProcessedException;
use OCP\Notification\IApp; use OCP\Notification\IApp;
use OCP\Notification\IManager; use OCP\Notification\IManager;
use OCP\Notification\INotification; use OCP\Notification\INotification;
@ -34,52 +38,39 @@ use OCP\RichObjectStrings\IValidator;
class Manager implements IManager { class Manager implements IManager {
/** @var IValidator */ /** @var IValidator */
protected $validator; protected $validator;
/** @var ILogger */
protected $logger;
/** @var IApp[] */ /** @var IApp[] */
protected $apps; protected $apps;
/** @var string[] */
protected $appClasses;
/** @var INotifier[] */ /** @var INotifier[] */
protected $notifiers; protected $notifiers;
/** @var string[] */
/** @var array[] */ protected $notifierClasses;
protected $notifiersInfo;
/** @var \Closure[] */
protected $appsClosures;
/** @var \Closure[] */
protected $notifiersClosures;
/** @var \Closure[] */
protected $notifiersInfoClosures;
/** @var bool */ /** @var bool */
protected $preparingPushNotification; protected $preparingPushNotification;
/** public function __construct(IValidator $validator,
* Manager constructor. ILogger $logger) {
*
* @param IValidator $validator
*/
public function __construct(IValidator $validator) {
$this->validator = $validator; $this->validator = $validator;
$this->logger = $logger;
$this->apps = []; $this->apps = [];
$this->notifiers = []; $this->notifiers = [];
$this->notifiersInfo = []; $this->appClasses = [];
$this->appsClosures = []; $this->notifierClasses = [];
$this->notifiersClosures = [];
$this->notifiersInfoClosures = [];
$this->preparingPushNotification = false; $this->preparingPushNotification = false;
} }
/** /**
* @param \Closure $service The service must implement IApp, otherwise a * @param string $appClass The service must implement IApp, otherwise a
* \InvalidArgumentException is thrown later * \InvalidArgumentException is thrown later
* @since 8.2.0 * @since 17.0.0
*/ */
public function registerApp(\Closure $service) { public function registerApp(string $appClass): void {
$this->appsClosures[] = $service; $this->appClasses[] = $appClass;
$this->apps = [];
} }
/** /**
@ -87,78 +78,93 @@ class Manager implements IManager {
* \InvalidArgumentException is thrown later * \InvalidArgumentException is thrown later
* @param \Closure $info An array with the keys 'id' and 'name' containing * @param \Closure $info An array with the keys 'id' and 'name' containing
* the app id and the app name * the app id and the app name
* @deprecated 17.0.0 use registerNotifierService instead.
* @since 8.2.0 - Parameter $info was added in 9.0.0 * @since 8.2.0 - Parameter $info was added in 9.0.0
*/ */
public function registerNotifier(\Closure $service, \Closure $info) { public function registerNotifier(\Closure $service, \Closure $info) {
$this->notifiersClosures[] = $service; $infoData = $info();
$this->notifiersInfoClosures[] = $info; $this->logger->logException(new \InvalidArgumentException(
$this->notifiers = []; 'Notifier ' . $infoData['name'] . ' (id: ' . $infoData['id'] . ') is not considered because it is using the old way to register.'
$this->notifiersInfo = []; ));
}
/**
* @param string $notifierService The service must implement INotifier, otherwise a
* \InvalidArgumentException is thrown later
* @since 17.0.0
*/
public function registerNotifierService(string $notifierService): void {
$this->notifierClasses[] = $notifierService;
} }
/** /**
* @return IApp[] * @return IApp[]
*/ */
protected function getApps(): array { protected function getApps(): array {
if (!empty($this->apps)) { if (empty($this->appClasses)) {
return $this->apps; return $this->apps;
} }
$this->apps = []; foreach ($this->appClasses as $appClass) {
foreach ($this->appsClosures as $closure) { try {
$app = $closure(); $app = \OC::$server->query($appClass);
if (!($app instanceof IApp)) { } catch (QueryException $e) {
throw new \InvalidArgumentException('The given notification app does not implement the IApp interface'); $this->logger->logException($e, [
'message' => 'Failed to load notification app class: ' . $appClass,
'app' => 'notifications',
]);
continue;
} }
if (!($app instanceof IApp)) {
$this->logger->error('Notification app class ' . $appClass . ' is not implementing ' . IApp::class, [
'app' => 'notifications',
]);
continue;
}
$this->apps[] = $app; $this->apps[] = $app;
} }
$this->appClasses = [];
return $this->apps; return $this->apps;
} }
/** /**
* @return INotifier[] * @return INotifier[]
*/ */
protected function getNotifiers(): array { public function getNotifiers(): array {
if (!empty($this->notifiers)) { if (empty($this->notifierClasses)) {
return $this->notifiers; return $this->notifiers;
} }
$this->notifiers = []; foreach ($this->notifierClasses as $notifierClass) {
foreach ($this->notifiersClosures as $closure) { try {
$notifier = $closure(); $notifier = \OC::$server->query($notifierClass);
if (!($notifier instanceof INotifier)) { } catch (QueryException $e) {
throw new \InvalidArgumentException('The given notifier does not implement the INotifier interface'); $this->logger->logException($e, [
'message' => 'Failed to load notification notifier class: ' . $notifierClass,
'app' => 'notifications',
]);
continue;
} }
if (!($notifier instanceof INotifier)) {
$this->logger->error('Notification notifier class ' . $notifierClass . ' is not implementing ' . INotifier::class, [
'app' => 'notifications',
]);
continue;
}
$this->notifiers[] = $notifier; $this->notifiers[] = $notifier;
} }
$this->notifierClasses = [];
return $this->notifiers; return $this->notifiers;
} }
/**
* @return array[]
*/
public function listNotifiers(): array {
if (!empty($this->notifiersInfo)) {
return $this->notifiersInfo;
}
$this->notifiersInfo = [];
foreach ($this->notifiersInfoClosures as $closure) {
$notifier = $closure();
if (!\is_array($notifier) || \count($notifier) !== 2 || !isset($notifier['id'], $notifier['name'])) {
throw new \InvalidArgumentException('The given notifier information is invalid');
}
if (isset($this->notifiersInfo[$notifier['id']])) {
throw new \InvalidArgumentException('The given notifier ID ' . $notifier['id'] . ' is already in use');
}
$this->notifiersInfo[$notifier['id']] = $notifier['name'];
}
return $this->notifiersInfo;
}
/** /**
* @return INotification * @return INotification
* @since 8.2.0 * @since 8.2.0
@ -172,14 +178,14 @@ class Manager implements IManager {
* @since 8.2.0 * @since 8.2.0
*/ */
public function hasNotifiers(): bool { public function hasNotifiers(): bool {
return !empty($this->notifiersClosures); return !empty($this->notifiers) || !empty($this->notifierClasses);
} }
/** /**
* @param bool $preparingPushNotification * @param bool $preparingPushNotification
* @since 14.0.0 * @since 14.0.0
*/ */
public function setPreparingPushNotification($preparingPushNotification) { public function setPreparingPushNotification(bool $preparingPushNotification): void {
$this->preparingPushNotification = $preparingPushNotification; $this->preparingPushNotification = $preparingPushNotification;
} }
@ -196,7 +202,7 @@ class Manager implements IManager {
* @throws \InvalidArgumentException When the notification is not valid * @throws \InvalidArgumentException When the notification is not valid
* @since 8.2.0 * @since 8.2.0
*/ */
public function notify(INotification $notification) { public function notify(INotification $notification): void {
if (!$notification->isValid()) { if (!$notification->isValid()) {
throw new \InvalidArgumentException('The given notification is invalid'); throw new \InvalidArgumentException('The given notification is invalid');
} }
@ -211,14 +217,35 @@ class Manager implements IManager {
} }
} }
/**
* Identifier of the notifier, only use [a-z0-9_]
*
* @return string
* @since 17.0.0
*/
public function getID(): string {
return 'core';
}
/**
* Human readable name describing the notifier
*
* @return string
* @since 17.0.0
*/
public function getName(): string {
return 'core';
}
/** /**
* @param INotification $notification * @param INotification $notification
* @param string $languageCode The code of the language that should be used to prepare the notification * @param string $languageCode The code of the language that should be used to prepare the notification
* @return INotification * @return INotification
* @throws \InvalidArgumentException When the notification was not prepared by a notifier * @throws \InvalidArgumentException When the notification was not prepared by a notifier
* @throws AlreadyProcessedException When the notification is not needed anymore and should be deleted
* @since 8.2.0 * @since 8.2.0
*/ */
public function prepare(INotification $notification, $languageCode): INotification { public function prepare(INotification $notification, string $languageCode): INotification {
$notifiers = $this->getNotifiers(); $notifiers = $this->getNotifiers();
foreach ($notifiers as $notifier) { foreach ($notifiers as $notifier) {
@ -226,6 +253,9 @@ class Manager implements IManager {
$notification = $notifier->prepare($notification, $languageCode); $notification = $notifier->prepare($notification, $languageCode);
} catch (\InvalidArgumentException $e) { } catch (\InvalidArgumentException $e) {
continue; continue;
} catch (AlreadyProcessedException $e) {
$this->markProcessed($notification);
throw new \InvalidArgumentException('The given notification has been processed');
} }
if (!($notification instanceof INotification) || !$notification->isValidParsed()) { if (!($notification instanceof INotification) || !$notification->isValidParsed()) {
@ -243,7 +273,7 @@ class Manager implements IManager {
/** /**
* @param INotification $notification * @param INotification $notification
*/ */
public function markProcessed(INotification $notification) { public function markProcessed(INotification $notification): void {
$apps = $this->getApps(); $apps = $this->getApps();
foreach ($apps as $app) { foreach ($apps as $app) {

View File

@ -1,5 +1,5 @@
<?php <?php
declare (strict_types = 1); declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2016, ownCloud, Inc. * @copyright Copyright (c) 2016, ownCloud, Inc.
* *
@ -99,11 +99,6 @@ class Notification implements INotification {
/** @var bool */ /** @var bool */
protected $hasPrimaryParsedAction; protected $hasPrimaryParsedAction;
/**
* Constructor
*
* @param IValidator $richValidator
*/
public function __construct(IValidator $richValidator) { public function __construct(IValidator $richValidator) {
$this->richValidator = $richValidator; $this->richValidator = $richValidator;
$this->app = ''; $this->app = '';
@ -134,8 +129,8 @@ class Notification implements INotification {
* @throws \InvalidArgumentException if the app id is invalid * @throws \InvalidArgumentException if the app id is invalid
* @since 8.2.0 * @since 8.2.0
*/ */
public function setApp(string $app) { public function setApp(string $app): INotification {
if (trim($app) === '' || isset($app[32])) { if ($app === '' || isset($app[32])) {
throw new \InvalidArgumentException('The given app name is invalid'); throw new \InvalidArgumentException('The given app name is invalid');
} }
$this->app = $app; $this->app = $app;
@ -146,7 +141,7 @@ class Notification implements INotification {
* @return string * @return string
* @since 8.2.0 * @since 8.2.0
*/ */
public function getApp() { public function getApp(): string {
return $this->app; return $this->app;
} }
@ -156,8 +151,8 @@ class Notification implements INotification {
* @throws \InvalidArgumentException if the user id is invalid * @throws \InvalidArgumentException if the user id is invalid
* @since 8.2.0 * @since 8.2.0
*/ */
public function setUser(string $user) { public function setUser(string $user): INotification {
if (trim($user) === '' || isset($user[64])) { if ($user === '' || isset($user[64])) {
throw new \InvalidArgumentException('The given user id is invalid'); throw new \InvalidArgumentException('The given user id is invalid');
} }
$this->user = $user; $this->user = $user;
@ -168,7 +163,7 @@ class Notification implements INotification {
* @return string * @return string
* @since 8.2.0 * @since 8.2.0
*/ */
public function getUser() { public function getUser(): string {
return $this->user; return $this->user;
} }
@ -178,7 +173,7 @@ class Notification implements INotification {
* @throws \InvalidArgumentException if the $dateTime is invalid * @throws \InvalidArgumentException if the $dateTime is invalid
* @since 9.0.0 * @since 9.0.0
*/ */
public function setDateTime(\DateTime $dateTime) { public function setDateTime(\DateTime $dateTime): INotification {
if ($dateTime->getTimestamp() === 0) { if ($dateTime->getTimestamp() === 0) {
throw new \InvalidArgumentException('The given date time is invalid'); throw new \InvalidArgumentException('The given date time is invalid');
} }
@ -190,7 +185,7 @@ class Notification implements INotification {
* @return \DateTime * @return \DateTime
* @since 9.0.0 * @since 9.0.0
*/ */
public function getDateTime() { public function getDateTime(): \DateTime {
return $this->dateTime; return $this->dateTime;
} }
@ -201,13 +196,13 @@ class Notification implements INotification {
* @throws \InvalidArgumentException if the object type or id is invalid * @throws \InvalidArgumentException if the object type or id is invalid
* @since 8.2.0 - 9.0.0: Type of $id changed to string * @since 8.2.0 - 9.0.0: Type of $id changed to string
*/ */
public function setObject(string $type, $id) { public function setObject(string $type, string $id): INotification {
if (trim($type) === '' || isset($type[64])) { if ($type === '' || isset($type[64])) {
throw new \InvalidArgumentException('The given object type is invalid'); throw new \InvalidArgumentException('The given object type is invalid');
} }
$this->objectType = $type; $this->objectType = $type;
if (!is_int($id) && (!is_string($id) || $id === '' || isset($id[64]))) { if ($id === '' || isset($id[64])) {
throw new \InvalidArgumentException('The given object id is invalid'); throw new \InvalidArgumentException('The given object id is invalid');
} }
$this->objectId = (string) $id; $this->objectId = (string) $id;
@ -218,7 +213,7 @@ class Notification implements INotification {
* @return string * @return string
* @since 8.2.0 * @since 8.2.0
*/ */
public function getObjectType() { public function getObjectType(): string {
return $this->objectType; return $this->objectType;
} }
@ -226,7 +221,7 @@ class Notification implements INotification {
* @return string * @return string
* @since 8.2.0 - 9.0.0: Return type changed to string * @since 8.2.0 - 9.0.0: Return type changed to string
*/ */
public function getObjectId() { public function getObjectId(): string {
return $this->objectId; return $this->objectId;
} }
@ -237,8 +232,8 @@ class Notification implements INotification {
* @throws \InvalidArgumentException if the subject or parameters are invalid * @throws \InvalidArgumentException if the subject or parameters are invalid
* @since 8.2.0 * @since 8.2.0
*/ */
public function setSubject(string $subject, array $parameters = []) { public function setSubject(string $subject, array $parameters = []): INotification {
if (trim($subject) === '' || isset($subject[64])) { if ($subject === '' || isset($subject[64])) {
throw new \InvalidArgumentException('The given subject is invalid'); throw new \InvalidArgumentException('The given subject is invalid');
} }
@ -252,15 +247,15 @@ class Notification implements INotification {
* @return string * @return string
* @since 8.2.0 * @since 8.2.0
*/ */
public function getSubject() { public function getSubject(): string {
return $this->subject; return $this->subject;
} }
/** /**
* @return string[] * @return array
* @since 8.2.0 * @since 8.2.0
*/ */
public function getSubjectParameters() { public function getSubjectParameters(): array {
return $this->subjectParameters; return $this->subjectParameters;
} }
@ -270,8 +265,8 @@ class Notification implements INotification {
* @throws \InvalidArgumentException if the subject is invalid * @throws \InvalidArgumentException if the subject is invalid
* @since 8.2.0 * @since 8.2.0
*/ */
public function setParsedSubject(string $subject) { public function setParsedSubject(string $subject): INotification {
if (trim($subject) === '') { if ($subject === '') {
throw new \InvalidArgumentException('The given parsed subject is invalid'); throw new \InvalidArgumentException('The given parsed subject is invalid');
} }
$this->subjectParsed = $subject; $this->subjectParsed = $subject;
@ -282,7 +277,7 @@ class Notification implements INotification {
* @return string * @return string
* @since 8.2.0 * @since 8.2.0
*/ */
public function getParsedSubject() { public function getParsedSubject(): string {
return $this->subjectParsed; return $this->subjectParsed;
} }
@ -293,8 +288,8 @@ class Notification implements INotification {
* @throws \InvalidArgumentException if the subject or parameters are invalid * @throws \InvalidArgumentException if the subject or parameters are invalid
* @since 11.0.0 * @since 11.0.0
*/ */
public function setRichSubject(string $subject, array $parameters = []) { public function setRichSubject(string $subject, array $parameters = []): INotification {
if (trim($subject) === '') { if ($subject === '') {
throw new \InvalidArgumentException('The given parsed subject is invalid'); throw new \InvalidArgumentException('The given parsed subject is invalid');
} }
@ -308,7 +303,7 @@ class Notification implements INotification {
* @return string * @return string
* @since 11.0.0 * @since 11.0.0
*/ */
public function getRichSubject() { public function getRichSubject(): string {
return $this->subjectRich; return $this->subjectRich;
} }
@ -316,7 +311,7 @@ class Notification implements INotification {
* @return array[] * @return array[]
* @since 11.0.0 * @since 11.0.0
*/ */
public function getRichSubjectParameters() { public function getRichSubjectParameters(): array {
return $this->subjectRichParameters; return $this->subjectRichParameters;
} }
@ -327,8 +322,8 @@ class Notification implements INotification {
* @throws \InvalidArgumentException if the message or parameters are invalid * @throws \InvalidArgumentException if the message or parameters are invalid
* @since 8.2.0 * @since 8.2.0
*/ */
public function setMessage(string $message, array $parameters = []) { public function setMessage(string $message, array $parameters = []): INotification {
if (trim($message) === '' || isset($message[64])) { if ($message === '' || isset($message[64])) {
throw new \InvalidArgumentException('The given message is invalid'); throw new \InvalidArgumentException('The given message is invalid');
} }
@ -342,15 +337,15 @@ class Notification implements INotification {
* @return string * @return string
* @since 8.2.0 * @since 8.2.0
*/ */
public function getMessage() { public function getMessage(): string {
return $this->message; return $this->message;
} }
/** /**
* @return string[] * @return array
* @since 8.2.0 * @since 8.2.0
*/ */
public function getMessageParameters() { public function getMessageParameters(): array {
return $this->messageParameters; return $this->messageParameters;
} }
@ -360,8 +355,8 @@ class Notification implements INotification {
* @throws \InvalidArgumentException if the message is invalid * @throws \InvalidArgumentException if the message is invalid
* @since 8.2.0 * @since 8.2.0
*/ */
public function setParsedMessage(string $message) { public function setParsedMessage(string $message): INotification {
if (trim($message) === '') { if ($message === '') {
throw new \InvalidArgumentException('The given parsed message is invalid'); throw new \InvalidArgumentException('The given parsed message is invalid');
} }
$this->messageParsed = $message; $this->messageParsed = $message;
@ -372,7 +367,7 @@ class Notification implements INotification {
* @return string * @return string
* @since 8.2.0 * @since 8.2.0
*/ */
public function getParsedMessage() { public function getParsedMessage(): string {
return $this->messageParsed; return $this->messageParsed;
} }
@ -383,8 +378,8 @@ class Notification implements INotification {
* @throws \InvalidArgumentException if the message or parameters are invalid * @throws \InvalidArgumentException if the message or parameters are invalid
* @since 11.0.0 * @since 11.0.0
*/ */
public function setRichMessage(string $message, array $parameters = []) { public function setRichMessage(string $message, array $parameters = []): INotification {
if (trim($message) === '') { if ($message === '') {
throw new \InvalidArgumentException('The given parsed message is invalid'); throw new \InvalidArgumentException('The given parsed message is invalid');
} }
@ -398,7 +393,7 @@ class Notification implements INotification {
* @return string * @return string
* @since 11.0.0 * @since 11.0.0
*/ */
public function getRichMessage() { public function getRichMessage(): string {
return $this->messageRich; return $this->messageRich;
} }
@ -406,7 +401,7 @@ class Notification implements INotification {
* @return array[] * @return array[]
* @since 11.0.0 * @since 11.0.0
*/ */
public function getRichMessageParameters() { public function getRichMessageParameters(): array {
return $this->messageRichParameters; return $this->messageRichParameters;
} }
@ -416,8 +411,8 @@ class Notification implements INotification {
* @throws \InvalidArgumentException if the link is invalid * @throws \InvalidArgumentException if the link is invalid
* @since 8.2.0 * @since 8.2.0
*/ */
public function setLink(string $link) { public function setLink(string $link): INotification {
if (trim($link) === '' || isset($link[4000])) { if ($link === '' || isset($link[4000])) {
throw new \InvalidArgumentException('The given link is invalid'); throw new \InvalidArgumentException('The given link is invalid');
} }
$this->link = $link; $this->link = $link;
@ -428,7 +423,7 @@ class Notification implements INotification {
* @return string * @return string
* @since 8.2.0 * @since 8.2.0
*/ */
public function getLink() { public function getLink(): string {
return $this->link; return $this->link;
} }
@ -438,8 +433,8 @@ class Notification implements INotification {
* @throws \InvalidArgumentException if the icon is invalid * @throws \InvalidArgumentException if the icon is invalid
* @since 11.0.0 * @since 11.0.0
*/ */
public function setIcon(string $icon) { public function setIcon(string $icon): INotification {
if (trim($icon) === '' || isset($icon[4000])) { if ($icon === '' || isset($icon[4000])) {
throw new \InvalidArgumentException('The given icon is invalid'); throw new \InvalidArgumentException('The given icon is invalid');
} }
$this->icon = $icon; $this->icon = $icon;
@ -450,7 +445,7 @@ class Notification implements INotification {
* @return string * @return string
* @since 11.0.0 * @since 11.0.0
*/ */
public function getIcon() { public function getIcon(): string {
return $this->icon; return $this->icon;
} }
@ -458,7 +453,7 @@ class Notification implements INotification {
* @return IAction * @return IAction
* @since 8.2.0 * @since 8.2.0
*/ */
public function createAction() { public function createAction(): IAction {
return new Action(); return new Action();
} }
@ -468,7 +463,7 @@ class Notification implements INotification {
* @throws \InvalidArgumentException if the action is invalid * @throws \InvalidArgumentException if the action is invalid
* @since 8.2.0 * @since 8.2.0
*/ */
public function addAction(IAction $action) { public function addAction(IAction $action): INotification {
if (!$action->isValid()) { if (!$action->isValid()) {
throw new \InvalidArgumentException('The given action is invalid'); throw new \InvalidArgumentException('The given action is invalid');
} }
@ -489,7 +484,7 @@ class Notification implements INotification {
* @return IAction[] * @return IAction[]
* @since 8.2.0 * @since 8.2.0
*/ */
public function getActions() { public function getActions(): array {
return $this->actions; return $this->actions;
} }
@ -499,7 +494,7 @@ class Notification implements INotification {
* @throws \InvalidArgumentException if the action is invalid * @throws \InvalidArgumentException if the action is invalid
* @since 8.2.0 * @since 8.2.0
*/ */
public function addParsedAction(IAction $action) { public function addParsedAction(IAction $action): INotification {
if (!$action->isValidParsed()) { if (!$action->isValidParsed()) {
throw new \InvalidArgumentException('The given parsed action is invalid'); throw new \InvalidArgumentException('The given parsed action is invalid');
} }
@ -524,7 +519,7 @@ class Notification implements INotification {
* @return IAction[] * @return IAction[]
* @since 8.2.0 * @since 8.2.0
*/ */
public function getParsedActions() { public function getParsedActions(): array {
return $this->actionsParsed; return $this->actionsParsed;
} }
@ -532,7 +527,7 @@ class Notification implements INotification {
* @return bool * @return bool
* @since 8.2.0 * @since 8.2.0
*/ */
public function isValid() { public function isValid(): bool {
return return
$this->isValidCommon() $this->isValidCommon()
&& &&
@ -544,7 +539,7 @@ class Notification implements INotification {
* @return bool * @return bool
* @since 8.2.0 * @since 8.2.0
*/ */
public function isValidParsed() { public function isValidParsed(): bool {
if ($this->getRichSubject() !== '' || !empty($this->getRichSubjectParameters())) { if ($this->getRichSubject() !== '' || !empty($this->getRichSubjectParameters())) {
try { try {
$this->richValidator->validate($this->getRichSubject(), $this->getRichSubjectParameters()); $this->richValidator->validate($this->getRichSubject(), $this->getRichSubjectParameters());
@ -568,10 +563,7 @@ class Notification implements INotification {
; ;
} }
/** protected function isValidCommon(): bool {
* @return bool
*/
protected function isValidCommon() {
return return
$this->getApp() !== '' $this->getApp() !== ''
&& &&

View File

@ -900,7 +900,8 @@ class Server extends ServerContainer implements IServerContainer {
}); });
$this->registerService(\OCP\Notification\IManager::class, function (Server $c) { $this->registerService(\OCP\Notification\IManager::class, function (Server $c) {
return new Manager( return new Manager(
$c->query(IValidator::class) $c->query(IValidator::class),
$c->getLogger()
); );
}); });
$this->registerAlias('NotificationManager', \OCP\Notification\IManager::class); $this->registerAlias('NotificationManager', \OCP\Notification\IManager::class);

View File

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2019 Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCP\Notification;
/**
* @since 17.0.0
*/
class AlreadyProcessedException extends \RuntimeException {
/**
* @since 17.0.0
*/
public function __construct() {
parent::__construct('Notification is processed already');
}
}

View File

@ -1,4 +1,5 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2016, ownCloud, Inc. * @copyright Copyright (c) 2016, ownCloud, Inc.
* *
@ -29,19 +30,27 @@ namespace OCP\Notification;
* @since 9.0.0 * @since 9.0.0
*/ */
interface IAction { interface IAction {
/**
* @param string $label
* @return $this
* @throws \InvalidArgumentException if the label is invalid
* @since 9.0.0
*/
public function setLabel($label);
/** /**
* @return string * @since 17.0.0
* @since 9.0.0
*/ */
public function getLabel(); public const TYPE_GET = 'GET';
/**
* @since 17.0.0
*/
public const TYPE_POST = 'POST';
/**
* @since 17.0.0
*/
public const TYPE_PUT = 'PUT';
/**
* @since 17.0.0
*/
public const TYPE_DELETE = 'DELETE';
/**
* @since 17.0.0
*/
public const TYPE_WEB = 'WEB';
/** /**
* @param string $label * @param string $label
@ -49,27 +58,41 @@ interface IAction {
* @throws \InvalidArgumentException if the label is invalid * @throws \InvalidArgumentException if the label is invalid
* @since 9.0.0 * @since 9.0.0
*/ */
public function setParsedLabel($label); public function setLabel(string $label): IAction;
/** /**
* @return string * @return string
* @since 9.0.0 * @since 9.0.0
*/ */
public function getParsedLabel(); public function getLabel(): string;
/** /**
* @param $primary bool * @param string $label
* @return $this
* @throws \InvalidArgumentException if the label is invalid
* @since 9.0.0
*/
public function setParsedLabel(string $label): IAction;
/**
* @return string
* @since 9.0.0
*/
public function getParsedLabel(): string;
/**
* @param bool $primary
* @return $this * @return $this
* @throws \InvalidArgumentException if $primary is invalid * @throws \InvalidArgumentException if $primary is invalid
* @since 9.0.0 * @since 9.0.0
*/ */
public function setPrimary($primary); public function setPrimary(bool $primary): IAction;
/** /**
* @return bool * @return bool
* @since 9.0.0 * @since 9.0.0
*/ */
public function isPrimary(); public function isPrimary(): bool;
/** /**
* @param string $link * @param string $link
@ -78,29 +101,29 @@ interface IAction {
* @throws \InvalidArgumentException if the link is invalid * @throws \InvalidArgumentException if the link is invalid
* @since 9.0.0 * @since 9.0.0
*/ */
public function setLink($link, $requestType); public function setLink(string $link, string $requestType): IAction;
/** /**
* @return string * @return string
* @since 9.0.0 * @since 9.0.0
*/ */
public function getLink(); public function getLink(): string;
/** /**
* @return string * @return string
* @since 9.0.0 * @since 9.0.0
*/ */
public function getRequestType(); public function getRequestType(): string;
/** /**
* @return bool * @return bool
* @since 9.0.0 * @since 9.0.0
*/ */
public function isValid(); public function isValid(): bool;
/** /**
* @return bool * @return bool
* @since 9.0.0 * @since 9.0.0
*/ */
public function isValidParsed(); public function isValidParsed(): bool;
} }

View File

@ -1,4 +1,5 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2016, ownCloud, Inc. * @copyright Copyright (c) 2016, ownCloud, Inc.
* *
@ -34,18 +35,18 @@ interface IApp {
* @throws \InvalidArgumentException When the notification is not valid * @throws \InvalidArgumentException When the notification is not valid
* @since 9.0.0 * @since 9.0.0
*/ */
public function notify(INotification $notification); public function notify(INotification $notification): void;
/** /**
* @param INotification $notification * @param INotification $notification
* @since 9.0.0 * @since 9.0.0
*/ */
public function markProcessed(INotification $notification); public function markProcessed(INotification $notification): void;
/** /**
* @param INotification $notification * @param INotification $notification
* @return int * @return int
* @since 9.0.0 * @since 9.0.0
*/ */
public function getCount(INotification $notification); public function getCount(INotification $notification): int;
} }

View File

@ -1,4 +1,5 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2016, ownCloud, Inc. * @copyright Copyright (c) 2016, ownCloud, Inc.
* *
@ -30,48 +31,56 @@ namespace OCP\Notification;
*/ */
interface IManager extends IApp, INotifier { interface IManager extends IApp, INotifier {
/** /**
* @param \Closure $service The service must implement IApp, otherwise a * @param string $appClass The service must implement IApp, otherwise a
* \InvalidArgumentException is thrown later * \InvalidArgumentException is thrown later
* @since 9.0.0 * @since 17.0.0
*/ */
public function registerApp(\Closure $service); public function registerApp(string $appClass): void;
/** /**
* @param \Closure $service The service must implement INotifier, otherwise a * @param \Closure $service The service must implement INotifier, otherwise a
* \InvalidArgumentException is thrown later * \InvalidArgumentException is thrown later
* @param \Closure $info An array with the keys 'id' and 'name' containing * @param \Closure $info An array with the keys 'id' and 'name' containing
* the app id and the app name * the app id and the app name
* @since 9.0.0 * @deprecated 17.0.0 use registerNotifierService instead.
* @since 8.2.0 - Parameter $info was added in 9.0.0
*/ */
public function registerNotifier(\Closure $service, \Closure $info); public function registerNotifier(\Closure $service, \Closure $info);
/** /**
* @return array App ID => App Name * @param string $notifierService The service must implement INotifier, otherwise a
* \InvalidArgumentException is thrown later
* @since 17.0.0
*/
public function registerNotifierService(string $notifierService): void;
/**
* @return INotifier[]
* @since 9.0.0 * @since 9.0.0
*/ */
public function listNotifiers(); public function getNotifiers(): array;
/** /**
* @return INotification * @return INotification
* @since 9.0.0 * @since 9.0.0
*/ */
public function createNotification(); public function createNotification(): INotification;
/** /**
* @return bool * @return bool
* @since 9.0.0 * @since 9.0.0
*/ */
public function hasNotifiers(); public function hasNotifiers(): bool;
/** /**
* @param bool $preparingPushNotification * @param bool $preparingPushNotification
* @since 14.0.0 * @since 14.0.0
*/ */
public function setPreparingPushNotification($preparingPushNotification); public function setPreparingPushNotification(bool $preparingPushNotification): void;
/** /**
* @return bool * @return bool
* @since 14.0.0 * @since 14.0.0
*/ */
public function isPreparingPushNotification(); public function isPreparingPushNotification(): bool;
} }

View File

@ -1,5 +1,5 @@
<?php <?php
declare (strict_types = 1); declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2016, ownCloud, Inc. * @copyright Copyright (c) 2016, ownCloud, Inc.
* *
@ -37,13 +37,13 @@ interface INotification {
* @throws \InvalidArgumentException if the app id is invalid * @throws \InvalidArgumentException if the app id is invalid
* @since 9.0.0 * @since 9.0.0
*/ */
public function setApp(string $app); public function setApp(string $app): INotification;
/** /**
* @return string * @return string
* @since 9.0.0 * @since 9.0.0
*/ */
public function getApp(); public function getApp(): string;
/** /**
* @param string $user * @param string $user
@ -51,13 +51,13 @@ interface INotification {
* @throws \InvalidArgumentException if the user id is invalid * @throws \InvalidArgumentException if the user id is invalid
* @since 9.0.0 * @since 9.0.0
*/ */
public function setUser(string $user); public function setUser(string $user): INotification;
/** /**
* @return string * @return string
* @since 9.0.0 * @since 9.0.0
*/ */
public function getUser(); public function getUser(): string;
/** /**
* @param \DateTime $dateTime * @param \DateTime $dateTime
@ -65,13 +65,13 @@ interface INotification {
* @throws \InvalidArgumentException if the $dateTime is invalid * @throws \InvalidArgumentException if the $dateTime is invalid
* @since 9.0.0 * @since 9.0.0
*/ */
public function setDateTime(\DateTime $dateTime); public function setDateTime(\DateTime $dateTime): INotification;
/** /**
* @return \DateTime * @return \DateTime
* @since 9.0.0 * @since 9.0.0
*/ */
public function getDateTime(); public function getDateTime(): \DateTime;
/** /**
* @param string $type * @param string $type
@ -80,19 +80,19 @@ interface INotification {
* @throws \InvalidArgumentException if the object type or id is invalid * @throws \InvalidArgumentException if the object type or id is invalid
* @since 9.0.0 * @since 9.0.0
*/ */
public function setObject(string $type, $id); public function setObject(string $type, string $id): INotification;
/** /**
* @return string * @return string
* @since 9.0.0 * @since 9.0.0
*/ */
public function getObjectType(); public function getObjectType(): string;
/** /**
* @return string * @return string
* @since 9.0.0 * @since 9.0.0
*/ */
public function getObjectId(); public function getObjectId(): string;
/** /**
* @param string $subject * @param string $subject
@ -101,19 +101,19 @@ interface INotification {
* @throws \InvalidArgumentException if the subject or parameters are invalid * @throws \InvalidArgumentException if the subject or parameters are invalid
* @since 9.0.0 * @since 9.0.0
*/ */
public function setSubject(string $subject, array $parameters = []); public function setSubject(string $subject, array $parameters = []): INotification;
/** /**
* @return string * @return string
* @since 9.0.0 * @since 9.0.0
*/ */
public function getSubject(); public function getSubject(): string;
/** /**
* @return string[] * @return array
* @since 9.0.0 * @since 9.0.0
*/ */
public function getSubjectParameters(); public function getSubjectParameters(): array;
/** /**
* Set a parsed subject * Set a parsed subject
@ -132,13 +132,13 @@ interface INotification {
* @throws \InvalidArgumentException if the subject is invalid * @throws \InvalidArgumentException if the subject is invalid
* @since 9.0.0 * @since 9.0.0
*/ */
public function setParsedSubject(string $subject); public function setParsedSubject(string $subject): INotification;
/** /**
* @return string * @return string
* @since 9.0.0 * @since 9.0.0
*/ */
public function getParsedSubject(); public function getParsedSubject(): string;
/** /**
* Set a RichObjectString subject * Set a RichObjectString subject
@ -157,19 +157,19 @@ interface INotification {
* @throws \InvalidArgumentException if the subject or parameters are invalid * @throws \InvalidArgumentException if the subject or parameters are invalid
* @since 11.0.0 * @since 11.0.0
*/ */
public function setRichSubject(string $subject, array $parameters = []); public function setRichSubject(string $subject, array $parameters = []): INotification;
/** /**
* @return string * @return string
* @since 11.0.0 * @since 11.0.0
*/ */
public function getRichSubject(); public function getRichSubject(): string;
/** /**
* @return array[] * @return array[]
* @since 11.0.0 * @since 11.0.0
*/ */
public function getRichSubjectParameters(); public function getRichSubjectParameters(): array;
/** /**
* @param string $message * @param string $message
@ -178,19 +178,19 @@ interface INotification {
* @throws \InvalidArgumentException if the message or parameters are invalid * @throws \InvalidArgumentException if the message or parameters are invalid
* @since 9.0.0 * @since 9.0.0
*/ */
public function setMessage(string $message, array $parameters = []); public function setMessage(string $message, array $parameters = []): INotification;
/** /**
* @return string * @return string
* @since 9.0.0 * @since 9.0.0
*/ */
public function getMessage(); public function getMessage(): string;
/** /**
* @return string[] * @return array
* @since 9.0.0 * @since 9.0.0
*/ */
public function getMessageParameters(); public function getMessageParameters(): array;
/** /**
* Set a parsed message * Set a parsed message
@ -209,13 +209,13 @@ interface INotification {
* @throws \InvalidArgumentException if the message is invalid * @throws \InvalidArgumentException if the message is invalid
* @since 9.0.0 * @since 9.0.0
*/ */
public function setParsedMessage(string $message); public function setParsedMessage(string $message): INotification;
/** /**
* @return string * @return string
* @since 9.0.0 * @since 9.0.0
*/ */
public function getParsedMessage(); public function getParsedMessage(): string;
/** /**
* Set a RichObjectString message * Set a RichObjectString message
@ -234,19 +234,19 @@ interface INotification {
* @throws \InvalidArgumentException if the message or parameters are invalid * @throws \InvalidArgumentException if the message or parameters are invalid
* @since 11.0.0 * @since 11.0.0
*/ */
public function setRichMessage(string $message, array $parameters = []); public function setRichMessage(string $message, array $parameters = []): INotification;
/** /**
* @return string * @return string
* @since 11.0.0 * @since 11.0.0
*/ */
public function getRichMessage(); public function getRichMessage(): string;
/** /**
* @return array[] * @return array[]
* @since 11.0.0 * @since 11.0.0
*/ */
public function getRichMessageParameters(); public function getRichMessageParameters(): array;
/** /**
* @param string $link * @param string $link
@ -254,13 +254,13 @@ interface INotification {
* @throws \InvalidArgumentException if the link is invalid * @throws \InvalidArgumentException if the link is invalid
* @since 9.0.0 * @since 9.0.0
*/ */
public function setLink(string $link); public function setLink(string $link): INotification;
/** /**
* @return string * @return string
* @since 9.0.0 * @since 9.0.0
*/ */
public function getLink(); public function getLink(): string;
/** /**
* @param string $icon * @param string $icon
@ -268,19 +268,19 @@ interface INotification {
* @throws \InvalidArgumentException if the icon is invalid * @throws \InvalidArgumentException if the icon is invalid
* @since 11.0.0 * @since 11.0.0
*/ */
public function setIcon(string $icon); public function setIcon(string $icon): INotification;
/** /**
* @return string * @return string
* @since 11.0.0 * @since 11.0.0
*/ */
public function getIcon(); public function getIcon(): string;
/** /**
* @return IAction * @return IAction
* @since 9.0.0 * @since 9.0.0
*/ */
public function createAction(); public function createAction(): IAction;
/** /**
* @param IAction $action * @param IAction $action
@ -288,13 +288,13 @@ interface INotification {
* @throws \InvalidArgumentException if the action is invalid * @throws \InvalidArgumentException if the action is invalid
* @since 9.0.0 * @since 9.0.0
*/ */
public function addAction(IAction $action); public function addAction(IAction $action): INotification;
/** /**
* @return IAction[] * @return IAction[]
* @since 9.0.0 * @since 9.0.0
*/ */
public function getActions(); public function getActions(): array;
/** /**
* @param IAction $action * @param IAction $action
@ -302,23 +302,23 @@ interface INotification {
* @throws \InvalidArgumentException if the action is invalid * @throws \InvalidArgumentException if the action is invalid
* @since 9.0.0 * @since 9.0.0
*/ */
public function addParsedAction(IAction $action); public function addParsedAction(IAction $action): INotification;
/** /**
* @return IAction[] * @return IAction[]
* @since 9.0.0 * @since 9.0.0
*/ */
public function getParsedActions(); public function getParsedActions(): array;
/** /**
* @return bool * @return bool
* @since 9.0.0 * @since 9.0.0
*/ */
public function isValid(); public function isValid(): bool;
/** /**
* @return bool * @return bool
* @since 9.0.0 * @since 9.0.0
*/ */
public function isValidParsed(); public function isValidParsed(): bool;
} }

View File

@ -1,4 +1,5 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2016, ownCloud, Inc. * @copyright Copyright (c) 2016, ownCloud, Inc.
* *
@ -29,12 +30,30 @@ namespace OCP\Notification;
* @since 9.0.0 * @since 9.0.0
*/ */
interface INotifier { interface INotifier {
/**
* Identifier of the notifier, only use [a-z0-9_]
*
* @return string
* @since 17.0.0
*/
public function getID(): string;
/**
* Human readable name describing the notifier
*
* @return string
* @since 17.0.0
*/
public function getName(): string;
/** /**
* @param INotification $notification * @param INotification $notification
* @param string $languageCode The code of the language that should be used to prepare the notification * @param string $languageCode The code of the language that should be used to prepare the notification
* @return INotification * @return INotification
* @throws \InvalidArgumentException When the notification was not prepared by a notifier * @throws \InvalidArgumentException When the notification was not prepared by a notifier
* @throws AlreadyProcessedException When the notification is not needed anymore and should be deleted
* @since 9.0.0 * @since 9.0.0
*/ */
public function prepare(INotification $notification, $languageCode); public function prepare(INotification $notification, string $languageCode): INotification;
} }

View File

@ -92,7 +92,7 @@ class RemoteWipeNotificationListenerTests extends TestCase {
$token->method('getId')->willReturn(123); $token->method('getId')->willReturn(123);
$notification->expects($this->once()) $notification->expects($this->once())
->method('setObject') ->method('setObject')
->with('token', 123) ->with('token', '123')
->willReturnSelf(); ->willReturnSelf();
$token->method('getName')->willReturn('Token 1'); $token->method('getName')->willReturn('Token 1');
$notification->expects($this->once()) $notification->expects($this->once())
@ -132,7 +132,7 @@ class RemoteWipeNotificationListenerTests extends TestCase {
$token->method('getId')->willReturn(123); $token->method('getId')->willReturn(123);
$notification->expects($this->once()) $notification->expects($this->once())
->method('setObject') ->method('setObject')
->with('token', 123) ->with('token', '123')
->willReturnSelf(); ->willReturnSelf();
$token->method('getName')->willReturn('Token 1'); $token->method('getName')->willReturn('Token 1');
$notification->expects($this->once()) $notification->expects($this->once())

View File

@ -55,14 +55,8 @@ class ActionTest extends TestCase {
public function dataSetLabelInvalid() { public function dataSetLabelInvalid() {
return [ return [
[true],
[false],
[0],
[1],
[''], [''],
[str_repeat('a', 33)], [str_repeat('a', 33)],
[[]],
[[str_repeat('a', 33)]],
]; ];
} }
@ -96,13 +90,7 @@ class ActionTest extends TestCase {
public function dataSetParsedLabelInvalid() { public function dataSetParsedLabelInvalid() {
return [ return [
[true],
[false],
[0],
[1],
[''], [''],
[[]],
[[str_repeat('a', 33)]],
]; ];
} }
@ -140,23 +128,11 @@ class ActionTest extends TestCase {
public function dataSetLinkInvalid() { public function dataSetLinkInvalid() {
return [ return [
// Invalid link // Invalid link
[true, 'GET'],
[false, 'GET'],
[0, 'GET'],
[1, 'GET'],
['', 'GET'], ['', 'GET'],
[str_repeat('a', 257), 'GET'], [str_repeat('a', 257), 'GET'],
[[], 'GET'],
[[str_repeat('a', 257)], 'GET'],
// Invalid type // Invalid type
['url', 'notGET'], ['url', 'notGET'],
['url', true],
['url', false],
['url', 0],
['url', 1],
['url', []],
['url', ['GET']],
]; ];
} }
@ -188,27 +164,6 @@ class ActionTest extends TestCase {
$this->assertSame($primary, $this->action->isPrimary()); $this->assertSame($primary, $this->action->isPrimary());
} }
public function dataSetPrimaryInvalid() {
return [
[0],
[1],
[''],
[str_repeat('a', 257)],
[[]],
[[str_repeat('a', 257)]],
];
}
/**
* @dataProvider dataSetPrimaryInvalid
* @param mixed $primary
*
* @expectedException \InvalidArgumentException
*/
public function testSetPrimaryInvalid($primary) {
$this->action->setPrimary($primary);
}
public function testIsValid() { public function testIsValid() {
$this->assertFalse($this->action->isValid()); $this->assertFalse($this->action->isValid());
$this->assertFalse($this->action->isValidParsed()); $this->assertFalse($this->action->isValidParsed());

View File

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2019 Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace Test\Notification;
use OCP\Notification\IApp;
use OCP\Notification\INotification;
class DummyApp implements IApp {
/**
* @param INotification $notification
* @throws \InvalidArgumentException When the notification is not valid
* @since 9.0.0
*/
public function notify(INotification $notification): void {
// TODO: Implement notify() method.
}
/**
* @param INotification $notification
* @since 9.0.0
*/
public function markProcessed(INotification $notification): void {
// TODO: Implement markProcessed() method.
}
/**
* @param INotification $notification
* @return int
* @since 9.0.0
*/
public function getCount(INotification $notification): int {
// TODO: Implement getCount() method.
}
}

View File

@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2019 Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace Test\Notification;
use OCP\Notification\AlreadyProcessedException;
use OCP\Notification\INotification;
use OCP\Notification\INotifier;
class DummyNotifier implements INotifier {
/**
* Identifier of the notifier, only use [a-z0-9_]
*
* @return string
* @since 17.0.0
*/
public function getID(): string {
// TODO: Implement getID() method.
}
/**
* Human readable name describing the notifier
*
* @return string
* @since 17.0.0
*/
public function getName(): string {
// TODO: Implement getName() method.
}
/**
* @param INotification $notification
* @param string $languageCode The code of the language that should be used to prepare the notification
* @return INotification
* @throws \InvalidArgumentException When the notification was not prepared by a notifier
* @throws AlreadyProcessedException When the notification is not needed anymore and should be deleted
* @since 9.0.0
*/
public function prepare(INotification $notification, string $languageCode): INotification {
// TODO: Implement prepare() method.
}
}

View File

@ -22,162 +22,72 @@
namespace Test\Notification; namespace Test\Notification;
use OC\Notification\Manager; use OC\Notification\Manager;
use OCP\ILogger;
use OCP\Notification\IApp; use OCP\Notification\IApp;
use OCP\Notification\IManager; use OCP\Notification\IManager;
use OCP\Notification\INotification; use OCP\Notification\INotification;
use OCP\Notification\INotifier; use OCP\Notification\INotifier;
use OCP\RichObjectStrings\IValidator; use OCP\RichObjectStrings\IValidator;
use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase; use Test\TestCase;
class ManagerTest extends TestCase { class ManagerTest extends TestCase {
/** @var IManager */ /** @var IManager */
protected $manager; protected $manager;
/** @var IValidator|MockObject */
protected $validator;
/** @var ILogger|MockObject */
protected $logger;
public function setUp() { public function setUp() {
parent::setUp(); parent::setUp();
$validator = $this->createMock(IValidator::class); $this->validator = $this->createMock(IValidator::class);
$this->manager = new Manager($validator); $this->logger = $this->createMock(ILogger::class);
$this->manager = new Manager($this->validator, $this->logger);
} }
public function testRegisterApp() { public function testRegisterApp() {
$app = $this->getMockBuilder(IApp::class)
->disableOriginalConstructor()
->getMock();
$closure = function() use ($app) { $this->assertEquals([], self::invokePrivate($this->manager, 'getApps'));
return $app;
};
$this->assertEquals([], $this->invokePrivate($this->manager, 'getApps')); $this->manager->registerApp(DummyApp::class);
$this->manager->registerApp($closure); $this->assertCount(1, self::invokePrivate($this->manager, 'getApps'));
$this->assertCount(1, self::invokePrivate($this->manager, 'getApps'));
$this->assertEquals([$app], $this->invokePrivate($this->manager, 'getApps')); $this->manager->registerApp(DummyApp::class);
$this->assertEquals([$app], $this->invokePrivate($this->manager, 'getApps'));
$this->manager->registerApp($closure); $this->assertCount(2, self::invokePrivate($this->manager, 'getApps'));
$this->assertEquals([$app, $app], $this->invokePrivate($this->manager, 'getApps'));
} }
/**
* @expectedException \InvalidArgumentException
*/
public function testRegisterAppInvalid() { public function testRegisterAppInvalid() {
$notifier = $this->getMockBuilder(INotifier::class) $this->manager->registerApp(DummyNotifier::class);
->disableOriginalConstructor()
->getMock();
$closure = function() use ($notifier) { $this->logger->expects($this->once())
return $notifier; ->method('error');
}; self::invokePrivate($this->manager, 'getApps');
$this->manager->registerApp($closure);
$this->invokePrivate($this->manager, 'getApps');
} }
public function testRegisterNotifier() { public function testRegisterNotifier() {
$notifier = $this->getMockBuilder(INotifier::class) $this->assertEquals([], self::invokePrivate($this->manager, 'getNotifiers'));
->disableOriginalConstructor()
->getMock();
$closure = function() use ($notifier) { $this->manager->registerNotifierService(DummyNotifier::class);
return $notifier;
};
$this->assertEquals([], $this->invokePrivate($this->manager, 'getNotifiers')); $this->assertCount(1, self::invokePrivate($this->manager, 'getNotifiers'));
$this->assertEquals([], $this->invokePrivate($this->manager, 'listNotifiers')); $this->assertCount(1, self::invokePrivate($this->manager, 'getNotifiers'));
$this->manager->registerNotifier($closure, function() { $this->manager->registerNotifierService(DummyNotifier::class);
return ['id' => 'test1', 'name' => 'Test One'];
});
$this->assertEquals([$notifier], $this->invokePrivate($this->manager, 'getNotifiers')); $this->assertCount(2, self::invokePrivate($this->manager, 'getNotifiers'));
$this->assertEquals(['test1' => 'Test One'], $this->invokePrivate($this->manager, 'listNotifiers'));
$this->assertEquals([$notifier], $this->invokePrivate($this->manager, 'getNotifiers'));
$this->assertEquals(['test1' => 'Test One'], $this->invokePrivate($this->manager, 'listNotifiers'));
$this->manager->registerNotifier($closure, function() {
return ['id' => 'test2', 'name' => 'Test Two'];
});
$this->assertEquals([$notifier, $notifier], $this->invokePrivate($this->manager, 'getNotifiers'));
$this->assertEquals(['test1' => 'Test One', 'test2' => 'Test Two'], $this->invokePrivate($this->manager, 'listNotifiers'));
} }
/**
* @expectedException \InvalidArgumentException
*/
public function testRegisterNotifierInvalid() { public function testRegisterNotifierInvalid() {
$app = $this->getMockBuilder(IApp::class) $this->manager->registerNotifierService(DummyApp::class);
->disableOriginalConstructor()
->getMock();
$closure = function() use ($app) { $this->logger->expects($this->once())
return $app; ->method('error');
}; self::invokePrivate($this->manager, 'getNotifiers');
$this->manager->registerNotifier($closure, function() {
return ['id' => 'test1', 'name' => 'Test One'];
});
$this->invokePrivate($this->manager, 'getNotifiers');
}
public function dataRegisterNotifierInfoInvalid() {
return [
[null],
['No array'],
[['id' => 'test1', 'name' => 'Test One', 'size' => 'Invalid']],
[['no-id' => 'test1', 'name' => 'Test One']],
[['id' => 'test1', 'no-name' => 'Test One']],
];
}
/**
* @dataProvider dataRegisterNotifierInfoInvalid
* @expectedException \InvalidArgumentException
* @param mixed $data
*/
public function testRegisterNotifierInfoInvalid($data) {
$app = $this->getMockBuilder(IApp::class)
->disableOriginalConstructor()
->getMock();
$closure = function() use ($app) {
return $app;
};
$this->manager->registerNotifier($closure, function() use ($data) {
return $data;
});
$this->manager->listNotifiers();
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The given notifier ID test1 is already in use
*/
public function testRegisterNotifierInfoDuplicate() {
$app = $this->getMockBuilder(IApp::class)
->disableOriginalConstructor()
->getMock();
$closure = function() use ($app) {
return $app;
};
$this->manager->registerNotifier($closure, function() {
return ['id' => 'test1', 'name' => 'Test One'];
});
$this->manager->registerNotifier($closure, function() {
return ['id' => 'test1', 'name' => 'Test One'];
});
$this->manager->listNotifiers();
} }
public function testCreateNotification() { public function testCreateNotification() {
@ -194,30 +104,19 @@ class ManagerTest extends TestCase {
->method('isValid') ->method('isValid')
->willReturn(true); ->willReturn(true);
/** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app */ $manager = $this->getMockBuilder(Manager::class)
$app = $this->getMockBuilder(IApp::class) ->setConstructorArgs([
->disableOriginalConstructor() $this->validator,
$this->logger,
])
->setMethods(['getApps'])
->getMock(); ->getMock();
$app->expects($this->once())
->method('notify')
->with($notification);
/** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app2 */ $manager->expects($this->once())
$app2 = $this->getMockBuilder(IApp::class) ->method('getApps')
->disableOriginalConstructor() ->willReturn([]);
->getMock();
$app2->expects($this->once())
->method('notify')
->with($notification);
$this->manager->registerApp(function() use ($app) { $manager->notify($notification);
return $app;
});
$this->manager->registerApp(function() use ($app2) {
return $app2;
});
$this->manager->notify($notification);
} }
/** /**
@ -232,127 +131,18 @@ class ManagerTest extends TestCase {
->method('isValid') ->method('isValid')
->willReturn(false); ->willReturn(false);
$this->manager->notify($notification); $manager = $this->getMockBuilder(Manager::class)
} ->setConstructorArgs([
$this->validator,
public function testPrepare() { $this->logger,
/** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */ ])
$notification = $this->getMockBuilder(INotification::class) ->setMethods(['getApps'])
->disableOriginalConstructor()
->getMock(); ->getMock();
$notification->expects($this->once())
->method('isValidParsed')
->willReturn(true);
/** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification2 */
$notification2 = $this->getMockBuilder(INotification::class)
->disableOriginalConstructor()
->getMock();
$notification2->expects($this->exactly(2))
->method('isValidParsed')
->willReturn(true);
/** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $notifier */ $manager->expects($this->never())
$notifier = $this->getMockBuilder(INotifier::class) ->method('getApps');
->disableOriginalConstructor()
->getMock();
$notifier->expects($this->once())
->method('prepare')
->with($notification, 'en')
->willReturnArgument(0);
/** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $notifier2 */ $manager->notify($notification);
$notifier2 = $this->getMockBuilder(INotifier::class)
->disableOriginalConstructor()
->getMock();
$notifier2->expects($this->once())
->method('prepare')
->with($notification, 'en')
->willReturn($notification2);
$this->manager->registerNotifier(function() use ($notifier) {
return $notifier;
}, function() {
return ['id' => 'test1', 'name' => 'Test One'];
});
$this->manager->registerNotifier(function() use ($notifier2) {
return $notifier2;
}, function() {
return ['id' => 'test2', 'name' => 'Test Two'];
});
$this->assertEquals($notification2, $this->manager->prepare($notification, 'en'));
}
/**
* @expectedException \InvalidArgumentException
*/
public function testPrepareInvalid() {
/** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification = $this->getMockBuilder(INotification::class)
->disableOriginalConstructor()
->getMock();
$notification->expects($this->once())
->method('isValidParsed')
->willReturn(false);
/** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $notifier */
$notifier = $this->getMockBuilder(INotifier::class)
->disableOriginalConstructor()
->getMock();
$notifier->expects($this->once())
->method('prepare')
->with($notification, 'de')
->willReturnArgument(0);
$this->manager->registerNotifier(function() use ($notifier) {
return $notifier;
}, function() {
return ['id' => 'test1', 'name' => 'Test One'];
});
$this->manager->prepare($notification, 'de');
}
public function testPrepareNotifierThrows() {
/** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification = $this->getMockBuilder(INotification::class)
->disableOriginalConstructor()
->getMock();
$notification->expects($this->once())
->method('isValidParsed')
->willReturn(true);
/** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $notifier */
$notifier = $this->getMockBuilder(INotifier::class)
->disableOriginalConstructor()
->getMock();
$notifier->expects($this->once())
->method('prepare')
->with($notification, 'de')
->willThrowException(new \InvalidArgumentException);
$this->manager->registerNotifier(function() use ($notifier) {
return $notifier;
}, function() {
return ['id' => 'test1', 'name' => 'Test One'];
});
$this->assertEquals($notification, $this->manager->prepare($notification, 'de'));
}
/**
* @expectedException \InvalidArgumentException
*/
public function testPrepareNoNotifier() {
/** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification = $this->getMockBuilder(INotification::class)
->disableOriginalConstructor()
->getMock();
$notification->expects($this->once())
->method('isValidParsed')
->willReturn(false);
$this->manager->prepare($notification, 'en');
} }
public function testMarkProcessed() { public function testMarkProcessed() {
@ -361,30 +151,19 @@ class ManagerTest extends TestCase {
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
/** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app */ $manager = $this->getMockBuilder(Manager::class)
$app = $this->getMockBuilder(IApp::class) ->setConstructorArgs([
->disableOriginalConstructor() $this->validator,
$this->logger,
])
->setMethods(['getApps'])
->getMock(); ->getMock();
$app->expects($this->once())
->method('markProcessed')
->with($notification);
/** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app2 */ $manager->expects($this->once())
$app2 = $this->getMockBuilder(IApp::class) ->method('getApps')
->disableOriginalConstructor() ->willReturn([]);
->getMock();
$app2->expects($this->once())
->method('markProcessed')
->with($notification);
$this->manager->registerApp(function() use ($app) { $manager->markProcessed($notification);
return $app;
});
$this->manager->registerApp(function() use ($app2) {
return $app2;
});
$this->manager->markProcessed($notification);
} }
public function testGetCount() { public function testGetCount() {
@ -393,31 +172,18 @@ class ManagerTest extends TestCase {
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
/** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app */ $manager = $this->getMockBuilder(Manager::class)
$app = $this->getMockBuilder(IApp::class) ->setConstructorArgs([
->disableOriginalConstructor() $this->validator,
$this->logger,
])
->setMethods(['getApps'])
->getMock(); ->getMock();
$app->expects($this->once())
->method('getCount')
->with($notification)
->willReturn(21);
/** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app2 */ $manager->expects($this->once())
$app2 = $this->getMockBuilder(IApp::class) ->method('getApps')
->disableOriginalConstructor() ->willReturn([]);
->getMock();
$app2->expects($this->once())
->method('getCount')
->with($notification)
->willReturn(42);
$this->manager->registerApp(function() use ($app) { $manager->getCount($notification);
return $app;
});
$this->manager->registerApp(function() use ($app2) {
return $app2;
});
$this->assertSame(63, $this->manager->getCount($notification));
} }
} }

View File

@ -63,29 +63,6 @@ class NotificationTest extends TestCase {
return $dataSets; return $dataSets;
} }
protected function dataInvalidStringType() {
return [
[true],
[false],
[16412],
[[]],
[null],
];
}
protected function dataInvalidInt() {
return [
[true],
[false],
[''],
['a'],
[str_repeat('a', 256)],
[[]],
[['a']],
[[str_repeat('a', 256)]],
];
}
public function dataSetApp() { public function dataSetApp() {
return $this->dataValidString(32); return $this->dataValidString(32);
} }
@ -104,10 +81,6 @@ class NotificationTest extends TestCase {
return $this->dataInvalidString(32); return $this->dataInvalidString(32);
} }
public function dataSetAppInvalidType() {
return $this->dataInvalidStringType();
}
/** /**
* @dataProvider dataSetAppInvalid * @dataProvider dataSetAppInvalid
* @param mixed $app * @param mixed $app
@ -118,16 +91,6 @@ class NotificationTest extends TestCase {
$this->notification->setApp($app); $this->notification->setApp($app);
} }
/**
* @dataProvider dataSetAppInvalidType
* @param mixed $app
*
* @expectedException \TypeError
*/
public function testSetAppInvalidType($app) {
$this->notification->setApp($app);
}
public function dataSetUser() { public function dataSetUser() {
return $this->dataValidString(64); return $this->dataValidString(64);
@ -147,10 +110,6 @@ class NotificationTest extends TestCase {
return $this->dataInvalidString(64); return $this->dataInvalidString(64);
} }
public function dataSetUserInvalidType() {
return $this->dataInvalidStringType();
}
/** /**
* @dataProvider dataSetUserInvalid * @dataProvider dataSetUserInvalid
* @param mixed $user * @param mixed $user
@ -161,16 +120,6 @@ class NotificationTest extends TestCase {
$this->notification->setUser($user); $this->notification->setUser($user);
} }
/**
* @dataProvider dataSetUserInvalidType
* @param mixed $user
*
* @expectedException \TypeError
*/
public function testSetUserInvalidType($user) {
$this->notification->setUser($user);
}
public function dataSetDateTime() { public function dataSetDateTime() {
$past = new \DateTime(); $past = new \DateTime();
$past->sub(new \DateInterval('P1Y')); $past->sub(new \DateInterval('P1Y'));
@ -216,48 +165,32 @@ class NotificationTest extends TestCase {
public function dataSetObject() { public function dataSetObject() {
return [ return [
['a', '21', '21'], ['a', '21'],
[str_repeat('a', 64), 42, '42'], [str_repeat('a', 64), '42'],
]; ];
} }
/** /**
* @dataProvider dataSetObject * @dataProvider dataSetObject
* @param string $type * @param string $type
* @param int|string $id * @param string $id
* @param string $exptectedId
*/ */
public function testSetObject($type, $id, $exptectedId) { public function testSetObject($type, $id) {
$this->assertSame('', $this->notification->getObjectType()); $this->assertSame('', $this->notification->getObjectType());
$this->assertSame('', $this->notification->getObjectId()); $this->assertSame('', $this->notification->getObjectId());
$this->assertSame($this->notification, $this->notification->setObject($type, $id)); $this->assertSame($this->notification, $this->notification->setObject($type, $id));
$this->assertSame($type, $this->notification->getObjectType()); $this->assertSame($type, $this->notification->getObjectType());
$this->assertSame($exptectedId, $this->notification->getObjectId()); $this->assertSame($id, $this->notification->getObjectId());
} }
public function dataSetObjectTypeInvalid() { public function dataSetObjectTypeInvalid() {
return $this->dataInvalidString(64); return $this->dataInvalidString(64);
} }
/**
* @dataProvider dataSetObjectTypeInvalid
* @param mixed $type
*
* @expectedException \InvalidArgumentException
* @expectedMessage 'The given object type is invalid'
*/
public function testSetObjectTypeInvalid($type) {
$this->notification->setObject($type, 1337);
}
public function dataSetObjectIdInvalid() { public function dataSetObjectIdInvalid() {
return [ return [
[true],
[false],
[''], [''],
[str_repeat('a', 64 + 1)], [str_repeat('a', 64 + 1)],
[[]],
[[str_repeat('a', 64 + 1)]],
]; ];
} }