3 commits - pykolab/xml tests/functional tests/unit wallace/module_invitationpolicy.py

Thomas Brüderli bruederli at kolabsys.com
Wed Aug 6 20:23:15 CEST 2014


 pykolab/xml/attendee.py                                    |   10 ++
 pykolab/xml/event.py                                       |    6 +
 tests/functional/test_wallace/test_007_invitationpolicy.py |   51 +++++++++++++
 tests/unit/test-003-event.py                               |    6 +
 wallace/module_invitationpolicy.py                         |   36 ++++++++-
 5 files changed, 102 insertions(+), 7 deletions(-)

New commits:
commit 389a93cb32fd319309aaf95979a7dcaf0070234f
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Wed Aug 6 14:23:08 2014 -0400

    Fix Attendee.copy_from(); new method Event.find_attendee() which is similar to get_attendee() but doesn't raise an exception

diff --git a/pykolab/xml/attendee.py b/pykolab/xml/attendee.py
index c4ccb96..087e832 100644
--- a/pykolab/xml/attendee.py
+++ b/pykolab/xml/attendee.py
@@ -108,9 +108,17 @@ class Attendee(kolabformat.Attendee):
 
     def copy_from(self, obj):
         if isinstance(obj, kolabformat.Attendee):
-            kolabformat.Attendee.__init__(self, obj)
             self.contactreference = ContactReference(obj.contact())
             self.email = self.contactreference.get_email()
+            kolabformat.Attendee.__init__(self, self.contactreference)
+
+            # manually copy all properities, copy constructor doesn't work :-(
+            self.setRSVP(obj.rsvp())
+            self.setRole(obj.role())
+            self.setCutype(obj.cutype())
+            self.setPartStat(obj.partStat())
+            self.setDelegatedTo(obj.delegatedTo())
+            self.setDelegatedFrom(obj.delegatedFrom())
 
     def delegate_from(self, delegators):
         crefs = []
diff --git a/pykolab/xml/event.py b/pykolab/xml/event.py
index eac764d..6655b8c 100644
--- a/pykolab/xml/event.py
+++ b/pykolab/xml/event.py
@@ -296,6 +296,12 @@ class Event(object):
         else:
             raise ValueError, _("Invalid argument value attendee %r, must be basestring or Attendee") % (attendee)
 
+    def find_attendee(self, attendee):
+        try:
+            return self.get_attendee(attendee)
+        except:
+            return None
+
     def get_attendee_by_email(self, email):
         if email in [x.get_email() for x in self.get_attendees()]:
             return [x for x in self.get_attendees() if x.get_email() == email][0]


commit 419ece40024c5c91e659473b49aa988270a44b72
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Wed Aug 6 14:21:40 2014 -0400

    Handle iTip REPLY messages with delegation

diff --git a/tests/functional/test_wallace/test_007_invitationpolicy.py b/tests/functional/test_wallace/test_007_invitationpolicy.py
index 9bc808f..568a0e8 100644
--- a/tests/functional/test_wallace/test_007_invitationpolicy.py
+++ b/tests/functional/test_wallace/test_007_invitationpolicy.py
@@ -105,6 +105,27 @@ END:VEVENT
 END:VCALENDAR
 """
 
+itip_delegated = """
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//pykolab-0.6.9-1//kolab.org//
+CALSCALE:GREGORIAN
+METHOD:REPLY
+BEGIN:VEVENT
+SUMMARY:%(summary)s
+UID:%(uid)s
+DTSTART;TZID=Europe/Berlin;VALUE=DATE-TIME:%(start)s
+DTEND;TZID=Europe/Berlin;VALUE=DATE-TIME:%(end)s
+DTSTAMP;VALUE=DATE-TIME:20140706T171038Z
+ORGANIZER;CN="Doe, John":MAILTO:%(organizer)s
+ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO=jack at ripper.com;ROLE=NON-PARTICIPANT:mailto:%(mailto)s
+ATTENDEE;PARTSTAT=%(partstat)s;DELEGATED-FROM=%(mailto)s;ROLE=REQ-PARTICIPANT:mailto:jack at ripper.com
+PRIORITY:0
+SEQUENCE:%(sequence)d
+END:VEVENT
+END:VCALENDAR
+"""
+
 mime_message = """MIME-Version: 1.0
 Content-Type: multipart/mixed;
  boundary="=_c8894dbdb8baeedacae836230e3436fd"
@@ -584,6 +605,36 @@ class TestWallaceInvitationpolicy(unittest.TestCase):
         self.assertEqual(event.get_attachment_data(0), 'This is a text attachment')
 
 
