diff --git a/apps/dav/lib/Connector/Sabre/ServerFactory.php b/apps/dav/lib/Connector/Sabre/ServerFactory.php index d3837bbb920f0..dc6384daefe46 100644 --- a/apps/dav/lib/Connector/Sabre/ServerFactory.php +++ b/apps/dav/lib/Connector/Sabre/ServerFactory.php @@ -136,7 +136,7 @@ public function createServer(string $baseUri, )); if ($this->userSession->isLoggedIn()) { - $server->addPlugin(new TagsPlugin($objectTree, $this->tagManager)); + $server->addPlugin(new TagsPlugin($objectTree, $this->tagManager, $this->eventDispatcher, $this->userSession)); $server->addPlugin(new SharesPlugin( $objectTree, $this->userSession, diff --git a/apps/dav/lib/Connector/Sabre/TagsPlugin.php b/apps/dav/lib/Connector/Sabre/TagsPlugin.php index 7f05d4d3c03a7..eb06fa5cef6c7 100644 --- a/apps/dav/lib/Connector/Sabre/TagsPlugin.php +++ b/apps/dav/lib/Connector/Sabre/TagsPlugin.php @@ -27,8 +27,10 @@ * License along with this library. If not, see . * */ +use OCP\EventDispatcher\IEventDispatcher; use OCP\ITagManager; use OCP\ITags; +use OCP\IUserSession; use Sabre\DAV\PropFind; use Sabre\DAV\PropPatch; @@ -67,6 +69,8 @@ class TagsPlugin extends \Sabre\DAV\ServerPlugin { public function __construct( private \Sabre\DAV\Tree $tree, private ITagManager $tagManager, + private IEventDispatcher $eventDispatcher, + private IUserSession $userSession, ) { $this->tagger = null; $this->cachedTags = []; @@ -251,7 +255,7 @@ public function handleUpdateProperties($path, PropPatch $propPatch) { return true; }); - $propPatch->handle(self::FAVORITE_PROPERTYNAME, function ($favState) use ($node) { + $propPatch->handle(self::FAVORITE_PROPERTYNAME, function ($favState) use ($node, $path) { if ((int)$favState === 1 || $favState === 'true') { $this->getTagger()->tagAs($node->getId(), self::TAG_FAVORITE); } else { diff --git a/apps/dav/lib/Server.php b/apps/dav/lib/Server.php index 6b56fc36f6078..7315b37a27ec1 100644 --- a/apps/dav/lib/Server.php +++ b/apps/dav/lib/Server.php @@ -295,7 +295,7 @@ public function __construct( } $this->server->addPlugin( new TagsPlugin( - $this->server->tree, \OC::$server->getTagManager() + $this->server->tree, \OC::$server->getTagManager(), \OC::$server->get(IEventDispatcher::class), \OC::$server->get(IUserSession::class) ) ); diff --git a/apps/dav/tests/unit/Connector/Sabre/TagsPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/TagsPluginTest.php index bdab8135b1c52..43c08a1a61cad 100644 --- a/apps/dav/tests/unit/Connector/Sabre/TagsPluginTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/TagsPluginTest.php @@ -13,8 +13,11 @@ use OCA\DAV\Connector\Sabre\TagList; use OCA\DAV\Connector\Sabre\TagsPlugin; use OCA\DAV\Upload\UploadFile; +use OCP\EventDispatcher\IEventDispatcher; use OCP\ITagManager; use OCP\ITags; +use OCP\IUser; +use OCP\IUserSession; use Sabre\DAV\Tree; class TagsPluginTest extends \Test\TestCase { @@ -42,6 +45,16 @@ class TagsPluginTest extends \Test\TestCase { */ private $tagger; + /** + * @var IEventDispatcher + */ + private $eventDispatcher; + + /** + * @var IUserSession + */ + private $userSession; + /** * @var TagsPlugin */ @@ -59,11 +72,24 @@ protected function setUp(): void { $this->tagManager = $this->getMockBuilder(ITagManager::class) ->disableOriginalConstructor() ->getMock(); + + $this->eventDispatcher = $this->getMockBuilder(IEventDispatcher::class) + ->disableOriginalConstructor() + ->getMock(); + $user = $this->createMock(IUser::class); + /** + * @var IUserSession + */ + $this->userSession = $this->createMock(IUserSession::class); + $this->userSession->expects($this->any()) + ->method('getUser') + ->withAnyParameters() + ->willReturn($user); $this->tagManager->expects($this->any()) ->method('load') ->with('files') ->willReturn($this->tagger); - $this->plugin = new TagsPlugin($this->tree, $this->tagManager); + $this->plugin = new TagsPlugin($this->tree, $this->tagManager, $this->eventDispatcher, $this->userSession); $this->plugin->initialize($this->server); } diff --git a/apps/files/composer/composer/autoload_classmap.php b/apps/files/composer/composer/autoload_classmap.php index e9e45bbd84abc..103a4377223d2 100644 --- a/apps/files/composer/composer/autoload_classmap.php +++ b/apps/files/composer/composer/autoload_classmap.php @@ -60,6 +60,8 @@ 'OCA\\Files\\Helper' => $baseDir . '/../lib/Helper.php', 'OCA\\Files\\Listener\\LoadSearchPluginsListener' => $baseDir . '/../lib/Listener/LoadSearchPluginsListener.php', 'OCA\\Files\\Listener\\LoadSidebarListener' => $baseDir . '/../lib/Listener/LoadSidebarListener.php', + 'OCA\\Files\\Listener\\NodeAddedToFavoriteListener' => $baseDir . '/../lib/Listener/NodeAddedToFavoriteListener.php', + 'OCA\\Files\\Listener\\NodeRemovedFromFavoriteListener' => $baseDir . '/../lib/Listener/NodeRemovedFromFavoriteListener.php', 'OCA\\Files\\Listener\\RenderReferenceEventListener' => $baseDir . '/../lib/Listener/RenderReferenceEventListener.php', 'OCA\\Files\\Listener\\SyncLivePhotosListener' => $baseDir . '/../lib/Listener/SyncLivePhotosListener.php', 'OCA\\Files\\Migration\\Version11301Date20191205150729' => $baseDir . '/../lib/Migration/Version11301Date20191205150729.php', diff --git a/apps/files/composer/composer/autoload_static.php b/apps/files/composer/composer/autoload_static.php index 59695e60fc792..bb2195eaf0f00 100644 --- a/apps/files/composer/composer/autoload_static.php +++ b/apps/files/composer/composer/autoload_static.php @@ -75,6 +75,8 @@ class ComposerStaticInitFiles 'OCA\\Files\\Helper' => __DIR__ . '/..' . '/../lib/Helper.php', 'OCA\\Files\\Listener\\LoadSearchPluginsListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSearchPluginsListener.php', 'OCA\\Files\\Listener\\LoadSidebarListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSidebarListener.php', + 'OCA\\Files\\Listener\\NodeAddedToFavoriteListener' => __DIR__ . '/..' . '/../lib/Listener/NodeAddedToFavoriteListener.php', + 'OCA\\Files\\Listener\\NodeRemovedFromFavoriteListener' => __DIR__ . '/..' . '/../lib/Listener/NodeRemovedFromFavoriteListener.php', 'OCA\\Files\\Listener\\RenderReferenceEventListener' => __DIR__ . '/..' . '/../lib/Listener/RenderReferenceEventListener.php', 'OCA\\Files\\Listener\\SyncLivePhotosListener' => __DIR__ . '/..' . '/../lib/Listener/SyncLivePhotosListener.php', 'OCA\\Files\\Migration\\Version11301Date20191205150729' => __DIR__ . '/..' . '/../lib/Migration/Version11301Date20191205150729.php', diff --git a/apps/files/lib/AppInfo/Application.php b/apps/files/lib/AppInfo/Application.php index d50a8d14f5ae9..84387983946aa 100644 --- a/apps/files/lib/AppInfo/Application.php +++ b/apps/files/lib/AppInfo/Application.php @@ -18,6 +18,8 @@ use OCA\Files\Event\LoadSidebar; use OCA\Files\Listener\LoadSearchPluginsListener; use OCA\Files\Listener\LoadSidebarListener; +use OCA\Files\Listener\NodeAddedToFavoriteListener; +use OCA\Files\Listener\NodeRemovedFromFavoriteListener; use OCA\Files\Listener\RenderReferenceEventListener; use OCA\Files\Listener\SyncLivePhotosListener; use OCA\Files\Notification\Notifier; @@ -33,12 +35,13 @@ use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\Collaboration\Reference\RenderReferenceEvent; use OCP\Collaboration\Resources\IProviderManager; -use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Cache\CacheEntryRemovedEvent; use OCP\Files\Events\Node\BeforeNodeCopiedEvent; use OCP\Files\Events\Node\BeforeNodeDeletedEvent; use OCP\Files\Events\Node\BeforeNodeRenamedEvent; use OCP\Files\Events\Node\NodeCopiedEvent; +use OCP\Files\Events\NodeAddedToFavorite; +use OCP\Files\Events\NodeRemovedFromFavorite; use OCP\Files\IRootFolder; use OCP\IConfig; use OCP\IL10N; @@ -96,7 +99,6 @@ public function register(IRegistrationContext $context): void { $c->get(IActivityManager::class), $c->get(ITagManager::class)->load(self::APP_ID), $server->getUserFolder(), - $c->get(IEventDispatcher::class), ); }); @@ -116,7 +118,8 @@ public function register(IRegistrationContext $context): void { $context->registerEventListener(BeforeNodeCopiedEvent::class, SyncLivePhotosListener::class); $context->registerEventListener(NodeCopiedEvent::class, SyncLivePhotosListener::class); $context->registerEventListener(LoadSearchPlugins::class, LoadSearchPluginsListener::class); - + $context->registerEventListener(NodeAddedToFavorite::class, NodeAddedToFavoriteListener::class); + $context->registerEventListener(NodeRemovedFromFavorite::class, NodeRemovedFromFavoriteListener::class); $context->registerSearchProvider(FilesSearchProvider::class); $context->registerNotifierService(Notifier::class); diff --git a/apps/files/lib/Listener/NodeAddedToFavoriteListener.php b/apps/files/lib/Listener/NodeAddedToFavoriteListener.php new file mode 100644 index 0000000000000..827c1851d3d6e --- /dev/null +++ b/apps/files/lib/Listener/NodeAddedToFavoriteListener.php @@ -0,0 +1,43 @@ + */ +class NodeAddedToFavoriteListener implements IEventListener { + public function __construct( + private IActivityManager $activityManager, + ) { + } + public function handle(Event $event):void { + if (!($event instanceof NodeAddedToFavorite)) { + return; + } + $activityEvent = $this->activityManager->generateEvent(); + try { + $activityEvent->setApp('files') + ->setObject('files', $event->getFileId(), $event->getPath()) + ->setType('favorite') + ->setAuthor($event->getUser()->getUID()) + ->setAffectedUser($event->getUser()->getUID()) + ->setTimestamp(time()) + ->setSubject( + FavoriteProvider::SUBJECT_ADDED, + ['id' => $event->getFileId(), 'path' => $event->getPath()] + ); + $this->activityManager->publish($activityEvent); + } catch (\InvalidArgumentException $e) { + } catch (\BadMethodCallException $e) { + } + } +} diff --git a/apps/files/lib/Listener/NodeRemovedFromFavoriteListener.php b/apps/files/lib/Listener/NodeRemovedFromFavoriteListener.php new file mode 100644 index 0000000000000..fe39d4af54043 --- /dev/null +++ b/apps/files/lib/Listener/NodeRemovedFromFavoriteListener.php @@ -0,0 +1,43 @@ + */ +class NodeRemovedFromFavoriteListener implements IEventListener { + public function __construct( + private IActivityManager $activityManager, + ) { + } + public function handle(Event $event):void { + if (!($event instanceof NodeRemovedFromFavorite)) { + return; + } + $activityEvent = $this->activityManager->generateEvent(); + try { + $activityEvent->setApp('files') + ->setObject('files', $event->getFileId(), $event->getPath()) + ->setType('favorite') + ->setAuthor($event->getUser()->getUID()) + ->setAffectedUser($event->getUser()->getUID()) + ->setTimestamp(time()) + ->setSubject( + FavoriteProvider::SUBJECT_REMOVED, + ['id' => $event->getFileId(), 'path' => $event->getPath()] + ); + $this->activityManager->publish($activityEvent); + } catch (\InvalidArgumentException $e) { + } catch (\BadMethodCallException $e) { + } + } +} diff --git a/apps/files/lib/Service/TagService.php b/apps/files/lib/Service/TagService.php index 450cd79505d21..63c54d01fd08e 100644 --- a/apps/files/lib/Service/TagService.php +++ b/apps/files/lib/Service/TagService.php @@ -7,15 +7,10 @@ */ namespace OCA\Files\Service; -use OCA\Files\Activity\FavoriteProvider; use OCP\Activity\IManager; -use OCP\EventDispatcher\IEventDispatcher; -use OCP\Files\Events\NodeAddedToFavorite; -use OCP\Files\Events\NodeRemovedFromFavorite; use OCP\Files\Folder; use OCP\Files\NotFoundException; use OCP\ITags; -use OCP\IUser; use OCP\IUserSession; /** @@ -28,7 +23,6 @@ public function __construct( private IManager $activityManager, private ?ITags $tagger, private ?Folder $homeFolder, - private IEventDispatcher $dispatcher, ) { } @@ -60,16 +54,10 @@ public function updateFileTags($path, $tags) { $newTags = array_diff($tags, $currentTags); foreach ($newTags as $tag) { - if ($tag === ITags::TAG_FAVORITE) { - $this->addActivity(true, $fileId, $path); - } $this->tagger->tagAs($fileId, $tag); } $deletedTags = array_diff($currentTags, $tags); foreach ($deletedTags as $tag) { - if ($tag === ITags::TAG_FAVORITE) { - $this->addActivity(false, $fileId, $path); - } $this->tagger->unTag($fileId, $tag); } @@ -77,40 +65,4 @@ public function updateFileTags($path, $tags) { // list is up to date, in case of concurrent changes ? return $tags; } - - /** - * @param bool $addToFavorite - * @param int $fileId - * @param string $path - */ - protected function addActivity($addToFavorite, $fileId, $path) { - $user = $this->userSession->getUser(); - if (!$user instanceof IUser) { - return; - } - - if ($addToFavorite) { - $event = new NodeAddedToFavorite($user, $fileId, $path); - } else { - $event = new NodeRemovedFromFavorite($user, $fileId, $path); - } - $this->dispatcher->dispatchTyped($event); - - $event = $this->activityManager->generateEvent(); - try { - $event->setApp('files') - ->setObject('files', $fileId, $path) - ->setType('favorite') - ->setAuthor($user->getUID()) - ->setAffectedUser($user->getUID()) - ->setTimestamp(time()) - ->setSubject( - $addToFavorite ? FavoriteProvider::SUBJECT_ADDED : FavoriteProvider::SUBJECT_REMOVED, - ['id' => $fileId, 'path' => $path] - ); - $this->activityManager->publish($event); - } catch (\InvalidArgumentException $e) { - } catch (\BadMethodCallException $e) { - } - } } diff --git a/apps/files/tests/Service/TagServiceTest.php b/apps/files/tests/Service/TagServiceTest.php index 50c8d586587cf..0e0149cc71b64 100644 --- a/apps/files/tests/Service/TagServiceTest.php +++ b/apps/files/tests/Service/TagServiceTest.php @@ -9,7 +9,6 @@ use OCA\Files\Service\TagService; use OCP\Activity\IManager; -use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Folder; use OCP\Files\NotFoundException; use OCP\ITags; @@ -41,9 +40,6 @@ class TagServiceTest extends \Test\TestCase { */ private $root; - /** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */ - private $dispatcher; - /** * @var TagService|\PHPUnit\Framework\MockObject\MockObject */ @@ -72,7 +68,6 @@ protected function setUp(): void { ->willReturn($user); $this->root = \OC::$server->getUserFolder(); - $this->dispatcher = $this->createMock(IEventDispatcher::class); $this->tagger = \OC::$server->getTagManager()->load('files'); $this->tagService = $this->getTagService(['addActivity']); @@ -89,7 +84,6 @@ protected function getTagService(array $methods = []) { $this->activityManager, $this->tagger, $this->root, - $this->dispatcher, ]) ->setMethods($methods) ->getMock(); @@ -107,9 +101,6 @@ public function testUpdateFileTags(): void { $tag1 = 'tag1'; $tag2 = 'tag2'; - $this->tagService->expects($this->never()) - ->method('addActivity'); - $subdir = $this->root->newFolder('subdir'); $testFile = $subdir->newFile('test.txt'); $testFile->putContent('test contents'); @@ -141,27 +132,6 @@ public function testUpdateFileTags(): void { } $this->assertTrue($caught); - $subdir->delete(); - } - - public function testFavoriteActivity(): void { - $subdir = $this->root->newFolder('subdir'); - $file = $subdir->newFile('test.txt'); - - $this->tagService->expects($this->exactly(2)) - ->method('addActivity') - ->withConsecutive( - [true, $file->getId(), 'subdir/test.txt'], - [false, $file->getId(), 'subdir/test.txt'] - ); - - // set tags - $this->tagService->updateFileTags('subdir/test.txt', [ITags::TAG_FAVORITE]); - - // remove tag - $this->tagService->updateFileTags('subdir/test.txt', []); - - $subdir->delete(); } } diff --git a/lib/private/TagManager.php b/lib/private/TagManager.php index f99653f2c052f..5c346e1443060 100644 --- a/lib/private/TagManager.php +++ b/lib/private/TagManager.php @@ -11,6 +11,7 @@ use OCP\Db\Exception as DBException; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventDispatcher; use OCP\EventDispatcher\IEventListener; use OCP\IDBConnection; use OCP\ITagManager; @@ -23,16 +24,14 @@ * @template-implements IEventListener */ class TagManager implements ITagManager, IEventListener { - private TagMapper $mapper; - private IUserSession $userSession; - private IDBConnection $connection; - private LoggerInterface $logger; - public function __construct(TagMapper $mapper, IUserSession $userSession, IDBConnection $connection, LoggerInterface $logger) { - $this->mapper = $mapper; - $this->userSession = $userSession; - $this->connection = $connection; - $this->logger = $logger; + public function __construct( + private TagMapper $mapper, + private IUserSession $userSession, + private IDBConnection $connection, + private LoggerInterface $logger, + private IEventDispatcher $dispatcher, + ) { } /** @@ -57,7 +56,7 @@ public function load($type, $defaultTags = [], $includeShared = false, $userId = } $userId = $this->userSession->getUser()->getUId(); } - return new Tags($this->mapper, $userId, $type, $this->logger, $this->connection, $defaultTags); + return new Tags($this->mapper, $userId, $type, $this->logger, $this->connection, $this->dispatcher, $this->userSession, $defaultTags); } /** diff --git a/lib/private/Tags.php b/lib/private/Tags.php index d59c1bd692853..0a37f4c9f4e10 100644 --- a/lib/private/Tags.php +++ b/lib/private/Tags.php @@ -11,8 +11,12 @@ use OC\Tagging\TagMapper; use OCP\DB\Exception; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Events\NodeAddedToFavorite; +use OCP\Files\Events\NodeRemovedFromFavorite; use OCP\IDBConnection; use OCP\ITags; +use OCP\IUserSession; use OCP\Share_Backend; use Psr\Log\LoggerInterface; @@ -21,10 +25,6 @@ class Tags implements ITags { * Used for storing objectid/categoryname pairs while rescanning. */ private static array $relations = []; - private string $type; - private string $user; - private IDBConnection $db; - private LoggerInterface $logger; private array $tags = []; /** @@ -38,11 +38,6 @@ class Tags implements ITags { */ private array $owners = []; - /** - * The Mapper we are using to communicate our Tag objects to the database. - */ - private TagMapper $mapper; - /** * The sharing backend for objects of $this->type. Required if * $this->includeShared === true to determine ownership of items. @@ -62,14 +57,18 @@ class Tags implements ITags { * * since 20.0.0 $includeShared isn't used anymore */ - public function __construct(TagMapper $mapper, string $user, string $type, LoggerInterface $logger, IDBConnection $connection, array $defaultTags = []) { - $this->mapper = $mapper; - $this->user = $user; - $this->type = $type; + public function __construct( + private TagMapper $mapper, + private string $user, + private string $type, + private LoggerInterface $logger, + private IDBConnection $db, + private IEventDispatcher $dispatcher, + private IUserSession $userSession, + array $defaultTags = [], + ) { $this->owners = [$this->user]; $this->tags = $this->mapper->loadTags($this->owners, $this->type); - $this->db = $connection; - $this->logger = $logger; if (count($defaultTags) > 0 && count($this->tags) === 0) { $this->addMultiple($defaultTags, true); @@ -502,7 +501,7 @@ public function removeFromFavorites($objid) { * @param string $tag The id or name of the tag * @return boolean Returns false on error. */ - public function tagAs($objid, $tag) { + public function tagAs($objid, $tag, string $path = '') { if (is_string($tag) && !is_numeric($tag)) { $tag = trim($tag); if ($tag === '') { @@ -532,6 +531,9 @@ public function tagAs($objid, $tag) { ]); return false; } + if ($tag === ITags::TAG_FAVORITE) { + $this->dispatcher->dispatchTyped(new NodeAddedToFavorite($this->userSession->getUser(), $objid, $path)); + } return true; } @@ -542,7 +544,7 @@ public function tagAs($objid, $tag) { * @param string $tag The id or name of the tag * @return boolean */ - public function unTag($objid, $tag) { + public function unTag($objid, $tag, string $path = '') { if (is_string($tag) && !is_numeric($tag)) { $tag = trim($tag); if ($tag === '') { @@ -569,6 +571,9 @@ public function unTag($objid, $tag) { ]); return false; } + if ($tag === ITags::TAG_FAVORITE) { + $this->dispatcher->dispatchTyped(new NodeRemovedFromFavorite($this->userSession->getUser(), $objid, $path)); + } return true; } diff --git a/tests/lib/TagsTest.php b/tests/lib/TagsTest.php index 1876897095486..7483ed15e6b14 100644 --- a/tests/lib/TagsTest.php +++ b/tests/lib/TagsTest.php @@ -7,6 +7,7 @@ namespace Test; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IDBConnection; use OCP\IUser; use OCP\IUserSession; @@ -48,7 +49,7 @@ protected function setUp(): void { $this->objectType = $this->getUniqueID('type_'); $this->tagMapper = new \OC\Tagging\TagMapper(\OC::$server->get(IDBConnection::class)); - $this->tagMgr = new \OC\TagManager($this->tagMapper, $this->userSession, \OC::$server->get(IDBConnection::class), \OC::$server->get(LoggerInterface::class)); + $this->tagMgr = new \OC\TagManager($this->tagMapper, $this->userSession, \OC::$server->get(IDBConnection::class), \OC::$server->get(LoggerInterface::class), \OC::$server->get(IEventDispatcher::class)); } protected function tearDown(): void { @@ -65,7 +66,7 @@ public function testTagManagerWithoutUserReturnsNull(): void { ->expects($this->any()) ->method('getUser') ->willReturn(null); - $this->tagMgr = new \OC\TagManager($this->tagMapper, $this->userSession, \OC::$server->getDatabaseConnection(), \OC::$server->get(LoggerInterface::class)); + $this->tagMgr = new \OC\TagManager($this->tagMapper, $this->userSession, \OC::$server->getDatabaseConnection(), \OC::$server->get(LoggerInterface::class), \OC::$server->get(IEventDispatcher::class)); $this->assertNull($this->tagMgr->load($this->objectType)); }