(WIP) notify user when mentioned in comments Fix doc, and create absolute URL for as notification link. PSR-4 compatibility changes also move notification creation to comments app Do not notify yourself unit test for controller and application smaller fixes - translatable app name - remove doubles in mention array - micro perf optimization - display name: special label for deleted users, keep user id for users that could not be fetched from userManager Comment Notification-Listener Unit Test fix email adresses remove notification when triggering comment was deleted add and adjust tests add missing @license tags simplify NotificationsController registration appinfo simplification, php docs make string easier to translate adjust test replace dispatcher-based listeners with a registration method and interface safer to not pass optional data parameter to setSubject for marking as processed. ID and mention suffices Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de> update comment Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>tags/v11.0RC2
@@ -41,22 +41,33 @@ $activityManager = \OC::$server->getActivityManager(); | |||
$activityManager->registerExtension(function() { | |||
$application = new \OCP\AppFramework\App('comments'); | |||
/** @var \OCA\Comments\Activity\Extension $extension */ | |||
$extension = $application->getContainer()->query('OCA\Comments\Activity\Extension'); | |||
$extension = $application->getContainer()->query(\OCA\Comments\Activity\Extension::class); | |||
return $extension; | |||
}); | |||
$managerListener = function(\OCP\Comments\CommentsEvent $event) use ($activityManager) { | |||
$application = new \OCP\AppFramework\App('comments'); | |||
/** @var \OCA\Comments\Activity\Listener $listener */ | |||
$listener = $application->getContainer()->query('OCA\Comments\Activity\Listener'); | |||
$listener->commentEvent($event); | |||
}; | |||
$eventDispatcher->addListener(\OCP\Comments\CommentsEvent::EVENT_ADD, $managerListener); | |||
$eventDispatcher->addListener(\OCP\Comments\CommentsEntityEvent::EVENT_ENTITY, function(\OCP\Comments\CommentsEntityEvent $event) { | |||
$event->addEntityCollection('files', function($name) { | |||
$nodes = \OC::$server->getUserFolder()->getById(intval($name)); | |||
return !empty($nodes); | |||
}); | |||
}); | |||
$notificationManager = \OC::$server->getNotificationManager(); | |||
$notificationManager->registerNotifier( | |||
function() { | |||
$application = new \OCP\AppFramework\App('comments'); | |||
return $application->getContainer()->query(\OCA\Comments\Notification\Notifier::class); | |||
}, | |||
function () { | |||
$l = \OC::$server->getL10N('comments'); | |||
return ['id' => 'comments', 'name' => $l->t('Comments')]; | |||
} | |||
); | |||
$commentsManager = \OC::$server->getCommentsManager(); | |||
$commentsManager->registerEventHandler(function () { | |||
$application = new \OCP\AppFramework\App('comments'); | |||
/** @var \OCA\Comments\Activity\Extension $extension */ | |||
$handler = $application->getContainer()->query(\OCA\Comments\EventHandler::class); | |||
return $handler; | |||
}); |
@@ -0,0 +1,28 @@ | |||
<?php | |||
/** | |||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de> | |||
* | |||
* @copyright Copyright (c) 2016, ownCloud, Inc. | |||
* @license AGPL-3.0 | |||
* | |||
* This code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License, version 3, | |||
* as published by the Free Software Foundation. | |||
* | |||
* 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, version 3, | |||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
use \OCA\Comments\AppInfo\Application; | |||
$application = new Application(); | |||
$application->registerRoutes($this, ['routes' => [ | |||
['name' => 'Notifications#view', 'url' => '/notifications/view/{id}', 'verb' => 'GET'], | |||
]]); |
@@ -0,0 +1,35 @@ | |||
<?php | |||
/** | |||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de> | |||
* | |||
* @license GNU AGPL version 3 or any later version | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library 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 library. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
namespace OCA\Comments\AppInfo; | |||
use OCA\Comments\Controller\Notifications; | |||
use OCP\AppFramework\App; | |||
class Application extends App { | |||
public function __construct (array $urlParams = array()) { | |||
parent::__construct('comments', $urlParams); | |||
$container = $this->getContainer(); | |||
$container->registerAlias('NotificationsController', Notifications::class); | |||
} | |||
} |
@@ -0,0 +1,138 @@ | |||
<?php | |||
/** | |||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de> | |||
* | |||
* @license GNU AGPL version 3 or any later version | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library 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 library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OCA\Comments\Controller; | |||
use OCP\AppFramework\Controller; | |||
use OCP\AppFramework\Http\NotFoundResponse; | |||
use OCP\AppFramework\Http\RedirectResponse; | |||
use OCP\AppFramework\Http\Response; | |||
use OCP\Comments\IComment; | |||
use OCP\Comments\ICommentsManager; | |||
use OCP\Files\Folder; | |||
use OCP\IRequest; | |||
use OCP\IURLGenerator; | |||
use OCP\IUserSession; | |||
use OCP\Notification\IManager; | |||
/** | |||
* Class Notifications | |||
* | |||
* @package OCA\Comments\Controller | |||
*/ | |||
class Notifications extends Controller { | |||
/** @var Folder */ | |||
protected $folder; | |||
/** @var ICommentsManager */ | |||
protected $commentsManager; | |||
/** @var IURLGenerator */ | |||
protected $urlGenerator; | |||
/** @var IManager */ | |||
protected $notificationManager; | |||
/** @var IUserSession */ | |||
protected $userSession; | |||
/** | |||
* Notifications constructor. | |||
* | |||
* @param string $appName | |||
* @param IRequest $request | |||
* @param ICommentsManager $commentsManager | |||
* @param Folder $folder | |||
* @param IURLGenerator $urlGenerator | |||
* @param IManager $notificationManager | |||
* @param IUserSession $userSession | |||
*/ | |||
public function __construct( | |||
$appName, | |||
IRequest $request, | |||
ICommentsManager $commentsManager, | |||
Folder $folder, | |||
IURLGenerator $urlGenerator, | |||
IManager $notificationManager, | |||
IUserSession $userSession | |||
) { | |||
parent::__construct($appName, $request); | |||
$this->commentsManager = $commentsManager; | |||
$this->folder = $folder; | |||
$this->urlGenerator = $urlGenerator; | |||
$this->notificationManager = $notificationManager; | |||
$this->userSession = $userSession; | |||
} | |||
/** | |||
* @NoAdminRequired | |||
* @NoCSRFRequired | |||
* | |||
* @param string $id the comment ID | |||
* @return Response | |||
*/ | |||
public function view($id) { | |||
try { | |||
$comment = $this->commentsManager->get($id); | |||
if($comment->getObjectType() !== 'files') { | |||
return new NotFoundResponse(); | |||
} | |||
$files = $this->folder->getById($comment->getObjectId()); | |||
if(count($files) === 0) { | |||
$this->markProcessed($comment); | |||
return new NotFoundResponse(); | |||
} | |||
$dir = $this->folder->getRelativePath($files[0]->getParent()->getPath()); | |||
$url = $this->urlGenerator->linkToRouteAbsolute( | |||
'files.view.index', | |||
[ | |||
'dir' => $dir, | |||
'scrollto' => $files[0]->getName() | |||
] | |||
); | |||
$this->markProcessed($comment); | |||
return new RedirectResponse($url); | |||
} catch (\Exception $e) { | |||
return new NotFoundResponse(); | |||
} | |||
} | |||
/** | |||
* Marks the notification about a comment as processed | |||
* @param IComment $comment | |||
*/ | |||
protected function markProcessed(IComment $comment) { | |||
$user = $this->userSession->getUser(); | |||
if(is_null($user)) { | |||
return; | |||
} | |||
$notification = $this->notificationManager->createNotification(); | |||
$notification->setApp('comments') | |||
->setObject('comment', $comment->getId()) | |||
->setSubject('mention') | |||
->setUser($user->getUID()); | |||
$this->notificationManager->markProcessed($notification); | |||
} | |||
} |
@@ -0,0 +1,78 @@ | |||
<?php | |||
/** | |||
* @copyright Copyright (c) 2016 Arthur Schiwon <blizzz@arthur-schiwon.de> | |||
* | |||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de> | |||
* | |||
* @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 OCA\Comments; | |||
use OCA\Comments\Activity\Listener as ActivityListener; | |||
use OCA\Comments\AppInfo\Application; | |||
use OCA\Comments\Notification\Listener as NotificationListener; | |||
use OCP\Comments\CommentsEvent; | |||
use OCP\Comments\ICommentsEventHandler; | |||
/** | |||
* Class EventHandler | |||
* | |||
* @package OCA\Comments | |||
*/ | |||
class EventHandler implements ICommentsEventHandler { | |||
/** @var Application */ | |||
protected $app; | |||
public function __construct(Application $app) { | |||
$this->app = $app; | |||
} | |||
/** | |||
* @param CommentsEvent $event | |||
*/ | |||
public function handle(CommentsEvent $event) { | |||
if($event->getComment()->getObjectType() !== 'files') { | |||
// this is a 'files'-specific Handler | |||
return; | |||
} | |||
if( $event->getEvent() === CommentsEvent::EVENT_ADD | |||
&& $event instanceof CommentsEvent | |||
) { | |||
$this->onAdd($event); | |||
return; | |||
} | |||
} | |||
/** | |||
* @param CommentsEvent $event | |||
*/ | |||
private function onAdd(CommentsEvent $event) { | |||
$c = $this->app->getContainer(); | |||
/** @var NotificationListener $notificationListener */ | |||
$notificationListener = $c->query(NotificationListener::class); | |||
$notificationListener->evaluate($event); | |||
/** @var ActivityListener $listener */ | |||
$activityListener = $c->query(ActivityListener::class); | |||
$activityListener->commentEvent($event); | |||
} | |||
} |
@@ -0,0 +1,130 @@ | |||
<?php | |||
/** | |||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de> | |||
* | |||
* @copyright Copyright (c) 2016, ownCloud, Inc. | |||
* @license AGPL-3.0 | |||
* | |||
* This code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License, version 3, | |||
* as published by the Free Software Foundation. | |||
* | |||
* 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, version 3, | |||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
namespace OCA\Comments\Notification; | |||
use OCP\Comments\CommentsEvent; | |||
use OCP\Comments\IComment; | |||
use OCP\IURLGenerator; | |||
use OCP\IUserManager; | |||
use OCP\Notification\IManager; | |||
class Listener { | |||
/** @var IManager */ | |||
protected $notificationManager; | |||
/** @var IUserManager */ | |||
protected $userManager; | |||
/** @var IURLGenerator */ | |||
protected $urlGenerator; | |||
/** | |||
* Listener constructor. | |||
* | |||
* @param IManager $notificationManager | |||
* @param IUserManager $userManager | |||
* @param IURLGenerator $urlGenerator | |||
*/ | |||
public function __construct( | |||
IManager $notificationManager, | |||
IUserManager $userManager, | |||
IURLGenerator $urlGenerator | |||
) { | |||
$this->notificationManager = $notificationManager; | |||
$this->userManager = $userManager; | |||
$this->urlGenerator = $urlGenerator; | |||
} | |||
/** | |||
* @param CommentsEvent $event | |||
*/ | |||
public function evaluate(CommentsEvent $event) { | |||
$comment = $event->getComment(); | |||
if($comment->getObjectType() !== 'files') { | |||
// comments App serves files only, other object types/apps need to | |||
// register their own ICommentsEventHandler and trigger notifications | |||
return; | |||
} | |||
$mentions = $this->extractMentions($comment->getMessage()); | |||
if(empty($mentions)) { | |||
// no one to notify | |||
return; | |||
} | |||
$notification = $this->instantiateNotification($comment); | |||
foreach($mentions as $mention) { | |||
$user = substr($mention, 1); // @username → username | |||
if( ($comment->getActorType() === 'users' && $user === $comment->getActorId()) | |||
|| !$this->userManager->userExists($user) | |||
) { | |||
// do not notify unknown users or yourself | |||
continue; | |||
} | |||
$notification->setUser($user); | |||
if($event->getEvent() === CommentsEvent::EVENT_DELETE) { | |||
$this->notificationManager->markProcessed($notification); | |||
} else { | |||
$this->notificationManager->notify($notification); | |||
} | |||
} | |||
} | |||
/** | |||
* creates a notification instance and fills it with comment data | |||
* | |||
* @param IComment $comment | |||
* @return \OCP\Notification\INotification | |||
*/ | |||
public function instantiateNotification(IComment $comment) { | |||
$notification = $this->notificationManager->createNotification(); | |||
$notification | |||
->setApp('comments') | |||
->setObject('comment', $comment->getId()) | |||
->setSubject('mention', [ $comment->getObjectType(), $comment->getObjectId() ]) | |||
->setDateTime($comment->getCreationDateTime()) | |||
->setLink($this->urlGenerator->linkToRouteAbsolute( | |||
'comments.Notifications.view', | |||
['id' => $comment->getId()]) | |||
); | |||
return $notification; | |||
} | |||
/** | |||
* extracts @-mentions out of a message body. | |||
* | |||
* @param string $message | |||
* @return string[] containing the mentions, e.g. ['@alice', '@bob'] | |||
*/ | |||
public function extractMentions($message) { | |||
$ok = preg_match_all('/\B@[a-z0-9_\-@\.\']+/i', $message, $mentions); | |||
if(!$ok || !isset($mentions[0]) || !is_array($mentions[0])) { | |||
return []; | |||
} | |||
return array_unique($mentions[0]); | |||
} | |||
} |
@@ -0,0 +1,115 @@ | |||
<?php | |||
/** | |||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de> | |||
* | |||
* @copyright Copyright (c) 2016, ownCloud, Inc. | |||
* @license AGPL-3.0 | |||
* | |||
* This code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License, version 3, | |||
* as published by the Free Software Foundation. | |||
* | |||
* 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, version 3, | |||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
namespace OCA\Comments\Notification; | |||
use OCP\Comments\ICommentsManager; | |||
use OCP\Comments\NotFoundException; | |||
use OCP\Files\Folder; | |||
use OCP\IUserManager; | |||
use OCP\L10N\IFactory; | |||
use OCP\Notification\INotification; | |||
use OCP\Notification\INotifier; | |||
class Notifier implements INotifier { | |||
/** @var IFactory */ | |||
protected $l10nFactory; | |||
/** @var Folder */ | |||
protected $userFolder; | |||
/** @var ICommentsManager */ | |||
protected $commentsManager; | |||
/** @var IUserManager */ | |||
protected $userManager; | |||
public function __construct( | |||
IFactory $l10nFactory, | |||
Folder $userFolder, | |||
ICommentsManager $commentsManager, | |||
IUserManager $userManager | |||
) { | |||
$this->l10nFactory = $l10nFactory; | |||
$this->userFolder = $userFolder; | |||
$this->commentsManager = $commentsManager; | |||
$this->userManager = $userManager; | |||
} | |||
/** | |||
* @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 | |||
*/ | |||
public function prepare(INotification $notification, $languageCode) { | |||
if($notification->getApp() !== 'comments') { | |||
throw new \InvalidArgumentException(); | |||
} | |||
try { | |||
$comment = $this->commentsManager->get($notification->getObjectId()); | |||
} catch(NotFoundException $e) { | |||
// needs to be converted to InvalidArgumentException, otherwise none Notifications will be shown at all | |||
throw new \InvalidArgumentException('Comment not found', 0, $e); | |||
} | |||
$l = $this->l10nFactory->get('comments', $languageCode); | |||
$displayName = $comment->getActorId(); | |||
$isDeletedActor = $comment->getActorType() === ICommentsManager::DELETED_USER; | |||
if($comment->getActorType() === 'users') { | |||
$commenter = $this->userManager->get($comment->getActorId()); | |||
if(!is_null($commenter)) { | |||
$displayName = $commenter->getDisplayName(); | |||
} | |||
} | |||
switch($notification->getSubject()) { | |||
case 'mention': | |||
$parameters = $notification->getSubjectParameters(); | |||
if($parameters[0] !== 'files') { | |||
throw new \InvalidArgumentException('Unsupported comment object'); | |||
} | |||
$nodes = $this->userFolder->getById($parameters[1]); | |||
if(empty($nodes)) { | |||
throw new \InvalidArgumentException('Cannot resolve file id to Node instance'); | |||
} | |||
$fileName = $nodes[0]->getName(); | |||
if($isDeletedActor) { | |||
$subject = (string) $l->t( | |||
'You were mentioned in a comment on "%s" by a now deleted user.', | |||
[ $fileName ] | |||
); | |||
} else { | |||
$subject = (string) $l->t( | |||
'You were mentioned in a comment on "%s" by %s.', | |||
[ $fileName, $displayName ] | |||
); | |||
} | |||
$notification->setParsedSubject($subject); | |||
return $notification; | |||
break; | |||
default: | |||
throw new \InvalidArgumentException('Invalid subject'); | |||
} | |||
} | |||
} |
@@ -0,0 +1,65 @@ | |||
<?php | |||
/** | |||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de> | |||
* | |||
* @copyright Copyright (c) 2016, ownCloud, Inc. | |||
* @license AGPL-3.0 | |||
* | |||
* This code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License, version 3, | |||
* as published by the Free Software Foundation. | |||
* | |||
* 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, version 3, | |||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
namespace OCA\Comments\Tests\Unit\AppInfo; | |||
use OCA\Comments\AppInfo\Application; | |||
use Test\TestCase; | |||
/** | |||
* Class ApplicationTest | |||
* | |||
* @group DB | |||
* | |||
* @package OCA\Comments\Tests\Unit\AppInfo | |||
*/ | |||
class ApplicationTest extends TestCase { | |||
protected function setUp() { | |||
parent::setUp(); | |||
\OC::$server->getUserManager()->createUser('dummy', '456'); | |||
\OC::$server->getUserSession()->setUser(\OC::$server->getUserManager()->get('dummy')); | |||
} | |||
protected function tearDown() { | |||
\OC::$server->getUserManager()->get('dummy')->delete(); | |||
parent::tearDown(); | |||
} | |||
public function test() { | |||
$app = new Application(); | |||
$c = $app->getContainer(); | |||
// assert service instances in the container are properly setup | |||
$s = $c->query('NotificationsController'); | |||
$this->assertInstanceOf('OCA\Comments\Controller\Notifications', $s); | |||
$services = [ | |||
'OCA\Comments\Activity\Extension', | |||
'OCA\Comments\Activity\Listener', | |||
'OCA\Comments\Notification\Listener' | |||
]; | |||
foreach($services as $service) { | |||
$s = $c->query($service); | |||
$this->assertInstanceOf($service, $s); | |||
} | |||
} | |||
} |
@@ -0,0 +1,162 @@ | |||
<?php | |||
/** | |||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de> | |||
* | |||
* @copyright Copyright (c) 2016, ownCloud, Inc. | |||
* @license AGPL-3.0 | |||
* | |||
* This code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License, version 3, | |||
* as published by the Free Software Foundation. | |||
* | |||
* 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, version 3, | |||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
namespace OCA\Comments\Tests\Unit\Controller; | |||
use OCA\Comments\Controller\Notifications; | |||
use OCP\Comments\NotFoundException; | |||
use Test\TestCase; | |||
class NotificationsTest extends TestCase { | |||
/** @var \OCA\Comments\Controller\Notifications */ | |||
protected $notificationsController; | |||
/** @var \OCP\Comments\ICommentsManager|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $commentsManager; | |||
/** @var \OCP\Files\Folder|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $folder; | |||
/** @var \OCP\IUserSession|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $session; | |||
/** @var \OCP\Notification\IManager|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $notificationManager; | |||
protected function setUp() { | |||
parent::setUp(); | |||
$this->commentsManager = $this->getMockBuilder('\OCP\Comments\ICommentsManager')->getMock(); | |||
$this->folder = $this->getMockBuilder('\OCP\Files\Folder')->getMock(); | |||
$this->session = $this->getMockBuilder('\OCP\IUserSession')->getMock(); | |||
$this->notificationManager = $this->getMockBuilder('\OCP\Notification\IManager')->getMock(); | |||
$this->notificationsController = new Notifications( | |||
'comments', | |||
$this->getMockBuilder('\OCP\IRequest')->getMock(), | |||
$this->commentsManager, | |||
$this->folder, | |||
$this->getMockBuilder('\OCP\IURLGenerator')->getMock(), | |||
$this->notificationManager, | |||
$this->session | |||
); | |||
} | |||
public function testViewSuccess() { | |||
$comment = $this->getMockBuilder('\OCP\Comments\IComment')->getMock(); | |||
$comment->expects($this->any()) | |||
->method('getObjectType') | |||
->will($this->returnValue('files')); | |||
$this->commentsManager->expects($this->any()) | |||
->method('get') | |||
->with('42') | |||
->will($this->returnValue($comment)); | |||
$file = $this->getMockBuilder('\OCP\Files\Node')->getMock(); | |||
$file->expects($this->once()) | |||
->method('getParent') | |||
->will($this->returnValue($this->getMockBuilder('\OCP\Files\Folder')->getMock())); | |||
$this->folder->expects($this->once()) | |||
->method('getById') | |||
->will($this->returnValue([$file])); | |||
$this->session->expects($this->once()) | |||
->method('getUser') | |||
->will($this->returnValue($this->getMockBuilder('\OCP\IUser')->getMock())); | |||
$notification = $this->getMockBuilder('\OCP\Notification\INotification')->getMock(); | |||
$notification->expects($this->any()) | |||
->method($this->anything()) | |||
->will($this->returnValue($notification)); | |||
$this->notificationManager->expects($this->once()) | |||
->method('createNotification') | |||
->will($this->returnValue($notification)); | |||
$this->notificationManager->expects($this->once()) | |||
->method('markProcessed') | |||
->with($notification); | |||
$response = $this->notificationsController->view('42'); | |||
$this->assertInstanceOf('\OCP\AppFramework\Http\RedirectResponse', $response); | |||
} | |||
public function testViewInvalidComment() { | |||
$this->commentsManager->expects($this->any()) | |||
->method('get') | |||
->with('42') | |||
->will($this->throwException(new NotFoundException())); | |||
$file = $this->getMockBuilder('\OCP\Files\Node')->getMock(); | |||
$file->expects($this->never()) | |||
->method('getParent'); | |||
$this->folder->expects($this->never()) | |||
->method('getById'); | |||
$this->session->expects($this->never()) | |||
->method('getUser'); | |||
$this->notificationManager->expects($this->never()) | |||
->method('createNotification'); | |||
$this->notificationManager->expects($this->never()) | |||
->method('markProcessed'); | |||
$response = $this->notificationsController->view('42'); | |||
$this->assertInstanceOf('\OCP\AppFramework\Http\NotFoundResponse', $response); | |||
} | |||
public function testViewNoFile() { | |||
$comment = $this->getMockBuilder('\OCP\Comments\IComment')->getMock(); | |||
$comment->expects($this->any()) | |||
->method('getObjectType') | |||
->will($this->returnValue('files')); | |||
$this->commentsManager->expects($this->any()) | |||
->method('get') | |||
->with('42') | |||
->will($this->returnValue($comment)); | |||
$this->folder->expects($this->once()) | |||
->method('getById') | |||
->will($this->returnValue([])); | |||
$this->session->expects($this->once()) | |||
->method('getUser') | |||
->will($this->returnValue($this->getMockBuilder('\OCP\IUser')->getMock())); | |||
$notification = $this->getMockBuilder('\OCP\Notification\INotification')->getMock(); | |||
$notification->expects($this->any()) | |||
->method($this->anything()) | |||
->will($this->returnValue($notification)); | |||
$this->notificationManager->expects($this->once()) | |||
->method('createNotification') | |||
->will($this->returnValue($notification)); | |||
$this->notificationManager->expects($this->once()) | |||
->method('markProcessed') | |||
->with($notification); | |||
$response = $this->notificationsController->view('42'); | |||
$this->assertInstanceOf('\OCP\AppFramework\Http\NotFoundResponse', $response); | |||
} | |||
} |
@@ -0,0 +1,152 @@ | |||
<?php | |||
/** | |||
* @copyright Copyright (c) 2016 Arthur Schiwon <blizzz@arthur-schiwon.de> | |||
* | |||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de> | |||
* | |||
* @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 OCA\Comments\Tests\Unit\Notification; | |||
use OCA\Comments\AppInfo\Application; | |||
use OCA\Comments\EventHandler; | |||
use OCP\Comments\CommentsEvent; | |||
use OCP\Comments\IComment; | |||
use OCA\Comments\Activity\Listener as ActivityListener; | |||
use OCA\Comments\Notification\Listener as NotificationListener; | |||
use OCP\IContainer; | |||
use Test\TestCase; | |||
class EventHandlerTest extends TestCase { | |||
/** @var EventHandler */ | |||
protected $eventHandler; | |||
/** @var Application|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $app; | |||
protected function setUp() { | |||
parent::setUp(); | |||
$this->app = $this->getMockBuilder(Application::class) | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$this->eventHandler = new EventHandler($this->app); | |||
} | |||
public function testNotFiles() { | |||
/** @var IComment|\PHPUnit_Framework_MockObject_MockObject $comment */ | |||
$comment = $this->getMockBuilder(IComment::class)->getMock(); | |||
$comment->expects($this->once()) | |||
->method('getObjectType') | |||
->willReturn('smiles'); | |||
/** @var CommentsEvent|\PHPUnit_Framework_MockObject_MockObject $event */ | |||
$event = $this->getMockBuilder(CommentsEvent::class) | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$event->expects($this->once()) | |||
->method('getComment') | |||
->willReturn($comment); | |||
$event->expects($this->never()) | |||
->method('getEvent'); | |||
$this->eventHandler->handle($event); | |||
} | |||
public function notHandledProvider() { | |||
return [ | |||
[CommentsEvent::EVENT_DELETE], | |||
[CommentsEvent::EVENT_UPDATE] | |||
]; | |||
} | |||
/** | |||
* @dataProvider notHandledProvider | |||
* @param $eventType | |||
*/ | |||
public function testNotHandled($eventType) { | |||
/** @var IComment|\PHPUnit_Framework_MockObject_MockObject $comment */ | |||
$comment = $this->getMockBuilder(IComment::class)->getMock(); | |||
$comment->expects($this->once()) | |||
->method('getObjectType') | |||
->willReturn('files'); | |||
/** @var CommentsEvent|\PHPUnit_Framework_MockObject_MockObject $event */ | |||
$event = $this->getMockBuilder(CommentsEvent::class) | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$event->expects($this->once()) | |||
->method('getComment') | |||
->willReturn($comment); | |||
$event->expects($this->once()) | |||
->method('getEvent') | |||
->willReturn($eventType); | |||
// further processing does not happen, because $event methods cannot be | |||
// access more than once. | |||
$this->eventHandler->handle($event); | |||
} | |||
public function testHandled() { | |||
/** @var IComment|\PHPUnit_Framework_MockObject_MockObject $comment */ | |||
$comment = $this->getMockBuilder(IComment::class)->getMock(); | |||
$comment->expects($this->once()) | |||
->method('getObjectType') | |||
->willReturn('files'); | |||
/** @var CommentsEvent|\PHPUnit_Framework_MockObject_MockObject $event */ | |||
$event = $this->getMockBuilder(CommentsEvent::class) | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$event->expects($this->atLeastOnce()) | |||
->method('getComment') | |||
->willReturn($comment); | |||
$event->expects($this->atLeastOnce()) | |||
->method('getEvent') | |||
->willReturn(CommentsEvent::EVENT_ADD); | |||
$notificationListener = $this->getMockBuilder(NotificationListener::class) | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$notificationListener->expects($this->once()) | |||
->method('evaluate') | |||
->with($event); | |||
$activityListener = $this->getMockBuilder(ActivityListener::class) | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$activityListener->expects($this->once()) | |||
->method('commentEvent') | |||
->with($event); | |||
/** @var IContainer|\PHPUnit_Framework_MockObject_MockObject $c */ | |||
$c = $this->getMockBuilder(IContainer::class)->getMock(); | |||
$c->expects($this->exactly(2)) | |||
->method('query') | |||
->withConsecutive([NotificationListener::class], [ActivityListener::class]) | |||
->willReturnOnConsecutiveCalls($notificationListener, $activityListener); | |||
$this->app->expects($this->once()) | |||
->method('getContainer') | |||
->willReturn($c); | |||
$this->eventHandler->handle($event); | |||
} | |||
} |
@@ -0,0 +1,360 @@ | |||
<?php | |||
/** | |||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de> | |||
* | |||
* @copyright Copyright (c) 2016, ownCloud, Inc. | |||
* @license AGPL-3.0 | |||
* | |||
* This code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License, version 3, | |||
* as published by the Free Software Foundation. | |||
* | |||
* 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, version 3, | |||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
namespace OCA\Comments\Tests\Unit\Notification; | |||
use OCA\Comments\Notification\Listener; | |||
use OCP\Comments\CommentsEvent; | |||
use OCP\Comments\IComment; | |||
use OCP\IURLGenerator; | |||
use OCP\IUserManager; | |||
use OCP\Notification\IManager; | |||
use OCP\Notification\INotification; | |||
use Test\TestCase; | |||
class ListenerTest extends TestCase { | |||
/** @var IManager|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $notificationManager; | |||
/** @var IUserManager|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $userManager; | |||
/** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $urlGenerator; | |||
/** @var Listener */ | |||
protected $listener; | |||
protected function setUp() { | |||
parent::setUp(); | |||
$this->notificationManager = $this->getMockBuilder('\OCP\Notification\IManager')->getMock(); | |||
$this->userManager = $this->getMockBuilder('\OCP\IUserManager')->getMock(); | |||
$this->urlGenerator = $this->getMockBuilder('OCP\IURLGenerator')->getMock(); | |||
$this->listener = new Listener( | |||
$this->notificationManager, | |||
$this->userManager, | |||
$this->urlGenerator | |||
); | |||
} | |||
public function eventProvider() { | |||
return [ | |||
[CommentsEvent::EVENT_ADD, 'notify'], | |||
[CommentsEvent::EVENT_DELETE, 'markProcessed'] | |||
]; | |||
} | |||
/** | |||
* @dataProvider eventProvider | |||
* @param string $eventType | |||
* @param string $notificationMethod | |||
*/ | |||
public function testEvaluate($eventType, $notificationMethod) { | |||
$message = '@foobar and @barfoo you should know, @foo@bar.com is valid' . | |||
' and so is @bar@foo.org@foobar.io I hope that clarifies everything.' . | |||
' cc @23452-4333-54353-2342 @yolo!'; | |||
/** @var IComment|\PHPUnit_Framework_MockObject_MockObject $comment */ | |||
$comment = $this->getMockBuilder('\OCP\Comments\IComment')->getMock(); | |||
$comment->expects($this->any()) | |||
->method('getObjectType') | |||
->will($this->returnValue('files')); | |||
$comment->expects($this->any()) | |||
->method('getCreationDateTime') | |||
->will($this->returnValue(new \DateTime())); | |||
$comment->expects($this->once()) | |||
->method('getMessage') | |||
->will($this->returnValue($message)); | |||
/** @var CommentsEvent|\PHPUnit_Framework_MockObject_MockObject $event */ | |||
$event = $this->getMockBuilder('\OCP\Comments\CommentsEvent') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$event->expects($this->once()) | |||
->method('getComment') | |||
->will($this->returnValue($comment)); | |||
$event->expects(($this->any())) | |||
->method(('getEvent')) | |||
->will($this->returnValue($eventType)); | |||
/** @var INotification|\PHPUnit_Framework_MockObject_MockObject $notification */ | |||
$notification = $this->getMockBuilder('\OCP\Notification\INotification')->getMock(); | |||
$notification->expects($this->any()) | |||
->method($this->anything()) | |||
->will($this->returnValue($notification)); | |||
$notification->expects($this->exactly(6)) | |||
->method('setUser'); | |||
$this->notificationManager->expects($this->once()) | |||
->method('createNotification') | |||
->will($this->returnValue($notification)); | |||
$this->notificationManager->expects($this->exactly(6)) | |||
->method($notificationMethod) | |||
->with($this->isInstanceOf('\OCP\Notification\INotification')); | |||
$this->userManager->expects($this->exactly(6)) | |||
->method('userExists') | |||
->withConsecutive( | |||
['foobar'], | |||
['barfoo'], | |||
['foo@bar.com'], | |||
['bar@foo.org@foobar.io'], | |||
['23452-4333-54353-2342'], | |||
['yolo'] | |||
) | |||
->will($this->returnValue(true)); | |||
$this->listener->evaluate($event); | |||
} | |||
/** | |||
* @dataProvider eventProvider | |||
* @param string $eventType | |||
*/ | |||
public function testEvaluateNoMentions($eventType) { | |||
$message = 'a boring comment without mentions'; | |||
/** @var IComment|\PHPUnit_Framework_MockObject_MockObject $comment */ | |||
$comment = $this->getMockBuilder('\OCP\Comments\IComment')->getMock(); | |||
$comment->expects($this->any()) | |||
->method('getObjectType') | |||
->will($this->returnValue('files')); | |||
$comment->expects($this->any()) | |||
->method('getCreationDateTime') | |||
->will($this->returnValue(new \DateTime())); | |||
$comment->expects($this->once()) | |||
->method('getMessage') | |||
->will($this->returnValue($message)); | |||
/** @var CommentsEvent|\PHPUnit_Framework_MockObject_MockObject $event */ | |||
$event = $this->getMockBuilder('\OCP\Comments\CommentsEvent') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$event->expects($this->once()) | |||
->method('getComment') | |||
->will($this->returnValue($comment)); | |||
$event->expects(($this->any())) | |||
->method(('getEvent')) | |||
->will($this->returnValue($eventType)); | |||
$this->notificationManager->expects($this->never()) | |||
->method('createNotification'); | |||
$this->notificationManager->expects($this->never()) | |||
->method('notify'); | |||
$this->notificationManager->expects($this->never()) | |||
->method('markProcessed'); | |||
$this->userManager->expects($this->never()) | |||
->method('userExists'); | |||
$this->listener->evaluate($event); | |||
} | |||
public function testUnsupportedCommentObjectType() { | |||
/** @var IComment|\PHPUnit_Framework_MockObject_MockObject $comment */ | |||
$comment = $this->getMockBuilder('\OCP\Comments\IComment')->getMock(); | |||
$comment->expects($this->once()) | |||
->method('getObjectType') | |||
->will($this->returnValue('vcards')); | |||
$comment->expects($this->never()) | |||
->method('getMessage'); | |||
/** @var CommentsEvent|\PHPUnit_Framework_MockObject_MockObject $event */ | |||
$event = $this->getMockBuilder('\OCP\Comments\CommentsEvent') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$event->expects($this->once()) | |||
->method('getComment') | |||
->will($this->returnValue($comment)); | |||
$event->expects(($this->any())) | |||
->method(('getEvent')) | |||
->will($this->returnValue(CommentsEvent::EVENT_ADD)); | |||
$this->listener->evaluate($event); | |||
} | |||
public function testEvaluateUserDoesNotExist() { | |||
$message = '@foobar bla bla bla'; | |||
/** @var IComment|\PHPUnit_Framework_MockObject_MockObject $comment */ | |||
$comment = $this->getMockBuilder('\OCP\Comments\IComment')->getMock(); | |||
$comment->expects($this->any()) | |||
->method('getObjectType') | |||
->will($this->returnValue('files')); | |||
$comment->expects($this->any()) | |||
->method('getCreationDateTime') | |||
->will($this->returnValue(new \DateTime())); | |||
$comment->expects($this->once()) | |||
->method('getMessage') | |||
->will($this->returnValue($message)); | |||
/** @var CommentsEvent|\PHPUnit_Framework_MockObject_MockObject $event */ | |||
$event = $this->getMockBuilder('\OCP\Comments\CommentsEvent') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$event->expects($this->once()) | |||
->method('getComment') | |||
->will($this->returnValue($comment)); | |||
$event->expects(($this->any())) | |||
->method(('getEvent')) | |||
->will($this->returnValue(CommentsEvent::EVENT_ADD)); | |||
/** @var INotification|\PHPUnit_Framework_MockObject_MockObject $notification */ | |||
$notification = $this->getMockBuilder('\OCP\Notification\INotification')->getMock(); | |||
$notification->expects($this->any()) | |||
->method($this->anything()) | |||
->will($this->returnValue($notification)); | |||
$notification->expects($this->never()) | |||
->method('setUser'); | |||
$this->notificationManager->expects($this->once()) | |||
->method('createNotification') | |||
->will($this->returnValue($notification)); | |||
$this->notificationManager->expects($this->never()) | |||
->method('notify'); | |||
$this->userManager->expects($this->once()) | |||
->method('userExists') | |||
->withConsecutive( | |||
['foobar'] | |||
) | |||
->will($this->returnValue(false)); | |||
$this->listener->evaluate($event); | |||
} | |||
/** | |||
* @dataProvider eventProvider | |||
* @param string $eventType | |||
* @param string $notificationMethod | |||
*/ | |||
public function testEvaluateOneMentionPerUser($eventType, $notificationMethod) { | |||
$message = '@foobar bla bla bla @foobar'; | |||
/** @var IComment|\PHPUnit_Framework_MockObject_MockObject $comment */ | |||
$comment = $this->getMockBuilder('\OCP\Comments\IComment')->getMock(); | |||
$comment->expects($this->any()) | |||
->method('getObjectType') | |||
->will($this->returnValue('files')); | |||
$comment->expects($this->any()) | |||
->method('getCreationDateTime') | |||
->will($this->returnValue(new \DateTime())); | |||
$comment->expects($this->once()) | |||
->method('getMessage') | |||
->will($this->returnValue($message)); | |||
/** @var CommentsEvent|\PHPUnit_Framework_MockObject_MockObject $event */ | |||
$event = $this->getMockBuilder('\OCP\Comments\CommentsEvent') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$event->expects($this->once()) | |||
->method('getComment') | |||
->will($this->returnValue($comment)); | |||
$event->expects(($this->any())) | |||
->method(('getEvent')) | |||
->will($this->returnValue($eventType)); | |||
/** @var INotification|\PHPUnit_Framework_MockObject_MockObject $notification */ | |||
$notification = $this->getMockBuilder('\OCP\Notification\INotification')->getMock(); | |||
$notification->expects($this->any()) | |||
->method($this->anything()) | |||
->will($this->returnValue($notification)); | |||
$notification->expects($this->once()) | |||
->method('setUser'); | |||
$this->notificationManager->expects($this->once()) | |||
->method('createNotification') | |||
->will($this->returnValue($notification)); | |||
$this->notificationManager->expects($this->once()) | |||
->method($notificationMethod) | |||
->with($this->isInstanceOf('\OCP\Notification\INotification')); | |||
$this->userManager->expects($this->once()) | |||
->method('userExists') | |||
->withConsecutive( | |||
['foobar'] | |||
) | |||
->will($this->returnValue(true)); | |||
$this->listener->evaluate($event); | |||
} | |||
/** | |||
* @dataProvider eventProvider | |||
* @param string $eventType | |||
*/ | |||
public function testEvaluateNoSelfMention($eventType) { | |||
$message = '@foobar bla bla bla'; | |||
/** @var IComment|\PHPUnit_Framework_MockObject_MockObject $comment */ | |||
$comment = $this->getMockBuilder('\OCP\Comments\IComment')->getMock(); | |||
$comment->expects($this->any()) | |||
->method('getObjectType') | |||
->will($this->returnValue('files')); | |||
$comment->expects($this->any()) | |||
->method('getActorType') | |||
->will($this->returnValue('users')); | |||
$comment->expects($this->any()) | |||
->method('getActorId') | |||
->will($this->returnValue('foobar')); | |||
$comment->expects($this->any()) | |||
->method('getCreationDateTime') | |||
->will($this->returnValue(new \DateTime())); | |||
$comment->expects($this->once()) | |||
->method('getMessage') | |||
->will($this->returnValue($message)); | |||
/** @var CommentsEvent|\PHPUnit_Framework_MockObject_MockObject $event */ | |||
$event = $this->getMockBuilder('\OCP\Comments\CommentsEvent') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$event->expects($this->once()) | |||
->method('getComment') | |||
->will($this->returnValue($comment)); | |||
$event->expects(($this->any())) | |||
->method(('getEvent')) | |||
->will($this->returnValue($eventType)); | |||
/** @var INotification|\PHPUnit_Framework_MockObject_MockObject $notification */ | |||
$notification = $this->getMockBuilder('\OCP\Notification\INotification')->getMock(); | |||
$notification->expects($this->any()) | |||
->method($this->anything()) | |||
->will($this->returnValue($notification)); | |||
$notification->expects($this->never()) | |||
->method('setUser'); | |||
$this->notificationManager->expects($this->once()) | |||
->method('createNotification') | |||
->will($this->returnValue($notification)); | |||
$this->notificationManager->expects($this->never()) | |||
->method('notify'); | |||
$this->notificationManager->expects($this->never()) | |||
->method('markProcessed'); | |||
$this->userManager->expects($this->never()) | |||
->method('userExists'); | |||
$this->listener->evaluate($event); | |||
} | |||
} |
@@ -0,0 +1,499 @@ | |||
<?php | |||
/** | |||
* @copyright Copyright (c) 2016 Arthur Schiwon <blizzz@arthur-schiwon.de> | |||
* | |||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de> | |||
* | |||
* @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 OCA\Comments\Tests\Unit\Notification; | |||
use OCA\Comments\Notification\Notifier; | |||
use OCP\Comments\IComment; | |||
use OCP\Comments\ICommentsManager; | |||
use OCP\Comments\NotFoundException; | |||
use OCP\Files\Folder; | |||
use OCP\Files\Node; | |||
use OCP\IL10N; | |||
use OCP\IUser; | |||
use OCP\IUserManager; | |||
use OCP\L10N\IFactory; | |||
use OCP\Notification\INotification; | |||
use Test\TestCase; | |||
class NotifierTest extends TestCase { | |||
/** @var Notifier */ | |||
protected $notifier; | |||
/** @var IFactory|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $l10nFactory; | |||
/** @var Folder|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $folder; | |||
/** @var ICommentsManager|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $commentsManager; | |||
/** @var IUserManager|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $userManager; | |||
/** @var string */ | |||
protected $lc = 'tlh_KX'; | |||
/** @var INotification|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $notification; | |||
/** @var IL10N|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $l; | |||
/** @var IComment|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $comment; | |||
protected function setUp() { | |||
parent::setUp(); | |||
$this->l10nFactory = $this->getMockBuilder('OCP\L10N\IFactory')->getMock(); | |||
$this->folder = $this->getMockBuilder('OCP\Files\Folder')->getMock(); | |||
$this->commentsManager = $this->getMockBuilder('OCP\Comments\ICommentsManager')->getMock(); | |||
$this->userManager = $this->getMockBuilder('OCP\IUserManager')->getMock(); | |||
$this->notifier = new Notifier( | |||
$this->l10nFactory, | |||
$this->folder, | |||
$this->commentsManager, | |||
$this->userManager | |||
); | |||
$this->l = $this->getMockBuilder('OCP\IL10N')->getMock(); | |||
$this->notification = $this->getMockBuilder('OCP\Notification\INotification')->getMock(); | |||
$this->comment = $this->getMockBuilder('OCP\Comments\IComment')->getMock(); | |||
} | |||
public function testPrepareSuccess() { | |||
$fileName = 'Gre\'thor.odp'; | |||
$displayName = 'Huraga'; | |||
$message = 'You were mentioned in a comment on "Gre\'thor.odp" by Huraga.'; | |||
/** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */ | |||
$user = $this->getMockBuilder('OCP\IUser')->getMock(); | |||
$user->expects($this->once()) | |||
->method('getDisplayName') | |||
->willReturn($displayName); | |||
/** @var Node|\PHPUnit_Framework_MockObject_MockObject */ | |||
$node = $this->getMockBuilder('OCP\Files\Node')->getMock(); | |||
$node | |||
->expects($this->once()) | |||
->method('getName') | |||
->willReturn($fileName); | |||
$this->folder | |||
->expects($this->once()) | |||
->method('getById') | |||
->with('678') | |||
->willReturn([$node]); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('getApp') | |||
->willReturn('comments'); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('getSubject') | |||
->willReturn('mention'); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('getSubjectParameters') | |||
->willReturn(['files', '678']); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('setParsedSubject') | |||
->with($message); | |||
$this->l | |||
->expects($this->once()) | |||
->method('t') | |||
->with('You were mentioned in a comment on "%s" by %s.', [$fileName, $displayName]) | |||
->willReturn($message); | |||
$this->l10nFactory | |||
->expects($this->once()) | |||
->method('get') | |||
->willReturn($this->l); | |||
$this->comment | |||
->expects($this->any()) | |||
->method('getActorId') | |||
->willReturn('huraga'); | |||
$this->comment | |||
->expects($this->any()) | |||
->method('getActorType') | |||
->willReturn('users'); | |||
$this->commentsManager | |||
->expects(($this->once())) | |||
->method('get') | |||
->willReturn($this->comment); | |||
$this->userManager | |||
->expects($this->once()) | |||
->method('get') | |||
->with('huraga') | |||
->willReturn($user); | |||
$this->notifier->prepare($this->notification, $this->lc); | |||
} | |||
public function testPrepareSuccessDeletedUser() { | |||
$fileName = 'Gre\'thor.odp'; | |||
$displayName = 'a now deleted user'; | |||
$message = 'You were mentioned in a comment on "Gre\'thor.odp" by a now deleted user.'; | |||
/** @var Node|\PHPUnit_Framework_MockObject_MockObject */ | |||
$node = $this->getMockBuilder('OCP\Files\Node')->getMock(); | |||
$node | |||
->expects($this->once()) | |||
->method('getName') | |||
->willReturn($fileName); | |||
$this->folder | |||
->expects($this->once()) | |||
->method('getById') | |||
->with('678') | |||
->willReturn([$node]); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('getApp') | |||
->willReturn('comments'); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('getSubject') | |||
->willReturn('mention'); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('getSubjectParameters') | |||
->willReturn(['files', '678']); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('setParsedSubject') | |||
->with($message); | |||
$this->l | |||
->expects($this->once()) | |||
->method('t') | |||
->with('You were mentioned in a comment on "%s" by a now deleted user.', [ $fileName ]) | |||
->willReturn($message); | |||
$this->l10nFactory | |||
->expects($this->once()) | |||
->method('get') | |||
->willReturn($this->l); | |||
$this->comment | |||
->expects($this->any()) | |||
->method('getActorId') | |||
->willReturn('huraga'); | |||
$this->comment | |||
->expects($this->any()) | |||
->method('getActorType') | |||
->willReturn(ICommentsManager::DELETED_USER); | |||
$this->commentsManager | |||
->expects(($this->once())) | |||
->method('get') | |||
->willReturn($this->comment); | |||
$this->userManager | |||
->expects($this->never()) | |||
->method('get'); | |||
$this->notifier->prepare($this->notification, $this->lc); | |||
} | |||
/** | |||
* @expectedException \InvalidArgumentException | |||
*/ | |||
public function testPrepareDifferentApp() { | |||
$this->folder | |||
->expects($this->never()) | |||
->method('getById'); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('getApp') | |||
->willReturn('constructions'); | |||
$this->notification | |||
->expects($this->never()) | |||
->method('getSubject'); | |||
$this->notification | |||
->expects($this->never()) | |||
->method('getSubjectParameters'); | |||
$this->notification | |||
->expects($this->never()) | |||
->method('setParsedSubject'); | |||
$this->l10nFactory | |||
->expects($this->never()) | |||
->method('get'); | |||
$this->commentsManager | |||
->expects(($this->never())) | |||
->method('get'); | |||
$this->userManager | |||
->expects($this->never()) | |||
->method('get'); | |||
$this->notifier->prepare($this->notification, $this->lc); | |||
} | |||
/** | |||
* @expectedException \InvalidArgumentException | |||
*/ | |||
public function testPrepareNotFound() { | |||
$this->folder | |||
->expects($this->never()) | |||
->method('getById'); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('getApp') | |||
->willReturn('comments'); | |||
$this->notification | |||
->expects($this->never()) | |||
->method('getSubject'); | |||
$this->notification | |||
->expects($this->never()) | |||
->method('getSubjectParameters'); | |||
$this->notification | |||
->expects($this->never()) | |||
->method('setParsedSubject'); | |||
$this->l10nFactory | |||
->expects($this->never()) | |||
->method('get'); | |||
$this->commentsManager | |||
->expects(($this->once())) | |||
->method('get') | |||
->willThrowException(new NotFoundException()); | |||
$this->userManager | |||
->expects($this->never()) | |||
->method('get'); | |||
$this->notifier->prepare($this->notification, $this->lc); | |||
} | |||
/** | |||
* @expectedException \InvalidArgumentException | |||
*/ | |||
public function testPrepareDifferentSubject() { | |||
$displayName = 'Huraga'; | |||
/** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */ | |||
$user = $this->getMockBuilder('OCP\IUser')->getMock(); | |||
$user->expects($this->once()) | |||
->method('getDisplayName') | |||
->willReturn($displayName); | |||
$this->folder | |||
->expects($this->never()) | |||
->method('getById'); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('getApp') | |||
->willReturn('comments'); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('getSubject') | |||
->willReturn('unlike'); | |||
$this->notification | |||
->expects($this->never()) | |||
->method('getSubjectParameters'); | |||
$this->notification | |||
->expects($this->never()) | |||
->method('setParsedSubject'); | |||
$this->l | |||
->expects($this->never()) | |||
->method('t'); | |||
$this->l10nFactory | |||
->expects($this->once()) | |||
->method('get') | |||
->willReturn($this->l); | |||
$this->comment | |||
->expects($this->any()) | |||
->method('getActorId') | |||
->willReturn('huraga'); | |||
$this->comment | |||
->expects($this->any()) | |||
->method('getActorType') | |||
->willReturn('users'); | |||
$this->commentsManager | |||
->expects(($this->once())) | |||
->method('get') | |||
->willReturn($this->comment); | |||
$this->userManager | |||
->expects($this->once()) | |||
->method('get') | |||
->with('huraga') | |||
->willReturn($user); | |||
$this->notifier->prepare($this->notification, $this->lc); | |||
} | |||
/** | |||
* @expectedException \InvalidArgumentException | |||
*/ | |||
public function testPrepareNotFiles() { | |||
$displayName = 'Huraga'; | |||
/** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */ | |||
$user = $this->getMockBuilder('OCP\IUser')->getMock(); | |||
$user->expects($this->once()) | |||
->method('getDisplayName') | |||
->willReturn($displayName); | |||
$this->folder | |||
->expects($this->never()) | |||
->method('getById'); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('getApp') | |||
->willReturn('comments'); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('getSubject') | |||
->willReturn('mention'); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('getSubjectParameters') | |||
->willReturn(['ships', '678']); | |||
$this->notification | |||
->expects($this->never()) | |||
->method('setParsedSubject'); | |||
$this->l | |||
->expects($this->never()) | |||
->method('t'); | |||
$this->l10nFactory | |||
->expects($this->once()) | |||
->method('get') | |||
->willReturn($this->l); | |||
$this->comment | |||
->expects($this->any()) | |||
->method('getActorId') | |||
->willReturn('huraga'); | |||
$this->comment | |||
->expects($this->any()) | |||
->method('getActorType') | |||
->willReturn('users'); | |||
$this->commentsManager | |||
->expects(($this->once())) | |||
->method('get') | |||
->willReturn($this->comment); | |||
$this->userManager | |||
->expects($this->once()) | |||
->method('get') | |||
->with('huraga') | |||
->willReturn($user); | |||
$this->notifier->prepare($this->notification, $this->lc); | |||
} | |||
/** | |||
* @expectedException \InvalidArgumentException | |||
*/ | |||
public function testPrepareUnresolvableFileID() { | |||
$displayName = 'Huraga'; | |||
/** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */ | |||
$user = $this->getMockBuilder('OCP\IUser')->getMock(); | |||
$user->expects($this->once()) | |||
->method('getDisplayName') | |||
->willReturn($displayName); | |||
$this->folder | |||
->expects($this->once()) | |||
->method('getById') | |||
->with('678') | |||
->willReturn([]); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('getApp') | |||
->willReturn('comments'); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('getSubject') | |||
->willReturn('mention'); | |||
$this->notification | |||
->expects($this->once()) | |||
->method('getSubjectParameters') | |||
->willReturn(['files', '678']); | |||
$this->notification | |||
->expects($this->never()) | |||
->method('setParsedSubject'); | |||
$this->l | |||
->expects($this->never()) | |||
->method('t'); | |||
$this->l10nFactory | |||
->expects($this->once()) | |||
->method('get') | |||
->willReturn($this->l); | |||
$this->comment | |||
->expects($this->any()) | |||
->method('getActorId') | |||
->willReturn('huraga'); | |||
$this->comment | |||
->expects($this->any()) | |||
->method('getActorType') | |||
->willReturn('users'); | |||
$this->commentsManager | |||
->expects(($this->once())) | |||
->method('get') | |||
->willReturn($this->comment); | |||
$this->userManager | |||
->expects($this->once()) | |||
->method('get') | |||
->with('huraga') | |||
->willReturn($user); | |||
$this->notifier->prepare($this->notification, $this->lc); | |||
} | |||
} |
@@ -161,6 +161,10 @@ class DIContainer extends SimpleContainer implements IAppContainer { | |||
return $this->getServer()->getRootFolder(); | |||
}); | |||
$this->registerService('OCP\\Files\\Folder', function() { | |||
return $this->getServer()->getUserFolder(); | |||
}); | |||
$this->registerService('OCP\\Http\\Client\\IClientService', function($c) { | |||
return $this->getServer()->getHTTPClientService(); | |||
}); |
@@ -26,6 +26,7 @@ namespace OC\Comments; | |||
use Doctrine\DBAL\Exception\DriverException; | |||
use OCP\Comments\CommentsEvent; | |||
use OCP\Comments\IComment; | |||
use OCP\Comments\ICommentsEventHandler; | |||
use OCP\Comments\ICommentsManager; | |||
use OCP\Comments\NotFoundException; | |||
use OCP\DB\QueryBuilder\IQueryBuilder; | |||
@@ -33,7 +34,6 @@ use OCP\IDBConnection; | |||
use OCP\IConfig; | |||
use OCP\ILogger; | |||
use OCP\IUser; | |||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | |||
class Manager implements ICommentsManager { | |||
@@ -46,30 +46,30 @@ class Manager implements ICommentsManager { | |||
/** @var IConfig */ | |||
protected $config; | |||
/** @var EventDispatcherInterface */ | |||
protected $dispatcher; | |||
/** @var IComment[] */ | |||
protected $commentsCache = []; | |||
/** @var \Closure[] */ | |||
protected $eventHandlerClosures = []; | |||
/** @var ICommentsEventHandler[] */ | |||
protected $eventHandlers = []; | |||
/** | |||
* Manager constructor. | |||
* | |||
* @param IDBConnection $dbConn | |||
* @param ILogger $logger | |||
* @param IConfig $config | |||
* @param EventDispatcherInterface $dispatcher | |||
*/ | |||
public function __construct( | |||
IDBConnection $dbConn, | |||
ILogger $logger, | |||
IConfig $config, | |||
EventDispatcherInterface $dispatcher | |||
IConfig $config | |||
) { | |||
$this->dbConn = $dbConn; | |||
$this->logger = $logger; | |||
$this->config = $config; | |||
$this->dispatcher = $dispatcher; | |||
} | |||
/** | |||
@@ -455,10 +455,7 @@ class Manager implements ICommentsManager { | |||
} | |||
if ($affectedRows > 0 && $comment instanceof IComment) { | |||
$this->dispatcher->dispatch(CommentsEvent::EVENT_DELETE, new CommentsEvent( | |||
CommentsEvent::EVENT_DELETE, | |||
$comment | |||
)); | |||
$this->sendEvent(CommentsEvent::EVENT_DELETE, $comment); | |||
} | |||
return ($affectedRows > 0); | |||
@@ -525,13 +522,9 @@ class Manager implements ICommentsManager { | |||
if ($affectedRows > 0) { | |||
$comment->setId(strval($qb->getLastInsertId())); | |||
$this->sendEvent(CommentsEvent::EVENT_ADD, $comment); | |||
} | |||
$this->dispatcher->dispatch(CommentsEvent::EVENT_ADD, new CommentsEvent( | |||
CommentsEvent::EVENT_ADD, | |||
$comment | |||
)); | |||
return $affectedRows > 0; | |||
} | |||
@@ -565,10 +558,7 @@ class Manager implements ICommentsManager { | |||
throw new NotFoundException('Comment to update does ceased to exist'); | |||
} | |||
$this->dispatcher->dispatch(CommentsEvent::EVENT_UPDATE, new CommentsEvent( | |||
CommentsEvent::EVENT_UPDATE, | |||
$comment | |||
)); | |||
$this->sendEvent(CommentsEvent::EVENT_UPDATE, $comment); | |||
return $affectedRows > 0; | |||
} | |||
@@ -751,4 +741,51 @@ class Manager implements ICommentsManager { | |||
} | |||
return ($affectedRows > 0); | |||
} | |||
/** | |||
* registers an Entity to the manager, so event notifications can be send | |||
* to consumers of the comments infrastructure | |||
* | |||
* @param \Closure $closure | |||
*/ | |||
public function registerEventHandler(\Closure $closure) { | |||
$this->eventHandlerClosures[] = $closure; | |||
$this->eventHandlers = []; | |||
} | |||
/** | |||
* returns valid, registered entities | |||
* | |||
* @return \OCP\Comments\ICommentsEventHandler[] | |||
*/ | |||
private function getEventHandlers() { | |||
if(!empty($this->eventHandlers)) { | |||
return $this->eventHandlers; | |||
} | |||
$this->eventHandlers = []; | |||
foreach ($this->eventHandlerClosures as $name => $closure) { | |||
$entity = $closure(); | |||
if (!($entity instanceof ICommentsEventHandler)) { | |||
throw new \InvalidArgumentException('The given entity does not implement the ICommentsEntity interface'); | |||
} | |||
$this->eventHandlers[$name] = $entity; | |||
} | |||
return $this->eventHandlers; | |||
} | |||
/** | |||
* sends notifications to the registered entities | |||
* | |||
* @param $eventType | |||
* @param IComment $comment | |||
*/ | |||
private function sendEvent($eventType, IComment $comment) { | |||
$entities = $this->getEventHandlers(); | |||
$event = new CommentsEvent($eventType, $comment); | |||
foreach ($entities as $entity) { | |||
$entity->handle($event); | |||
} | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
<?php | |||
/** | |||
* @copyright Copyright (c) 2016 Arthur Schiwon <blizzz@arthur-schiwon.de> | |||
* | |||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de> | |||
* | |||
* @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\Comments; | |||
/** | |||
* Interface ICommentsEventHandler | |||
* | |||
* @package OCP\Comments | |||
* @since 9.2.0 | |||
*/ | |||
interface ICommentsEventHandler { | |||
/** | |||
* @param CommentsEvent $event | |||
* @since 9.2.0 | |||
*/ | |||
public function handle(CommentsEvent $event); | |||
} |
@@ -237,4 +237,13 @@ interface ICommentsManager { | |||
*/ | |||
public function deleteReadMarksOnObject($objectType, $objectId); | |||
/** | |||
* registers an Entity to the manager, so event notifications can be send | |||
* to consumers of the comments infrastructure | |||
* | |||
* @param \Closure $closure | |||
* @since 9.2.0 | |||
*/ | |||
public function registerEventHandler(\Closure $closure); | |||
} |
@@ -38,4 +38,6 @@ class FakeManager implements \OCP\Comments\ICommentsManager { | |||
public function deleteReadMarksFromUser(\OCP\IUser $user) {} | |||
public function deleteReadMarksOnObject($objectType, $objectId) {} | |||
public function registerEventHandler(\Closure $closure) {} | |||
} |
@@ -2,6 +2,9 @@ | |||
namespace Test\Comments; | |||
use OC\Comments\Comment; | |||
use OCP\Comments\CommentsEvent; | |||
use OCP\Comments\ICommentsEventHandler; | |||
use OCP\Comments\ICommentsManager; | |||
use OCP\IUser; | |||
use Test\TestCase; | |||
@@ -355,7 +358,7 @@ class ManagerTest extends TestCase { | |||
public function testSaveNew() { | |||
$manager = $this->getManager(); | |||
$comment = new \OC\Comments\Comment(); | |||
$comment = new Comment(); | |||
$comment | |||
->setActor('users', 'alice') | |||
->setObject('files', 'file64') | |||
@@ -375,7 +378,7 @@ class ManagerTest extends TestCase { | |||
public function testSaveUpdate() { | |||
$manager = $this->getManager(); | |||
$comment = new \OC\Comments\Comment(); | |||
$comment = new Comment(); | |||
$comment | |||
->setActor('users', 'alice') | |||
->setObject('files', 'file64') | |||
@@ -396,7 +399,7 @@ class ManagerTest extends TestCase { | |||
*/ | |||
public function testSaveUpdateException() { | |||
$manager = $this->getManager(); | |||
$comment = new \OC\Comments\Comment(); | |||
$comment = new Comment(); | |||
$comment | |||
->setActor('users', 'alice') | |||
->setObject('files', 'file64') | |||
@@ -415,7 +418,7 @@ class ManagerTest extends TestCase { | |||
*/ | |||
public function testSaveIncomplete() { | |||
$manager = $this->getManager(); | |||
$comment = new \OC\Comments\Comment(); | |||
$comment = new Comment(); | |||
$comment->setMessage('from no one to nothing'); | |||
$manager->save($comment); | |||
} | |||
@@ -426,7 +429,7 @@ class ManagerTest extends TestCase { | |||
$manager = $this->getManager(); | |||
for($i = 0; $i < 3; $i++) { | |||
$comment = new \OC\Comments\Comment(); | |||
$comment = new Comment(); | |||
$comment | |||
->setActor('users', 'alice') | |||
->setObject('files', 'file64') | |||
@@ -630,4 +633,35 @@ class ManagerTest extends TestCase { | |||
$this->assertNull($dateTimeGet); | |||
} | |||
public function testSendEvent() { | |||
$handler1 = $this->getMockBuilder(ICommentsEventHandler::class)->getMock(); | |||
$handler1->expects($this->exactly(3)) | |||
->method('handle'); | |||
$handler2 = $this->getMockBuilder(ICommentsEventHandler::class)->getMock(); | |||
$handler1->expects($this->exactly(3)) | |||
->method('handle'); | |||
$manager = $this->getManager(); | |||
$manager->registerEventHandler(function () use ($handler1) {return $handler1; }); | |||
$manager->registerEventHandler(function () use ($handler2) {return $handler2; }); | |||
$comment = new Comment(); | |||
$comment | |||
->setActor('users', 'alice') | |||
->setObject('files', 'file64') | |||
->setMessage('very beautiful, I am impressed!') | |||
->setVerb('comment'); | |||
// Add event | |||
$manager->save($comment); | |||
// Update event | |||
$comment->setMessage('Different topic'); | |||
$manager->save($comment); | |||
// Delete event | |||
$manager->delete($comment->getId()); | |||
} | |||
} |