diff --git a/radicale/app/propfind.py b/radicale/app/propfind.py index 009c61dc..6a3cea6d 100644 --- a/radicale/app/propfind.py +++ b/radicale/app/propfind.py @@ -392,7 +392,8 @@ class ApplicationPartPropfind(ApplicationBase): return httputils.REQUEST_TIMEOUT with self._storage.acquire_lock("r", user): items_iter = iter(self._storage.discover( - path, environ.get("HTTP_DEPTH", "0"))) + path, environ.get("HTTP_DEPTH", "0"), + None, self._rights._user_groups)) # take root item for rights checking item = next(items_iter, None) if not item: diff --git a/radicale/storage/multifilesystem/discover.py b/radicale/storage/multifilesystem/discover.py index 00316141..9a951764 100644 --- a/radicale/storage/multifilesystem/discover.py +++ b/radicale/storage/multifilesystem/discover.py @@ -18,6 +18,7 @@ import os import posixpath +import base64 from typing import Callable, ContextManager, Iterator, Optional, cast from radicale import pathutils, types @@ -36,7 +37,8 @@ class StoragePartDiscover(StorageBase): def discover( self, path: str, depth: str = "0", child_context_manager: Optional[ - Callable[[str, Optional[str]], ContextManager[None]]] = None + Callable[[str, Optional[str]], ContextManager[None]]] = None, + user_groups: Set[str] = set([]) ) -> Iterator[types.CollectionOrItem]: # assert isinstance(self, multifilesystem.Storage) if child_context_manager is None: @@ -102,3 +104,13 @@ class StoragePartDiscover(StorageBase): with child_context_manager(sane_child_path, None): yield self._collection_class( cast(multifilesystem.Storage, self), child_path) + for group in user_groups: + href = base64.b64encode(group.encode('utf-8')).decode('ascii') + logger.debug(f"searching for group calendar {group} {href}") + sane_child_path = f"GROUPS/{href}" + if not os.path.isdir(pathutils.path_to_filesystem(folder, sane_child_path)): + continue + child_path = f"/GROUPS/{href}/" + with child_context_manager(sane_child_path, None): + yield self._collection_class( + cast(multifilesystem.Storage, self), child_path)