From e55f4ba3b9ccdf2a6cacb7e1d56d307b5d9a0427 Mon Sep 17 00:00:00 2001 From: VicDeo Date: Mon, 30 Sep 2019 14:37:35 +0300 Subject: [PATCH] Take medial search config into account while searching for remote users --- apps/dav/lib/CardDAV/AddressBookImpl.php | 2 +- apps/dav/lib/CardDAV/CardDavBackend.php | 40 ++++++++++++++++++- .../unit/CardDAV/AddressBookImplTest.php | 4 +- .../lib/Controller/ShareesController.php | 11 ++++- apps/files_sharing/tests/API/ShareesTest.php | 12 ++++-- 5 files changed, 60 insertions(+), 9 deletions(-) diff --git a/apps/dav/lib/CardDAV/AddressBookImpl.php b/apps/dav/lib/CardDAV/AddressBookImpl.php index a3e09102306d..aa08c3bb34fc 100644 --- a/apps/dav/lib/CardDAV/AddressBookImpl.php +++ b/apps/dav/lib/CardDAV/AddressBookImpl.php @@ -91,7 +91,7 @@ public function getDisplayName() { * @since 5.0.0 */ public function search($pattern, $searchProperties, $options, $limit = null, $offset = null) { - $results = $this->backend->search($this->getKey(), $pattern, $searchProperties, $limit, $offset); + $results = $this->backend->searchEx($this->getKey(), $pattern, $searchProperties, $options, $limit, $offset); $vCards = []; foreach ($results as $result) { diff --git a/apps/dav/lib/CardDAV/CardDavBackend.php b/apps/dav/lib/CardDAV/CardDavBackend.php index c10807de58f9..d758fdac34f1 100644 --- a/apps/dav/lib/CardDAV/CardDavBackend.php +++ b/apps/dav/lib/CardDAV/CardDavBackend.php @@ -812,14 +812,52 @@ public function updateShares(IShareable $shareable, $add, $remove) { * @return array an array of contacts which are arrays of key-value-pairs */ public function search($addressBookId, $pattern, $searchProperties, $limit = 100, $offset = 0) { + return $this->searchEx($addressBookId, $pattern, $searchProperties, [], $limit, $offset); + } + + /** + * search contact with options + * + * @param int $addressBookId + * @param string $pattern which should match within the $searchProperties + * @param array $searchProperties defines the properties within the query pattern should match + * @param array $options + * available options: + * 'matchMode' + * - 'ANY' (default) - pattern can be anywhere in property value + * - 'START' - property value should start with pattern + * - 'END' - property value should end with pattern + * - 'EXACT' - property value should match the pattern exactly + * @param int $limit + * @param int $offset + * @return array an array of contacts which are arrays of key-value-pairs + */ + public function searchEx($addressBookId, $pattern, $searchProperties, $options, $limit = 100, $offset = 0) { $query = $this->db->getQueryBuilder(); $query2 = $this->db->getQueryBuilder(); $query2->selectDistinct('cp.cardid')->from($this->dbCardsPropertiesTable, 'cp'); + + $matchMode = $options['matchMode'] ?? 'any'; + switch ($matchMode) { + case 'START': + $searchPattern = $this->db->escapeLikeParameter($pattern) . '%'; + break; + case 'END': + $searchPattern = '%' . $this->db->escapeLikeParameter($pattern); + break; + case 'EXACT': + $searchPattern = $this->db->escapeLikeParameter($pattern); + break; + case 'ANY': + default: + $searchPattern = '%' . $this->db->escapeLikeParameter($pattern) . '%'; + } + foreach ($searchProperties as $property) { $query2->orWhere( $query2->expr()->andX( $query2->expr()->eq('cp.name', $query->createNamedParameter($property)), - $query2->expr()->iLike('cp.value', $query->createNamedParameter('%' . $this->db->escapeLikeParameter($pattern) . '%')) + $query2->expr()->iLike('cp.value', $query->createNamedParameter($searchPattern)) ) ); } diff --git a/apps/dav/tests/unit/CardDAV/AddressBookImplTest.php b/apps/dav/tests/unit/CardDAV/AddressBookImplTest.php index af113a85803a..fa891d1d76b6 100644 --- a/apps/dav/tests/unit/CardDAV/AddressBookImplTest.php +++ b/apps/dav/tests/unit/CardDAV/AddressBookImplTest.php @@ -102,8 +102,8 @@ public function testSearch() { $pattern = 'pattern'; $searchProperties = ['properties']; - $this->backend->expects($this->once())->method('search') - ->with($this->addressBookInfo['id'], $pattern, $searchProperties, 10, 0) + $this->backend->expects($this->once())->method('searchEx') + ->with($this->addressBookInfo['id'], $pattern, $searchProperties, [], 10, 0) ->willReturn( [ ['uri' => 'foo.vcf', 'carddata' => 'cardData1'], diff --git a/apps/files_sharing/lib/Controller/ShareesController.php b/apps/files_sharing/lib/Controller/ShareesController.php index 72036ee3697b..d3b917edd17f 100644 --- a/apps/files_sharing/lib/Controller/ShareesController.php +++ b/apps/files_sharing/lib/Controller/ShareesController.php @@ -360,7 +360,16 @@ protected function getRemote($search) { // Fetch remote search properties from app config $searchProperties = \explode(',', $this->config->getAppValue('dav', 'remote_search_properties', 'CLOUD,FN')); // Search in contacts - $addressBookContacts = $this->contactsManager->search($search, $searchProperties, [], $this->limit, $this->offset); + $matchMode = $this->config->getSystemValue('accounts.enable_medial_search', true) === true + ? 'ANY' + : 'START'; + $addressBookContacts = $this->contactsManager->search( + $search, + $searchProperties, + [ 'matchMode' => $matchMode ], + $this->limit, + $this->offset + ); $foundRemoteById = false; foreach ($addressBookContacts as $contact) { if (isset($contact['isLocalSystemBook'])) { diff --git a/apps/files_sharing/tests/API/ShareesTest.php b/apps/files_sharing/tests/API/ShareesTest.php index 4901fda818ba..fc0537e6111c 100644 --- a/apps/files_sharing/tests/API/ShareesTest.php +++ b/apps/files_sharing/tests/API/ShareesTest.php @@ -1426,10 +1426,14 @@ public function testGetRemote($searchTerm, $contacts, $shareeEnumeration, $exact $this->invokePrivate($this->sharees, 'limit', [2]); $this->invokePrivate($this->sharees, 'offset', [0]); + $configMap = [ + ['trusted_domains', [], ['trusted.domain.tld', 'trusted2.domain.tld']], + ['accounts.enable_medial_search', true, true] + ]; + $this->config->expects($this->any()) ->method('getSystemValue') - ->with('trusted_domains') - ->willReturn(['trusted.domain.tld', 'trusted2.domain.tld']); + ->will($this->returnValueMap($configMap)); $this->userSearch->expects($this->any()) ->method('isSearchable') ->willReturn($isSearchable); @@ -1448,7 +1452,7 @@ public function testGetRemote($searchTerm, $contacts, $shareeEnumeration, $exact $this->invokePrivate($this->sharees, 'shareeEnumeration', [$shareeEnumeration]); $this->contactsManager->expects($this->any()) ->method('search') - ->with($searchTerm, ['EMAIL', 'CLOUD', 'FN'], [], 2, 0) + ->with($searchTerm, ['EMAIL', 'CLOUD', 'FN'], ['matchMode' => 'ANY'], 2, 0) ->willReturn($contacts); $this->invokePrivate($this->sharees, 'getRemote', [$searchTerm]); @@ -1961,7 +1965,7 @@ public function testGetUserWithSearchAttributes() { $exactExpected = [['label' => 'Bob', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'testBob']]]; $expected = []; - + $this->invokePrivate($this->sharees, 'getUsers', [$searchTerm]); $result = $this->invokePrivate($this->sharees, 'result'); $this->assertEquals($exactExpected, $result['exact']['users']);