Skip to content

Commit fd6ce5f

Browse files
artongebackportbot[bot]
authored andcommitted
fix: Dispatch favorite event with an actual path
The `$path` argument was added in #48612, but was never actually used by the callers. The path was therefore missing in the favorite/unfavorite events, which lead to a broken activity information. I also added a fallback to handle `addToFavorites` and `removeFromFavorites`, which are part of a public API, and are calling `tagAs` and `untag` without `$path`. Fix nextcloud/activity#2134 Signed-off-by: Louis Chemineau <louis@chmn.me> [skip ci]
1 parent d0966a7 commit fd6ce5f

File tree

6 files changed

+59
-22
lines changed

6 files changed

+59
-22
lines changed

apps/dav/lib/Connector/Sabre/TagsPlugin.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,9 @@ private function prefetchTagsForFileIds(array $fileIds) {
173173
*
174174
* @param int $fileId
175175
* @param array $tags array of tag strings
176+
* @param string $path path of the file
176177
*/
177-
private function updateTags($fileId, $tags) {
178+
private function updateTags($fileId, $tags, string $path) {
178179
$tagger = $this->getTagger();
179180
$currentTags = $this->getTags($fileId);
180181

@@ -183,14 +184,14 @@ private function updateTags($fileId, $tags) {
183184
if ($tag === self::TAG_FAVORITE) {
184185
continue;
185186
}
186-
$tagger->tagAs($fileId, $tag);
187+
$tagger->tagAs($fileId, $tag, $path);
187188
}
188189
$deletedTags = array_diff($currentTags, $tags);
189190
foreach ($deletedTags as $tag) {
190191
if ($tag === self::TAG_FAVORITE) {
191192
continue;
192193
}
193-
$tagger->unTag($fileId, $tag);
194+
$tagger->unTag($fileId, $tag, $path);
194195
}
195196
}
196197

@@ -258,16 +259,16 @@ public function handleUpdateProperties($path, PropPatch $propPatch) {
258259
return;
259260
}
260261

261-
$propPatch->handle(self::TAGS_PROPERTYNAME, function ($tagList) use ($node) {
262-
$this->updateTags($node->getId(), $tagList->getTags());
262+
$propPatch->handle(self::TAGS_PROPERTYNAME, function ($tagList) use ($node, $path) {
263+
$this->updateTags($node->getId(), $tagList->getTags(), $path);
263264
return true;
264265
});
265266

266267
$propPatch->handle(self::FAVORITE_PROPERTYNAME, function ($favState) use ($node, $path) {
267268
if ((int)$favState === 1 || $favState === 'true') {
268-
$this->getTagger()->tagAs($node->getId(), self::TAG_FAVORITE);
269+
$this->getTagger()->tagAs($node->getId(), self::TAG_FAVORITE, $path);
269270
} else {
270-
$this->getTagger()->unTag($node->getId(), self::TAG_FAVORITE);
271+
$this->getTagger()->unTag($node->getId(), self::TAG_FAVORITE, $path);
271272
}
272273

273274
if (is_null($favState)) {

apps/files/lib/Service/TagService.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ public function updateFileTags($path, $tags) {
5454

5555
$newTags = array_diff($tags, $currentTags);
5656
foreach ($newTags as $tag) {
57-
$this->tagger->tagAs($fileId, $tag);
57+
$this->tagger->tagAs($fileId, $tag, $path);
5858
}
5959
$deletedTags = array_diff($currentTags, $tags);
6060
foreach ($deletedTags as $tag) {
61-
$this->tagger->unTag($fileId, $tag);
61+
$this->tagger->unTag($fileId, $tag, $path);
6262
}
6363

6464
// TODO: re-read from tagger to make sure the

lib/private/TagManager.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use OCP\EventDispatcher\Event;
1414
use OCP\EventDispatcher\IEventDispatcher;
1515
use OCP\EventDispatcher\IEventListener;
16+
use OCP\Files\IRootFolder;
1617
use OCP\IDBConnection;
1718
use OCP\ITagManager;
1819
use OCP\ITags;
@@ -31,6 +32,7 @@ public function __construct(
3132
private IDBConnection $connection,
3233
private LoggerInterface $logger,
3334
private IEventDispatcher $dispatcher,
35+
private IRootFolder $rootFolder,
3436
) {
3537
}
3638

@@ -56,7 +58,8 @@ public function load($type, $defaultTags = [], $includeShared = false, $userId =
5658
}
5759
$userId = $this->userSession->getUser()->getUId();
5860
}
59-
return new Tags($this->mapper, $userId, $type, $this->logger, $this->connection, $this->dispatcher, $this->userSession, $defaultTags);
61+
$userFolder = $this->rootFolder->getUserFolder($userId);
62+
return new Tags($this->mapper, $userId, $type, $this->logger, $this->connection, $this->dispatcher, $this->userSession, $userFolder, $defaultTags);
6063
}
6164

6265
/**

lib/private/Tags.php

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use OCP\EventDispatcher\IEventDispatcher;
1515
use OCP\Files\Events\NodeAddedToFavorite;
1616
use OCP\Files\Events\NodeRemovedFromFavorite;
17+
use OCP\Files\Folder;
1718
use OCP\IDBConnection;
1819
use OCP\ITags;
1920
use OCP\IUserSession;
@@ -65,6 +66,7 @@ public function __construct(
6566
private IDBConnection $db,
6667
private IEventDispatcher $dispatcher,
6768
private IUserSession $userSession,
69+
private Folder $userFolder,
6870
array $defaultTags = [],
6971
) {
7072
$this->owners = [$this->user];
@@ -495,12 +497,8 @@ public function removeFromFavorites($objid) {
495497

496498
/**
497499
* Creates a tag/object relation.
498-
*
499-
* @param int $objid The id of the object
500-
* @param string $tag The id or name of the tag
501-
* @return boolean Returns false on error.
502500
*/
503-
public function tagAs($objid, $tag, string $path = '') {
501+
public function tagAs($objid, $tag, ?string $path = null) {
504502
if (is_string($tag) && !is_numeric($tag)) {
505503
$tag = trim($tag);
506504
if ($tag === '') {
@@ -531,19 +529,24 @@ public function tagAs($objid, $tag, string $path = '') {
531529
return false;
532530
}
533531
if ($tag === ITags::TAG_FAVORITE) {
532+
if ($path === null) {
533+
$node = $this->userFolder->getFirstNodeById($objid);
534+
if ($node !== null) {
535+
$path = $node->getPath();
536+
} else {
537+
throw new Exception('Failed to favorite: node with id ' . $objid . ' not found');
538+
}
539+
}
540+
534541
$this->dispatcher->dispatchTyped(new NodeAddedToFavorite($this->userSession->getUser(), $objid, $path));
535542
}
536543
return true;
537544
}
538545

539546
/**
540547
* Delete single tag/object relation from the db
541-
*
542-
* @param int $objid The id of the object
543-
* @param string $tag The id or name of the tag
544-
* @return boolean
545548
*/
546-
public function unTag($objid, $tag, string $path = '') {
549+
public function unTag($objid, $tag, ?string $path = null) {
547550
if (is_string($tag) && !is_numeric($tag)) {
548551
$tag = trim($tag);
549552
if ($tag === '') {
@@ -571,6 +574,15 @@ public function unTag($objid, $tag, string $path = '') {
571574
return false;
572575
}
573576
if ($tag === ITags::TAG_FAVORITE) {
577+
if ($path === null) {
578+
$node = $this->userFolder->getFirstNodeById($objid);
579+
if ($node !== null) {
580+
$path = $node->getPath();
581+
} else {
582+
throw new Exception('Failed to unfavorite: node with id ' . $objid . ' not found');
583+
}
584+
}
585+
574586
$this->dispatcher->dispatchTyped(new NodeRemovedFromFavorite($this->userSession->getUser(), $objid, $path));
575587
}
576588
return true;

lib/public/ITags.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,20 +184,26 @@ public function removeFromFavorites($objid);
184184
*
185185
* @param int $objid The id of the object
186186
* @param string $tag The id or name of the tag
187+
* @param string $path The optional path of the node. Used when dispatching the favorite change event.
187188
* @return boolean Returns false on database error.
188189
* @since 6.0.0
190+
* @since 31.0.0 Added the $path argument.
191+
* @since 33.0.0 Change $path default value from '' to null.
189192
*/
190-
public function tagAs($objid, $tag);
193+
public function tagAs($objid, $tag, ?string $path = null);
191194

192195
/**
193196
* Delete single tag/object relation from the db
194197
*
195198
* @param int $objid The id of the object
196199
* @param string $tag The id or name of the tag
200+
* @param string $path The optional path of the node. Used when dispatching the favorite change event.
197201
* @return boolean
198202
* @since 6.0.0
203+
* @since 31.0.0 Added the $path argument.
204+
* @since 33.0.0 Change $path default value from '' to null.
199205
*/
200-
public function unTag($objid, $tag);
206+
public function unTag($objid, $tag, ?string $path = null);
201207

202208
/**
203209
* Delete tags from the database

tests/lib/TagsTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
namespace Test;
99

1010
use OCP\EventDispatcher\IEventDispatcher;
11+
use OCP\Files\Folder;
12+
use OCP\Files\IRootFolder;
13+
use OCP\Files\Node;
1114
use OCP\IDBConnection;
1215
use OCP\IUser;
1316
use OCP\IUserSession;
@@ -46,6 +49,18 @@ protected function setUp(): void {
4649
->expects($this->any())
4750
->method('getUser')
4851
->willReturn($this->user);
52+
$userFolder = $this->createMock(Folder::class);
53+
$node = $this->createMock(Node::class);
54+
$this->rootFolder = $this->createMock(IRootFolder::class);
55+
$this->rootFolder
56+
->method('getUserFolder')
57+
->willReturnCallback(fn () => $userFolder);
58+
$userFolder
59+
->method('getFirstNodeById')
60+
->willReturnCallback(fn () => $node);
61+
$node
62+
->method('getPath')
63+
->willReturnCallback(fn () => 'file.txt');
4964

5065
$this->objectType = $this->getUniqueID('type_');
5166
$this->tagMapper = new \OC\Tagging\TagMapper(\OC::$server->get(IDBConnection::class));

0 commit comments

Comments
 (0)