diff --git a/apps/dav/lib/Connector/Sabre/TagsPlugin.php b/apps/dav/lib/Connector/Sabre/TagsPlugin.php index 9f9c3be24c5ef..c92003a65415e 100644 --- a/apps/dav/lib/Connector/Sabre/TagsPlugin.php +++ b/apps/dav/lib/Connector/Sabre/TagsPlugin.php @@ -41,7 +41,7 @@ class TagsPlugin extends \Sabre\DAV\ServerPlugin { public const NS_OWNCLOUD = 'http://owncloud.org/ns'; public const TAGS_PROPERTYNAME = '{http://owncloud.org/ns}tags'; public const FAVORITE_PROPERTYNAME = '{http://owncloud.org/ns}favorite'; - public const TAG_FAVORITE = '_$!!$_'; + public const TAG_FAVORITE = ITags::TAG_FAVORITE; /** * Reference to main server object diff --git a/apps/files/lib/Service/TagService.php b/apps/files/lib/Service/TagService.php index 9e5661eef6fcc..975d594003eb1 100644 --- a/apps/files/lib/Service/TagService.php +++ b/apps/files/lib/Service/TagService.php @@ -54,6 +54,9 @@ public function updateFileTags($path, $tags) { throw new \RuntimeException('No homeFolder set'); } + // Only handle the favorite tag + $tags = array_filter($tags, static fn (string $tag): bool => $tag === ITags::TAG_FAVORITE); + $fileId = $this->homeFolder->get($path)->getId(); $currentTags = $this->tagger->getTagsForObjects([$fileId]); diff --git a/apps/files/tests/Service/TagServiceTest.php b/apps/files/tests/Service/TagServiceTest.php index b914489053fbc..97e78d2b746c8 100644 --- a/apps/files/tests/Service/TagServiceTest.php +++ b/apps/files/tests/Service/TagServiceTest.php @@ -82,8 +82,7 @@ protected function tearDown(): void { } public function testUpdateFileTags(): void { - $tag1 = 'tag1'; - $tag2 = 'tag2'; + $tag1 = ITags::TAG_FAVORITE; $subdir = $this->root->newFolder('subdir'); $testFile = $subdir->newFile('test.txt'); @@ -92,26 +91,17 @@ public function testUpdateFileTags(): void { $fileId = $testFile->getId(); // set tags - $this->tagService->updateFileTags('subdir/test.txt', [$tag1, $tag2]); + $this->tagService->updateFileTags('subdir/test.txt', [$tag1]); // Sync to reload tags - $this->tagger->addMultiple([], sync:true); + $this->tagger->addMultiple([], sync: true); $this->assertEquals([$fileId], $this->tagger->getIdsForTag($tag1)); - $this->assertEquals([$fileId], $this->tagger->getIdsForTag($tag2)); - - // remove tag - $this->tagService->updateFileTags('subdir/test.txt', [$tag2]); - // Sync to reload tags - $this->tagger->addMultiple([], sync:true); - $this->assertEquals([], $this->tagger->getIdsForTag($tag1)); - $this->assertEquals([$fileId], $this->tagger->getIdsForTag($tag2)); // clear tags $this->tagService->updateFileTags('subdir/test.txt', []); // Sync to reload tags - $this->tagger->addMultiple([], sync:true); + $this->tagger->addMultiple([], sync: true); $this->assertEquals([], $this->tagger->getIdsForTag($tag1)); - $this->assertEquals([], $this->tagger->getIdsForTag($tag2)); // non-existing file $caught = false; diff --git a/lib/private/Tags.php b/lib/private/Tags.php index ec06259db70ce..b11ac49ce0428 100644 --- a/lib/private/Tags.php +++ b/lib/private/Tags.php @@ -194,17 +194,12 @@ public function getTagsForObjects(array $objIds) { */ #[\Override] public function getIdsForTag($tag) { - $tagId = false; - if (is_numeric($tag)) { - $tagId = $tag; - } elseif (is_string($tag)) { - $tag = trim($tag); - if ($tag === '') { - $this->logger->debug(__METHOD__ . ' Cannot use empty tag names', ['app' => 'core']); - return false; - } - $tagId = $this->getTagId($tag); + $tag = trim((string)$tag); + if ($tag === '') { + $this->logger->debug(__METHOD__ . ' Cannot use empty tag names', ['app' => 'core']); + return false; } + $tagId = $this->getTagIdByIdOrName($tag); if ($tagId === false) { $l10n = Util::getL10N('core'); @@ -504,18 +499,15 @@ public function removeFromFavorites($objid) { */ #[\Override] public function tagAs($objid, $tag, ?string $path = null) { - if (is_string($tag) && !is_numeric($tag)) { - $tag = trim($tag); - if ($tag === '') { - $this->logger->debug(__METHOD__ . ', Cannot add an empty tag'); - return false; - } - if (!$this->hasTag($tag)) { - $this->add($tag); - } + $tag = trim((string)$tag); + if ($tag === '') { + $this->logger->debug(__METHOD__ . ', Cannot add an empty tag'); + return false; + } + $tagId = $this->getTagIdByIdOrName($tag); + if ($tagId === false) { + $this->add($tag); $tagId = $this->getTagId($tag); - } else { - $tagId = $tag; } $qb = $this->db->getQueryBuilder(); $qb->insert(self::RELATION_TABLE) @@ -553,16 +545,12 @@ public function tagAs($objid, $tag, ?string $path = null) { */ #[\Override] public function unTag($objid, $tag, ?string $path = null) { - if (is_string($tag) && !is_numeric($tag)) { - $tag = trim($tag); - if ($tag === '') { - $this->logger->debug(__METHOD__ . ', Tag name is empty'); - return false; - } - $tagId = $this->getTagId($tag); - } else { - $tagId = $tag; + $tag = trim((string)$tag); + if ($tag === '') { + $this->logger->debug(__METHOD__ . ', Tag name is empty'); + return false; } + $tagId = $this->getTagIdByIdOrName($tag); try { $qb = $this->db->getQueryBuilder(); @@ -671,6 +659,24 @@ private function getTagId($name) { return false; } + /** + * Get a tag's ID from either its ID or its name. + * + * A numeric value is only accepted as ID if it is the ID of one of the loaded tags. + * + * @param string $tag The tag ID or name to look for. + * @return string|bool The tag's id or false if no matching tag is found. + */ + private function getTagIdByIdOrName(string $tag) { + if (is_numeric($tag)) { + $key = $this->getTagById($tag); + if ($key !== false) { + return $this->tags[$key]->id ?? false; + } + } + return $this->getTagId($tag); + } + /** * Get a tag by its name. * diff --git a/tests/lib/TagsTest.php b/tests/lib/TagsTest.php index e2ef9eb25c024..2a69e8d87566a 100644 --- a/tests/lib/TagsTest.php +++ b/tests/lib/TagsTest.php @@ -306,6 +306,38 @@ public function testUnTag(): void { $this->assertEquals(0, count($tagger->getIdsForTag('Family'))); } + public function testTagById(): void { + $tagger = $this->tagMgr->load($this->objectType); + $tagId = $tagger->add('Family'); + + $this->assertTrue($tagger->tagAs(1, (string)$tagId)); + $this->assertEquals([1], $tagger->getIdsForTag('Family')); + $this->assertEquals([1], $tagger->getIdsForTag($tagId)); + $this->assertTrue($tagger->unTag(1, (string)$tagId)); + $this->assertEquals([], $tagger->getIdsForTag('Family')); + $this->assertEquals(1, count($tagger->getTags())); + } + + public function testTagByNumericValue(): void { + $otherTagger = $this->tagMgr->load($this->objectType, [], false, self::getUniqueID('user_')); + $otherTagId = $otherTagger->add('Family'); + $this->assertTrue($otherTagger->tagAs(1, 'Family')); + + $tagger = $this->tagMgr->load($this->objectType); + + // Treated as the name of an own tag + $this->assertTrue($tagger->tagAs(2, (string)$otherTagId)); + $this->assertTrue($tagger->hasTag((string)$otherTagId)); + $this->assertEquals([2], $tagger->getIdsForTag((string)$otherTagId)); + $this->assertEquals([1], $otherTagger->getIdsForTag('Family')); + + $tagger->unTag(1, (string)$otherTagId); + $this->assertEquals([1], $otherTagger->getIdsForTag('Family')); + + $tagger->unTag(2, (string)$otherTagId); + $this->assertEquals([], $tagger->getIdsForTag((string)$otherTagId)); + } + public function testFavorite(): void { $tagger = $this->tagMgr->load($this->objectType); $this->assertTrue($tagger->addToFavorites(1));