|
|
|
@ -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,62 @@ class CustomPropertiesBackend implements BackendInterface { |
|
|
|
$this->userCache = array_merge($this->userCache, $propsByPath); |
|
|
|
} |
|
|
|
|
|
|
|
private function cacheCalendars(CalendarHome $node, array $requestedProperties): 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
|
|
|
|
$allowedProps = array_intersect(self::PUBLISHED_READ_ONLY_PROPERTIES, $requestedProperties); |
|
|
|
if (empty($allowedProps)) { |
|
|
|
return; |
|
|
|
} |
|
|
|
$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, $allowedProps); |
|
|
|
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 |
|
|
|
* |
|
|
|
|