Ver Fonte

Improve WebDAV compatibility

Add getlastmodified and getcontentlength properties, and fix nested
collections support. Fix #321.
Guillaume Ayoub há 10 anos atrás
pai
commit
65659fc909
2 ficheiros alterados com 23 adições e 12 exclusões
  1. 19 12
      radicale/storage.py
  2. 4 0
      radicale/xmlutils.py

+ 19 - 12
radicale/storage.py

@@ -114,14 +114,19 @@ def path_to_filesystem(root, *paths):
 
 
 class Item:
-    def __init__(self, item, href, etag):
+    def __init__(self, item, href, etag, last_modified=None):
         self.item = item
         self.href = href
         self.etag = etag
+        self.last_modified = last_modified
 
     def __getattr__(self, attr):
         return getattr(self.item, attr)
 
+    @property
+    def content_length(self):
+        return len(self.serialize().encode(config.get("encoding", "request")))
+
 
 class Collection:
     """Collection stored in several files per calendar."""
@@ -170,8 +175,7 @@ class Collection:
             return
 
         # Try to guess if the path leads to a collection or an item
-        if os.path.exists(path_to_filesystem(
-                FOLDER, *attributes[:-1]) + ".props"):
+        if os.path.isfile(path_to_filesystem(FOLDER, sane_path)):
             attributes.pop()
 
         path = "/".join(attributes)
@@ -185,12 +189,11 @@ class Collection:
             if items:
                 for item in items:
                     yield collection.get(item[0])
-            else:
-                _, directories, _ = next(os.walk(collection._filesystem_path))
-                for sub_path in directories:
-                    full_path = os.path.join(collection._filesystem_path, sub_path)
-                    if os.path.exists(path_to_filesystem(full_path)):
-                        yield cls(posixpath.join(path, sub_path))
+            _, directories, _ = next(os.walk(collection._filesystem_path))
+            for sub_path in directories:
+                full_path = os.path.join(collection._filesystem_path, sub_path)
+                if os.path.exists(path_to_filesystem(full_path)):
+                    yield cls(posixpath.join(path, sub_path))
 
     @classmethod
     def create_collection(cls, href, collection=None, tag=None):
@@ -248,7 +251,11 @@ class Collection:
             if os.path.isfile(path):
                 with open(path, encoding=STORAGE_ENCODING) as fd:
                     text = fd.read()
-                return Item(vobject.readOne(text), href, get_etag(text))
+                last_modified = time.strftime(
+                    "%a, %d %b %Y %H:%M:%S GMT",
+                    time.gmtime(os.path.getmtime(path)))
+                return Item(
+                    vobject.readOne(text), href, get_etag(text), last_modified)
         else:
             log.LOGGER.debug(
                 "Can't tranlate name safely to filesystem, "
@@ -365,10 +372,10 @@ class Collection:
     @property
     def last_modified(self):
         """Get the HTTP-datetime of when the collection was modified."""
-        last = max([
+        last = max([os.path.getmtime(self._filesystem_path)] + [
             os.path.getmtime(os.path.join(self._filesystem_path, filename))
             for filename in os.listdir(self._filesystem_path)] or [0])
-        return time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(last))
+        return time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(last))
 
     def serialize(self):
         items = []

+ 4 - 0
radicale/xmlutils.py

@@ -276,6 +276,8 @@ def _propfind_response(path, item, props, user, write=False):
             tag = ET.Element(_tag("D", "href"))
             tag.text = _href(path)
             element.append(tag)
+        elif tag == _tag("D", "getlastmodified"):
+            element.text = item.last_modified
         elif tag in (_tag("D", "principal-collection-set"),
                      _tag("C", "calendar-user-address-set"),
                      _tag("CR", "addressbook-home-set"),
@@ -377,6 +379,8 @@ def _propfind_response(path, item, props, user, write=False):
         elif tag == _tag("D", "resourcetype"):
             # resourcetype must be returned empty for non-collection elements
             pass
+        elif tag == _tag("D", "getcontentlength"):
+            element.text = str(item.content_length)
         else:
             is404 = True