Browse Source

MKCALENDAR now actually creates the calendar.

Lukasz Langa 14 years ago
parent
commit
85e283830a
3 changed files with 50 additions and 2 deletions
  1. 5 0
      radicale/__init__.py
  2. 2 2
      radicale/ical.py
  3. 43 0
      radicale/xmlutils.py

+ 5 - 0
radicale/__init__.py

@@ -256,6 +256,11 @@ class Application(object):
 
 
     def mkcalendar(self, environ, calendar, content):
     def mkcalendar(self, environ, calendar, content):
         """Manage MKCALENDAR request."""
         """Manage MKCALENDAR request."""
+        props = xmlutils.props_from_request(content)
+        tz = props.get('C:calendar-timezone')
+        if tz:
+            calendar.replace('', tz)
+        calendar.write()
         return client.CREATED, {}, None
         return client.CREATED, {}, None
 
 
     def options(self, environ, calendar, content):
     def options(self, environ, calendar, content):

+ 2 - 2
radicale/ical.py

@@ -33,7 +33,7 @@ from radicale import config
 
 
 
 
 FOLDER = os.path.expanduser(config.get("storage", "folder"))
 FOLDER = os.path.expanduser(config.get("storage", "folder"))
-    
+
 
 
 # This function overrides the builtin ``open`` function for this module
 # This function overrides the builtin ``open`` function for this module
 # pylint: disable=W0622
 # pylint: disable=W0622
@@ -242,7 +242,7 @@ class Calendar(object):
         # Create folder if absent
         # Create folder if absent
         if not os.path.exists(os.path.dirname(self.path)):
         if not os.path.exists(os.path.dirname(self.path)):
             os.makedirs(os.path.dirname(self.path))
             os.makedirs(os.path.dirname(self.path))
-        
+
         text = serialize(headers, items)
         text = serialize(headers, items)
         return open(self.path, "w").write(text)
         return open(self.path, "w").write(text)
 
 

+ 43 - 0
radicale/xmlutils.py

@@ -27,6 +27,12 @@ in them for XML requests (all but PUT).
 
 
 """
 """
 
 
+try:
+    from collections import OrderedDict
+except ImportError:
+    # Python 2.6
+    OrderedDict = dict
+import re
 import xml.etree.ElementTree as ET
 import xml.etree.ElementTree as ET
 
 
 from radicale import client, config, ical
 from radicale import client, config, ical
@@ -39,7 +45,11 @@ NAMESPACES = {
     "ICAL": "http://apple.com/ns/ical/"}
     "ICAL": "http://apple.com/ns/ical/"}
 
 
 
 
+NAMESPACES_REV = {}
+
+
 for short, url in NAMESPACES.items():
 for short, url in NAMESPACES.items():
+    NAMESPACES_REV[url] = short
     if hasattr(ET, "register_namespace"):
     if hasattr(ET, "register_namespace"):
         # Register namespaces cleanly with Python 2.7+ and 3.2+ ...
         # Register namespaces cleanly with Python 2.7+ and 3.2+ ...
         ET.register_namespace("" if short == "D" else short, url)
         ET.register_namespace("" if short == "D" else short, url)
@@ -48,6 +58,14 @@ for short, url in NAMESPACES.items():
         ET._namespace_map[url] = short
         ET._namespace_map[url] = short
 
 
 
 
+CLARK_TAG_REGEX = re.compile(r"""
+    {                        # {
+    (?P<namespace>[^}]*)     # namespace URL
+    }                        # }
+    (?P<tag>.*)              # short tag name
+    """, re.VERBOSE)
+
+
 def _pretty_xml(element, level=0):
 def _pretty_xml(element, level=0):
     """Indent an ElementTree ``element`` and its children."""
     """Indent an ElementTree ``element`` and its children."""
     i = "\n" + level * "  "
     i = "\n" + level * "  "
@@ -87,6 +105,31 @@ def name_from_path(path, calendar):
     return path_parts[-1] if (len(path_parts) - len(calendar_parts)) else None
     return path_parts[-1] if (len(path_parts) - len(calendar_parts)) else None
 
 
 
 
+def props_from_request(xml_request):
+    """Returns a list of properties as a dictionary."""
+
+    result = OrderedDict()
+    root = ET.fromstring(xml_request.encode("utf8"))
+
+    set_element = root.find(_tag("D", "set"))
+    if not set_element:
+        set_element = root
+
+    prop_element = set_element.find(_tag("D", "prop"))
+    if prop_element:
+        for prop in prop_element:
+            match = CLARK_TAG_REGEX.match(prop.tag)
+            if match and match.group('namespace') in NAMESPACES_REV:
+                args = {
+                    'ns': NAMESPACES_REV[match.group('namespace')],
+                    'tag': match.group('tag')}
+                tag_name = '%(ns)s:%(tag)s' % args
+            else:
+                tag_name = prop.tag
+            result[tag_name] = prop.text
+    return result
+
+
 def delete(path, calendar):
 def delete(path, calendar):
     """Read and answer DELETE requests.
     """Read and answer DELETE requests.