diff --git a/radicale/__init__.py b/radicale/__init__.py index 7e8deb5f..564a39f9 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -355,7 +355,7 @@ class Application(object): def do_DELETE(self, environ, read_collections, write_collections, content, user): """Manage DELETE request.""" - if not len(write_collections): + if not write_collections: return NOT_ALLOWED collection = write_collections[0] @@ -387,7 +387,7 @@ class Application(object): answer = b"\nRadicaleRadicale works!" return client.OK, headers, answer - if not len(read_collections): + if not read_collections: return NOT_ALLOWED collection = read_collections[0] @@ -407,8 +407,8 @@ class Application(object): else: return client.NOT_FOUND, {}, None elif not collection.exists: - log.LOGGER.debug("Collection %s unknown" % collection.name) - return client.NOT_FOUND + log.LOGGER.debug("Collection at %s unknown" % environ["PATH_INFO"]) + return client.NOT_FOUND, {}, None else: # Get whole collection answer_text = collection.text @@ -431,7 +431,7 @@ class Application(object): def do_MKCALENDAR(self, environ, read_collections, write_collections, content, user): """Manage MKCALENDAR request.""" - if not len(write_collections): + if not write_collections: return NOT_ALLOWED collection = write_collections[0] @@ -450,7 +450,7 @@ class Application(object): def do_MKCOL(self, environ, read_collections, write_collections, content, user): """Manage MKCOL request.""" - if not len(write_collections): + if not write_collections: return NOT_ALLOWED collection = write_collections[0] @@ -465,7 +465,7 @@ class Application(object): def do_MOVE(self, environ, read_collections, write_collections, content, user): """Manage MOVE request.""" - if not len(write_collections): + if not write_collections: return NOT_ALLOWED from_collection = write_collections[0] @@ -510,7 +510,8 @@ class Application(object): def do_PROPFIND(self, environ, read_collections, write_collections, content, user): """Manage PROPFIND request.""" - # Rights is handled by collection in xmlutils.propfind + if not any(collection.exists for collection in read_collections): + return client.NOT_FOUND, {}, None headers = { "DAV": "1, 2, 3, calendar-access, addressbook, extended-mkcol", "Content-Type": "text/xml"} @@ -521,7 +522,7 @@ class Application(object): def do_PROPPATCH(self, environ, read_collections, write_collections, content, user): """Manage PROPPATCH request.""" - if not len(write_collections): + if not write_collections: return NOT_ALLOWED collection = write_collections[0] @@ -536,7 +537,7 @@ class Application(object): def do_PUT(self, environ, read_collections, write_collections, content, user): """Manage PUT request.""" - if not len(write_collections): + if not write_collections: return NOT_ALLOWED collection = write_collections[0] @@ -571,7 +572,7 @@ class Application(object): def do_REPORT(self, environ, read_collections, write_collections, content, user): """Manage REPORT request.""" - if not len(read_collections): + if not read_collections: return NOT_ALLOWED collection = read_collections[0] diff --git a/radicale/ical.py b/radicale/ical.py index a3439c4c..a2ff2e75 100644 --- a/radicale/ical.py +++ b/radicale/ical.py @@ -222,8 +222,7 @@ class Collection(object): return [] # Try to guess if the path leads to a collection or an item - if (cls.is_leaf("/".join(attributes[:-1])) or not - path.endswith(("/", "/caldav", "/carddav"))): + if cls.is_leaf("/".join(attributes[:-1])): attributes.pop() result = [] diff --git a/radicale/storage.py b/radicale/storage.py index 6deb328a..0f85b494 100644 --- a/radicale/storage.py +++ b/radicale/storage.py @@ -77,6 +77,10 @@ class Collection(ical.Collection): if not os.path.exists(self._filesystem_path): os.makedirs(self._filesystem_path) + def set_mimetype(self, mimetype): + self._create_dirs() + return super().set_mimetype(mimetype) + def save(self, text): self._create_dirs() item_types = ( @@ -185,7 +189,6 @@ class Collection(ical.Collection): old_properties = properties.copy() yield properties # On exit - self._create_dirs() if old_properties != properties: with open(self._props_path, "w") as prop_file: json.dump(properties, prop_file) diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index d7fe1558..72e555f4 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -192,9 +192,8 @@ def propfind(path, xml_request, read_collections, write_collections, user=None): Read rfc4918-9.1 for info. - The collections parameter is a list of collections that are - to be included in the output. Rights checking has to be done - by the caller. + The collections parameter is a list of collections that are to be included + in the output. """ # Reading request @@ -231,6 +230,7 @@ def _propfind_response(path, item, props, user, write=False): """Build and return a PROPFIND response.""" is_collection = isinstance(item, ical.Collection) if is_collection: + is_leaf = item.is_leaf(item.path) with item.props as properties: collection_props = properties @@ -271,15 +271,17 @@ def _propfind_response(path, item, props, user, write=False): # This is not a Todo # pylint: disable=W0511 human_tag = _tag_from_clark(tag) - if is_collection and human_tag in collection_props: - # TODO: what do we have to do if it's not a collection? - components = collection_props[human_tag].split(",") + if is_collection and is_leaf: + if human_tag in collection_props: + components = collection_props[human_tag].split(",") + else: + components = ("VTODO", "VEVENT", "VJOURNAL") + for component in components: + comp = ET.Element(_tag("C", "comp")) + comp.set("name", component) + element.append(comp) else: - components = ("VTODO", "VEVENT", "VJOURNAL") - for component in components: - comp = ET.Element(_tag("C", "comp")) - comp.set("name", component) - element.append(comp) + is404 = True # pylint: enable=W0511 elif tag == _tag("D", "current-user-principal") and user: tag = ET.Element(_tag("D", "href")) @@ -310,7 +312,7 @@ def _propfind_response(path, item, props, user, write=False): if item.is_principal: tag = ET.Element(_tag("D", "principal")) element.append(tag) - if item.is_leaf(item.path) or ( + if is_leaf or ( not item.exists and item.resource_type): # 2nd case happens when the collection is not stored yet, # but the resource type is guessed @@ -321,23 +323,26 @@ def _propfind_response(path, item, props, user, write=False): element.append(tag) tag = ET.Element(_tag("D", "collection")) element.append(tag) - elif tag == _tag("D", "owner") and item.owner_url: - element.text = item.owner_url - elif tag == _tag("CS", "getctag"): - element.text = item.etag - elif tag == _tag("C", "calendar-timezone"): - element.text = ical.serialize( - item.tag, item.headers, item.timezones) - elif tag == _tag("D", "displayname"): - element.text = item.name - elif tag == _tag("ICAL", "calendar-color"): - element.text = item.color - else: - human_tag = _tag_from_clark(tag) - if human_tag in collection_props: - element.text = collection_props[human_tag] + elif is_leaf: + if tag == _tag("D", "owner") and item.owner_url: + element.text = item.owner_url + elif tag == _tag("CS", "getctag"): + element.text = item.etag + elif tag == _tag("C", "calendar-timezone"): + element.text = ical.serialize( + item.tag, item.headers, item.timezones) + elif tag == _tag("D", "displayname"): + element.text = item.name + elif tag == _tag("ICAL", "calendar-color"): + element.text = item.color else: - is404 = True + human_tag = _tag_from_clark(tag) + if human_tag in collection_props: + element.text = collection_props[human_tag] + else: + is404 = True + else: + is404 = True # Not for collections elif tag == _tag("D", "getcontenttype"): element.text = "%s; component=%s" % (