pykolab/itip tests/functional tests/unit wallace/module_invitationpolicy.py wallace/module_resources.py

Thomas Brüderli bruederli at kolabsys.com
Mon Mar 2 18:57:46 CET 2015


 pykolab/itip/__init__.py                                      |   16 +--
 tests/functional/test_wallace/test_005_resource_invitation.py |   42 ++++++++--
 tests/unit/test-011-itip.py                                   |    3 
 wallace/module_invitationpolicy.py                            |    1 
 wallace/module_resources.py                                   |   20 +++-
 5 files changed, 61 insertions(+), 21 deletions(-)

New commits:
commit e0cdbb50abceae359934f6421445491315069ab7
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Mon Mar 2 12:57:32 2015 -0500

    Store reservations for single occurrences with the same UID in one object (#4766)

diff --git a/pykolab/itip/__init__.py b/pykolab/itip/__init__.py
index a81015b..83c9fe1 100644
--- a/pykolab/itip/__init__.py
+++ b/pykolab/itip/__init__.py
@@ -184,10 +184,10 @@ def check_event_conflict(kolab_event, itip_event):
                     _iv = _ix
 
             # iterate through all exceptions (non-recurring)
-            elif _is is None and not itip_event['xml'].is_recurring() and itip_event['xml'].has_exceptions() and len(itip_event['xml'].get_exceptions()) > _ii:
-                _ix = itip_event['xml'].get_exceptions()[_ii]
-                _is = to_dt(_ix.get_start())
-                _ie = to_dt(_ix.get_end())
+            elif _is is None and not itip_event['xml'].is_recurring() and len(itip_event['xml'].get_exceptions()) > _ii:
+                _iv = itip_event['xml'].get_exceptions()[_ii]
+                _is = to_dt(_iv.get_start())
+                _ie = to_dt(_iv.get_end())
                 _ii += 1
 
         _es = to_dt(kolab_event.get_next_occurence(_es)) if kolab_event.is_recurring() else None
@@ -202,10 +202,10 @@ def check_event_conflict(kolab_event, itip_event):
                 _ev = _ex
 
         # iterate through all exceptions (non-recurring)
-        elif _es is None and not kolab_event.is_recurring() and kolab_event.has_exceptions() and len(kolab_event.get_exceptions()) > _ei:
-            _ex = kolab_event.get_exceptions()[_ei]
-            _es = to_dt(_ex.get_start())
-            _ee = to_dt(_ex.get_end())
+        elif _es is None and not kolab_event.is_recurring() and len(kolab_event.get_exceptions()) > _ei:
+            _ev = kolab_event.get_exceptions()[_ei]
+            _es = to_dt(_ev.get_start())
+            _ee = to_dt(_ev.get_end())
             _ei += 1
 
     return conflict
diff --git a/tests/functional/test_wallace/test_005_resource_invitation.py b/tests/functional/test_wallace/test_005_resource_invitation.py
index e7ac0f3..af84fa6 100644
--- a/tests/functional/test_wallace/test_005_resource_invitation.py
+++ b/tests/functional/test_wallace/test_005_resource_invitation.py
@@ -360,7 +360,7 @@ class TestResourceInvitation(unittest.TestCase):
 
         return found
 
-    def check_resource_calendar_event(self, mailbox, uid=None, instance=None):
+    def check_resource_calendar_event(self, mailbox, uid=None):
         imap = IMAP()
         imap.connect()
 
@@ -383,7 +383,7 @@ class TestResourceInvitation(unittest.TestCase):
                     continue
 
                 found = event_from_message(event_message)
-                if found and (instance is None or found.is_recurring() or xmlutils.dates_equal(instance, found.get_recurrence_id())):
+                if found:
                     break
 
             time.sleep(1)
@@ -904,16 +904,34 @@ class TestResourceInvitation(unittest.TestCase):
         self.assertIsInstance(accept, email.message.Message)
         self.assertIn("RECURRENCE-ID;TZID=Europe/London:" + start.strftime('%Y%m%dT%H%M%S'), str(accept))
 
-        # the resource calendar now has two reservations stored
-        one = self.check_resource_calendar_event(self.boxter['kolabtargetfolder'], uid, start)
+        # the resource calendar now has two reservations stored in one object
+        one = self.check_resource_calendar_event(self.boxter['kolabtargetfolder'], uid)
         self.assertIsInstance(one, pykolab.xml.Event)
         self.assertIsInstance(one.get_recurrence_id(), datetime.datetime)
         self.assertEqual(one.get_start().hour, exstart.hour)
 
-        two = self.check_resource_calendar_event(self.boxter['kolabtargetfolder'], uid, nextstart)
+        two = one.get_instance(nextstart)
         self.assertIsInstance(two, pykolab.xml.Event)
         self.assertIsInstance(two.get_recurrence_id(), datetime.datetime)
 
+        self.purge_mailbox(self.john['mailbox'])
+
+        # send rescheduling request to the 2nd instance
+        self.send_itip_update(self.boxter['mail'], uid, nextstart + datetime.timedelta(hours=2), sequence=2, instance=nextstart)
+
+        accept = self.check_message_received(self.itip_reply_subject % { 'summary':'test', 'status':participant_status_label('ACCEPTED') })
+        self.assertIsInstance(accept, email.message.Message)
+        self.assertIn("RECURRENCE-ID;TZID=Europe/London:" + nextstart.strftime('%Y%m%dT%H%M%S'), str(accept))
+
+        event = self.check_resource_calendar_event(self.boxter['kolabtargetfolder'], uid)
+        self.assertIsInstance(event, pykolab.xml.Event)
+        self.assertEqual(len(event.get_exceptions()), 1)
+
+        two = event.get_instance(nextstart)
+        self.assertIsInstance(two, pykolab.xml.Event)
+        self.assertEqual(two.get_sequence(), 2)
+        self.assertEqual(two.get_start().hour, 20)
+
 
     def test_019_cancel_single_occurrence(self):
         self.purge_mailbox(self.john['mailbox'])
@@ -937,6 +955,20 @@ class TestResourceInvitation(unittest.TestCase):
         self.assertEqual(exception.get_status(True), 'CANCELLED')
         self.assertTrue(exception.get_transparency())
 
+        self.purge_mailbox(self.john['mailbox'])
+
+        # store a single occurrence with recurrence-id
+        start = datetime.datetime(2015,3,2, 18,30,0)
+        uid = self.send_itip_invitation(self.passat['mail'], start, instance=start)
+
+        accept = self.check_message_received(self.itip_reply_subject % { 'summary':'test', 'status':participant_status_label('ACCEPTED') })
+        self.assertIsInstance(accept, email.message.Message)
+
+        self.send_itip_cancel(self.passat['mail'], uid, instance=start)
+
+        time.sleep(5)  # wait for IMAP to update
+        self.assertEqual(self.check_resource_calendar_event(self.passat['kolabtargetfolder'], uid), None)
+
 
     def test_020_owner_confirmation_single_occurrence(self):
         self.purge_mailbox(self.john['mailbox'])
diff --git a/tests/unit/test-011-itip.py b/tests/unit/test-011-itip.py
index 8179aa9..e47d314 100644
--- a/tests/unit/test-011-itip.py
+++ b/tests/unit/test-011-itip.py
@@ -501,6 +501,7 @@ class TestITip(unittest.TestCase):
         second.set_start(dtstart + datetime.timedelta(hours=1))
         second.set_end(dtstart + datetime.timedelta(hours=2))
         second.set_recurrence_id(dtstart)
+        second.set_transparency(True)
         itip_event['xml'].add_exception(second)
         self.assertEqual(len(itip_event['xml'].get_exceptions()), 1)
 
@@ -514,7 +515,7 @@ class TestITip(unittest.TestCase):
         event.set_start(datetime.datetime(2012,7,15, 11,0,0, tzinfo=itip_event['start'].tzinfo))
         event.set_end(datetime.datetime(2012,7,15, 11,30,0, tzinfo=itip_event['start'].tzinfo))
 
-        self.assertTrue(itip.check_event_conflict(event, itip_event), "Conflicting dates (exception)")
+        self.assertFalse(itip.check_event_conflict(event, itip_event), "Conflicting dates (exception)")
 
 
     def test_003_send_reply(self):
diff --git a/wallace/module_invitationpolicy.py b/wallace/module_invitationpolicy.py
index 70bf627..d6503a0 100644
--- a/wallace/module_invitationpolicy.py
+++ b/wallace/module_invitationpolicy.py
@@ -826,7 +826,6 @@ def find_existing_object(uid, type, recurrence_id, user_rec, lock=False):
 
                     # return master, even if instance is not found
                     if not event and master.uid == uid:
-                        log.debug("Instance not found, returning master" % (), level=8)
                         return (event, master)
 
                 if event is not None:
diff --git a/wallace/module_resources.py b/wallace/module_resources.py
index c1a684c..6742658 100644
--- a/wallace/module_resources.py
+++ b/wallace/module_resources.py
@@ -336,7 +336,7 @@ def execute(*args, **kw):
                         log.debug(_("Cancellation for entire event %r: deleting") % (itip_event['uid']), level=8)
                         delete_resource_event(itip_event['uid'], resources[resource], event._msguid)
                     # just cancel one single occurrence: add exception with status=cancelled
-                    elif master and master.is_recurring():
+                    elif master is not None:
                         log.debug(_("Cancellation for a single occurrence %r of %r: updating...") % (itip_event['recurrence-id'], itip_event['uid']), level=8)
                         event.set_status('CANCELLED')
                         event.set_transparency(True)
@@ -687,9 +687,9 @@ def read_resource_calendar(resource_rec, itip_events):
             for itip in itip_events:
                 conflict = check_event_conflict(event, itip)
 
-                if event.get_uid() == itip['uid'] and (event.is_recurring() or itip['recurrence-id'] == event.get_recurrence_id()):
+                if event.get_uid() == itip['uid']:
                     setattr(event, '_msguid', msguid)
-                    if event.is_recurring():
+                    if event.is_recurring() or itip['recurrence-id']:
                         resource_rec['existing_master'] = event
                     else:
                         resource_rec['existing_events'].append(event)
@@ -740,21 +740,29 @@ def find_existing_event(uid, recurrence_id, resource_rec):
             event = event_from_message(message_from_string(data[0][1]))
 
             # find instance in a recurring series
-            if recurrence_id and event.is_recurring():
+            if recurrence_id and (event.is_recurring() or event.has_exceptions()):
                 master = event
                 event = master.get_instance(recurrence_id)
                 setattr(master, '_msguid', msguid)
 
+                # return master, even if instance is not found
+                if not event and master.uid == uid:
+                    return (event, master)
+
             # compare recurrence-id and skip to next message if not matching
-            elif recurrence_id and not event.is_recurring() and not xmlutils.dates_equal(recurrence_id, event.get_recurrence_id()):
+            elif recurrence_id and not xmlutils.dates_equal(recurrence_id, event.get_recurrence_id()):
                 log.debug(_("Recurrence-ID not matching on message %s, skipping: %r != %r") % (
                     msguid, recurrence_id, event.get_recurrence_id()
                 ), level=8)
                 continue
-            setattr(event, '_msguid', msguid)
+
+            if event is not None:
+                setattr(event, '_msguid', msguid)
 
         except Exception, e:
             log.error(_("Failed to parse event from message %s/%s: %r") % (mailbox, num, e))
+            event = None
+            master = None
             continue
 
         if event and event.uid == uid:




More information about the commits mailing list