diff options
author | Arthur Schiwon <blizzz@arthur-schiwon.de> | 2023-04-27 22:24:16 +0200 |
---|---|---|
committer | Arthur Schiwon <blizzz@arthur-schiwon.de> | 2023-05-09 23:51:48 +0200 |
commit | 6bff6a56672f08ebe1255bfad73abebd91b25428 (patch) | |
tree | 093af1d534e73a053a9a4ea24ea4ebf3eaada283 /apps/dav/lib | |
parent | f734a7646639549b626c05b12a789c8cdedf2511 (diff) | |
download | nextcloud-server-6bff6a56672f08ebe1255bfad73abebd91b25428.tar.gz nextcloud-server-6bff6a56672f08ebe1255bfad73abebd91b25428.zip |
PoC: SystemTags endpoint to return tags used by a user with meta data
Target case is photos app: when visiting the tags category, all systemtags
of the whole cloud are retrieved. In subequent steps the next tag is
requested until the browser view is filled with tag tiles (i.e. previews
are requested just as well).
With this approach, we incorpoate the dav search and look for user related
tags that are used by them, and already returns the statistics (number of
files tagged with the respective tag) as well as a file id for the purpose
to load the preview. This defaults to the file with the highest id.
Call:
curl -s -u 'user:password' \
'https://my.nc.srv/remote.php/dav/systemtags-current' \
-X PROPFIND -H 'Accept: text/plain' \
-H 'Accept-Language: en-US,en;q=0.5' -H 'Depth: 1' \
-H 'Content-Type: text/plain;charset=UTF-8' \
--data @/home/doe/request-systemtag-props.xml
With request-systemtag-props.xml:
<?xml version="1.0" encoding="UTF-8"?>
<d:propfind xmlns:d="DAV:">
<d:prop xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
<oc:id/>
<oc:display-name/>
<oc:user-visible/>
<oc:user-assignable/>
<oc:can-assign/>
<nc:files-assigned/>
<nc:reference-fileid/>
</d:prop>
</d:propfind>
Example output:
…
<d:response>
<d:href>/master/remote.php/dav/systemtags/84</d:href>
<d:propstat>
<d:prop>
<oc:id>84</oc:id>
<oc:display-name>Computer</oc:display-name>
<oc:user-visible>true</oc:user-visible>
<oc:user-assignable>true</oc:user-assignable>
<oc:can-assign>true</oc:can-assign>
<nc:files-assigned>42</nc:files-assigned>
<nc:reference-fileid>924022</nc:reference-fileid>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:response>
<d:href>/remote.php/dav/systemtags/97</d:href>
<d:propstat>
<d:prop>
<oc:id>97</oc:id>
<oc:display-name>Bear</oc:display-name>
<oc:user-visible>true</oc:user-visible>
<oc:user-assignable>true</oc:user-assignable>
<oc:can-assign>true</oc:can-assign>
<nc:files-assigned>1</nc:files-assigned>
<nc:reference-fileid>923422</nc:reference-fileid>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
…
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
Diffstat (limited to 'apps/dav/lib')
-rw-r--r-- | apps/dav/lib/RootCollection.php | 7 | ||||
-rw-r--r-- | apps/dav/lib/SystemTag/SystemTagNode.php | 19 | ||||
-rw-r--r-- | apps/dav/lib/SystemTag/SystemTagPlugin.php | 24 | ||||
-rw-r--r-- | apps/dav/lib/SystemTag/SystemTagsInUseCollection.php | 67 |
4 files changed, 117 insertions, 0 deletions
diff --git a/apps/dav/lib/RootCollection.php b/apps/dav/lib/RootCollection.php index bacb550b415..ffc2c262cae 100644 --- a/apps/dav/lib/RootCollection.php +++ b/apps/dav/lib/RootCollection.php @@ -48,6 +48,7 @@ use OCP\Accounts\IAccountManager; use OCP\App\IAppManager; use OCP\AppFramework\Utility\ITimeFactory; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\IRootFolder; use OCP\IConfig; use Psr\Log\LoggerInterface; use Sabre\DAV\SimpleCollection; @@ -65,6 +66,7 @@ class RootCollection extends SimpleCollection { $dispatcher = \OC::$server->get(IEventDispatcher::class); $config = \OC::$server->get(IConfig::class); $proxyMapper = \OC::$server->query(ProxyMapper::class); + $rootFolder = \OCP\Server::get(IRootFolder::class); $userPrincipalBackend = new Principal( $userManager, @@ -131,6 +133,10 @@ class RootCollection extends SimpleCollection { $groupManager, \OC::$server->getEventDispatcher() ); + $systemTagInUseCollection = new SystemTag\SystemTagsInUseCollection( + $userSession, + $rootFolder + ); $commentsCollection = new Comments\RootCollection( \OC::$server->getCommentsManager(), $userManager, @@ -179,6 +185,7 @@ class RootCollection extends SimpleCollection { $systemAddressBookRoot]), $systemTagCollection, $systemTagRelationsCollection, + $systemTagInUseCollection, $commentsCollection, $uploadCollection, $avatarCollection, diff --git a/apps/dav/lib/SystemTag/SystemTagNode.php b/apps/dav/lib/SystemTag/SystemTagNode.php index 7310cdb19a2..8ade5085b03 100644 --- a/apps/dav/lib/SystemTag/SystemTagNode.php +++ b/apps/dav/lib/SystemTag/SystemTagNode.php @@ -64,6 +64,9 @@ class SystemTagNode implements \Sabre\DAV\INode { */ protected $isAdmin; + protected int $numberOfFiles = -1; + protected int $referenceFileId = -1; + /** * Sets up the node, expects a full path name * @@ -179,4 +182,20 @@ class SystemTagNode implements \Sabre\DAV\INode { throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found', 0, $e); } } + + public function getNumberOfFiles(): int { + return $this->numberOfFiles; + } + + public function setNumberOfFiles(int $numberOfFiles): void { + $this->numberOfFiles = $numberOfFiles; + } + + public function getReferenceFileId(): int { + return $this->referenceFileId; + } + + public function setReferenceFileId(int $referenceFileId): void { + $this->referenceFileId = $referenceFileId; + } } diff --git a/apps/dav/lib/SystemTag/SystemTagPlugin.php b/apps/dav/lib/SystemTag/SystemTagPlugin.php index c5c828cfbff..52ddc7b1b40 100644 --- a/apps/dav/lib/SystemTag/SystemTagPlugin.php +++ b/apps/dav/lib/SystemTag/SystemTagPlugin.php @@ -61,6 +61,8 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { public const GROUPS_PROPERTYNAME = '{http://owncloud.org/ns}groups'; public const CANASSIGN_PROPERTYNAME = '{http://owncloud.org/ns}can-assign'; public const SYSTEM_TAGS_PROPERTYNAME = '{http://nextcloud.org/ns}system-tags'; + public const NUM_FILES_PROPERTYNAME = '{http://nextcloud.org/ns}files-assigned'; + public const FILEID_PROPERTYNAME = '{http://nextcloud.org/ns}reference-fileid'; /** * @var \Sabre\DAV\Server $server @@ -242,6 +244,11 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { return; } + // child nodes from systemtags-current should point to normal tag endpoint + if (preg_match('/^systemtags-current\/[0-9]+/', $propFind->getPath())) { + $propFind->setPath(str_replace('systemtags-current/', 'systemtags/', $propFind->getPath())); + } + $propFind->handle(self::ID_PROPERTYNAME, function () use ($node) { return $node->getSystemTag()->getId(); }); @@ -276,6 +283,16 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { } return implode('|', $groups); }); + + if ($node instanceof SystemTagNode) { + $propFind->handle(self::NUM_FILES_PROPERTYNAME, function () use ($node): int { + return $node->getNumberOfFiles(); + }); + + $propFind->handle(self::FILEID_PROPERTYNAME, function () use ($node): int { + return $node->getReferenceFileId(); + }); + } } private function propfindForFile(PropFind $propFind, Node $node): void { @@ -370,6 +387,8 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { self::USERVISIBLE_PROPERTYNAME, self::USERASSIGNABLE_PROPERTYNAME, self::GROUPS_PROPERTYNAME, + self::NUM_FILES_PROPERTYNAME, + self::FILEID_PROPERTYNAME, ], function ($props) use ($node) { $tag = $node->getSystemTag(); $name = $tag->getName(); @@ -406,6 +425,11 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { $this->tagManager->setTagGroups($tag, $groupIds); } + if (isset($props[self::NUM_FILES_PROPERTYNAME]) || isset($props[self::FILEID_PROPERTYNAME])) { + // read-only properties + throw new Forbidden(); + } + if ($updateTag) { $node->update($name, $userVisible, $userAssignable); } diff --git a/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php b/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php new file mode 100644 index 00000000000..938b14e1f65 --- /dev/null +++ b/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php @@ -0,0 +1,67 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Arthur Schiwon <blizzz@arthur-schiwon.de> + * + * @author Arthur Schiwon <blizzz@arthur-schiwon.de> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +namespace OCA\DAV\SystemTag; + +use OC\SystemTag\SystemTag; +use OCP\Files\IRootFolder; +use OCP\IUserSession; +use OCP\SystemTag\ISystemTagManager; +use Sabre\DAV\Exception\Forbidden; + +class SystemTagsInUseCollection extends \Sabre\DAV\SimpleCollection { + protected IUserSession $userSession; + protected IRootFolder $rootFolder; + + public function __construct(IUserSession $userSession, IRootFolder $rootFolder) { + $this->userSession = $userSession; + $this->rootFolder = $rootFolder; + $this->name = 'systemtags-current'; + } + + public function setName($name): void { + throw new Forbidden('Permission denied to rename this collection'); + } + + public function getChildren() { + $user = $this->userSession->getUser(); + if ($user === null) { + throw new Forbidden('Permission denied to read this collection'); + } + + $userFolder = $this->rootFolder->getUserFolder($user->getUID()); + $result = $userFolder->getSystemTags('image'); + $children = []; + foreach ($result as $tagData) { + $tag = new SystemTag((string)$tagData['id'], $tagData['name'], (bool)$tagData['visibility'], (bool)$tagData['editable']); + $node = new SystemTagNode($tag, $user, false, \OCP\Server::get(ISystemTagManager::class)); + $node->setNumberOfFiles($tagData['number_files']); + $node->setReferenceFileId($tagData['ref_file_id']); + $children[] = $node; + } + return $children; + } +} |