@ -9,13 +9,20 @@
namespace OCA\DAV\DAV;
use Exception;
use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\CalDAV\Calendar;
use OCA\DAV\CalDAV\CalendarHome;
use OCA\DAV\CalDAV\CalendarObject;
use OCA\DAV\CalDAV\DefaultCalendarValidator;
use OCA\DAV\CalDAV\Integration\ExternalCalendar;
use OCA\DAV\CalDAV\Outbox;
use OCA\DAV\CalDAV\Trashbin\TrashbinHome;
use OCA\DAV\Connector\Sabre\Directory;
use OCA\DAV\Db\PropertyMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use OCP\IUser;
use Sabre\CalDAV\Schedule\Inbox;
use Sabre\DAV\Exception as DavException;
use Sabre\DAV\PropertyStorage\Backend\BackendInterface;
use Sabre\DAV\PropFind;
@ -98,10 +105,9 @@ class CustomPropertiesBackend implements BackendInterface {
/**
* Properties cache
*
* @var array
*/
private $userCache = [];
private array $userCache = [];
private array $publishedCache = [];
private XmlService $xmlService;
/**
@ -114,6 +120,7 @@ class CustomPropertiesBackend implements BackendInterface {
private Tree $tree,
private IDBConnection $connection,
private IUser $user,
private PropertyMapper $propertyMapper,
private DefaultCalendarValidator $defaultCalendarValidator,
) {
$this->xmlService = new XmlService();
@ -197,6 +204,13 @@ class CustomPropertiesBackend implements BackendInterface {
$this->cacheDirectory($path, $node);
}
if ($node instanceof CalendarHome & & $propFind->getDepth() !== 0) {
$backend = $node->getCalDAVBackend();
if ($backend instanceof CalDavBackend) {
$this->cacheCalendars($node, $requestedProps);
}
}
if ($node instanceof CalendarObject) {
// No custom properties supported on individual events
return;
@ -316,6 +330,10 @@ class CustomPropertiesBackend implements BackendInterface {
return [];
}
if (isset($this->publishedCache[$path])) {
return $this->publishedCache[$path];
}
$qb = $this->connection->getQueryBuilder();
$qb->select('*')
->from(self::TABLE_NAME)
@ -326,6 +344,7 @@ class CustomPropertiesBackend implements BackendInterface {
$props[$row['propertyname']] = $this->decodeValueFromDatabase($row['propertyvalue'], $row['valuetype']);
}
$result->closeCursor();
$this->publishedCache[$path] = $props;
return $props;
}
@ -364,6 +383,58 @@ class CustomPropertiesBackend implements BackendInterface {
$this->userCache = array_merge($this->userCache, $propsByPath);
}
private function cacheCalendars(CalendarHome $node): void {
$calendars = $node->getChildren();
$users = [];
foreach ($calendars as $calendar) {
if ($calendar instanceof Calendar) {
$user = str_replace('principals/users/', '', $calendar->getPrincipalURI());
if (!isset($users[$user])) {
$users[$user] = ['calendars/' . $user];
}
$users[$user][] = 'calendars/' . $user . '/' . $calendar->getUri();
} elseif ($calendar instanceof Inbox || $calendar instanceof Outbox || $calendar instanceof TrashbinHome || $calendar instanceof ExternalCalendar) {
if ($calendar->getOwner()) {
$user = str_replace('principals/users/', '', $calendar->getOwner());
if (!isset($users[$user])) {
$users[$user] = ['calendars/' . $user];
}
$users[$user][] = 'calendars/' . $user . '/' . $calendar->getName();
}
}
}
// user properties
$properties = $this->propertyMapper->findPropertiesByPathsAndUsers($users);
$propsByPath = [];
foreach ($users as $paths) {
foreach ($paths as $path) {
$propsByPath[$path] = [];
}
}
foreach ($properties as $property) {
$propsByPath[$property->getPropertypath()][$property->getPropertyname()] = $this->decodeValueFromDatabase($property->getPropertyvalue(), $property->getValuetype());
}
$this->userCache = array_merge($this->userCache, $propsByPath);
// published properties
$paths = [];
foreach ($users as $nestedPaths) {
$paths = array_merge($paths, $nestedPaths);
}
$paths = array_unique($paths);
$propsByPath = array_fill_keys(array_values($paths), []);
$properties = $this->propertyMapper->findPropertiesByPaths($paths);
foreach ($properties as $property) {
$propsByPath[$property->getPropertypath()][$property->getPropertyname()] = $this->decodeValueFromDatabase($property->getPropertyvalue(), $property->getValuetype());
}
$this->publishedCache = array_merge($this->publishedCache, $propsByPath);
}
/**
* Returns a list of properties for the given path and current user
*