From e433c88e926c72877755b167ec465e293a895f32 Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Fri, 15 Nov 2024 11:06:35 +0100 Subject: [PATCH] feat(systemtags): add color support backend Signed-off-by: skjnldsv --- apps/dav/lib/SystemTag/SystemTagNode.php | 5 ++- apps/dav/lib/SystemTag/SystemTagPlugin.php | 14 +++++- .../SystemTag/SystemTagsInUseCollection.php | 2 +- .../composer/composer/autoload_classmap.php | 2 + .../composer/composer/autoload_static.php | 2 + .../Version31000Date20241018063111.php | 8 +--- .../Version31000Date20241114171300.php | 43 +++++++++++++++++++ lib/private/SystemTag/SystemTag.php | 23 +++------- lib/private/SystemTag/SystemTagManager.php | 42 ++++-------------- lib/public/SystemTag/ISystemTag.php | 7 +++ 10 files changed, 86 insertions(+), 62 deletions(-) rename {core/Migrations => apps/systemtags/lib/Migration}/Version31000Date20241018063111.php (89%) create mode 100644 apps/systemtags/lib/Migration/Version31000Date20241114171300.php diff --git a/apps/dav/lib/SystemTag/SystemTagNode.php b/apps/dav/lib/SystemTag/SystemTagNode.php index ed4eb44cbbd43..350547865f9ab 100644 --- a/apps/dav/lib/SystemTag/SystemTagNode.php +++ b/apps/dav/lib/SystemTag/SystemTagNode.php @@ -86,12 +86,13 @@ public function setName($name) { * @param string $name new tag name * @param bool $userVisible user visible * @param bool $userAssignable user assignable + * @param string $color color * * @throws NotFound whenever the given tag id does not exist * @throws Forbidden whenever there is no permission to update said tag * @throws Conflict whenever a tag already exists with the given attributes */ - public function update($name, $userVisible, $userAssignable): void { + public function update($name, $userVisible, $userAssignable, $color): void { try { if (!$this->tagManager->canUserSeeTag($this->tag, $this->user)) { throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist'); @@ -110,7 +111,7 @@ public function update($name, $userVisible, $userAssignable): void { } } - $this->tagManager->updateTag($this->tag->getId(), $name, $userVisible, $userAssignable); + $this->tagManager->updateTag($this->tag->getId(), $name, $userVisible, $userAssignable, $color); } catch (TagNotFoundException $e) { throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist'); } catch (TagAlreadyExistsException $e) { diff --git a/apps/dav/lib/SystemTag/SystemTagPlugin.php b/apps/dav/lib/SystemTag/SystemTagPlugin.php index 00585953b2917..afa4b8149d045 100644 --- a/apps/dav/lib/SystemTag/SystemTagPlugin.php +++ b/apps/dav/lib/SystemTag/SystemTagPlugin.php @@ -49,6 +49,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { public const NUM_FILES_PROPERTYNAME = '{http://nextcloud.org/ns}files-assigned'; public const REFERENCE_FILEID_PROPERTYNAME = '{http://nextcloud.org/ns}reference-fileid'; public const OBJECTIDS_PROPERTYNAME = '{http://nextcloud.org/ns}object-ids'; + public const COLOR_PROPERTYNAME = '{http://nextcloud.org/ns}color'; /** * @var \Sabre\DAV\Server $server @@ -243,6 +244,10 @@ public function handleGetProperties( return $this->tagManager->canUserAssignTag($node->getSystemTag(), $this->userSession->getUser()) ? 'true' : 'false'; }); + $propFind->handle(self::COLOR_PROPERTYNAME, function () use ($node) { + return $node->getSystemTag()->getColor() ?? ''; + }); + $propFind->handle(self::GROUPS_PROPERTYNAME, function () use ($node) { if (!$this->groupManager->isAdmin($this->userSession->getUser()->getUID())) { // property only available for admins @@ -406,6 +411,7 @@ public function handleUpdateProperties($path, PropPatch $propPatch) { self::GROUPS_PROPERTYNAME, self::NUM_FILES_PROPERTYNAME, self::REFERENCE_FILEID_PROPERTYNAME, + self::COLOR_PROPERTYNAME, ], function ($props) use ($node) { if (!($node instanceof SystemTagNode)) { return false; @@ -415,6 +421,7 @@ public function handleUpdateProperties($path, PropPatch $propPatch) { $name = $tag->getName(); $userVisible = $tag->isUserVisible(); $userAssignable = $tag->isUserAssignable(); + $color = $tag->getColor(); $updateTag = false; @@ -435,6 +442,11 @@ public function handleUpdateProperties($path, PropPatch $propPatch) { $updateTag = true; } + if (isset($props[self::COLOR_PROPERTYNAME])) { + $color = $props[self::COLOR_PROPERTYNAME]; + $updateTag = true; + } + if (isset($props[self::GROUPS_PROPERTYNAME])) { if (!$this->groupManager->isAdmin($this->userSession->getUser()->getUID())) { // property only available for admins @@ -452,7 +464,7 @@ public function handleUpdateProperties($path, PropPatch $propPatch) { } if ($updateTag) { - $node->update($name, $userVisible, $userAssignable); + $node->update($name, $userVisible, $userAssignable, $color); } return true; diff --git a/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php b/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php index 9b02a5be42c5e..f11482b04ee1e 100644 --- a/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php +++ b/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php @@ -73,7 +73,7 @@ public function getChildren(): array { $result = $this->systemTagsInFilesDetector->detectAssignedSystemTagsIn($userFolder, $this->mediaType); $children = []; foreach ($result as $tagData) { - $tag = new SystemTag((string)$tagData['id'], $tagData['name'], (bool)$tagData['visibility'], (bool)$tagData['editable'], $tagData['etag']); + $tag = new SystemTag((string)$tagData['id'], $tagData['name'], (bool)$tagData['visibility'], (bool)$tagData['editable'], $tagData['etag'], $tagData['color']); // read only, so we can submit the isAdmin parameter as false generally $node = new SystemTagNode($tag, $user, false, $this->systemTagManager, $this->tagMapper); $node->setNumberOfFiles((int)$tagData['number_files']); diff --git a/apps/systemtags/composer/composer/autoload_classmap.php b/apps/systemtags/composer/composer/autoload_classmap.php index 20174ee466797..e6c60728ff6ea 100644 --- a/apps/systemtags/composer/composer/autoload_classmap.php +++ b/apps/systemtags/composer/composer/autoload_classmap.php @@ -16,6 +16,8 @@ 'OCA\\SystemTags\\Listeners\\BeforeSabrePubliclyLoadedListener' => $baseDir . '/../lib/Listeners/BeforeSabrePubliclyLoadedListener.php', 'OCA\\SystemTags\\Listeners\\BeforeTemplateRenderedListener' => $baseDir . '/../lib/Listeners/BeforeTemplateRenderedListener.php', 'OCA\\SystemTags\\Listeners\\LoadAdditionalScriptsListener' => $baseDir . '/../lib/Listeners/LoadAdditionalScriptsListener.php', + 'OCA\\SystemTags\\Migration\\Version31000Date20241018063111' => $baseDir . '/../lib/Migration/Version31000Date20241018063111.php', + 'OCA\\SystemTags\\Migration\\Version31000Date20241114171300' => $baseDir . '/../lib/Migration/Version31000Date20241114171300.php', 'OCA\\SystemTags\\Search\\TagSearchProvider' => $baseDir . '/../lib/Search/TagSearchProvider.php', 'OCA\\SystemTags\\Settings\\Admin' => $baseDir . '/../lib/Settings/Admin.php', ); diff --git a/apps/systemtags/composer/composer/autoload_static.php b/apps/systemtags/composer/composer/autoload_static.php index 04dae4aa52f2a..3d61ea1a1c17d 100644 --- a/apps/systemtags/composer/composer/autoload_static.php +++ b/apps/systemtags/composer/composer/autoload_static.php @@ -31,6 +31,8 @@ class ComposerStaticInitSystemTags 'OCA\\SystemTags\\Listeners\\BeforeSabrePubliclyLoadedListener' => __DIR__ . '/..' . '/../lib/Listeners/BeforeSabrePubliclyLoadedListener.php', 'OCA\\SystemTags\\Listeners\\BeforeTemplateRenderedListener' => __DIR__ . '/..' . '/../lib/Listeners/BeforeTemplateRenderedListener.php', 'OCA\\SystemTags\\Listeners\\LoadAdditionalScriptsListener' => __DIR__ . '/..' . '/../lib/Listeners/LoadAdditionalScriptsListener.php', + 'OCA\\SystemTags\\Migration\\Version31000Date20241018063111' => __DIR__ . '/..' . '/../lib/Migration/Version31000Date20241018063111.php', + 'OCA\\SystemTags\\Migration\\Version31000Date20241114171300' => __DIR__ . '/..' . '/../lib/Migration/Version31000Date20241114171300.php', 'OCA\\SystemTags\\Search\\TagSearchProvider' => __DIR__ . '/..' . '/../lib/Search/TagSearchProvider.php', 'OCA\\SystemTags\\Settings\\Admin' => __DIR__ . '/..' . '/../lib/Settings/Admin.php', ); diff --git a/core/Migrations/Version31000Date20241018063111.php b/apps/systemtags/lib/Migration/Version31000Date20241018063111.php similarity index 89% rename from core/Migrations/Version31000Date20241018063111.php rename to apps/systemtags/lib/Migration/Version31000Date20241018063111.php index ce4c42df15918..f813c4e0dee5d 100644 --- a/core/Migrations/Version31000Date20241018063111.php +++ b/apps/systemtags/lib/Migration/Version31000Date20241018063111.php @@ -7,7 +7,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace OC\Core\Migrations; +namespace OCA\SystemTags\Migration; use Closure; use Doctrine\DBAL\Types\Types; @@ -26,12 +26,6 @@ #[AddIndex(table: 'systemtag_object_mapping', type: IndexType::INDEX, description: 'Adding objecttype index to systemtag_object_mapping')] class Version31000Date20241018063111 extends SimpleMigrationStep { - /** - * @param IOutput $output - * @param Closure(): ISchemaWrapper $schemaClosure - * @param array $options - * @return null|ISchemaWrapper - */ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { /** @var ISchemaWrapper $schema */ $schema = $schemaClosure(); diff --git a/apps/systemtags/lib/Migration/Version31000Date20241114171300.php b/apps/systemtags/lib/Migration/Version31000Date20241114171300.php new file mode 100644 index 0000000000000..5830d3aefae63 --- /dev/null +++ b/apps/systemtags/lib/Migration/Version31000Date20241114171300.php @@ -0,0 +1,43 @@ +hasTable('systemtag')) { + $table = $schema->getTable('systemtag'); + + if (!$table->hasColumn('color')) { + $table->addColumn('color', Types::STRING, [ + 'notnull' => false, + 'length' => 6, + ]); + } + } + + return $schema; + } +} diff --git a/lib/private/SystemTag/SystemTag.php b/lib/private/SystemTag/SystemTag.php index 8c64f2389d01e..1e3e40e3218dd 100644 --- a/lib/private/SystemTag/SystemTag.php +++ b/lib/private/SystemTag/SystemTag.php @@ -17,40 +17,26 @@ public function __construct( private bool $userVisible, private bool $userAssignable, private ?string $etag = null, + private ?string $color = null ) { } - /** - * {@inheritdoc} - */ public function getId(): string { return $this->id; } - /** - * {@inheritdoc} - */ public function getName(): string { return $this->name; } - /** - * {@inheritdoc} - */ public function isUserVisible(): bool { return $this->userVisible; } - /** - * {@inheritdoc} - */ public function isUserAssignable(): bool { return $this->userAssignable; } - /** - * {@inheritdoc} - */ public function getAccessLevel(): int { if (!$this->userVisible) { return self::ACCESS_LEVEL_INVISIBLE; @@ -63,10 +49,11 @@ public function getAccessLevel(): int { return self::ACCESS_LEVEL_PUBLIC; } - /** - * {@inheritdoc} - */ public function getETag(): ?string { return $this->etag; } + + public function getColor(): ?string { + return $this->color; + } } diff --git a/lib/private/SystemTag/SystemTagManager.php b/lib/private/SystemTag/SystemTagManager.php index 70bb8e6e70b25..45315ea1ef34a 100644 --- a/lib/private/SystemTag/SystemTagManager.php +++ b/lib/private/SystemTag/SystemTagManager.php @@ -45,9 +45,6 @@ public function __construct( ->andWhere($query->expr()->eq('editable', $query->createParameter('editable'))); } - /** - * {@inheritdoc} - */ public function getTagsByIds($tagIds, ?IUser $user = null): array { if (!\is_array($tagIds)) { $tagIds = [$tagIds]; @@ -92,9 +89,6 @@ public function getTagsByIds($tagIds, ?IUser $user = null): array { return $tags; } - /** - * {@inheritdoc} - */ public function getAllTags($visibilityFilter = null, $nameSearchPattern = null): array { $tags = []; @@ -130,9 +124,6 @@ public function getAllTags($visibilityFilter = null, $nameSearchPattern = null): return $tags; } - /** - * {@inheritdoc} - */ public function getTag(string $tagName, bool $userVisible, bool $userAssignable): ISystemTag { // Length of name column is 64 $truncatedTagName = substr($tagName, 0, 64); @@ -153,9 +144,6 @@ public function getTag(string $tagName, bool $userVisible, bool $userAssignable) return $this->createSystemTagFromRow($row); } - /** - * {@inheritdoc} - */ public function createTag(string $tagName, bool $userVisible, bool $userAssignable): ISystemTag { // Length of name column is 64 $truncatedTagName = substr($tagName, 0, 64); @@ -194,14 +182,12 @@ public function createTag(string $tagName, bool $userVisible, bool $userAssignab return $tag; } - /** - * {@inheritdoc} - */ public function updateTag( string $tagId, string $newName, bool $userVisible, bool $userAssignable, + string $color = '' ): void { try { $tags = $this->getTagsByIds($tagId); @@ -218,7 +204,9 @@ public function updateTag( $tagId, $truncatedNewName, $userVisible, - $userAssignable + $userAssignable, + $beforeUpdate->getETag(), + $color ); $query = $this->connection->getQueryBuilder(); @@ -226,11 +214,13 @@ public function updateTag( ->set('name', $query->createParameter('name')) ->set('visibility', $query->createParameter('visibility')) ->set('editable', $query->createParameter('editable')) + ->set('color', $query->createParameter('color')) ->where($query->expr()->eq('id', $query->createParameter('tagid'))) ->setParameter('name', $truncatedNewName) ->setParameter('visibility', $userVisible ? 1 : 0) ->setParameter('editable', $userAssignable ? 1 : 0) - ->setParameter('tagid', $tagId); + ->setParameter('tagid', $tagId) + ->setParameter('color', $color); try { if ($query->execute() === 0) { @@ -251,9 +241,6 @@ public function updateTag( )); } - /** - * {@inheritdoc} - */ public function deleteTags($tagIds): void { if (!\is_array($tagIds)) { $tagIds = [$tagIds]; @@ -303,9 +290,6 @@ public function deleteTags($tagIds): void { } } - /** - * {@inheritdoc} - */ public function canUserAssignTag(ISystemTag $tag, ?IUser $user): bool { if ($user === null) { return false; @@ -335,9 +319,6 @@ public function canUserAssignTag(ISystemTag $tag, ?IUser $user): bool { return false; } - /** - * {@inheritdoc} - */ public function canUserSeeTag(ISystemTag $tag, ?IUser $user): bool { // If no user, then we only show public tags if (!$user && $tag->getAccessLevel() === ISystemTag::ACCESS_LEVEL_PUBLIC) { @@ -361,12 +342,9 @@ public function canUserSeeTag(ISystemTag $tag, ?IUser $user): bool { } private function createSystemTagFromRow($row): SystemTag { - return new SystemTag((string)$row['id'], $row['name'], (bool)$row['visibility'], (bool)$row['editable'], $row['etag']); + return new SystemTag((string)$row['id'], $row['name'], (bool)$row['visibility'], (bool)$row['editable'], $row['etag'], $row['color']); } - /** - * {@inheritdoc} - */ public function setTagGroups(ISystemTag $tag, array $groupIds): void { // delete relationships first $this->connection->beginTransaction(); @@ -398,9 +376,6 @@ public function setTagGroups(ISystemTag $tag, array $groupIds): void { } } - /** - * {@inheritdoc} - */ public function getTagGroups(ISystemTag $tag): array { $groupIds = []; $query = $this->connection->getQueryBuilder(); @@ -418,4 +393,5 @@ public function getTagGroups(ISystemTag $tag): array { return $groupIds; } + } diff --git a/lib/public/SystemTag/ISystemTag.php b/lib/public/SystemTag/ISystemTag.php index 593c127ba63c1..4fd93831955bf 100644 --- a/lib/public/SystemTag/ISystemTag.php +++ b/lib/public/SystemTag/ISystemTag.php @@ -89,4 +89,11 @@ public function getAccessLevel(): int; * @since 31.0.0 */ public function getETag(): ?string; + + /** + * Returns the color of the tag + * + * @since 31.0.0 + */ + public function getColor(): ?string; }