diff --git a/radicale/__init__.py b/radicale/__init__.py index 6bbdc5a1..42d0936a 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -166,8 +166,8 @@ class Application(object): content = None # Find calendar(s) - items = ical.Calendar.from_path(environ["PATH_INFO"], - environ.get("HTTP_DEPTH", "0")) + items = ical.Calendar.from_path( + environ["PATH_INFO"], environ.get("HTTP_DEPTH", "0")) # Get function corresponding to method function = getattr(self, environ["REQUEST_METHOD"].lower()) diff --git a/radicale/ical.py b/radicale/ical.py index c8c26563..393956d2 100644 --- a/radicale/ical.py +++ b/radicale/ical.py @@ -163,7 +163,12 @@ class Calendar(object): tag = "VCALENDAR" def __init__(self, path, principal=False): - """Initialize the calendar with ``cal`` and ``user`` parameters.""" + """Initialize the calendar. + + ``path`` must be the normalized relative path of the calendar, using + the slash as the folder delimiter, with no leading nor trailing slash. + + """ self.encoding = "utf-8" split_path = path.split("/") self.owner = split_path[0] if len(split_path) > 1 else None @@ -193,9 +198,8 @@ class Calendar(object): result = [] path = "/".join(attributes[:min(len(attributes), 2)]) - path = path.replace("/", os.sep) - abs_path = os.path.join(FOLDER, path) - if os.path.isdir(abs_path) or len(attributes) == 1: + abs_path = os.path.join(FOLDER, path.replace("/", os.sep)) + if os.path.isdir(abs_path): if depth == "0": result.append(cls(path, principal=True)) else: @@ -203,11 +207,10 @@ class Calendar(object): result.append(cls(path, principal=True)) try: for filename in next(os.walk(abs_path))[2]: - file_path = os.path.join(path, filename) if cls.is_vcalendar(os.path.join(abs_path, filename)): - result.append(cls(file_path)) + result.append(cls(os.path.join(path, filename))) except StopIteration: - # directory does not exist yet + # Directory does not exist yet pass else: calendar = cls(path) @@ -298,8 +301,6 @@ class Calendar(object): def write(self, headers=None, items=None): """Write calendar with given parameters.""" - if self.is_principal: - return headers = headers or self.headers or ( Header("PRODID:-//Radicale//NONSGML Radicale Server//EN"), Header("VERSION:2.0")) @@ -415,11 +416,11 @@ class Calendar(object): def owner_url(self): """Get the calendar URL according to its owner.""" if self.owner: - return ('/%s/' % self.owner).replace('//', '/') + return "/%s/" % self.owner else: return None @property def url(self): """Get the standard calendar URL.""" - return ('/%s/' % self.local_path).replace('//', '/') + return "/%s/" % self.local_path diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index 37f6f806..b5d28bca 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -201,7 +201,7 @@ def _propfind_response(path, item, props, user): response = ET.Element(_tag("D", "response")) href = ET.Element(_tag("D", "href")) - href.text = item.url if is_calendar else "%s/%s" % (path, item.name) + href.text = item.local_path if is_calendar else "%s/%s" % (path, item.name) response.append(href) propstat404 = ET.Element(_tag("D", "propstat")) @@ -264,9 +264,11 @@ def _propfind_response(path, item, props, user): if tag == _tag("D", "getcontenttype"): element.text = "text/calendar" elif tag == _tag("D", "resourcetype"): - if not item.is_principal: - tag = ET.Element(_tag("C", "calendar")) + if item.is_principal: + tag = ET.Element(_tag("D", "principal")) element.append(tag) + tag = ET.Element(_tag("C", "calendar")) + element.append(tag) tag = ET.Element(_tag("D", "collection")) element.append(tag) elif tag == _tag("D", "owner") and item.owner_url: @@ -284,6 +286,9 @@ def _propfind_response(path, item, props, user): # Not for calendars elif tag == _tag("D", "getcontenttype"): element.text = "text/calendar; component=%s" % item.tag.lower() + elif tag == _tag("D", "resourcetype"): + # resourcetype must be returned empty for non-collection elements + pass else: is404 = True