diff --git a/apps/comments/lib/Activity/Provider.php b/apps/comments/lib/Activity/Provider.php index ee53357efdb..a8c14b6686a 100644 --- a/apps/comments/lib/Activity/Provider.php +++ b/apps/comments/lib/Activity/Provider.php @@ -18,8 +18,6 @@ use OCP\IUserManager; use OCP\L10N\IFactory; class Provider implements IProvider { - protected ?IL10N $l = null; - public function __construct( protected IFactory $languageFactory, protected IURLGenerator $url, @@ -42,9 +40,9 @@ class Provider implements IProvider { throw new UnknownActivityException(); } - $this->l = $this->languageFactory->get('comments', $language); - if ($event->getSubject() === 'add_comment_subject') { + $l = $this->languageFactory->get('comments', $language); + $this->parseMessage($event); if ($this->activityManager->getRequirePNG()) { $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/comment.png'))); @@ -54,13 +52,13 @@ class Provider implements IProvider { if ($this->activityManager->isFormattingFilteredObject()) { try { - return $this->parseShortVersion($event); + return $this->parseShortVersion($event, $l); } catch (UnknownActivityException) { // Ignore and simply use the long version... } } - return $this->parseLongVersion($event); + return $this->parseLongVersion($event, $l); } throw new UnknownActivityException(); @@ -69,15 +67,15 @@ class Provider implements IProvider { /** * @throws UnknownActivityException */ - protected function parseShortVersion(IEvent $event): IEvent { + protected function parseShortVersion(IEvent $event, IL10N $l): IEvent { $subjectParameters = $this->getSubjectParameters($event); if ($event->getSubject() === 'add_comment_subject') { if ($subjectParameters['actor'] === $this->activityManager->getCurrentUserId()) { - $event->setRichSubject($this->l->t('You commented'), []); + $event->setRichSubject($l->t('You commented'), []); } else { $author = $this->generateUserParameter($subjectParameters['actor']); - $event->setRichSubject($this->l->t('{author} commented'), [ + $event->setRichSubject($l->t('{author} commented'), [ 'author' => $author, ]); } @@ -91,24 +89,24 @@ class Provider implements IProvider { /** * @throws UnknownActivityException */ - protected function parseLongVersion(IEvent $event): IEvent { + protected function parseLongVersion(IEvent $event, IL10N $l): IEvent { $subjectParameters = $this->getSubjectParameters($event); if ($event->getSubject() === 'add_comment_subject') { if ($subjectParameters['actor'] === $this->activityManager->getCurrentUserId()) { - $event->setParsedSubject($this->l->t('You commented on %1$s', [ + $event->setParsedSubject($l->t('You commented on %1$s', [ $subjectParameters['filePath'], ])) - ->setRichSubject($this->l->t('You commented on {file}'), [ + ->setRichSubject($l->t('You commented on {file}'), [ 'file' => $this->generateFileParameter($subjectParameters['fileId'], $subjectParameters['filePath']), ]); } else { $author = $this->generateUserParameter($subjectParameters['actor']); - $event->setParsedSubject($this->l->t('%1$s commented on %2$s', [ + $event->setParsedSubject($l->t('%1$s commented on %2$s', [ $author['name'], $subjectParameters['filePath'], ])) - ->setRichSubject($this->l->t('{author} commented on {file}'), [ + ->setRichSubject($l->t('{author} commented on {file}'), [ 'author' => $author, 'file' => $this->generateFileParameter($subjectParameters['fileId'], $subjectParameters['filePath']), ]); diff --git a/apps/comments/lib/Activity/Setting.php b/apps/comments/lib/Activity/Setting.php index 7fbf4001b20..2f332d99b43 100644 --- a/apps/comments/lib/Activity/Setting.php +++ b/apps/comments/lib/Activity/Setting.php @@ -11,7 +11,7 @@ use OCP\IL10N; class Setting extends ActivitySettings { public function __construct( - protected IL10N $l, + protected readonly IL10N $l, ) { } @@ -23,11 +23,11 @@ class Setting extends ActivitySettings { return $this->l->t('Comments for files'); } - public function getGroupIdentifier() { + public function getGroupIdentifier(): string { return 'files'; } - public function getGroupName() { + public function getGroupName(): string { return $this->l->t('Files'); } diff --git a/apps/comments/lib/Listener/CommentsEntityEventListener.php b/apps/comments/lib/Listener/CommentsEntityEventListener.php index 5aeeb3c63ea..215d8b7a52c 100644 --- a/apps/comments/lib/Listener/CommentsEntityEventListener.php +++ b/apps/comments/lib/Listener/CommentsEntityEventListener.php @@ -27,6 +27,10 @@ class CommentsEntityEventListener implements IEventListener { return; } + if ($this->userId === null) { + return; + } + $event->addEntityCollection('files', function ($name): bool { $nodes = $this->rootFolder->getUserFolder($this->userId)->getById((int)$name); return !empty($nodes); diff --git a/apps/comments/lib/Listener/CommentsEventListener.php b/apps/comments/lib/Listener/CommentsEventListener.php index a1e44995162..55a1190ea11 100644 --- a/apps/comments/lib/Listener/CommentsEventListener.php +++ b/apps/comments/lib/Listener/CommentsEventListener.php @@ -35,8 +35,7 @@ class CommentsEventListener implements IEventListener { } $eventType = $event->getEvent(); - if ($eventType === CommentsEvent::EVENT_ADD - ) { + if ($eventType === CommentsEvent::EVENT_ADD) { $this->notificationHandler($event); $this->activityHandler($event); return; diff --git a/apps/comments/tests/Unit/Activity/ListenerTest.php b/apps/comments/tests/Unit/Activity/ListenerTest.php index 675a28a16b1..949cdd70e13 100644 --- a/apps/comments/tests/Unit/Activity/ListenerTest.php +++ b/apps/comments/tests/Unit/Activity/ListenerTest.php @@ -12,7 +12,7 @@ use OCA\Comments\Activity\Listener; use OCP\Activity\IEvent; use OCP\Activity\IManager; use OCP\App\IAppManager; -use OCP\Comments\CommentsEvent; +use OCP\Comments\Events\CommentAddedEvent; use OCP\Comments\IComment; use OCP\Files\Config\ICachedMountFileInfo; use OCP\Files\Config\IMountProviderCollection; @@ -66,14 +66,7 @@ class ListenerTest extends TestCase { ->method('getObjectType') ->willReturn('files'); - /** @var CommentsEvent|MockObject $event */ - $event = $this->createMock(CommentsEvent::class); - $event->expects($this->any()) - ->method('getComment') - ->willReturn($comment); - $event->expects($this->any()) - ->method('getEvent') - ->willReturn(CommentsEvent::EVENT_ADD); + $event = new CommentAddedEvent($comment); /** @var IUser|MockObject $ownerUser */ $ownerUser = $this->createMock(IUser::class); diff --git a/apps/comments/tests/Unit/EventHandlerTest.php b/apps/comments/tests/Unit/EventHandlerTest.php index 9d26f828d70..3e6ddf5eed6 100644 --- a/apps/comments/tests/Unit/EventHandlerTest.php +++ b/apps/comments/tests/Unit/EventHandlerTest.php @@ -12,6 +12,10 @@ use OCA\Comments\Activity\Listener as ActivityListener; use OCA\Comments\Listener\CommentsEventListener; use OCA\Comments\Notification\Listener as NotificationListener; use OCP\Comments\CommentsEvent; +use OCP\Comments\Events\BeforeCommentUpdatedEvent; +use OCP\Comments\Events\CommentAddedEvent; +use OCP\Comments\Events\CommentDeletedEvent; +use OCP\Comments\Events\CommentUpdatedEvent; use OCP\Comments\IComment; use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; @@ -50,10 +54,10 @@ class EventHandlerTest extends TestCase { public static function handledProvider(): array { return [ - [CommentsEvent::EVENT_DELETE], - [CommentsEvent::EVENT_UPDATE], - [CommentsEvent::EVENT_PRE_UPDATE], - [CommentsEvent::EVENT_ADD] + ['delete'], + ['update'], + ['pre_update'], + ['add'] ]; } @@ -65,14 +69,12 @@ class EventHandlerTest extends TestCase { ->method('getObjectType') ->willReturn('files'); - /** @var CommentsEvent|MockObject $event */ - $event = $this->createMock(CommentsEvent::class); - $event->expects($this->atLeastOnce()) - ->method('getComment') - ->willReturn($comment); - $event->expects($this->atLeastOnce()) - ->method('getEvent') - ->willReturn($eventType); + $event = match ($eventType) { + 'add' => new CommentAddedEvent($comment), + 'pre_update' => new BeforeCommentUpdatedEvent($comment), + 'update' => new CommentUpdatedEvent($comment), + 'delete' => new CommentDeletedEvent($comment), + }; $this->notificationListener->expects($this->once()) ->method('evaluate') diff --git a/apps/comments/tests/Unit/Notification/ListenerTest.php b/apps/comments/tests/Unit/Notification/ListenerTest.php index 356a26f23cd..f2114d0b15b 100644 --- a/apps/comments/tests/Unit/Notification/ListenerTest.php +++ b/apps/comments/tests/Unit/Notification/ListenerTest.php @@ -8,7 +8,10 @@ namespace OCA\Comments\Tests\Unit\Notification; use OCA\Comments\Notification\Listener; -use OCP\Comments\CommentsEvent; +use OCP\Comments\Events\BeforeCommentUpdatedEvent; +use OCP\Comments\Events\CommentAddedEvent; +use OCP\Comments\Events\CommentDeletedEvent; +use OCP\Comments\Events\CommentUpdatedEvent; use OCP\Comments\IComment; use OCP\IURLGenerator; use OCP\IUserManager; @@ -37,10 +40,10 @@ class ListenerTest extends TestCase { public static function eventProvider(): array { return [ - [CommentsEvent::EVENT_ADD, 'notify'], - [CommentsEvent::EVENT_UPDATE, 'notify'], - [CommentsEvent::EVENT_PRE_UPDATE, 'markProcessed'], - [CommentsEvent::EVENT_DELETE, 'markProcessed'] + ['add', 'notify'], + ['update', 'notify'], + ['pre_update', 'markProcessed'], + ['delete', 'markProcessed'] ]; } @@ -49,7 +52,7 @@ class ListenerTest extends TestCase { * @param string $notificationMethod */ #[\PHPUnit\Framework\Attributes\DataProvider('eventProvider')] - public function testEvaluate($eventType, $notificationMethod): void { + public function testEvaluate(string $eventType, $notificationMethod): void { /** @var IComment|MockObject $comment */ $comment = $this->createMock(IComment::class); $comment->expects($this->any()) @@ -72,14 +75,12 @@ class ListenerTest extends TestCase { ->method('getId') ->willReturn('1234'); - /** @var CommentsEvent|MockObject $event */ - $event = $this->createMock(CommentsEvent::class); - $event->expects($this->once()) - ->method('getComment') - ->willReturn($comment); - $event->expects(($this->any())) - ->method(('getEvent')) - ->willReturn($eventType); + $event = match ($eventType) { + 'add' => new CommentAddedEvent($comment), + 'pre_update' => new BeforeCommentUpdatedEvent($comment), + 'update' => new CommentUpdatedEvent($comment), + 'delete' => new CommentDeletedEvent($comment), + }; /** @var INotification|MockObject $notification */ $notification = $this->createMock(INotification::class); @@ -124,14 +125,12 @@ class ListenerTest extends TestCase { ->method('getMentions') ->willReturn([]); - /** @var CommentsEvent|MockObject $event */ - $event = $this->createMock(CommentsEvent::class); - $event->expects($this->once()) - ->method('getComment') - ->willReturn($comment); - $event->expects(($this->any())) - ->method(('getEvent')) - ->willReturn($eventType); + $event = match ($eventType) { + 'add' => new CommentAddedEvent($comment), + 'pre_update' => new BeforeCommentUpdatedEvent($comment), + 'update' => new CommentUpdatedEvent($comment), + 'delete' => new CommentDeletedEvent($comment), + }; $this->notificationManager->expects($this->never()) ->method('createNotification'); @@ -162,14 +161,7 @@ class ListenerTest extends TestCase { ->method('getId') ->willReturn('1234'); - /** @var CommentsEvent|MockObject $event */ - $event = $this->createMock(CommentsEvent::class); - $event->expects($this->once()) - ->method('getComment') - ->willReturn($comment); - $event->expects(($this->any())) - ->method(('getEvent')) - ->willReturn(CommentsEvent::EVENT_ADD); + $event = new CommentAddedEvent($comment); /** @var INotification|MockObject $notification */ $notification = $this->createMock(INotification::class); diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index eb57014b27d..a667b0a34fa 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -268,6 +268,10 @@ return array( 'OCP\\Command\\ICommand' => $baseDir . '/lib/public/Command/ICommand.php', 'OCP\\Comments\\CommentsEntityEvent' => $baseDir . '/lib/public/Comments/CommentsEntityEvent.php', 'OCP\\Comments\\CommentsEvent' => $baseDir . '/lib/public/Comments/CommentsEvent.php', + 'OCP\\Comments\\Events\\BeforeCommentUpdatedEvent' => $baseDir . '/lib/public/Comments/Events/BeforeCommentUpdatedEvent.php', + 'OCP\\Comments\\Events\\CommentAddedEvent' => $baseDir . '/lib/public/Comments/Events/CommentAddedEvent.php', + 'OCP\\Comments\\Events\\CommentDeletedEvent' => $baseDir . '/lib/public/Comments/Events/CommentDeletedEvent.php', + 'OCP\\Comments\\Events\\CommentUpdatedEvent' => $baseDir . '/lib/public/Comments/Events/CommentUpdatedEvent.php', 'OCP\\Comments\\IComment' => $baseDir . '/lib/public/Comments/IComment.php', 'OCP\\Comments\\ICommentsEventHandler' => $baseDir . '/lib/public/Comments/ICommentsEventHandler.php', 'OCP\\Comments\\ICommentsManager' => $baseDir . '/lib/public/Comments/ICommentsManager.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 96e3b10f50d..cb6fc743175 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -309,6 +309,10 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Command\\ICommand' => __DIR__ . '/../../..' . '/lib/public/Command/ICommand.php', 'OCP\\Comments\\CommentsEntityEvent' => __DIR__ . '/../../..' . '/lib/public/Comments/CommentsEntityEvent.php', 'OCP\\Comments\\CommentsEvent' => __DIR__ . '/../../..' . '/lib/public/Comments/CommentsEvent.php', + 'OCP\\Comments\\Events\\BeforeCommentUpdatedEvent' => __DIR__ . '/../../..' . '/lib/public/Comments/Events/BeforeCommentUpdatedEvent.php', + 'OCP\\Comments\\Events\\CommentAddedEvent' => __DIR__ . '/../../..' . '/lib/public/Comments/Events/CommentAddedEvent.php', + 'OCP\\Comments\\Events\\CommentDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/Comments/Events/CommentDeletedEvent.php', + 'OCP\\Comments\\Events\\CommentUpdatedEvent' => __DIR__ . '/../../..' . '/lib/public/Comments/Events/CommentUpdatedEvent.php', 'OCP\\Comments\\IComment' => __DIR__ . '/../../..' . '/lib/public/Comments/IComment.php', 'OCP\\Comments\\ICommentsEventHandler' => __DIR__ . '/../../..' . '/lib/public/Comments/ICommentsEventHandler.php', 'OCP\\Comments\\ICommentsManager' => __DIR__ . '/../../..' . '/lib/public/Comments/ICommentsManager.php', diff --git a/lib/private/Comments/Manager.php b/lib/private/Comments/Manager.php index 6042443c8b6..84737897bb4 100644 --- a/lib/private/Comments/Manager.php +++ b/lib/private/Comments/Manager.php @@ -9,6 +9,10 @@ namespace OC\Comments; use OCP\AppFramework\Utility\ITimeFactory; use OCP\Comments\CommentsEvent; +use OCP\Comments\Events\BeforeCommentUpdatedEvent; +use OCP\Comments\Events\CommentAddedEvent; +use OCP\Comments\Events\CommentDeletedEvent; +use OCP\Comments\Events\CommentUpdatedEvent; use OCP\Comments\IComment; use OCP\Comments\ICommentsEventHandler; use OCP\Comments\ICommentsManager; @@ -902,7 +906,7 @@ class Manager implements ICommentsManager { if ($comment->getVerb() === 'reaction_deleted') { $this->deleteReaction($comment); } - $this->sendEvent(CommentsEvent::EVENT_DELETE, $comment); + $this->sendEvent(new CommentDeletedEvent($comment)); } return ($affectedRows > 0); @@ -1147,7 +1151,7 @@ class Manager implements ICommentsManager { if ($comment->getVerb() === 'reaction') { $this->addReaction($comment); } - $this->sendEvent(CommentsEvent::EVENT_ADD, $comment); + $this->sendEvent(new CommentAddedEvent($comment)); } return $affectedRows > 0; @@ -1233,11 +1237,11 @@ class Manager implements ICommentsManager { * @return bool * @throws NotFoundException */ - protected function update(IComment $comment) { + protected function update(IComment $comment): bool { // for properly working preUpdate Events we need the old comments as is // in the DB and overcome caching. Also avoid that outdated information stays. $this->uncache($comment->getId()); - $this->sendEvent(CommentsEvent::EVENT_PRE_UPDATE, $this->get($comment->getId())); + $this->sendEvent(new BeforeCommentUpdatedEvent($this->get($comment->getId()))); $this->uncache($comment->getId()); $result = $this->updateQuery($comment); @@ -1246,7 +1250,7 @@ class Manager implements ICommentsManager { $this->deleteReaction($comment); } - $this->sendEvent(CommentsEvent::EVENT_UPDATE, $comment); + $this->sendEvent(new CommentUpdatedEvent($comment)); return $result; } @@ -1528,14 +1532,10 @@ class Manager implements ICommentsManager { } /** - * sends notifications to the registered entities - * - * @param $eventType - * @param IComment $comment + * Sends notifications to the registered entities */ - private function sendEvent($eventType, IComment $comment) { + private function sendEvent(CommentsEvent $event): void { $entities = $this->getEventHandlers(); - $event = new CommentsEvent($eventType, $comment); foreach ($entities as $entity) { $entity->handle($event); } diff --git a/lib/public/Comments/CommentsEntityEvent.php b/lib/public/Comments/CommentsEntityEvent.php index 39568151b61..9adac1030a4 100644 --- a/lib/public/Comments/CommentsEntityEvent.php +++ b/lib/public/Comments/CommentsEntityEvent.php @@ -7,6 +7,7 @@ */ namespace OCP\Comments; +use OCP\AppFramework\Attribute\Consumable; use OCP\EventDispatcher\Event; /** @@ -15,6 +16,7 @@ use OCP\EventDispatcher\Event; * @since 9.1.0 * @since 28.0.0 Dispatched as a typed event */ +#[Consumable(since: '9.1.0')] class CommentsEntityEvent extends Event { /** * @since 9.1.0 @@ -22,8 +24,8 @@ class CommentsEntityEvent extends Event { */ public const EVENT_ENTITY = 'OCP\Comments\ICommentsManager::registerEntity'; - /** @var \Closure[] */ - protected $collections; + /** @var (\Closure(string $id): bool)[] */ + protected array $collections = []; /** * DispatcherEvent constructor. @@ -32,19 +34,18 @@ class CommentsEntityEvent extends Event { */ public function __construct() { parent::__construct(); - $this->collections = []; } /** * @param string $name - * @param \Closure $entityExistsFunction The closure should take one - * argument, which is the id of the entity, that comments - * should be handled for. The return should then be bool, - * depending on whether comments are allowed (true) or not. + * @param \Closure(string $id):bool $entityExistsFunction The closure should take one + * argument, which is the id of the entity, that comments + * should be handled for. The return should then be bool, + * depending on whether comments are allowed (true) or not. * @throws \OutOfBoundsException when the entity name is already taken * @since 9.1.0 */ - public function addEntityCollection($name, \Closure $entityExistsFunction) { + public function addEntityCollection(string $name, \Closure $entityExistsFunction): void { if (isset($this->collections[$name])) { throw new \OutOfBoundsException('Duplicate entity name "' . $name . '"'); } @@ -53,10 +54,10 @@ class CommentsEntityEvent extends Event { } /** - * @return \Closure[] + * @return (\Closure(string $id): bool)[] * @since 9.1.0 */ - public function getEntityCollections() { + public function getEntityCollections(): array { return $this->collections; } } diff --git a/lib/public/Comments/CommentsEvent.php b/lib/public/Comments/CommentsEvent.php index 04d592d4f1e..deaeb4b4009 100644 --- a/lib/public/Comments/CommentsEvent.php +++ b/lib/public/Comments/CommentsEvent.php @@ -7,68 +7,66 @@ */ namespace OCP\Comments; +use OCP\AppFramework\Attribute\Consumable; use OCP\EventDispatcher\Event; /** * Class CommentsEvent * * @since 9.0.0 + * + * In the future, once the deprecated methods are removed, this class will be abstract. */ +#[Consumable(since: '9.0.0')] class CommentsEvent extends Event { /** * @since 11.0.0 - * @deprecated 22.0.0 + * @deprecated 33.0.0 Use \OCP\Comments\Events\CommentAddedEvent instead. */ public const EVENT_ADD = 'OCP\Comments\ICommentsManager::addComment'; /** * @since 11.0.0 - * @deprecated 22.0.0 + * @deprecated 33.0.0 Use \OCP\Comments\Events\BeforeCommentUpdatedEvent instead. */ public const EVENT_PRE_UPDATE = 'OCP\Comments\ICommentsManager::preUpdateComment'; /** * @since 11.0.0 - * @deprecated 22.0.0 + * @deprecated 33.0.0 Use \OCP\Comments\Events\CommentUpdatedEvent instead. */ public const EVENT_UPDATE = 'OCP\Comments\ICommentsManager::updateComment'; /** * @since 11.0.0 - * @deprecated 22.0.0 + * @deprecated 33.0.0 Use \OCP\Comments\Events\CommentDeletedEvent instead. */ public const EVENT_DELETE = 'OCP\Comments\ICommentsManager::deleteComment'; - /** @var string */ - protected $event; - /** @var IComment */ - protected $comment; - /** - * DispatcherEvent constructor. + * CommentsEvent constructor. * - * @param string $event - * @param IComment $comment * @since 9.0.0 */ - public function __construct($event, IComment $comment) { - $this->event = $event; - $this->comment = $comment; + public function __construct( + protected readonly string $event, + protected readonly IComment $comment, + ) { + parent::__construct(); } /** - * @return string * @since 9.0.0 + * @depreacted Since 33.0.0 use instanceof CommentAddedEvent, CommentRemovedEvent, CommentUpdatedEvent or BeforeCommentUpdatedEvent instead. */ - public function getEvent() { + public function getEvent(): string { return $this->event; } /** - * @return IComment * @since 9.0.0 */ - public function getComment() { + public function getComment(): IComment { return $this->comment; } } diff --git a/lib/public/Comments/Events/BeforeCommentUpdatedEvent.php b/lib/public/Comments/Events/BeforeCommentUpdatedEvent.php new file mode 100644 index 00000000000..c8b0b172c8a --- /dev/null +++ b/lib/public/Comments/Events/BeforeCommentUpdatedEvent.php @@ -0,0 +1,28 @@ +