diff options
author | skjnldsv <skjnldsv@protonmail.com> | 2024-10-22 15:56:03 +0200 |
---|---|---|
committer | skjnldsv <skjnldsv@protonmail.com> | 2024-10-29 09:08:31 +0100 |
commit | 14e2a8d3f982656e2a7c23c006fd59fdeebc80bd (patch) | |
tree | 216f9b391e4815daed88dbbf475252ad89fc42ae /apps/dav/lib | |
parent | f24b93e5067e54244d14eb08ad8ed8330a03724b (diff) | |
download | nextcloud-server-14e2a8d3f982656e2a7c23c006fd59fdeebc80bd.tar.gz nextcloud-server-14e2a8d3f982656e2a7c23c006fd59fdeebc80bd.zip |
feat(systemtags): add etag support and handle proppatch
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
Diffstat (limited to 'apps/dav/lib')
-rw-r--r-- | apps/dav/lib/SystemTag/SystemTagNode.php | 9 | ||||
-rw-r--r-- | apps/dav/lib/SystemTag/SystemTagObjectType.php | 36 | ||||
-rw-r--r-- | apps/dav/lib/SystemTag/SystemTagPlugin.php | 43 | ||||
-rw-r--r-- | apps/dav/lib/SystemTag/SystemTagsInUseCollection.php | 2 | ||||
-rw-r--r-- | apps/dav/lib/SystemTag/SystemTagsObjectList.php | 50 |
5 files changed, 125 insertions, 15 deletions
diff --git a/apps/dav/lib/SystemTag/SystemTagNode.php b/apps/dav/lib/SystemTag/SystemTagNode.php index 154bfa493f2..ed4eb44cbbd 100644 --- a/apps/dav/lib/SystemTag/SystemTagNode.php +++ b/apps/dav/lib/SystemTag/SystemTagNode.php @@ -184,7 +184,12 @@ class SystemTagNode implements \Sabre\DAV\ICollection { } public function getChildren() { - // We currently don't have a method to list allowed tag mappings types - return [new SystemTagObjectType($this->tag, 'files', $this->tagManager, $this->tagMapper)]; + $objectTypes = $this->tagMapper->getAvailableObjectTypes(); + return array_map( + function ($objectType) { + return new SystemTagObjectType($this->tag, $objectType, $this->tagManager, $this->tagMapper); + }, + $objectTypes + ); } } diff --git a/apps/dav/lib/SystemTag/SystemTagObjectType.php b/apps/dav/lib/SystemTag/SystemTagObjectType.php index 0279e4411d8..0e1368854cd 100644 --- a/apps/dav/lib/SystemTag/SystemTagObjectType.php +++ b/apps/dav/lib/SystemTag/SystemTagObjectType.php @@ -14,7 +14,7 @@ use Sabre\DAV\Exception\MethodNotAllowed; * SystemTagObjectType property * This property represent a type of object which tags are assigned to. */ -class SystemTagObjectType implements \Sabre\DAV\INode { +class SystemTagObjectType implements \Sabre\DAV\IFile { public const NS_NEXTCLOUD = 'http://nextcloud.org/ns'; /** @var string[] */ @@ -39,19 +39,43 @@ class SystemTagObjectType implements \Sabre\DAV\INode { return $this->objectsIds; } - public function delete() { - throw new MethodNotAllowed(); + /** + * Returns the system tag represented by this node + * + * @return ISystemTag system tag + */ + public function getSystemTag() { + return $this->tag; } public function getName() { return $this->type; } + public function getLastModified() { + return null; + } + + public function getETag() { + return '"' . $this->tag->getETag() . '"'; + } + public function setName($name) { throw new MethodNotAllowed(); } - - public function getLastModified() { - return null; + public function put($data) { + throw new MethodNotAllowed(); + } + public function get() { + throw new MethodNotAllowed(); + } + public function delete() { + throw new MethodNotAllowed(); + } + public function getContentType() { + throw new MethodNotAllowed(); + } + public function getSize() { + throw new MethodNotAllowed(); } } diff --git a/apps/dav/lib/SystemTag/SystemTagPlugin.php b/apps/dav/lib/SystemTag/SystemTagPlugin.php index 687b47284eb..c88a69f1154 100644 --- a/apps/dav/lib/SystemTag/SystemTagPlugin.php +++ b/apps/dav/lib/SystemTag/SystemTagPlugin.php @@ -8,6 +8,7 @@ namespace OCA\DAV\SystemTag; use OCA\DAV\Connector\Sabre\Directory; +use OCA\DAV\Connector\Sabre\FilesPlugin; use OCA\DAV\Connector\Sabre\Node; use OCP\IGroupManager; use OCP\IUser; @@ -20,6 +21,7 @@ use OCP\Util; use Sabre\DAV\Exception\BadRequest; use Sabre\DAV\Exception\Conflict; use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\PreconditionFailed; use Sabre\DAV\Exception\UnsupportedMediaType; use Sabre\DAV\PropFind; use Sabre\DAV\PropPatch; @@ -80,6 +82,9 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { */ public function initialize(\Sabre\DAV\Server $server) { $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc'; + $server->xml->namespaceMap[self::NS_NEXTCLOUD] = 'nc'; + + $server->xml->elementMap[self::OBJECTIDS_PROPERTYNAME] = SystemTagsObjectList::class; $server->protectedProperties[] = self::ID_PROPERTYNAME; @@ -213,6 +218,10 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { $propFind->setPath(str_replace('systemtags-assigned/', 'systemtags/', $propFind->getPath())); } + $propFind->handle(FilesPlugin::GETETAG_PROPERTYNAME, function () use ($node): string|null { + return $node->getSystemTag()->getETag(); + }); + $propFind->handle(self::ID_PROPERTYNAME, function () use ($node) { return $node->getSystemTag()->getId(); }); @@ -359,9 +368,37 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { */ public function handleUpdateProperties($path, PropPatch $propPatch) { $node = $this->server->tree->getNodeForPath($path); - if (!($node instanceof SystemTagNode)) { + if (!($node instanceof SystemTagNode) && !($node instanceof SystemTagObjectType)) { return; } + + $propPatch->handle([self::OBJECTIDS_PROPERTYNAME], function ($props) use ($node) { + if (!($node instanceof SystemTagObjectType)) { + return false; + } + + if (isset($props[self::OBJECTIDS_PROPERTYNAME])) { + $propValue = $props[self::OBJECTIDS_PROPERTYNAME]; + if (!($propValue instanceof SystemTagsObjectList) || count($propValue?->getObjects() ?: []) === 0) { + throw new BadRequest('Invalid object-ids property'); + } + + $objects = $propValue->getObjects(); + $objectTypes = array_unique(array_values($objects)); + + if (count($objectTypes) !== 1 || $objectTypes[0] !== $node->getName()) { + throw new BadRequest('Invalid object-ids property. All object types must be of the same type: ' . $node->getName()); + } + + $this->tagMapper->setObjectIdsForTag($node->getSystemTag()->getId(), $node->getName(), array_keys($objects)); + } + + if ($props[self::OBJECTIDS_PROPERTYNAME] === null) { + $this->tagMapper->setObjectIdsForTag($node->getSystemTag()->getId(), $node->getName(), []); + } + + return true; + }); $propPatch->handle([ self::DISPLAYNAME_PROPERTYNAME, @@ -371,6 +408,10 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { self::NUM_FILES_PROPERTYNAME, self::REFERENCE_FILEID_PROPERTYNAME, ], function ($props) use ($node) { + if (!($node instanceof SystemTagNode)) { + return false; + } + $tag = $node->getSystemTag(); $name = $tag->getName(); $userVisible = $tag->isUserVisible(); diff --git a/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php b/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php index c27926ec410..9b02a5be42c 100644 --- a/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php +++ b/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php @@ -73,7 +73,7 @@ class SystemTagsInUseCollection extends SimpleCollection { $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']); + $tag = new SystemTag((string)$tagData['id'], $tagData['name'], (bool)$tagData['visibility'], (bool)$tagData['editable'], $tagData['etag']); // 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/dav/lib/SystemTag/SystemTagsObjectList.php b/apps/dav/lib/SystemTag/SystemTagsObjectList.php index e25f1c804ee..0743b8d8130 100644 --- a/apps/dav/lib/SystemTag/SystemTagsObjectList.php +++ b/apps/dav/lib/SystemTag/SystemTagsObjectList.php @@ -1,4 +1,5 @@ <?php + declare(strict_types=1); /** @@ -7,21 +8,60 @@ declare(strict_types=1); */ namespace OCA\DAV\SystemTag; +use Sabre\Xml\Reader; use Sabre\Xml\Writer; +use Sabre\Xml\XmlDeserializable; use Sabre\Xml\XmlSerializable; /** * This property contains multiple "object-id" elements. */ -class SystemTagsObjectList implements XmlSerializable { +class SystemTagsObjectList implements XmlSerializable, XmlDeserializable { + public const NS_NEXTCLOUD = 'http://nextcloud.org/ns'; + public const OBJECTID_ROOT_PROPERTYNAME = '{http://nextcloud.org/ns}object-id'; + public const OBJECTID_PROPERTYNAME = '{http://nextcloud.org/ns}id'; + public const OBJECTTYPE_PROPERTYNAME = '{http://nextcloud.org/ns}type'; /** * @param array<string, string> $objects An array of object ids and their types */ public function __construct( private array $objects, - ) { } + ) { + } + + public function getObjects(): array { + return $this->objects; + } + + public static function xmlDeserialize(Reader $reader) { + $tree = $reader->parseInnerTree(); + if ($tree === null) { + return null; + } + + $objects = []; + foreach ($tree as $elem) { + if ($elem['name'] === self::OBJECTID_ROOT_PROPERTYNAME) { + $value = $elem['value']; + $id = ''; + $type = ''; + foreach ($value as $subElem) { + if ($subElem['name'] === self::OBJECTID_PROPERTYNAME) { + $id = $subElem['value']; + } elseif ($subElem['name'] === self::OBJECTTYPE_PROPERTYNAME) { + $type = $subElem['value']; + } + } + if ($id !== '' && $type !== '') { + $objects[$id] = $type; + } + } + } + + return new self($objects); + } /** * The xmlSerialize method is called during xml writing. @@ -31,9 +71,9 @@ class SystemTagsObjectList implements XmlSerializable { */ public function xmlSerialize(Writer $writer) { foreach ($this->objects as $objectsId => $type) { - $writer->startElement('{' . self::NS_NEXTCLOUD . '}object-id'); - $writer->writeElement('{' . self::NS_NEXTCLOUD . '}id', $objectsId); - $writer->writeElement('{' . self::NS_NEXTCLOUD . '}type', $type); + $writer->startElement(SystemTagPlugin::OBJECTIDS_PROPERTYNAME); + $writer->writeElement(self::OBJECTID_PROPERTYNAME, $objectsId); + $writer->writeElement(self::OBJECTTYPE_PROPERTYNAME, $type); $writer->endElement(); } } |