From ab6add54c7d11d34230b2ce55f30e87f68b1c28d Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Thu, 1 Aug 2019 18:37:50 +0200 Subject: [PATCH] Allow to do a principal property search based on metadata keys Signed-off-by: Georg Ehrke --- .../AbstractPrincipalBackend.php | 74 ++++++++++++++++++- .../AbstractPrincipalBackendTest.php | 20 +++++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/apps/dav/lib/CalDAV/ResourceBooking/AbstractPrincipalBackend.php b/apps/dav/lib/CalDAV/ResourceBooking/AbstractPrincipalBackend.php index bc96041d91..aab5fcab8a 100644 --- a/apps/dav/lib/CalDAV/ResourceBooking/AbstractPrincipalBackend.php +++ b/apps/dav/lib/CalDAV/ResourceBooking/AbstractPrincipalBackend.php @@ -184,6 +184,37 @@ abstract class AbstractPrincipalBackend implements BackendInterface { return $this->rowToPrincipal($row, $metadata); } + /** + * @param int $id + * @return array|null + */ + public function getPrincipalById($id):?array { + $query = $this->db->getQueryBuilder(); + $query->select(['id', 'backend_id', 'resource_id', 'email', 'displayname']) + ->from($this->dbTableName) + ->where($query->expr()->eq('id', $query->createNamedParameter($id))); + $stmt = $query->execute(); + $row = $stmt->fetch(\PDO::FETCH_ASSOC); + + if(!$row) { + return null; + } + + $metaDataQuery = $this->db->getQueryBuilder(); + $metaDataQuery->select(['key', 'value']) + ->from($this->dbMetaDataTableName) + ->where($metaDataQuery->expr()->eq($this->dbForeignKeyName, $metaDataQuery->createNamedParameter($row['id']))); + $metaDataStmt = $metaDataQuery->execute(); + $metaDataRows = $metaDataStmt->fetchAll(\PDO::FETCH_ASSOC); + $metadata = []; + + foreach($metaDataRows as $metaDataRow) { + $metadata[$metaDataRow['key']] = $metaDataRow['value']; + } + + return $this->rowToPrincipal($row, $metadata); + } + /** * Returns the list of members for a group-principal * @@ -296,7 +327,15 @@ abstract class AbstractPrincipalBackend implements BackendInterface { break; default: - $results[] = []; + $rowsByMetadata = $this->searchPrincipalsByMetadataKey($prop, $value); + $filteredRows = array_filter($rowsByMetadata, function($row) use ($usersGroups) { + return $this->isAllowedToAccessResource($row, $usersGroups); + }); + + $results[] = array_map(function($row) { + return $row['uri']; + }, $filteredRows); + break; } } @@ -317,6 +356,39 @@ abstract class AbstractPrincipalBackend implements BackendInterface { } } + /** + * Searches principals based on their metadata keys. + * This allows to search for all principals with a specific key. + * e.g.: + * '{http://nextcloud.com/ns}room-building-address' => 'ABC Street 123, ...' + * + * @param $key + * @param $value + * @return array + */ + private function searchPrincipalsByMetadataKey($key, $value):array { + $query = $this->db->getQueryBuilder(); + $query->select([$this->dbForeignKeyName]) + ->from($this->dbMetaDataTableName) + ->where($query->expr()->eq('key', $query->createNamedParameter($key))) + ->andWhere($query->expr()->iLike('value', $query->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%'))); + $stmt = $query->execute(); + + $rows = []; + while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { + $id = $row[$this->dbForeignKeyName]; + + $principalRow = $this->getPrincipalById($id); + if (!$principalRow) { + continue; + } + + $rows[] = $principalRow; + } + + return $rows; + } + /** * @param string $uri * @param string $principalPrefix diff --git a/apps/dav/tests/unit/CalDAV/ResourceBooking/AbstractPrincipalBackendTest.php b/apps/dav/tests/unit/CalDAV/ResourceBooking/AbstractPrincipalBackendTest.php index eb9faa574a..f4019d86e2 100644 --- a/apps/dav/tests/unit/CalDAV/ResourceBooking/AbstractPrincipalBackendTest.php +++ b/apps/dav/tests/unit/CalDAV/ResourceBooking/AbstractPrincipalBackendTest.php @@ -219,6 +219,26 @@ abstract class AbstractPrincipalBackendTest extends TestCase { ]; } + public function testSearchPrincipalsByMetadataKey() { + $user = $this->createMock(IUser::class); + $this->userSession->expects($this->once()) + ->method('getUser') + ->with() + ->will($this->returnValue($user)); + $this->groupManager->expects($this->once()) + ->method('getUserGroupIds') + ->with($user) + ->will($this->returnValue(['group1', 'group2'])); + + $actual = $this->principalBackend->searchPrincipals($this->principalPrefix, [ + '{http://nextcloud.com/ns}meta3' => 'value', + ]); + + $this->assertEquals([ + $this->principalPrefix . '/backend2-res4', + ], $actual); + } + public function testSearchPrincipalsByCalendarUserAddressSet() { $user = $this->createMock(IUser::class); $this->userSession->method('getUser')