aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Wurst <christoph@winzerhof-wurst.at>2021-06-08 13:57:00 +0200
committerChristoph Wurst <christoph@winzerhof-wurst.at>2021-06-08 13:57:00 +0200
commitbaf4ad1774da57c1ce4b53be317c295688d63f71 (patch)
treec3e59ee5bde7c465e7aa16e885783a2d827b9f17
parentb3cfa1859b14384ae8134e8eb88c171667f77799 (diff)
downloadnextcloud-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.php71
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;
}