[Guido Günther]
> I checked that callers and they don't distinguish False and None so this
> looks good.

Good.  I checked it too, and hope this part can be commited right away
to reduce the number of patches I need to track. :)

> Since this all ends up in answering the report request from a client I
> think we should set a proper response code (400) in report() for that
> particular imtem of the MultiStatus repose. just as we unconditionally
> set 200 atm. Does this make sense?

Make sense to me.  Throwing any exception will cause do_REPORT to send
client.BAD_REQUEST.

> We don't have calypso specific exception's yet. Is it time to introduce
> these or do we just raise ValueError?

In this case, I guess ValueError will do just fine.  Rewriting.

>> +        # Tried calling do_REPORT() directly, but lacked the arguments
>> +        # needed to get the CollectionHTTPHandler class working.  Use
>> +        # match_filter() directly instead.
>
> Hmm...either we want to teaat do_REPORT than we should try harder or we
> just want to exercise match_filter in which case i would leave the
> comment out.

I'll drop the comment.  This test started out with an intention to test
do_REPORT(), but now it is testing match_filter() instead.  We can (and
probably should) write another script to test do_REPORT(). :)

> Given we do the exception raising from above we should also test if we
> can catch that here.

Done. :)

Attached is a new and improved version of
0002-Allow-time-range-query-filters-to-be-open-ended.patch.

--
Happy hacking
Petter Reinholdtsen
>From 5539956cbcf94aa4b293d66732f0a7cfef38934f Mon Sep 17 00:00:00 2001
From: Petter Reinholdtsen <[email protected]>
Date: Mon, 25 Jan 2016 09:32:20 +0000
Subject: [PATCH 2/2] Allow time-range query filters to be open ended.

RFC 4791 state that the start or end attribute (but not boht) can
be skipped.  Allow this in the code, and add a test case to verify
that this work.
---
 calypso/xmlutils.py              | 13 ++++++
 tests/data/from-korganizer.ics   | 85 ++++++++++++++++++++++++++++++++++++
 tests/test_matchfilterelement.py | 93 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 191 insertions(+)
 create mode 100644 tests/data/from-korganizer.ics
 create mode 100644 tests/test_matchfilterelement.py

diff --git a/calypso/xmlutils.py b/calypso/xmlutils.py
index 67290b7..2df60b2 100644
--- a/calypso/xmlutils.py
+++ b/calypso/xmlutils.py
@@ -275,6 +275,19 @@ def match_filter_element(vobject, fe):
             return False
         start = fe.get("start")
         end = fe.get("end")
+        # According to RFC 4791, one of start and stop must be set,
+        # but the other can be empty.  If both are empty, the
+        # specification is violated.
+        if start is None and end is None:
+            msg = "time-range missing both start and stop attribute (required by RFC 4791)"
+            log.error(msg)
+            raise ValueError(msg)
+        # RFC 4791 state if start is missing, assume it is -infinity
+        if start is None:
+            start = "00010101T000000Z" # start of year one
+        # RFC 4791 state if end is missing, assume it is +infinity
+        if end is None:
+            end = "99991231T235959Z" # last date with four digit year
         if rruleset is None:
             rruleset = dateutil.rrule.rruleset()
             dtstart = vobject.dtstart.value
