2 commits - pykolab/itip pykolab/xml tests/unit
Thomas Brüderli
bruederli at kolabsys.com
Wed Feb 18 17:18:44 CET 2015
pykolab/itip/__init__.py | 16 +++++++++++++++-
pykolab/xml/event.py | 42 ++++++++++++++++++++++++++++++++++++++----
tests/unit/test-003-event.py | 24 ++++++++++++++++++++++++
tests/unit/test-011-itip.py | 17 +++++++++++++++++
4 files changed, 94 insertions(+), 5 deletions(-)
New commits:
commit e25e91e5c23621c53e1c0034cf5d3c42e939363e
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Tue Feb 17 09:43:42 2015 +0100
Add utility methods to update attendees with propagation to recurrence exceptions
diff --git a/pykolab/xml/event.py b/pykolab/xml/event.py
index a054053..325cbc5 100644
--- a/pykolab/xml/event.py
+++ b/pykolab/xml/event.py
@@ -150,10 +150,14 @@ class Event(object):
exception._load_attendees()
self._exceptions.append(exception)
- def add_attendee(self, email, name=None, rsvp=False, role=None, participant_status=None, cutype="INDIVIDUAL", params=None):
- attendee = Attendee(email, name, rsvp, role, participant_status, cutype, params)
- self._attendees.append(attendee)
- self.event.setAttendees(self._attendees)
+ def add_attendee(self, email_or_attendee, name=None, rsvp=False, role=None, participant_status=None, cutype="INDIVIDUAL", params=None):
+ if isinstance(email_or_attendee, Attendee):
+ attendee = email_or_attendee
+ else:
+ attendee = Attendee(email_or_attendee, name, rsvp, role, participant_status, cutype, params)
+
+ # apply update to self and all exceptions
+ self.update_attendees([attendee])
def add_category(self, category):
self._categories.append(ustr(category))
@@ -695,6 +699,14 @@ class Event(object):
def get_transparency(self):
return self.event.transparency()
+ def set_attendees(self, _attendees):
+ self._attendees = _attendees
+ self.event.setAttendees(self._attendees)
+
+ # apply update to all exceptions
+ for exception in self._exceptions:
+ exception.merge_attendee_data(_attendees)
+
def set_attendee_participant_status(self, attendee, status, rsvp=None):
"""
Set the participant status of an attendee to status.
@@ -709,6 +721,28 @@ class Event(object):
if rsvp is not None:
attendee.set_rsvp(rsvp)
+ # apply update to self and all exceptions
+ self.update_attendees([attendee])
+
+ def update_attendees(self, _attendees):
+ self.merge_attendee_data(_attendees)
+
+ for exception in self._exceptions:
+ exception.merge_attendee_data(_attendees)
+
+ def merge_attendee_data(self, _attendees):
+ for attendee in _attendees:
+ found = False
+
+ for candidate in self._attendees:
+ if candidate.get_email() == attendee.get_email():
+ candidate.copy_from(attendee)
+ found = True
+ break
+
+ if not found:
+ self._attendees.append(attendee)
+
self.event.setAttendees(self._attendees)
def set_classification(self, classification):
diff --git a/tests/unit/test-003-event.py b/tests/unit/test-003-event.py
index 042d56a..1d0ad10 100644
--- a/tests/unit/test-003-event.py
+++ b/tests/unit/test-003-event.py
@@ -404,6 +404,13 @@ class TestEventXML(unittest.TestCase):
def test_009_invalid_participant_status(self):
self.assertRaises(InvalidAttendeeParticipantStatusError, self.event.set_attendee_participant_status, "jane at doe.org", "INVALID")
+ def test_009_update_attendees(self):
+ jane = self.event.get_attendee("jane at doe.org")
+ jane.set_name("Jane (GI) Doe")
+ self.event.update_attendees([jane])
+ self.assertEqual(len(self.event.get_attendees()), 2)
+ self.assertEqual(self.event.get_attendee("jane at doe.org").get_name(), "Jane (GI) Doe")
+
def test_010_datetime_from_string(self):
self.assertRaises(InvalidEventDateError, self.event.set_start, "2012-05-23 11:58:00")
@@ -842,6 +849,23 @@ END:VEVENT
self.assertEqual(property_to_string('attach', data['attach'][0]), "noname.1395223627.5555")
+ def test_027_merge_attendee_data(self):
+ event = event_from_string(xml_event)
+
+ jane = event.get_attendee("jane at example.org")
+ jane.set_participant_status('TENTATIVE')
+ jack = Attendee("jack at example.org", name="Jack", role='OPT-PARTICIPANT')
+
+ # update jane + add jack
+ event.update_attendees([jane,jack])
+ self.assertEqual(len(event.get_attendees()), 3)
+ self.assertEqual(event.get_attendee("jane at example.org").get_participant_status(), kolabformat.PartTentative)
+
+ exception = event.get_exceptions()[0]
+ self.assertEqual(len(exception.get_attendees()), 2)
+ self.assertEqual(event.get_attendee("jane at example.org").get_participant_status(), kolabformat.PartTentative)
+ self.assertEqual(event.get_attendee("jack at example.org").get_name(), "Jack")
+
def _find_prop_in_list(self, diff, name):
for prop in diff:
if prop['property'] == name:
commit 28cff75a01981c596051129e7b7f5f3a14781d62
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Tue Feb 17 07:16:37 2015 +0100
Take recurrence exceptions into accout when checking for conflicts
diff --git a/pykolab/itip/__init__.py b/pykolab/itip/__init__.py
index cae8075..848b2d7 100644
--- a/pykolab/itip/__init__.py
+++ b/pykolab/itip/__init__.py
@@ -166,12 +166,26 @@ def check_event_conflict(kolab_event, itip_event):
while not conflict and _is is not None:
# log.debug("* Comparing event dates at %s/%s with %s/%s" % (_es, _ee, _is, _ie), level=9)
conflict = check_date_conflict(_es, _ee, _is, _ie)
- _is = to_dt(itip_event['xml'].get_next_occurence(_is)) if kolab_event.is_recurring() else None
+ _is = to_dt(itip_event['xml'].get_next_occurence(_is)) if itip_event['xml'].is_recurring() else None
_ie = to_dt(itip_event['xml'].get_occurence_end_date(_is))
+ # get full occurrence to compare the dates from a possible exception
+ if _is is not None and len(itip_event['xml'].get_exceptions()):
+ _ix = itip_event['xml'].get_instance(_is)
+ if _ix is not None:
+ _is = to_dt(_ix.get_start())
+ _ie = to_dt(_ix.get_end())
+
_es = to_dt(kolab_event.get_next_occurence(_es)) if kolab_event.is_recurring() else None
_ee = to_dt(kolab_event.get_occurence_end_date(_es))
+ # get full instance to compare the dates from a possible exception
+ if _es is not None and len(kolab_event.get_exceptions()):
+ _ex = kolab_event.get_instance(_es)
+ if _ex is not None:
+ _es = to_dt(_ex.get_start())
+ _ee = to_dt(_ex.get_end())
+
return conflict
diff --git a/tests/unit/test-011-itip.py b/tests/unit/test-011-itip.py
index e5edee5..dafa645 100644
--- a/tests/unit/test-011-itip.py
+++ b/tests/unit/test-011-itip.py
@@ -451,6 +451,23 @@ class TestITip(unittest.TestCase):
event4.set_end(datetime.datetime(2012,7,1, 10,30,0, tzinfo=pytz.utc))
self.assertFalse(itip.check_event_conflict(event4, itip_event), "No conflict in two recurring events")
+ itip_event = itip.events_from_message(message_from_string(itip_non_multipart))[0]
+
+ rrule.setFrequency(kolabformat.RecurrenceRule.Daily)
+ rrule.setCount(10)
+
+ event5 = Event()
+ event5.set_recurrence(rrule);
+ event5.set_start(datetime.datetime(2012,7,9, 10,0,0, tzinfo=pytz.timezone("Europe/London")))
+ event5.set_end(datetime.datetime(2012,7,9, 11,0,0, tzinfo=pytz.timezone("Europe/London")))
+
+ exception = Event(from_string=str(event5))
+ exception.set_start(datetime.datetime(2012,7,13, 14,0,0, tzinfo=pytz.timezone("Europe/London")))
+ exception.set_end(datetime.datetime(2012,7,13, 16,0,0, tzinfo=pytz.timezone("Europe/London")))
+ exception.set_recurrence_id(datetime.datetime(2012,7,13, 10,0,0, tzinfo=pytz.timezone("Europe/London")), False)
+ event5.add_exception(exception)
+ self.assertFalse(itip.check_event_conflict(event5, itip_event), "No conflict with exception date")
+
def test_003_send_reply(self):
itip_events = itip.events_from_message(message_from_string(itip_non_multipart))
More information about the commits
mailing list