+    def test_006_invitation_reply_delegated(self):
+        self.purge_mailbox(self.john['mailbox'])
+
+        start = datetime.datetime(2014,8,28, 14,30,0, tzinfo=pytz.timezone("Europe/Berlin"))
+        uid = self.create_calendar_event(start, user=self.john)
+
+        event = self.check_user_calendar_event(self.john['kolabtargetfolder'], uid)
+        self.assertIsInstance(event, pykolab.xml.Event)
+
+        # send a reply from jane to john
+        self.send_itip_reply(uid, self.jane['mail'], self.john['mail'], start=start, template=itip_delegated, partstat='NEEDS-ACTION')
+
+        # check for the updated event in john's calendar
+        time.sleep(10)
+        event = self.check_user_calendar_event(self.john['kolabtargetfolder'], uid)
+        self.assertIsInstance(event, pykolab.xml.Event)
+
+        attendee = event.get_attendee(self.jane['mail'])
+        self.assertIsInstance(attendee, pykolab.xml.Attendee)
+        self.assertEqual(attendee.get_participant_status(), kolabformat.PartDelegated)
+        # FIXME: self.assertEqual(len(attendee.get_delegated_to()), 1)
+        # FIXME: self.assertEqual(attendee.get_delegated_to(True)[0], 'jack at ripper.com')
+
+        delegatee = event.get_attendee('jack at ripper.com')
+        self.assertIsInstance(delegatee, pykolab.xml.Attendee)
+        self.assertEqual(delegatee.get_participant_status(), kolabformat.PartNeedsAction)
+        # FIXME: self.assertEqual(len(delegatee.get_delegated_from()), 1)
+        # FIXME: self.assertEqual(delegatee.get_delegated_from(True)[0], self.jane['mail'])
+
+
     def test_007_invitation_cancel(self):
         self.purge_mailbox(self.john['mailbox'])
 
diff --git a/wallace/module_invitationpolicy.py b/wallace/module_invitationpolicy.py
index 92e1fea..6dfc111 100644
--- a/wallace/module_invitationpolicy.py
+++ b/wallace/module_invitationpolicy.py
@@ -424,7 +424,7 @@ def process_itip_reply(itip_event, policy, recipient_email, sender_email, receiv
             return MESSAGE_FORWARD
 
         # find existing event in user's calendar
-        # TODO: set/check lock to avoid concurrent wallace processes trying to update the same event simultaneously
+        # sets/checks lock to avoid concurrent wallace processes trying to update the same event simultaneously
         existing = find_existing_event(itip_event['uid'], receiving_user, True)
 
         if existing:
@@ -438,13 +438,41 @@ def process_itip_reply(itip_event, policy, recipient_email, sender_email, receiv
 
             log.debug(_("Auto-updating event %r on iTip REPLY") % (existing.uid), level=8)
             try:
+                existing_attendee = existing.get_attendee(sender_email)
                 existing.set_attendee_participant_status(sender_email, sender_attendee.get_participant_status(), rsvp=False)
             except Exception, e:
                 log.error("Could not find corresponding attende in organizer's event: %r" % (e))
 
-                # TODO: accept new participant if ACT_ACCEPT ?
-                remove_write_lock(existing._lock_key)
-                return MESSAGE_FORWARD
+                # append delegated-from attendee ?
+                if len(sender_attendee.get_delegated_from()) > 0:
+                    existing._attendees.append(sender_attendee)
+                    existing.event.setAttendees(existing._attendees)
+                else:
+                    # TODO: accept new participant if ACT_ACCEPT ?
+                    remove_write_lock(existing._lock_key)
+                    return MESSAGE_FORWARD
+
+            # append delegated-to attendee
+            if len(sender_attendee.get_delegated_to()) > 0:
+                try:
+                    delegatee_email = sender_attendee.get_delegated_to(True)[0]
+                    sender_delegatee = itip_event['xml'].get_attendee_by_email(delegatee_email)
+                    existing_delegatee = existing.find_attendee(delegatee_email)
+
+                    if not existing_delegatee:
+                        existing._attendees.append(sender_delegatee)
+                        log.debug(_("Add delegatee: %r") % (sender_delegatee.to_dict()), level=9)
+                    else:
+                        existing_delegatee.copy_from(sender_delegatee)
+                        log.debug(_("Update existing delegatee: %r") % (existing_delegatee.to_dict()), level=9)
+
+                    # copy all parameters from replying attendee (e.g. delegated-to, role, etc.)
+                    existing_attendee.copy_from(sender_attendee)
+                    existing.event.setAttendees(existing._attendees)
+                    log.debug(_("Update delegator: %r") % (existing_attendee.to_dict()), level=9)
+
+                except Exception, e:
+                    log.error("Could not find delegated-to attendee: %r" % (e))
 
             # update the organizer's copy of the event
             if update_event(existing, receiving_user):


commit 31077c43c6ece15a6e5d9488e1c211e38abb2651
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Wed Aug 6 12:58:10 2014 -0400

    Test DELEGATED-* parameters

diff --git a/tests/unit/test-003-event.py b/tests/unit/test-003-event.py
index 4736b19..fa5d0fe 100644
--- a/tests/unit/test-003-event.py
+++ b/tests/unit/test-003-event.py
@@ -460,8 +460,10 @@ END:VEVENT
                 break
 
         self.assertEqual(len(itip_event['attendee']), 2)
-        self.assertEqual(itip_event['attendee'][0].lower(), 'mailto:jane at doe.org')
-        self.assertEqual(itip_event['attendee'][1].lower(), 'mailto:jack at ripper.com')
+        self.assertEqual(str(itip_event['attendee'][0]).lower(), 'mailto:jane at doe.org')
+        self.assertEqual(str(itip_event['attendee'][1]).lower(), 'mailto:jack at ripper.com')
+        self.assertEqual(itip_event['attendee'][0].params['delegated-to'], 'jack at ripper.com')
+        self.assertEqual(itip_event['attendee'][1].params['delegated-from'], 'jane at doe.org')
 
 
     def test_020_calendaring_recurrence(self):




More information about the commits mailing list