fix: search with more than one search tags

Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
pull/39202/head
Arthur Schiwon 2 years ago
parent 4e5c3bd166
commit 4ac77f0f7a
No known key found for this signature in database
GPG Key ID: 7424F1874854DF23
  1. 26
      apps/dav/lib/Connector/Sabre/FilesReportPlugin.php
  2. 410
      apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php

@ -27,7 +27,6 @@
*/
namespace OCA\DAV\Connector\Sabre;
use OC\Files\Node\LazyFolder;
use OC\Files\View;
use OCP\App\IAppManager;
use OCP\Files\Folder;
@ -46,7 +45,6 @@ use Sabre\DAV\Xml\Element\Response;
use Sabre\DAV\Xml\Response\MultiStatus;
class FilesReportPlugin extends ServerPlugin {
// namespace
public const NS_OWNCLOUD = 'http://owncloud.org/ns';
public const NS_NEXTCLOUD = 'http://nextcloud.org/ns';
@ -335,12 +333,28 @@ class FilesReportPlugin extends ServerPlugin {
// exposed in API yet
if (
!empty($systemTagIds)
&& ($this->userFolder instanceof \OC\Files\Node\Folder
|| $this->userFolder instanceof LazyFolder)
&& (method_exists($this->userFolder, 'searchBySystemTag'))
) {
$tags = $this->tagManager->getTagsByIds($systemTagIds);
$tagName = (current($tags))->getName();
$nodes = $this->userFolder->searchBySystemTag($tagName, $this->userSession->getUser()->getUID(), $limit ?? 0, $offset ?? 0);
foreach ($tags as $tag) {
if (!$tag->isUserVisible()) {
// searchBySystemTag() also has the criteria to include only user visible tags. They can be skipped early nevertheless.
continue;
}
$tagName = $tag->getName();
$tmpNodes = $this->userFolder->searchBySystemTag($tagName, $this->userSession->getUser()->getUID(), $limit ?? 0, $offset ?? 0);
if (count($nodes) === 0) {
$nodes = $tmpNodes;
} else {
$nodes = array_uintersect($nodes, $tmpNodes, function (\OCP\Files\Node $a, \OCP\Files\Node $b): int {
return $a->getId() - $b->getId();
});
}
if ($nodes === []) {
// there cannot be a common match when nodes are empty early.
return $nodes;
}
}
}
return $nodes;

@ -44,45 +44,48 @@ use OCP\IUserSession;
use OCP\SystemTag\ISystemTag;
use OCP\SystemTag\ISystemTagManager;
use OCP\SystemTag\ISystemTagObjectMapper;
use PHPUnit\Framework\MockObject\MockObject;
use Sabre\DAV\INode;
use Sabre\DAV\Tree;
use Sabre\HTTP\ResponseInterface;
class FilesReportPluginTest extends \Test\TestCase {
/** @var \Sabre\DAV\Server|\PHPUnit\Framework\MockObject\MockObject */
/** @var \Sabre\DAV\Server|MockObject */
private $server;
/** @var \Sabre\DAV\Tree|\PHPUnit\Framework\MockObject\MockObject */
/** @var \Sabre\DAV\Tree|MockObject */
private $tree;
/** @var ISystemTagObjectMapper|\PHPUnit\Framework\MockObject\MockObject */
/** @var ISystemTagObjectMapper|MockObject */
private $tagMapper;
/** @var ISystemTagManager|\PHPUnit\Framework\MockObject\MockObject */
/** @var ISystemTagManager|MockObject */
private $tagManager;
/** @var ITags|\PHPUnit\Framework\MockObject\MockObject */
/** @var ITags|MockObject */
private $privateTags;
private ITagManager|MockObject $privateTagManager;
/** @var \OCP\IUserSession */
private $userSession;
/** @var FilesReportPluginImplementation */
private $plugin;
/** @var View|\PHPUnit\Framework\MockObject\MockObject **/
/** @var View|MockObject **/
private $view;
/** @var IGroupManager|\PHPUnit\Framework\MockObject\MockObject **/
/** @var IGroupManager|MockObject **/
private $groupManager;
/** @var Folder|\PHPUnit\Framework\MockObject\MockObject **/
/** @var Folder|MockObject **/
private $userFolder;
/** @var IPreview|\PHPUnit\Framework\MockObject\MockObject * */
/** @var IPreview|MockObject * */
private $previewManager;
/** @var IAppManager|\PHPUnit\Framework\MockObject\MockObject * */
/** @var IAppManager|MockObject * */
private $appManager;
protected function setUp(): void {
@ -124,8 +127,8 @@ class FilesReportPluginTest extends \Test\TestCase {
$this->tagMapper = $this->createMock(ISystemTagObjectMapper::class);
$this->userSession = $this->createMock(IUserSession::class);
$this->privateTags = $this->createMock(ITags::class);
$privateTagManager = $this->createMock(ITagManager::class);
$privateTagManager->expects($this->any())
$this->privateTagManager = $this->createMock(ITagManager::class);
$this->privateTagManager->expects($this->any())
->method('load')
->with('files')
->willReturn($this->privateTags);
@ -145,7 +148,7 @@ class FilesReportPluginTest extends \Test\TestCase {
$this->view,
$this->tagManager,
$this->tagMapper,
$privateTagManager,
$this->privateTagManager,
$this->userSession,
$this->groupManager,
$this->userFolder,
@ -217,17 +220,6 @@ class FilesReportPluginTest extends \Test\TestCase {
->method('isAdmin')
->willReturn(true);
$this->tagMapper->expects($this->exactly(2))
->method('getObjectIdsForTags')
->withConsecutive(
['123', 'files'],
['456', 'files'],
)
->willReturnOnConsecutiveCalls(
['111', '222'],
['111', '222', '333'],
);
$reportTargetNode = $this->getMockBuilder(Directory::class)
->disableOriginalConstructor()
->getMock();
@ -255,20 +247,40 @@ class FilesReportPluginTest extends \Test\TestCase {
->with('/' . $path)
->willReturn($reportTargetNode);
$filesNode1 = $this->getMockBuilder(Folder::class)
->disableOriginalConstructor()
->getMock();
$filesNode2 = $this->getMockBuilder(File::class)
->disableOriginalConstructor()
->getMock();
$filesNode2->method('getSize')
$filesNode1 = $this->createMock(File::class);
$filesNode1->expects($this->any())
->method('getSize')
->willReturn(12);
$filesNode2 = $this->createMock(Folder::class);
$filesNode2->expects($this->any())
->method('getSize')
->willReturn(10);
$tag123 = $this->createMock(ISystemTag::class);
$tag123->expects($this->any())
->method('getName')
->willReturn('OneTwoThree');
$tag123->expects($this->any())
->method('isUserVisible')
->willReturn(true);
$tag456 = $this->createMock(ISystemTag::class);
$tag456->expects($this->any())
->method('getName')
->willReturn('FourFiveSix');
$tag456->expects($this->any())
->method('isUserVisible')
->willReturn(true);
$this->tagManager->expects($this->once())
->method('getTagsByIds')
->with(['123', '456'])
->willReturn([$tag123, $tag456]);
$this->userFolder->expects($this->exactly(2))
->method('getById')
->method('searchBySystemTag')
->withConsecutive(
['111'],
['222'],
['OneTwoThree'],
['FourFiveSix'],
)
->willReturnOnConsecutiveCalls(
[$filesNode1],
@ -317,7 +329,7 @@ class FilesReportPluginTest extends \Test\TestCase {
[$filesNode2],
);
/** @var \OCA\DAV\Connector\Sabre\Directory|\PHPUnit\Framework\MockObject\MockObject $reportTargetNode */
/** @var \OCA\DAV\Connector\Sabre\Directory|MockObject $reportTargetNode */
$result = $this->plugin->findNodesByFileIds($reportTargetNode, ['111', '222']);
$this->assertCount(2, $result);
@ -370,7 +382,7 @@ class FilesReportPluginTest extends \Test\TestCase {
[$filesNode2],
);
/** @var \OCA\DAV\Connector\Sabre\Directory|\PHPUnit\Framework\MockObject\MockObject $reportTargetNode */
/** @var \OCA\DAV\Connector\Sabre\Directory|MockObject $reportTargetNode */
$result = $this->plugin->findNodesByFileIds($reportTargetNode, ['111', '222']);
$this->assertCount(2, $result);
@ -454,20 +466,38 @@ class FilesReportPluginTest extends \Test\TestCase {
->method('isAdmin')
->willReturn(true);
$this->tagMapper->expects($this->exactly(1))
->method('getObjectIdsForTags')
->withConsecutive(
['123', 'files']
)
->willReturnMap([
['123', 'files', 0, '', ['111', '222']],
]);
$rules = [
['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
];
$this->assertEquals(['111', '222'], $this->invokePrivate($this->plugin, 'processFilterRules', [$rules]));
$filesNode1 = $this->createMock(File::class);
$filesNode1->expects($this->any())
->method('getSize')
->willReturn(12);
$filesNode2 = $this->createMock(Folder::class);
$filesNode2->expects($this->any())
->method('getSize')
->willReturn(10);
$tag123 = $this->createMock(ISystemTag::class);
$tag123->expects($this->any())
->method('getName')
->willReturn('OneTwoThree');
$tag123->expects($this->any())
->method('isUserVisible')
->willReturn(true);
$this->tagManager->expects($this->once())
->method('getTagsByIds')
->with(['123'])
->willReturn([$tag123]);
$this->userFolder->expects($this->once())
->method('searchBySystemTag')
->with('OneTwoThree')
->willReturn([$filesNode1, $filesNode2]);
$this->assertEquals([$filesNode1, $filesNode2], $this->invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, 0, 0]));
}
public function testProcessFilterRulesAndCondition(): void {
@ -475,23 +505,65 @@ class FilesReportPluginTest extends \Test\TestCase {
->method('isAdmin')
->willReturn(true);
$this->tagMapper->expects($this->exactly(2))
->method('getObjectIdsForTags')
$filesNode1 = $this->createMock(File::class);
$filesNode1->expects($this->any())
->method('getSize')
->willReturn(12);
$filesNode1->expects($this->any())
->method('getId')
->willReturn(111);
$filesNode2 = $this->createMock(Folder::class);
$filesNode2->expects($this->any())
->method('getSize')
->willReturn(10);
$filesNode2->expects($this->any())
->method('getId')
->willReturn(222);
$filesNode3 = $this->createMock(File::class);
$filesNode3->expects($this->any())
->method('getSize')
->willReturn(14);
$filesNode3->expects($this->any())
->method('getId')
->willReturn(333);
$tag123 = $this->createMock(ISystemTag::class);
$tag123->expects($this->any())
->method('getName')
->willReturn('OneTwoThree');
$tag123->expects($this->any())
->method('isUserVisible')
->willReturn(true);
$tag456 = $this->createMock(ISystemTag::class);
$tag456->expects($this->any())
->method('getName')
->willReturn('FourFiveSix');
$tag456->expects($this->any())
->method('isUserVisible')
->willReturn(true);
$this->tagManager->expects($this->once())
->method('getTagsByIds')
->with(['123', '456'])
->willReturn([$tag123, $tag456]);
$this->userFolder->expects($this->exactly(2))
->method('searchBySystemTag')
->withConsecutive(
['123', 'files'],
['456', 'files']
['OneTwoThree'],
['FourFiveSix'],
)
->willReturnMap([
['123', 'files', 0, '', ['111', '222']],
['456', 'files', 0, '', ['222', '333']],
]);
->willReturnOnConsecutiveCalls(
[$filesNode1, $filesNode2],
[$filesNode2, $filesNode3],
);
$rules = [
['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
];
$this->assertEquals(['222'], array_values($this->invokePrivate($this->plugin, 'processFilterRules', [$rules])));
$this->assertEquals([$filesNode2], array_values($this->invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null])));
}
public function testProcessFilterRulesAndConditionWithOneEmptyResult(): void {
@ -499,23 +571,58 @@ class FilesReportPluginTest extends \Test\TestCase {
->method('isAdmin')
->willReturn(true);
$this->tagMapper->expects($this->exactly(2))
->method('getObjectIdsForTags')
$filesNode1 = $this->createMock(File::class);
$filesNode1->expects($this->any())
->method('getSize')
->willReturn(12);
$filesNode1->expects($this->any())
->method('getId')
->willReturn(111);
$filesNode2 = $this->createMock(Folder::class);
$filesNode2->expects($this->any())
->method('getSize')
->willReturn(10);
$filesNode2->expects($this->any())
->method('getId')
->willReturn(222);
$tag123 = $this->createMock(ISystemTag::class);
$tag123->expects($this->any())
->method('getName')
->willReturn('OneTwoThree');
$tag123->expects($this->any())
->method('isUserVisible')
->willReturn(true);
$tag456 = $this->createMock(ISystemTag::class);
$tag456->expects($this->any())
->method('getName')
->willReturn('FourFiveSix');
$tag456->expects($this->any())
->method('isUserVisible')
->willReturn(true);
$this->tagManager->expects($this->once())
->method('getTagsByIds')
->with(['123', '456'])
->willReturn([$tag123, $tag456]);
$this->userFolder->expects($this->exactly(2))
->method('searchBySystemTag')
->withConsecutive(
['123', 'files'],
['456', 'files']
['OneTwoThree'],
['FourFiveSix'],
)
->willReturnMap([
['123', 'files', 0, '', ['111', '222']],
['456', 'files', 0, '', []],
]);
->willReturnOnConsecutiveCalls(
[$filesNode1, $filesNode2],
[],
);
$rules = [
['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
];
$this->assertEquals([], array_values($this->invokePrivate($this->plugin, 'processFilterRules', [$rules])));
$this->assertEquals([], $this->invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null]));
}
public function testProcessFilterRulesAndConditionWithFirstEmptyResult(): void {
@ -523,23 +630,55 @@ class FilesReportPluginTest extends \Test\TestCase {
->method('isAdmin')
->willReturn(true);
$this->tagMapper->expects($this->exactly(1))
->method('getObjectIdsForTags')
->withConsecutive(
['123', 'files'],
['456', 'files']
)
->willReturnMap([
['123', 'files', 0, '', []],
['456', 'files', 0, '', ['111', '222']],
]);
$filesNode1 = $this->createMock(File::class);
$filesNode1->expects($this->any())
->method('getSize')
->willReturn(12);
$filesNode1->expects($this->any())
->method('getId')
->willReturn(111);
$filesNode2 = $this->createMock(Folder::class);
$filesNode2->expects($this->any())
->method('getSize')
->willReturn(10);
$filesNode2->expects($this->any())
->method('getId')
->willReturn(222);
$tag123 = $this->createMock(ISystemTag::class);
$tag123->expects($this->any())
->method('getName')
->willReturn('OneTwoThree');
$tag123->expects($this->any())
->method('isUserVisible')
->willReturn(true);
$tag456 = $this->createMock(ISystemTag::class);
$tag456->expects($this->any())
->method('getName')
->willReturn('FourFiveSix');
$tag456->expects($this->any())
->method('isUserVisible')
->willReturn(true);
$this->tagManager->expects($this->once())
->method('getTagsByIds')
->with(['123', '456'])
->willReturn([$tag123, $tag456]);
$this->userFolder->expects($this->once())
->method('searchBySystemTag')
->with('OneTwoThree')
->willReturnOnConsecutiveCalls(
[],
[$filesNode1, $filesNode2],
);
$rules = [
['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
];
$this->assertEquals([], array_values($this->invokePrivate($this->plugin, 'processFilterRules', [$rules])));
$this->assertEquals([], $this->invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null]));
}
public function testProcessFilterRulesAndConditionWithEmptyMidResult(): void {
@ -547,18 +686,63 @@ class FilesReportPluginTest extends \Test\TestCase {
->method('isAdmin')
->willReturn(true);
$this->tagMapper->expects($this->exactly(2))
->method('getObjectIdsForTags')
->withConsecutive(
['123', 'files'],
['456', 'files'],
['789', 'files']
)
->willReturnMap([
['123', 'files', 0, '', ['111', '222']],
['456', 'files', 0, '', ['333']],
['789', 'files', 0, '', ['111', '222']],
]);
$filesNode1 = $this->createMock(File::class);
$filesNode1->expects($this->any())
->method('getSize')
->willReturn(12);
$filesNode1->expects($this->any())
->method('getId')
->willReturn(111);
$filesNode2 = $this->createMock(Folder::class);
$filesNode2->expects($this->any())
->method('getSize')
->willReturn(10);
$filesNode2->expects($this->any())
->method('getId')
->willReturn(222);
$filesNode3 = $this->createMock(Folder::class);
$filesNode3->expects($this->any())
->method('getSize')
->willReturn(13);
$filesNode3->expects($this->any())
->method('getId')
->willReturn(333);
$tag123 = $this->createMock(ISystemTag::class);
$tag123->expects($this->any())
->method('getName')
->willReturn('OneTwoThree');
$tag123->expects($this->any())
->method('isUserVisible')
->willReturn(true);
$tag456 = $this->createMock(ISystemTag::class);
$tag456->expects($this->any())
->method('getName')
->willReturn('FourFiveSix');
$tag456->expects($this->any())
->method('isUserVisible')
->willReturn(true);
$tag789 = $this->createMock(ISystemTag::class);
$tag789->expects($this->any())
->method('getName')
->willReturn('SevenEightNein');
$tag789->expects($this->any())
->method('isUserVisible')
->willReturn(true);
$this->tagManager->expects($this->once())
->method('getTagsByIds')
->with(['123', '456', '789'])
->willReturn([$tag123, $tag456, $tag789]);
$this->userFolder->expects($this->exactly(2))
->method('searchBySystemTag')
->withConsecutive(['OneTwoThree'], ['FourFiveSix'], ['SevenEightNein'])
->willReturnOnConsecutiveCalls(
[$filesNode1, $filesNode2],
[$filesNode3],
[$filesNode1, $filesNode2],
);
$rules = [
['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
@ -566,7 +750,7 @@ class FilesReportPluginTest extends \Test\TestCase {
['name' => '{http://owncloud.org/ns}systemtag', 'value' => '789'],
];
$this->assertEquals([], array_values($this->invokePrivate($this->plugin, 'processFilterRules', [$rules])));
$this->assertEquals([], array_values($this->invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null])));
}
public function testProcessFilterRulesInvisibleTagAsAdmin(): void {
@ -614,7 +798,7 @@ class FilesReportPluginTest extends \Test\TestCase {
['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
];
$this->assertEquals(['222'], array_values($this->invokePrivate($this->plugin, 'processFilterRules', [$rules])));
$this->assertEquals(['222'], array_values($this->invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null])));
}
@ -655,7 +839,7 @@ class FilesReportPluginTest extends \Test\TestCase {
['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
];
$this->invokePrivate($this->plugin, 'processFilterRules', [$rules]);
$this->invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null]);
}
public function testProcessFilterRulesVisibleTagAsUser(): void {
@ -663,48 +847,58 @@ class FilesReportPluginTest extends \Test\TestCase {
->method('isAdmin')
->willReturn(false);
$tag1 = $this->getMockBuilder(ISystemTag::class)
->disableOriginalConstructor()
->getMock();
$tag1 = $this->createMock(ISystemTag::class);
$tag1->expects($this->any())
->method('getId')
->willReturn('123');
$tag1->expects($this->any())
->method('isUserVisible')
->willReturn(true);
$tag1->expects($this->any())
->method('getName')
->willReturn('OneTwoThree');
$tag2 = $this->getMockBuilder(ISystemTag::class)
->disableOriginalConstructor()
->getMock();
$tag2 = $this->createMock(ISystemTag::class);
$tag2->expects($this->any())
->method('getId')
->willReturn('123');
$tag2->expects($this->any())
->method('isUserVisible')
->willReturn(true);
$tag2->expects($this->any())
->method('getName')
->willReturn('FourFiveSix');
$this->tagManager->expects($this->once())
->method('getTagsByIds')
->with(['123', '456'])
->willReturn([$tag1, $tag2]);
$this->tagMapper->expects($this->exactly(2))
->method('getObjectIdsForTags')
->withConsecutive(
['123'],
['456'],
)
->willReturnOnConsecutiveCalls(
['111', '222'],
['222', '333'],
);
$filesNode1 = $this->createMock(File::class);
$filesNode1->expects($this->any())
->method('getSize')
->willReturn(12);
$filesNode2 = $this->createMock(Folder::class);
$filesNode2->expects($this->any())
->method('getSize')
->willReturn(10);
$this->tagManager->expects($this->once())
->method('getTagsByIds')
->with(['123', '456'])
->willReturn([$tag1, $tag2]);
// main assertion: only user visible tags are being passed through.
$this->userFolder->expects($this->exactly(1))
->method('searchBySystemTag')
->with('FourFiveSix', $this->anything(), $this->anything(), $this->anything());
$rules = [
['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
];
$this->assertEquals(['222'], array_values($this->invokePrivate($this->plugin, 'processFilterRules', [$rules])));
$this->invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null]);
}
public function testProcessFavoriteFilter(): void {
@ -716,7 +910,7 @@ class FilesReportPluginTest extends \Test\TestCase {
->method('getFavorites')
->willReturn(['456', '789']);
$this->assertEquals(['456', '789'], array_values($this->invokePrivate($this->plugin, 'processFilterRules', [$rules])));
$this->assertEquals(['456', '789'], array_values($this->invokePrivate($this->plugin, 'processFilterRulesForFileIDs', [$rules])));
}
public function filesBaseUriProvider() {

Loading…
Cancel
Save