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"\n
RadicaleRadicale 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" % (