diff --git a/tests/data/from-korganizer.ics b/tests/data/from-korganizer.ics
new file mode 100644
index 0000000..d48d9e8
--- /dev/null
+++ b/tests/data/from-korganizer.ics
@@ -0,0 +1,85 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//K Desktop Environment//NONSGML libkcal 4.3//EN
+BEGIN:VTIMEZONE
+TZID:Europe/Oslo
+BEGIN:STANDARD
+DTSTART:19011213T212852
+RDATE;VALUE=DATE-TIME:19011213T212852
+TZNAME:CET
+TZOFFSETFROM:+0043
+TZOFFSETTO:+0100
+END:STANDARD
+BEGIN:STANDARD
+DTSTART:19800928T030000
+RRULE:FREQ=YEARLY;COUNT=16;BYDAY=-1SU;BYMONTH=9
+TZNAME:CET
+TZOFFSETFROM:+0200
+TZOFFSETTO:+0100
+END:STANDARD
+BEGIN:STANDARD
+DTSTART:19961027T030000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:CET
+TZOFFSETFROM:+0200
+TZOFFSETTO:+0100
+END:STANDARD
+BEGIN:STANDARD
+DTSTART:19160930T000000
+RDATE;VALUE=DATE-TIME:19160930T000000
+RDATE;VALUE=DATE-TIME:19421102T030000
+RDATE;VALUE=DATE-TIME:19431004T030000
+RDATE;VALUE=DATE-TIME:19441002T030000
+RDATE;VALUE=DATE-TIME:19451001T030000
+RDATE;VALUE=DATE-TIME:19590920T030000
+RDATE;VALUE=DATE-TIME:19600918T030000
+RDATE;VALUE=DATE-TIME:19610917T030000
+RDATE;VALUE=DATE-TIME:19620916T030000
+RDATE;VALUE=DATE-TIME:19630915T030000
+RDATE;VALUE=DATE-TIME:19640920T030000
+RDATE;VALUE=DATE-TIME:19650919T030000
+TZNAME:CET
+TZOFFSETFROM:+0200
+TZOFFSETTO:+0100
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19810329T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
+TZNAME:CEST
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0200
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19160522T010000
+RDATE;VALUE=DATE-TIME:19160522T010000
+RDATE;VALUE=DATE-TIME:19400810T230000
+RDATE;VALUE=DATE-TIME:19430329T020000
+RDATE;VALUE=DATE-TIME:19440403T020000
+RDATE;VALUE=DATE-TIME:19450402T020000
+RDATE;VALUE=DATE-TIME:19590315T020000
+RDATE;VALUE=DATE-TIME:19600320T020000
+RDATE;VALUE=DATE-TIME:19610319T020000
+RDATE;VALUE=DATE-TIME:19620318T020000
+RDATE;VALUE=DATE-TIME:19630317T020000
+RDATE;VALUE=DATE-TIME:19640315T020000
+RDATE;VALUE=DATE-TIME:19650425T020000
+RDATE;VALUE=DATE-TIME:19800406T020000
+TZNAME:CEST
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0200
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:KOrganizer-1559275381.105
+DTSTART;TZID=Europe/Oslo:20160122T130000
+DTEND;TZID=Europe/Oslo:20160122T133000
+CREATED:20160121T201051Z
+DTSTAMP:20160121T202651Z
+LAST-MODIFIED:20160121T202651Z
+SEQUENCE:2
+SUMMARY:Time to party
+TRANSP:OPAQUE
+END:VEVENT
+X-CALYPSO-NAME:1453407071.R507.ics
+X-KDE-ICAL-IMPLEMENTATION-VERSION:1.0
+END:VCALENDAR
diff --git a/tests/test_matchfilterelement.py b/tests/test_matchfilterelement.py
new file mode 100644
index 0000000..c920da7
--- /dev/null
+++ b/tests/test_matchfilterelement.py
@@ -0,0 +1,93 @@
+# vim: set fileencoding=utf-8 :
+"""Test matching filter handling """
+
+import sys
+import subprocess
+import tempfile
+import shutil
+import unittest
+import xml.etree.ElementTree as ET
+
+import calypso.config
+from calypso.webdav import Collection
+from calypso import xmlutils
+
+
+class TestMatchFilterElement(unittest.TestCase):
+    test_vcalendar = "tests/data/from-korganizer.ics"
+
+    def setUp(self):
+        self.tmpdir = tempfile.mkdtemp()
+        calypso.config.set('storage', 'folder', self.tmpdir)
+        subprocess.call(["git", "init", self.tmpdir]),
+
+    def tearDown(self):
+        if self.tmpdir:
+            shutil.rmtree(self.tmpdir)
+
+    def test_start_end(self):
+        """
+Check that the time-range parser accept ranges where start or stop is
+missing.
+"""
+        xml_request1 ="""
+<calendar-query xmlns="urn:ietf:params:xml:ns:caldav">
+ <prop xmlns="DAV:">
+  <getetag xmlns="DAV:"/>
+  <resourcetype xmlns="DAV:"/>
+ </prop>
+ <filter xmlns="urn:ietf:params:xml:ns:caldav">
+  <comp-filter xmlns="urn:ietf:params:xml:ns:caldav" name="VCALENDAR">
+    <time-range xmlns="urn:ietf:params:xml:ns:caldav" start="20151021T201004Z"/>
+  </comp-filter>
+ </filter>
+</calendar-query>
+"""
+        xml_request2 ="""
+<calendar-query xmlns="urn:ietf:params:xml:ns:caldav">
+ <prop xmlns="DAV:">
+  <getetag xmlns="DAV:"/>
+  <resourcetype xmlns="DAV:"/>
+ </prop>
+ <filter xmlns="urn:ietf:params:xml:ns:caldav">
+  <comp-filter xmlns="urn:ietf:params:xml:ns:caldav" name="VCALENDAR">
+    <time-range xmlns="urn:ietf:params:xml:ns:caldav" end="20151021T201004Z"/>
+  </comp-filter>
+ </filter>
+</calendar-query>
+"""
+        xml_request3 ="""
+<calendar-query xmlns="urn:ietf:params:xml:ns:caldav">
+ <prop xmlns="DAV:">
+  <getetag xmlns="DAV:"/>
+  <resourcetype xmlns="DAV:"/>
+ </prop>
+ <filter xmlns="urn:ietf:params:xml:ns:caldav">
+  <comp-filter xmlns="urn:ietf:params:xml:ns:caldav" name="VCALENDAR">
+    <time-range xmlns="urn:ietf:params:xml:ns:caldav"/>
+  </comp-filter>
+ </filter>
+</calendar-query>
+"""
+        collection = Collection("")
+        self.assertTrue(collection.import_file(self.test_vcalendar))
+        self.assertEqual(len(collection.items), 1)
+
+        truecount = 0
+        rejected = 0
+        for xml_request in [xml_request1, xml_request2, xml_request3]:
+            try:
+                root = ET.fromstring(xml_request)
+                filter_element = root.find(xmlutils._tag("C", "filter"))
+                for item in collection.items:
+                    answer = xmlutils.match_filter(item, filter_element)
+                    if answer:
+                        truecount = truecount + 1
+            except ValueError as e:
+                # Detect rejection of xml_request3
+                print(str(e))
+                rejected = rejected + 1
+                pass
+        # The text vcalendar entry is either before or after the cutoff point.
+        self.assertEqual(truecount, 1)
+        self.assertEqual(rejected, 1)
-- 
2.7.0.rc3

_______________________________________________
Calypso mailing list
[email protected]
http://keithp.com/mailman/listinfo/calypso

Reply via email to