diff options
author | Robin Appelman <robin@icewind.nl> | 2023-07-25 17:08:50 +0200 |
---|---|---|
committer | Robin Appelman <robin@icewind.nl> | 2023-07-26 14:36:37 +0200 |
commit | 31c483b759ddca29e6d0a511205c41267fc762bf (patch) | |
tree | 0145942fdf8f66fde8f5ae78c239dfb15ca458e9 /apps/dav | |
parent | 19e7704c85d0e8aa1c8ea2ca7e8bf47d549ec0e2 (diff) | |
download | nextcloud-server-31c483b759ddca29e6d0a511205c41267fc762bf.tar.gz nextcloud-server-31c483b759ddca29e6d0a511205c41267fc762bf.zip |
preload shares for calendars when listing calendars
Signed-off-by: Robin Appelman <robin@icewind.nl>
Diffstat (limited to 'apps/dav')
-rw-r--r-- | apps/dav/lib/CalDAV/CalDavBackend.php | 4 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/CalendarHome.php | 5 | ||||
-rw-r--r-- | apps/dav/lib/DAV/Sharing/Backend.php | 48 | ||||
-rw-r--r-- | apps/dav/lib/DAV/Sharing/Plugin.php | 16 |
4 files changed, 73 insertions, 0 deletions
diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index a948c54ad58..4fb5493cc1c 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -2858,6 +2858,10 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription return $this->calendarSharingBackend->getShares($resourceId); } + public function preloadShares(array $resourceIds): void { + $this->calendarSharingBackend->preloadShares($resourceIds); + } + /** * @param boolean $value * @param \OCA\DAV\CalDAV\Calendar $calendar diff --git a/apps/dav/lib/CalDAV/CalendarHome.php b/apps/dav/lib/CalDAV/CalendarHome.php index a59e76d121f..cbf5cebc9e7 100644 --- a/apps/dav/lib/CalDAV/CalendarHome.php +++ b/apps/dav/lib/CalDAV/CalendarHome.php @@ -58,6 +58,7 @@ class CalendarHome extends \Sabre\CalDAV\CalendarHome { /** @var LoggerInterface */ private $logger; + private ?array $cachedChildren = null; public function __construct(BackendInterface $caldavBackend, $principalInfo, LoggerInterface $logger) { parent::__construct($caldavBackend, $principalInfo); @@ -97,6 +98,9 @@ class CalendarHome extends \Sabre\CalDAV\CalendarHome { * @inheritdoc */ public function getChildren() { + if ($this->cachedChildren) { + return $this->cachedChildren; + } $calendars = $this->caldavBackend->getCalendarsForUser($this->principalInfo['uri']); $objects = []; foreach ($calendars as $calendar) { @@ -136,6 +140,7 @@ class CalendarHome extends \Sabre\CalDAV\CalendarHome { } } + $this->cachedChildren = $objects; return $objects; } diff --git a/apps/dav/lib/DAV/Sharing/Backend.php b/apps/dav/lib/DAV/Sharing/Backend.php index 813f99dcbbd..74b34b81b22 100644 --- a/apps/dav/lib/DAV/Sharing/Backend.php +++ b/apps/dav/lib/DAV/Sharing/Backend.php @@ -30,6 +30,7 @@ namespace OCA\DAV\DAV\Sharing; use OCA\DAV\Connector\Sabre\Principal; use OCP\AppFramework\Db\TTransactional; +use OCP\Cache\CappedMemoryCache; use OCP\IDBConnection; use OCP\IGroupManager; use OCP\IUserManager; @@ -48,12 +49,15 @@ class Backend { public const ACCESS_READ_WRITE = 2; public const ACCESS_READ = 3; + private CappedMemoryCache $shareCache; + public function __construct(IDBConnection $db, IUserManager $userManager, IGroupManager $groupManager, Principal $principalBackend, string $resourceType) { $this->db = $db; $this->userManager = $userManager; $this->groupManager = $groupManager; $this->principalBackend = $principalBackend; $this->resourceType = $resourceType; + $this->shareCache = new CappedMemoryCache(); } /** @@ -61,6 +65,7 @@ class Backend { * @param list<string> $remove */ public function updateShares(IShareable $shareable, array $add, array $remove): void { + $this->shareCache->clear(); $this->atomic(function () use ($shareable, $add, $remove) { foreach ($add as $element) { $principal = $this->principalBackend->findByUri($element['href'], ''); @@ -81,6 +86,7 @@ class Backend { * @param array{href: string, commonName: string, readOnly: bool} $element */ private function shareWith(IShareable $shareable, array $element): void { + $this->shareCache->clear(); $user = $element['href']; $parts = explode(':', $user, 2); if ($parts[0] !== 'principal') { @@ -124,6 +130,7 @@ class Backend { } public function deleteAllShares(int $resourceId): void { + $this->shareCache->clear(); $query = $this->db->getQueryBuilder(); $query->delete('dav_shares') ->where($query->expr()->eq('resourceid', $query->createNamedParameter($resourceId))) @@ -132,6 +139,7 @@ class Backend { } public function deleteAllSharesByUser(string $principaluri): void { + $this->shareCache->clear(); $query = $this->db->getQueryBuilder(); $query->delete('dav_shares') ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principaluri))) @@ -140,6 +148,7 @@ class Backend { } private function unshare(IShareable $shareable, string $element): void { + $this->shareCache->clear(); $parts = explode(':', $element, 2); if ($parts[0] !== 'principal') { return; @@ -172,6 +181,10 @@ class Backend { * @return list<array{href: string, commonName: string, status: int, readOnly: bool, '{http://owncloud.org/ns}principal': string, '{http://owncloud.org/ns}group-share': bool}> */ public function getShares(int $resourceId): array { + $cached = $this->shareCache->get($resourceId); + if ($cached) { + return $cached; + } $query = $this->db->getQueryBuilder(); $result = $query->select(['principaluri', 'access']) ->from('dav_shares') @@ -193,9 +206,44 @@ class Backend { ]; } + $this->shareCache->set((string)$resourceId, $shares); return $shares; } + public function preloadShares(array $resourceIds): void { + $resourceIds = array_filter($resourceIds, function(int $resourceId) { + return !isset($this->shareCache[$resourceId]); + }); + if (count($resourceIds) === 0) { + return; + } + $query = $this->db->getQueryBuilder(); + $result = $query->select(['resourceid', 'principaluri', 'access']) + ->from('dav_shares') + ->where($query->expr()->in('resourceid', $query->createNamedParameter($resourceIds, IQueryBuilder::PARAM_INT_ARRAY))) + ->andWhere($query->expr()->eq('type', $query->createNamedParameter($this->resourceType))) + ->groupBy(['principaluri', 'access', 'resourceid']) + ->executeQuery(); + + $sharesByResource = array_fill_keys($resourceIds, []); + while ($row = $result->fetch()) { + $resourceId = (int)$row['resourceid']; + $p = $this->principalBackend->getPrincipalByPath($row['principaluri']); + $sharesByResource[$resourceId][] = [ + 'href' => "principal:{$row['principaluri']}", + 'commonName' => isset($p['{DAV:}displayname']) ? (string)$p['{DAV:}displayname'] : '', + 'status' => 1, + 'readOnly' => (int) $row['access'] === self::ACCESS_READ, + '{http://owncloud.org/ns}principal' => (string)$row['principaluri'], + '{http://owncloud.org/ns}group-share' => isset($p['uri']) ? str_starts_with($p['uri'], 'principals/groups') : false + ]; + } + + foreach ($resourceIds as $resourceId) { + $this->shareCache->set($resourceId, $sharesByResource[$resourceId]); + } + } + /** * For shared resources the sharee is set in the ACL of the resource * diff --git a/apps/dav/lib/DAV/Sharing/Plugin.php b/apps/dav/lib/DAV/Sharing/Plugin.php index a4b2cd3681c..8ddcb664fd5 100644 --- a/apps/dav/lib/DAV/Sharing/Plugin.php +++ b/apps/dav/lib/DAV/Sharing/Plugin.php @@ -24,6 +24,8 @@ */ namespace OCA\DAV\DAV\Sharing; +use OCA\DAV\CalDAV\CalDavBackend; +use OCA\DAV\CalDAV\CalendarHome; use OCA\DAV\Connector\Sabre\Auth; use OCA\DAV\DAV\Sharing\Xml\Invite; use OCA\DAV\DAV\Sharing\Xml\ShareRequest; @@ -201,6 +203,20 @@ class Plugin extends ServerPlugin { * @return void */ public function propFind(PropFind $propFind, INode $node) { + if ($node instanceof CalendarHome && $propFind->getDepth() === 1) { + $backend = $node->getCalDAVBackend(); + if ($backend instanceof CalDavBackend) { + $calendars = $node->getChildren(); + $calendars = array_filter($calendars, function (INode $node) { + return $node instanceof IShareable; + }); + /** @var int[] $resourceIds */ + $resourceIds = array_map(function (IShareable $node) { + return $node->getResourceId(); + }, $calendars); + $backend->preloadShares($resourceIds); + } + } if ($node instanceof IShareable) { $propFind->handle('{' . Plugin::NS_OWNCLOUD . '}invite', function () use ($node) { return new Invite( |