diff --git a/apps/comments/appinfo/app.php b/apps/comments/appinfo/app.php
index df41bdfa32..771b35d9c6 100644
--- a/apps/comments/appinfo/app.php
+++ b/apps/comments/appinfo/app.php
@@ -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;
+});
diff --git a/apps/comments/appinfo/routes.php b/apps/comments/appinfo/routes.php
new file mode 100644
index 0000000000..ab751ddb2a
--- /dev/null
+++ b/apps/comments/appinfo/routes.php
@@ -0,0 +1,28 @@
+
+ *
+ * @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
+ *
+ */
+
+use \OCA\Comments\AppInfo\Application;
+
+$application = new Application();
+$application->registerRoutes($this, ['routes' => [
+ ['name' => 'Notifications#view', 'url' => '/notifications/view/{id}', 'verb' => 'GET'],
+]]);
diff --git a/apps/comments/lib/AppInfo/Application.php b/apps/comments/lib/AppInfo/Application.php
new file mode 100644
index 0000000000..f168779cd0
--- /dev/null
+++ b/apps/comments/lib/AppInfo/Application.php
@@ -0,0 +1,35 @@
+
+ *
+ * @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 .
+ */
+
+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);
+ }
+}
diff --git a/apps/comments/lib/Controller/Notifications.php b/apps/comments/lib/Controller/Notifications.php
new file mode 100644
index 0000000000..f76f160534
--- /dev/null
+++ b/apps/comments/lib/Controller/Notifications.php
@@ -0,0 +1,138 @@
+
+ *
+ * @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 .
+ *
+ */
+
+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);
+ }
+}
diff --git a/apps/comments/lib/EventHandler.php b/apps/comments/lib/EventHandler.php
new file mode 100644
index 0000000000..a32bb8ffa7
--- /dev/null
+++ b/apps/comments/lib/EventHandler.php
@@ -0,0 +1,78 @@
+
+ *
+ * @author Arthur Schiwon
+ *
+ * @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 .
+ *
+ */
+
+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);
+ }
+}
diff --git a/apps/comments/lib/Notification/Listener.php b/apps/comments/lib/Notification/Listener.php
new file mode 100644
index 0000000000..5e979fd9bf
--- /dev/null
+++ b/apps/comments/lib/Notification/Listener.php
@@ -0,0 +1,130 @@
+
+ *
+ * @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
+ *
+ */
+
+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]);
+ }
+}
diff --git a/apps/comments/lib/Notification/Notifier.php b/apps/comments/lib/Notification/Notifier.php
new file mode 100644
index 0000000000..df05f29730
--- /dev/null
+++ b/apps/comments/lib/Notification/Notifier.php
@@ -0,0 +1,115 @@
+
+ *
+ * @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
+ *
+ */
+
+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');
+ }
+
+ }
+}
diff --git a/apps/comments/tests/Unit/AppInfo/ApplicationTest.php b/apps/comments/tests/Unit/AppInfo/ApplicationTest.php
new file mode 100644
index 0000000000..c11d785749
--- /dev/null
+++ b/apps/comments/tests/Unit/AppInfo/ApplicationTest.php
@@ -0,0 +1,65 @@
+
+ *
+ * @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
+ *
+ */
+
+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);
+ }
+ }
+}
diff --git a/apps/comments/tests/Unit/Controller/NotificationsTest.php b/apps/comments/tests/Unit/Controller/NotificationsTest.php
new file mode 100644
index 0000000000..5ab3978821
--- /dev/null
+++ b/apps/comments/tests/Unit/Controller/NotificationsTest.php
@@ -0,0 +1,162 @@
+
+ *
+ * @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
+ *
+ */
+
+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);
+ }
+}
diff --git a/apps/comments/tests/Unit/EventHandlerTest.php b/apps/comments/tests/Unit/EventHandlerTest.php
new file mode 100644
index 0000000000..7a63032997
--- /dev/null
+++ b/apps/comments/tests/Unit/EventHandlerTest.php
@@ -0,0 +1,152 @@
+
+ *
+ * @author Arthur Schiwon
+ *
+ * @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 .
+ *
+ */
+
+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);
+ }
+
+}
diff --git a/apps/comments/tests/Unit/Notification/ListenerTest.php b/apps/comments/tests/Unit/Notification/ListenerTest.php
new file mode 100644
index 0000000000..98a0375e49
--- /dev/null
+++ b/apps/comments/tests/Unit/Notification/ListenerTest.php
@@ -0,0 +1,360 @@
+
+ *
+ * @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
+ *
+ */
+
+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);
+ }
+
+}
diff --git a/apps/comments/tests/Unit/Notification/NotifierTest.php b/apps/comments/tests/Unit/Notification/NotifierTest.php
new file mode 100644
index 0000000000..f3cc0153ab
--- /dev/null
+++ b/apps/comments/tests/Unit/Notification/NotifierTest.php
@@ -0,0 +1,499 @@
+
+ *
+ * @author Arthur Schiwon
+ *
+ * @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 .
+ *
+ */
+
+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);
+ }
+
+}
diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php
index b6f8d8f458..3f2212a7f2 100644
--- a/lib/private/AppFramework/DependencyInjection/DIContainer.php
+++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php
@@ -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();
});
diff --git a/lib/private/Comments/Manager.php b/lib/private/Comments/Manager.php
index 59678775d8..f7b23dd5f5 100644
--- a/lib/private/Comments/Manager.php
+++ b/lib/private/Comments/Manager.php
@@ -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);
+ }
+ }
}
diff --git a/lib/public/Comments/ICommentsEventHandler.php b/lib/public/Comments/ICommentsEventHandler.php
new file mode 100644
index 0000000000..3352419901
--- /dev/null
+++ b/lib/public/Comments/ICommentsEventHandler.php
@@ -0,0 +1,39 @@
+
+ *
+ * @author Arthur Schiwon
+ *
+ * @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 .
+ *
+ */
+
+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);
+}
diff --git a/lib/public/Comments/ICommentsManager.php b/lib/public/Comments/ICommentsManager.php
index f2edaaa5ea..98169fb335 100644
--- a/lib/public/Comments/ICommentsManager.php
+++ b/lib/public/Comments/ICommentsManager.php
@@ -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);
+
}
diff --git a/tests/lib/Comments/FakeManager.php b/tests/lib/Comments/FakeManager.php
index 7186529e71..7cd146e7cb 100644
--- a/tests/lib/Comments/FakeManager.php
+++ b/tests/lib/Comments/FakeManager.php
@@ -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) {}
}
diff --git a/tests/lib/Comments/ManagerTest.php b/tests/lib/Comments/ManagerTest.php
index 730d82d9d0..9c0f791c0c 100644
--- a/tests/lib/Comments/ManagerTest.php
+++ b/tests/lib/Comments/ManagerTest.php
@@ -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());
+ }
+
}