pykolab/xml tests/functional wallace/module_invitationpolicy.py

Thomas Brüderli bruederli at kolabsys.com
Wed Jul 16 18:45:56 CEST 2014


 pykolab/xml/event.py                                       |    6 +
 tests/functional/test_wallace/test_007_invitationpolicy.py |   35 ++++++++---
 wallace/module_invitationpolicy.py                         |   41 +++++++++++--
 3 files changed, 68 insertions(+), 14 deletions(-)

New commits:
commit 166d4f4d0649a3a5ab2d23b26d271f0579602720
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Sun Jul 6 23:38:04 2014 -0400

    Add test case for CANCEL iTip messages

diff --git a/pykolab/xml/event.py b/pykolab/xml/event.py
index ea84cc4..e438343 100644
--- a/pykolab/xml/event.py
+++ b/pykolab/xml/event.py
@@ -433,6 +433,9 @@ class Event(object):
     def get_sequence(self):
         return self.event.sequence()
 
+    def get_transparency(self):
+        return self.event.transparency()
+
     def set_attendee_participant_status(self, attendee, status):
         """
             Set the participant status of an attendee to status.
@@ -664,6 +667,9 @@ class Event(object):
     def set_uid(self, uid):
         self.event.setUid(str(uid))
 
+    def set_transparency(self, transp):
+        return self.event.setTransparency(transp)
+
     def __str__(self):
         event_xml = kolabformat.writeEvent(self.event)
 
diff --git a/tests/functional/test_wallace/test_007_invitationpolicy.py b/tests/functional/test_wallace/test_007_invitationpolicy.py
index 0490ec1..10a377f 100644
--- a/tests/functional/test_wallace/test_007_invitationpolicy.py
+++ b/tests/functional/test_wallace/test_007_invitationpolicy.py
@@ -159,7 +159,7 @@ class TestWallaceInvitationpolicy(unittest.TestCase):
             'dn': 'uid=manager,ou=People,dc=example,dc=org',
             'mailbox': 'user/jane.manager at example.org',
             'kolabtargetfolder': 'user/jane.manager/Calendar at example.org',
-            'kolabinvitationpolicy': ['ACT_ACCEPT_IF_NO_CONFLICT','ACT_REJECT_IF_CONFLICT']
+            'kolabinvitationpolicy': ['ACT_ACCEPT_IF_NO_CONFLICT','ACT_REJECT_IF_CONFLICT', 'ACT_UPDATE']
         }
 
         from tests.functional.user_add import user_add
@@ -240,16 +240,19 @@ class TestWallaceInvitationpolicy(unittest.TestCase):
             },
             mailto,
             attendee_email,
-            method="REPLY")
+            method='REPLY')
 
         return uid
 
-    def send_itip_cancel(self, resource_email, uid):
-        self.send_message(itip_cancellation % (
-                uid,
-                resource_email
-            ),
-            resource_email)
+    def send_itip_cancel(self, attendee_email, uid, summary="test", sequence=1):
+        self.send_message(itip_cancellation % {
+                'uid': uid,
+                'mailto': attendee_email,
+                'summary': summary,
+                'sequence': sequence,
+            },
+            attendee_email,
+            method='CANCEL')
 
         return uid
 
@@ -446,4 +449,20 @@ class TestWallaceInvitationpolicy(unittest.TestCase):
         attendee = event.get_attendee(self.jane['mail'])
         self.assertIsInstance(attendee, pykolab.xml.Attendee)
         self.assertEqual(attendee.get_participant_status(), kolabformat.PartAccepted)
+
+    def test_005_invitation_cancel(self):
+        uid = self.send_itip_invitation(self.jane['mail'], summary="cancelled")
+
+        response = self.check_message_received('"cancelled" has been ACCEPTED', self.jane['mail'])
+        self.assertIsInstance(response, email.message.Message)
+
+        self.send_itip_cancel(self.jane['mail'], uid, summary="cancelled")
+
+        time.sleep(10)
+        event = self.check_user_calendar_event(self.jane['kolabtargetfolder'], uid)
+        self.assertIsInstance(event, pykolab.xml.Event)
+        self.assertEqual(event.get_summary(), "cancelled")
+        self.assertEqual(event.get_status(), 'CANCELLED')
+        self.assertTrue(event.get_transparency())
+
         
\ No newline at end of file
diff --git a/wallace/module_invitationpolicy.py b/wallace/module_invitationpolicy.py
index b5863c2..d4ed7d5 100644
--- a/wallace/module_invitationpolicy.py
+++ b/wallace/module_invitationpolicy.py
@@ -303,7 +303,8 @@ def process_itip_request(itip_event, policy, recipient_email, sender_email, rece
     nonpart = receiving_attendee.get_role() == kolabformat.NonParticipant
     partstat = receiving_attendee.get_participant_status()
     save_event = not nonpart or not partstat == kolabformat.PartNeedsAction
-    scheduling_required = receiving_attendee.get_rsvp() or partstat == kolabformat.PartNeedsAction
+    rsvp = receiving_attendee.get_rsvp()
+    scheduling_required = rsvp or partstat == kolabformat.PartNeedsAction
     condition_fulfilled = True
 
     # find existing event in user's calendar
@@ -325,7 +326,7 @@ def process_itip_request(itip_event, policy, recipient_email, sender_email, rece
         log.debug(_("Precondition for event %r fulfilled: %r") % (itip_event['uid'], condition_fulfilled), level=5)
 
     # if RSVP, send an iTip REPLY
-    if scheduling_required:
+    if rsvp or scheduling_required:
         respond_with = None
         if policy & ACT_ACCEPT and condition_fulfilled:
             respond_with = 'TENTATIVE' if policy & MOD_TENTATIVE else 'ACCEPTED'
@@ -348,6 +349,10 @@ def process_itip_request(itip_event, policy, recipient_email, sender_email, rece
             send_reply(recipient_email, itip_event, invitation_response_text(),
                 subject=_('"%(summary)s" has been %(status)s'))
 
+        # elif partstat == kolabformat.PartNeedsAction and conf.get('wallace','invitationpolicy_always_copy_to_calendar'):
+            # TODO: copy the invitation into the user's calendar with unchanged PARTSTAT
+            # TODO: or use ACT_POSTPONE for this?
+
         else:
             # policy doesn't match, pass on to next one
             return None
@@ -407,8 +412,7 @@ def process_itip_reply(itip_event, policy, recipient_email, sender_email, receiv
                 return MESSAGE_FORWARD
 
             # update the organizer's copy of the event
-            delete_event(existing)
-            if store_event(existing, receiving_user, existing._imap_folder):
+            if update_event(existing, receiving_user):
                 # TODO: send (consolidated) notification to organizer if policy & ACT_UPDATE_AND_NOTIFY:
                 # TODO: update all other attendee's copies if conf.get('wallace','invitationpolicy_autoupdate_other_attendees_on_reply'):
                 return MESSAGE_PROCESSED
@@ -430,9 +434,23 @@ def process_itip_cancel(itip_event, policy, recipient_email, sender_email, recei
         log.info(_("Pass cancellation for manual processing"))
         return MESSAGE_FORWARD
 
-    # update_event_in_user_calendar(itip_event, receiving_user)
+    # auto-update the local copy with STATUS=CANCELLED
+    if policy & ACT_UPDATE:
+        # find existing event in user's calendar
+        existing = find_existing_event(itip_event, receiving_user)
+
+        if existing:
+            existing.set_status('CANCELLED')
+            existing.set_transparency(True)
+            if update_event(existing, receiving_user):
+                # TODO: send cancellation notification if policy & ACT_UPDATE_AND_NOTIFY: ?
+                return MESSAGE_PROCESSED
+
+        else:
+            log.error(_("The event referred by this reply was not found in the user's calendars. Forwarding to Inbox."))
+            return MESSAGE_FORWARD
 
-    return MESSAGE_PROCESSED
+    return None
 
 
 def user_dn_from_email_address(email_address):
@@ -659,6 +677,17 @@ def check_availability(itip_event, receiving_user):
     return not conflict
 
 
+def update_event(event, user_rec):
+    """
+        Update the given event in IMAP (i.e. delete + append)
+    """
+    if hasattr(event, '_imap_folder'):
+        delete_event(event)
+        return store_event(event, user_rec, event._imap_folder)
+
+    return False
+
+
 def store_event(event, user_rec, targetfolder=None):
     """
         Append the given event object to the user's default calendar




More information about the commits mailing list