summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Bruederli <bruederli@kolabsys.com>2015-02-20 09:44:22 (GMT)
committerThomas Bruederli <bruederli@kolabsys.com>2015-02-20 09:44:22 (GMT)
commit05f1d4e5787acde1835337ca5dff4b86470fe53e (patch)
treee4b8f0b37b6211cb4aefedb987bf4c9295859305
parente43e509c773c7f69ab4c479c708d20aae0cf063d (diff)
downloadpykolab-05f1d4e5787acde1835337ca5dff4b86470fe53e.tar.gz
Support iTip CANCEL requests with THISANDFUTRE range
-rw-r--r--pykolab/xml/event.py3
-rw-r--r--tests/functional/test_wallace/test_007_invitationpolicy.py30
-rw-r--r--wallace/module_invitationpolicy.py9
3 files changed, 40 insertions, 2 deletions
diff --git a/pykolab/xml/event.py b/pykolab/xml/event.py
index 2d9a424..dbe938c 100644
--- a/pykolab/xml/event.py
+++ b/pykolab/xml/event.py
@@ -702,6 +702,9 @@ class Event(object):
def get_transparency(self):
return self.event.transparency()
+ def get_recurrence(self):
+ return RecurrenceRule(self.event.recurrenceRule())
+
def set_attendees(self, _attendees, recursive=False):
if recursive:
self._attendees = []
diff --git a/tests/functional/test_wallace/test_007_invitationpolicy.py b/tests/functional/test_wallace/test_007_invitationpolicy.py
index 4507dd1..cc99c73 100644
--- a/tests/functional/test_wallace/test_007_invitationpolicy.py
+++ b/tests/functional/test_wallace/test_007_invitationpolicy.py
@@ -445,11 +445,14 @@ class TestWallaceInvitationpolicy(unittest.TestCase):
return uid
- def send_itip_cancel(self, attendee_email, uid, template=None, summary="test", sequence=1, instance=None):
+ def send_itip_cancel(self, attendee_email, uid, template=None, summary="test", sequence=1, instance=None, thisandfuture=False):
recurrence_id = ''
if instance is not None:
- recurrence_id = "\nRECURRENCE-ID;TZID=Europe/Berlin:" + instance.strftime('%Y%m%dT%H%M%S')
+ recurrence_id = "\nRECURRENCE-ID;TZID=Europe/Berlin%s:%s" % (
+ ';RANGE=THISANDFUTURE' if thisandfuture else '',
+ instance.strftime('%Y%m%dT%H%M%S')
+ )
self.send_message((template if template is not None else itip_cancellation) % {
'uid': uid,
@@ -1226,6 +1229,29 @@ class TestWallaceInvitationpolicy(unittest.TestCase):
response = self.check_message_received(self.itip_reply_subject % { 'summary':'new booking', 'status':participant_status_label('ACCEPTED') }, self.jane['mail'])
self.assertIsInstance(response, email.message.Message)
+ def test_017_cancel_thisandfuture(self):
+ self.purge_mailbox(self.john['mailbox'])
+
+ start = datetime.datetime(2015,5,4, 6,30,0)
+ uid = self.send_itip_invitation(self.mark['mail'], summary="recurring", start=start, template=itip_recurring)
+
+ response = self.check_message_received(self.itip_reply_subject % { 'summary':'recurring', 'status':participant_status_label('ACCEPTED') }, self.mark['mail'])
+ self.assertIsInstance(response, email.message.Message)
+
+ event = self.check_user_calendar_event(self.mark['kolabcalendarfolder'], uid)
+ self.assertIsInstance(event, pykolab.xml.Event)
+
+ exdate = start + datetime.timedelta(days=14)
+ self.send_itip_cancel(self.mark['mail'], uid, summary="recurring ended", instance=exdate, thisandfuture=True)
+
+ time.sleep(10)
+ event = self.check_user_calendar_event(self.mark['kolabcalendarfolder'], uid)
+ self.assertIsInstance(event, pykolab.xml.Event)
+
+ rrule = event.get_recurrence().to_dict()
+ self.assertIsInstance(rrule['until'], datetime.datetime)
+ self.assertEqual(rrule['until'].strftime('%Y%m%d'), (exdate - datetime.timedelta(days=1)).strftime('%Y%m%d'))
+
def test_018_invite_individual_occurrences(self):
self.purge_mailbox(self.john['mailbox'])
diff --git a/wallace/module_invitationpolicy.py b/wallace/module_invitationpolicy.py
index 4ac7eef..993cd5e 100644
--- a/wallace/module_invitationpolicy.py
+++ b/wallace/module_invitationpolicy.py
@@ -18,6 +18,7 @@
#
import datetime
+import pytz
import os
import tempfile
import time
@@ -656,6 +657,14 @@ def process_itip_cancel(itip_event, policy, recipient_email, sender_email, recei
))
return MESSAGE_FORWARD
+ # on this-and-future cancel requests, set the recurrence until date on the master event
+ if itip_event['recurrence-id'] and master and itip_event['xml'].get_thisandfuture():
+ rrule = master.get_recurrence()
+ rrule.set_count(0)
+ rrule.set_until(existing.get_start().astimezone(pytz.utc) + datetime.timedelta(days=-1))
+ master.set_recurrence(rrule)
+ existing.set_recurrence_id(existing.get_recurrence_id(), True)
+
existing.set_status('CANCELLED')
existing.set_transparency(True)
if update_object(existing, receiving_user, master):