mirror of
https://github.com/nextcloud/server.git
synced 2026-06-09 00:32:29 -04:00
feat(dav): add systemtag object IDs listing
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
This commit is contained in:
parent
0893d4b4d2
commit
f24b93e506
11 changed files with 179 additions and 18 deletions
|
|
@ -362,6 +362,7 @@ return array(
|
|||
'OCA\\DAV\\SystemTag\\SystemTagList' => $baseDir . '/../lib/SystemTag/SystemTagList.php',
|
||||
'OCA\\DAV\\SystemTag\\SystemTagMappingNode' => $baseDir . '/../lib/SystemTag/SystemTagMappingNode.php',
|
||||
'OCA\\DAV\\SystemTag\\SystemTagNode' => $baseDir . '/../lib/SystemTag/SystemTagNode.php',
|
||||
'OCA\\DAV\\SystemTag\\SystemTagObjectType' => $baseDir . '/../lib/SystemTag/SystemTagObjectType.php',
|
||||
'OCA\\DAV\\SystemTag\\SystemTagPlugin' => $baseDir . '/../lib/SystemTag/SystemTagPlugin.php',
|
||||
'OCA\\DAV\\SystemTag\\SystemTagsByIdCollection' => $baseDir . '/../lib/SystemTag/SystemTagsByIdCollection.php',
|
||||
'OCA\\DAV\\SystemTag\\SystemTagsInUseCollection' => $baseDir . '/../lib/SystemTag/SystemTagsInUseCollection.php',
|
||||
|
|
|
|||
|
|
@ -377,6 +377,7 @@ class ComposerStaticInitDAV
|
|||
'OCA\\DAV\\SystemTag\\SystemTagList' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagList.php',
|
||||
'OCA\\DAV\\SystemTag\\SystemTagMappingNode' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagMappingNode.php',
|
||||
'OCA\\DAV\\SystemTag\\SystemTagNode' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagNode.php',
|
||||
'OCA\\DAV\\SystemTag\\SystemTagObjectType' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagObjectType.php',
|
||||
'OCA\\DAV\\SystemTag\\SystemTagPlugin' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagPlugin.php',
|
||||
'OCA\\DAV\\SystemTag\\SystemTagsByIdCollection' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagsByIdCollection.php',
|
||||
'OCA\\DAV\\SystemTag\\SystemTagsInUseCollection' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagsInUseCollection.php',
|
||||
|
|
|
|||
|
|
@ -105,11 +105,7 @@ class RootCollection extends SimpleCollection {
|
|||
|
||||
$publicCalendarRoot = new PublicCalendarRoot($caldavBackend, $l10n, $config, $logger);
|
||||
|
||||
$systemTagCollection = new SystemTagsByIdCollection(
|
||||
\OC::$server->getSystemTagManager(),
|
||||
\OC::$server->getUserSession(),
|
||||
$groupManager
|
||||
);
|
||||
$systemTagCollection = Server::get(SystemTagsByIdCollection::class);
|
||||
$systemTagRelationsCollection = new SystemTagsRelationsCollection(
|
||||
\OC::$server->getSystemTagManager(),
|
||||
\OC::$server->getSystemTagObjectMapper(),
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ namespace OCA\DAV\SystemTag;
|
|||
use OCP\IUser;
|
||||
use OCP\SystemTag\ISystemTag;
|
||||
use OCP\SystemTag\ISystemTagManager;
|
||||
use OCP\SystemTag\ISystemTagObjectMapper;
|
||||
use OCP\SystemTag\TagAlreadyExistsException;
|
||||
|
||||
use OCP\SystemTag\TagNotFoundException;
|
||||
use Sabre\DAV\Exception\Conflict;
|
||||
use Sabre\DAV\Exception\Forbidden;
|
||||
|
|
@ -21,7 +21,7 @@ use Sabre\DAV\Exception\NotFound;
|
|||
/**
|
||||
* DAV node representing a system tag, with the name being the tag id.
|
||||
*/
|
||||
class SystemTagNode implements \Sabre\DAV\INode {
|
||||
class SystemTagNode implements \Sabre\DAV\ICollection {
|
||||
|
||||
protected int $numberOfFiles = -1;
|
||||
protected int $referenceFileId = -1;
|
||||
|
|
@ -43,8 +43,9 @@ class SystemTagNode implements \Sabre\DAV\INode {
|
|||
/**
|
||||
* Whether to allow permissions for admins
|
||||
*/
|
||||
protected $isAdmin,
|
||||
protected bool $isAdmin,
|
||||
protected ISystemTagManager $tagManager,
|
||||
protected ISystemTagObjectMapper $tagMapper,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -164,4 +165,26 @@ class SystemTagNode implements \Sabre\DAV\INode {
|
|||
public function setReferenceFileId(int $referenceFileId): void {
|
||||
$this->referenceFileId = $referenceFileId;
|
||||
}
|
||||
|
||||
public function createFile($name, $data = null) {
|
||||
throw new MethodNotAllowed();
|
||||
}
|
||||
|
||||
public function createDirectory($name) {
|
||||
throw new MethodNotAllowed();
|
||||
}
|
||||
|
||||
public function getChild($name) {
|
||||
return new SystemTagObjectType($this->tag, $name, $this->tagManager, $this->tagMapper);
|
||||
}
|
||||
|
||||
public function childExists($name) {
|
||||
$objectTypes = $this->tagMapper->getAvailableObjectTypes();
|
||||
return in_array($name, $objectTypes);
|
||||
}
|
||||
|
||||
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)];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
57
apps/dav/lib/SystemTag/SystemTagObjectType.php
Normal file
57
apps/dav/lib/SystemTag/SystemTagObjectType.php
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
namespace OCA\DAV\SystemTag;
|
||||
|
||||
use OCP\SystemTag\ISystemTag;
|
||||
use OCP\SystemTag\ISystemTagManager;
|
||||
use OCP\SystemTag\ISystemTagObjectMapper;
|
||||
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 {
|
||||
public const NS_NEXTCLOUD = 'http://nextcloud.org/ns';
|
||||
|
||||
/** @var string[] */
|
||||
private array $objectsIds = [];
|
||||
|
||||
public function __construct(
|
||||
private ISystemTag $tag,
|
||||
private string $type,
|
||||
private ISystemTagManager $tagManager,
|
||||
private ISystemTagObjectMapper $tagMapper,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of object ids that have this tag assigned.
|
||||
*/
|
||||
public function getObjectsIds(): array {
|
||||
if (empty($this->objectsIds)) {
|
||||
$this->objectsIds = $this->tagMapper->getObjectIdsForTags($this->tag->getId(), $this->type);
|
||||
}
|
||||
|
||||
return $this->objectsIds;
|
||||
}
|
||||
|
||||
public function delete() {
|
||||
throw new MethodNotAllowed();
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function setName($name) {
|
||||
throw new MethodNotAllowed();
|
||||
}
|
||||
|
||||
public function getLastModified() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -37,6 +37,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
|
|||
|
||||
// namespace
|
||||
public const NS_OWNCLOUD = 'http://owncloud.org/ns';
|
||||
public const NS_NEXTCLOUD = 'http://nextcloud.org/ns';
|
||||
public const ID_PROPERTYNAME = '{http://owncloud.org/ns}id';
|
||||
public const DISPLAYNAME_PROPERTYNAME = '{http://owncloud.org/ns}display-name';
|
||||
public const USERVISIBLE_PROPERTYNAME = '{http://owncloud.org/ns}user-visible';
|
||||
|
|
@ -45,7 +46,8 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
|
|||
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';
|
||||
public const REFERENCE_FILEID_PROPERTYNAME = '{http://nextcloud.org/ns}reference-fileid';
|
||||
public const OBJECTIDS_PROPERTYNAME = '{http://nextcloud.org/ns}object-ids';
|
||||
|
||||
/**
|
||||
* @var \Sabre\DAV\Server $server
|
||||
|
|
@ -202,7 +204,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!($node instanceof SystemTagNode) && !($node instanceof SystemTagMappingNode)) {
|
||||
if (!($node instanceof SystemTagNode) && !($node instanceof SystemTagMappingNode) && !($node instanceof SystemTagObjectType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -251,9 +253,25 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
|
|||
return $node->getNumberOfFiles();
|
||||
});
|
||||
|
||||
$propFind->handle(self::FILEID_PROPERTYNAME, function () use ($node): int {
|
||||
$propFind->handle(self::REFERENCE_FILEID_PROPERTYNAME, function () use ($node): int {
|
||||
return $node->getReferenceFileId();
|
||||
});
|
||||
|
||||
$propFind->handle(self::OBJECTIDS_PROPERTYNAME, function () use ($node): SystemTagsObjectList {
|
||||
$objectTypes = $this->tagMapper->getAvailableObjectTypes();
|
||||
$objects = [];
|
||||
foreach ($objectTypes as $type) {
|
||||
$systemTagObjectType = new SystemTagObjectType($node->getSystemTag(), $type, $this->tagManager, $this->tagMapper);
|
||||
$objects = array_merge($objects, array_fill_keys($systemTagObjectType->getObjectsIds(), $type));
|
||||
}
|
||||
return new SystemTagsObjectList($objects);
|
||||
});
|
||||
}
|
||||
|
||||
if ($node instanceof SystemTagObjectType) {
|
||||
$propFind->handle(self::OBJECTIDS_PROPERTYNAME, function () use ($node): SystemTagsObjectList {
|
||||
return new SystemTagsObjectList(array_fill_keys($node->getObjectsIds(), $node->getName()));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -351,7 +369,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
|
|||
self::USERASSIGNABLE_PROPERTYNAME,
|
||||
self::GROUPS_PROPERTYNAME,
|
||||
self::NUM_FILES_PROPERTYNAME,
|
||||
self::FILEID_PROPERTYNAME,
|
||||
self::REFERENCE_FILEID_PROPERTYNAME,
|
||||
], function ($props) use ($node) {
|
||||
$tag = $node->getSystemTag();
|
||||
$name = $tag->getName();
|
||||
|
|
@ -388,7 +406,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
|
|||
$this->tagManager->setTagGroups($tag, $groupIds);
|
||||
}
|
||||
|
||||
if (isset($props[self::NUM_FILES_PROPERTYNAME]) || isset($props[self::FILEID_PROPERTYNAME])) {
|
||||
if (isset($props[self::NUM_FILES_PROPERTYNAME]) || isset($props[self::REFERENCE_FILEID_PROPERTYNAME])) {
|
||||
// read-only properties
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use OCP\IGroupManager;
|
|||
use OCP\IUserSession;
|
||||
use OCP\SystemTag\ISystemTag;
|
||||
use OCP\SystemTag\ISystemTagManager;
|
||||
use OCP\SystemTag\ISystemTagObjectMapper;
|
||||
use OCP\SystemTag\TagNotFoundException;
|
||||
use Sabre\DAV\Exception\BadRequest;
|
||||
use Sabre\DAV\Exception\Forbidden;
|
||||
|
|
@ -30,6 +31,7 @@ class SystemTagsByIdCollection implements ICollection {
|
|||
private ISystemTagManager $tagManager,
|
||||
private IUserSession $userSession,
|
||||
private IGroupManager $groupManager,
|
||||
protected ISystemTagObjectMapper $tagMapper,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -162,6 +164,6 @@ class SystemTagsByIdCollection implements ICollection {
|
|||
* @return SystemTagNode
|
||||
*/
|
||||
private function makeNode(ISystemTag $tag) {
|
||||
return new SystemTagNode($tag, $this->userSession->getUser(), $this->isAdmin(), $this->tagManager);
|
||||
return new SystemTagNode($tag, $this->userSession->getUser(), $this->isAdmin(), $this->tagManager, $this->tagMapper);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use OCP\Files\IRootFolder;
|
|||
use OCP\Files\NotPermittedException;
|
||||
use OCP\IUserSession;
|
||||
use OCP\SystemTag\ISystemTagManager;
|
||||
use OCP\SystemTag\ISystemTagObjectMapper;
|
||||
use Sabre\DAV\Exception\Forbidden;
|
||||
use Sabre\DAV\Exception\NotFound;
|
||||
use Sabre\DAV\SimpleCollection;
|
||||
|
|
@ -28,6 +29,7 @@ class SystemTagsInUseCollection extends SimpleCollection {
|
|||
protected IUserSession $userSession,
|
||||
protected IRootFolder $rootFolder,
|
||||
protected ISystemTagManager $systemTagManager,
|
||||
protected ISystemTagObjectMapper $tagMapper,
|
||||
SystemTagsInFilesDetector $systemTagsInFilesDetector,
|
||||
protected string $mediaType = '',
|
||||
) {
|
||||
|
|
@ -46,7 +48,7 @@ class SystemTagsInUseCollection extends SimpleCollection {
|
|||
if ($this->mediaType !== '') {
|
||||
throw new NotFound('Invalid media type');
|
||||
}
|
||||
return new self($this->userSession, $this->rootFolder, $this->systemTagManager, $this->systemTagsInFilesDetector, $name);
|
||||
return new self($this->userSession, $this->rootFolder, $this->systemTagManager, $this->tagMapper, $this->systemTagsInFilesDetector, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -73,7 +75,7 @@ class SystemTagsInUseCollection extends SimpleCollection {
|
|||
foreach ($result as $tagData) {
|
||||
$tag = new SystemTag((string)$tagData['id'], $tagData['name'], (bool)$tagData['visibility'], (bool)$tagData['editable']);
|
||||
// read only, so we can submit the isAdmin parameter as false generally
|
||||
$node = new SystemTagNode($tag, $user, false, $this->systemTagManager);
|
||||
$node = new SystemTagNode($tag, $user, false, $this->systemTagManager, $this->tagMapper);
|
||||
$node->setNumberOfFiles((int)$tagData['number_files']);
|
||||
$node->setReferenceFileId((int)$tagData['ref_file_id']);
|
||||
$children[] = $node;
|
||||
|
|
|
|||
40
apps/dav/lib/SystemTag/SystemTagsObjectList.php
Normal file
40
apps/dav/lib/SystemTag/SystemTagsObjectList.php
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCA\DAV\SystemTag;
|
||||
|
||||
use Sabre\Xml\Writer;
|
||||
use Sabre\Xml\XmlSerializable;
|
||||
|
||||
/**
|
||||
* This property contains multiple "object-id" elements.
|
||||
*/
|
||||
class SystemTagsObjectList implements XmlSerializable {
|
||||
public const NS_NEXTCLOUD = 'http://nextcloud.org/ns';
|
||||
|
||||
/**
|
||||
* @param array<string, string> $objects An array of object ids and their types
|
||||
*/
|
||||
public function __construct(
|
||||
private array $objects,
|
||||
) { }
|
||||
|
||||
/**
|
||||
* The xmlSerialize method is called during xml writing.
|
||||
*
|
||||
* @param Writer $writer
|
||||
* @return void
|
||||
*/
|
||||
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->endElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ use OCA\DAV\SystemTag\SystemTagNode;
|
|||
use OCP\IUser;
|
||||
use OCP\SystemTag\ISystemTag;
|
||||
use OCP\SystemTag\ISystemTagManager;
|
||||
use OCP\SystemTag\ISystemTagObjectMapper;
|
||||
use OCP\SystemTag\TagAlreadyExistsException;
|
||||
use OCP\SystemTag\TagNotFoundException;
|
||||
use Sabre\DAV\Exception\Forbidden;
|
||||
|
|
@ -23,6 +24,11 @@ class SystemTagNodeTest extends \Test\TestCase {
|
|||
*/
|
||||
private $tagManager;
|
||||
|
||||
/**
|
||||
* @var ISystemTagObjectMapper|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private $tagMapper;
|
||||
|
||||
/**
|
||||
* @var IUser
|
||||
*/
|
||||
|
|
@ -33,6 +39,8 @@ class SystemTagNodeTest extends \Test\TestCase {
|
|||
|
||||
$this->tagManager = $this->getMockBuilder(ISystemTagManager::class)
|
||||
->getMock();
|
||||
$this->tagMapper = $this->getMockBuilder(ISystemTagObjectMapper::class)
|
||||
->getMock();
|
||||
$this->user = $this->getMockBuilder(IUser::class)
|
||||
->getMock();
|
||||
}
|
||||
|
|
@ -45,7 +53,8 @@ class SystemTagNodeTest extends \Test\TestCase {
|
|||
$tag,
|
||||
$this->user,
|
||||
$isAdmin,
|
||||
$this->tagManager
|
||||
$this->tagManager,
|
||||
$this->tagMapper,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@ use OCP\IGroupManager;
|
|||
use OCP\IUser;
|
||||
use OCP\IUserSession;
|
||||
use OCP\SystemTag\ISystemTagManager;
|
||||
use OCP\SystemTag\ISystemTagObjectMapper;
|
||||
use OCP\SystemTag\TagNotFoundException;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
class SystemTagsByIdCollectionTest extends \Test\TestCase {
|
||||
|
||||
|
|
@ -40,21 +42,31 @@ class SystemTagsByIdCollectionTest extends \Test\TestCase {
|
|||
$this->user->expects($this->any())
|
||||
->method('getUID')
|
||||
->willReturn('testuser');
|
||||
|
||||
/** @var IUserSession|MockObject */
|
||||
$userSession = $this->getMockBuilder(IUserSession::class)
|
||||
->getMock();
|
||||
$userSession->expects($this->any())
|
||||
->method('getUser')
|
||||
->willReturn($this->user);
|
||||
|
||||
/** @var IGroupManager|MockObject */
|
||||
$groupManager = $this->getMockBuilder(IGroupManager::class)
|
||||
->getMock();
|
||||
$groupManager->expects($this->any())
|
||||
->method('isAdmin')
|
||||
->with('testuser')
|
||||
->willReturn($isAdmin);
|
||||
|
||||
/** @var ISystemTagObjectMapper|MockObject */
|
||||
$tagMapper = $this->getMockBuilder(ISystemTagObjectMapper::class)
|
||||
->getMock();
|
||||
|
||||
return new SystemTagsByIdCollection(
|
||||
$this->tagManager,
|
||||
$userSession,
|
||||
$groupManager
|
||||
$groupManager,
|
||||
$tagMapper,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue