[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
