diff options
author | Christoph Wurst <christoph@winzerhof-wurst.at> | 2021-06-08 13:57:00 +0200 |
---|---|---|
committer | Christoph Wurst <christoph@winzerhof-wurst.at> | 2021-06-08 13:57:00 +0200 |
commit | baf4ad1774da57c1ce4b53be317c295688d63f71 (patch) | |
tree | c3e59ee5bde7c465e7aa16e885783a2d827b9f17 | |
parent | b3cfa1859b14384ae8134e8eb88c171667f77799 (diff) | |
download | nextcloud-server-baf4ad1774da57c1ce4b53be317c295688d63f71.tar.gz nextcloud-server-baf4ad1774da57c1ce4b53be317c295688d63f71.zip |
Allow certain custom DAV props to be readable by everyone
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
-rw-r--r-- | apps/dav/lib/DAV/CustomPropertiesBackend.php | 71 |
1 files changed, 57 insertions, 14 deletions
diff --git a/apps/dav/lib/DAV/CustomPropertiesBackend.php b/apps/dav/lib/DAV/CustomPropertiesBackend.php index d60bfddabfb..1bd207e0967 100644 --- a/apps/dav/lib/DAV/CustomPropertiesBackend.php +++ b/apps/dav/lib/DAV/CustomPropertiesBackend.php @@ -31,15 +31,19 @@ use Sabre\DAV\PropertyStorage\Backend\BackendInterface; use Sabre\DAV\PropFind; use Sabre\DAV\PropPatch; use Sabre\DAV\Tree; +use function array_intersect; class CustomPropertiesBackend implements BackendInterface { + /** @var string */ + private const TABLE_NAME = 'properties'; + /** * Ignored properties * - * @var array + * @var string[] */ - private $ignoredProperties = [ + private const IGNORED_PROPERTIES = [ '{DAV:}getcontentlength', '{DAV:}getcontenttype', '{DAV:}getetag', @@ -53,6 +57,15 @@ class CustomPropertiesBackend implements BackendInterface { ]; /** + * Properties set by one user, readable by all others + * + * @var array[] + */ + private const PUBLISHED_READ_ONLY_PROPERTIES = [ + '{urn:ietf:params:xml:ns:caldav}calendar-availability', + ]; + + /** * @var Tree */ private $tree; @@ -72,7 +85,7 @@ class CustomPropertiesBackend implements BackendInterface { * * @var array */ - private $cache = []; + private $userCache = []; /** * @param Tree $tree node tree @@ -101,7 +114,7 @@ class CustomPropertiesBackend implements BackendInterface { // these might appear $requestedProps = array_diff( $requestedProps, - $this->ignoredProperties + self::IGNORED_PROPERTIES ); // substr of calendars/ => path is inside the CalDAV component @@ -128,8 +141,12 @@ class CustomPropertiesBackend implements BackendInterface { return; } - $props = $this->getProperties($path, $requestedProps); - foreach ($props as $propName => $propValue) { + // First fetch the published properties (set by another user), then get the ones set by + // the current user. If both are set then the latter as priority. + foreach ($this->getPublishedProperties($path, $requestedProps) as $propName => $propValue) { + $propFind->set($propName, $propValue); + } + foreach ($this->getUserProperties($path, $requestedProps) as $propName => $propValue) { $propFind->set($propName, $propValue); } } @@ -160,7 +177,7 @@ class CustomPropertiesBackend implements BackendInterface { $statement->execute([$this->user->getUID(), $this->formatPath($path)]); $statement->closeCursor(); - unset($this->cache[$path]); + unset($this->userCache[$path]); } /** @@ -181,7 +198,33 @@ class CustomPropertiesBackend implements BackendInterface { } /** - * Returns a list of properties for this nodes.; + * @param string $path + * @param string[] $requestedProperties + * + * @return array + */ + private function getPublishedProperties(string $path, array $requestedProperties): array { + $allowedProps = array_intersect(self::PUBLISHED_READ_ONLY_PROPERTIES, $requestedProperties); + + if (empty($allowedProps)) { + return []; + } + + $qb = $this->connection->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('propertypath', $qb->createNamedParameter($path))); + $result = $qb->executeQuery(); + $props = []; + while ($row = $result->fetch()) { + $props[$row['propertyname']] = $row['propertyvalue']; + } + $result->closeCursor(); + return $props; + } + + /** + * Returns a list of properties for the given path and current user * * @param string $path * @param array $requestedProperties requested properties or empty array for "all" @@ -191,9 +234,9 @@ class CustomPropertiesBackend implements BackendInterface { * http://www.example.org/namespace#author If the array is empty, all * properties should be returned */ - private function getProperties(string $path, array $requestedProperties) { - if (isset($this->cache[$path])) { - return $this->cache[$path]; + private function getUserProperties(string $path, array $requestedProperties) { + if (isset($this->userCache[$path])) { + return $this->userCache[$path]; } // TODO: chunking if more than 1000 properties @@ -222,7 +265,7 @@ class CustomPropertiesBackend implements BackendInterface { $result->closeCursor(); - $this->cache[$path] = $props; + $this->userCache[$path] = $props; return $props; } @@ -245,7 +288,7 @@ class CustomPropertiesBackend implements BackendInterface { ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?'; // TODO: use "insert or update" strategy ? - $existing = $this->getProperties($path, []); + $existing = $this->getUserProperties($path, []); $this->connection->beginTransaction(); foreach ($properties as $propertyName => $propertyValue) { // If it was null, we need to delete the property @@ -283,7 +326,7 @@ class CustomPropertiesBackend implements BackendInterface { } $this->connection->commit(); - unset($this->cache[$path]); + unset($this->userCache[$path]); return true; } |