diff options
author | Thomas Bruederli <bruederli@kolabsys.com> | 2014-07-07 01:49:12 -0400 |
---|---|---|
committer | Thomas Bruederli <bruederli@kolabsys.com> | 2014-07-07 01:49:12 -0400 |
commit | d80f5c0fbb69f7b976275563e8b9b9521e9ca55e (patch) | |
tree | 350263f9c20fb49f5aab665933293b9ad225e4bf | |
parent | 951c796336c854474697754110b903c4ce90ccf5 (diff) | |
download | pykolab-d80f5c0fbb69f7b976275563e8b9b9521e9ca55e.tar.gz |
Move unit tests for pykolab.itip to a separate file; fix failing wallace module test
-rw-r--r-- | tests/unit/test-011-itip.py | 400 | ||||
-rw-r--r-- | tests/unit/test-011-wallace_resources.py | 206 | ||||
-rw-r--r-- | wallace/module_resources.py | 2 |
3 files changed, 405 insertions, 203 deletions
diff --git a/tests/unit/test-011-itip.py b/tests/unit/test-011-itip.py new file mode 100644 index 0000000..abbaa92 --- /dev/null +++ b/tests/unit/test-011-itip.py @@ -0,0 +1,400 @@ +import pykolab +import datetime +import pytz +import kolabformat + +from pykolab import itip +from pykolab.xml import Event + +from icalendar import Calendar +from email import message +from email import message_from_string +from wallace import module_resources +from twisted.trial import unittest + +# define some iTip MIME messages + +itip_multipart = """MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="=_c8894dbdb8baeedacae836230e3436fd" +From: "Doe, John" <john.doe@example.org> +Date: Fri, 13 Jul 2012 13:54:14 +0100 +Message-ID: <240fe7ae7e139129e9eb95213c1016d7@example.org> +User-Agent: Roundcube Webmail/0.9-0.3.el6.kolab_3.0 +To: resource-collection-car@example.org +Subject: "test" has been updated + +--=_c8894dbdb8baeedacae836230e3436fd +Content-Type: text/plain; charset=UTF-8; format=flowed +Content-Transfer-Encoding: quoted-printable + +*test* + +--=_c8894dbdb8baeedacae836230e3436fd +Content-Type: text/calendar; charset=UTF-8; method=REQUEST; + name=event.ics +Content-Disposition: attachment; + filename=event.ics +Content-Transfer-Encoding: quoted-printable + +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Roundcube Webmail 0.9-0.3.el6.kolab_3.0//NONSGML Calendar//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:626421779C777FBE9C9B85A80D04DDFA-A4BF5BBB9FEAA271 +DTSTAMP:20120713T1254140 +DTSTART;TZID=3DEurope/London:20120713T100000 +DTEND;TZID=3DEurope/London:20120713T110000 +SUMMARY:test +DESCRIPTION:test +ORGANIZER;CN=3D"Doe, John":mailto:john.doe@example.org +ATTENDEE;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DNEEDS-ACTION;RSVP=3DTRUE:mailt= +o:resource-collection-car@example.org +ATTENDEE;ROLE=3DOPT-PARTICIPANT;PARTSTAT=3DNEEDS-ACTION;RSVP=3DTRUE:mailto:anoth= +er-resource@example.org +TRANSP:OPAQUE +END:VEVENT +END:VCALENDAR + +--=_c8894dbdb8baeedacae836230e3436fd-- +""" + +itip_non_multipart = """Return-Path: <john.doe@example.org> +Sender: john.doe@example.org +Content-Type: text/calendar; method=REQUEST; charset=UTF-8 +Content-Transfer-Encoding: quoted-printable +To: resource-collection-car@example.org +From: john.doe@example.org +Date: Mon, 24 Feb 2014 11:27:28 +0100 +Message-ID: <1a3aa8995e83dd24cf9247e538ac913a@example.org> +Subject: test + +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Roundcube Webmail 0.9-0.3.el6.kolab_3.0//NONSGML Calendar//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:626421779C777FBE9C9B85A80D04DDFA-A4BF5BBB9FEAA271 +DTSTAMP:20120713T1254140 +DTSTART;TZID=3DEurope/London:20120713T100000 +DTEND;TZID=3DEurope/London:20120713T110000 +SUMMARY:test +DESCRIPTION:test +ORGANIZER;CN=3D"Doe, John":mailto:john.doe@example.org +ATTENDEE;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DACCEPTED;RSVP=3DTRUE:mailt= +o:resource-collection-car@example.org +TRANSP:OPAQUE +END:VEVENT +END:VCALENDAR +""" + +itip_google_multipart = """MIME-Version: 1.0 +Message-ID: <001a11c2ad84243e0604f3246bae@google.com> +Date: Mon, 24 Feb 2014 10:27:28 +0000 +Subject: =?ISO-8859-1?Q?Invitation=3A_iTip_from_Apple_=40_Mon_Feb_24=2C_2014_12pm_?= + =?ISO-8859-1?Q?=2D_1pm_=28Tom_=26_T=E4m=29?= +From: "john.doe" <john.doe@gmail.com> +To: <john.sample@example.org> +Content-Type: multipart/mixed; boundary=001a11c2ad84243df004f3246bad + +--001a11c2ad84243df004f3246bad +Content-Type: multipart/alternative; boundary=001a11c2ad84243dec04f3246bab + +--001a11c2ad84243dec04f3246bab +Content-Type: text/plain; charset=ISO-8859-1; format=flowed; delsp=yes + +<some text content here> + +--001a11c2ad84243dec04f3246bab +Content-Type: text/html; charset=ISO-8859-1 +Content-Transfer-Encoding: quoted-printable + +<div style=3D""><!-- some HTML message content here --></div> +--001a11c2ad84243dec04f3246bab +Content-Type: text/calendar; charset=UTF-8; method=REQUEST +Content-Transfer-Encoding: 7bit + +BEGIN:VCALENDAR +PRODID:-//Google Inc//Google Calendar 70.9054//EN +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +DTSTART:20140224T110000Z +DTEND:20140224T120000Z +DTSTAMP:20140224T102728Z +ORGANIZER:mailto:kepjllr6mcq7d0959u4cdc7000@group.calendar.google.com +UID:0BE2F640-5814-47C9-ABAE-E7E959204E76 +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE + ;X-NUM-GUESTS=0:mailto:kepjllr6mcq7d0959u4cdc7000@group.calendar.google.com +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP= + TRUE;CN=John Sample;X-NUM-GUESTS=0:mailto:john.sample@example.org +CREATED:20140224T102728Z +DESCRIPTION:Testing Multipart structure\\nView your event at http://www.goog + le.com/calendar/event?action=VIEW&eid=XzYxMTRhY2k2Nm9xMzBiOWw3MG9qOGI5azZ0M + WppYmExODkwa2FiYTU2dDJqaWQ5cDY4bzM4aDluNm8gdGhvbWFzQGJyb3RoZXJsaS5jaA&tok=N + TIja2VwamxscjZtY3E3ZDA5NTl1NGNkYzcwMDBAZ3JvdXAuY2FsZW5kYXIuZ29vZ2xlLmNvbTkz + NTcyYTU2YmUwNWMxNjY0Zjc3OTU0MzhmMDcwY2FhN2NjZjIzYWM&ctz=Europe/Zurich&hl=en + . +LAST-MODIFIED:20140224T102728Z +LOCATION: +SEQUENCE:5 +STATUS:CONFIRMED +SUMMARY:iTip from Apple +TRANSP:OPAQUE +END:VEVENT +END:VCALENDAR + +--001a11c2ad84243dec04f3246bab-- +--001a11c2ad84243df004f3246bad +Content-Type: application/ics; name="invite.ics" +Content-Disposition: attachment; filename="invite.ics" +Content-Transfer-Encoding: base64 + +QkVHSU46VkNBTEVOREFSDQpQUk9ESUQ6LS8vR29vZ2xlIEluYy8vR29vZ2xlIENhbGVuZGFyIDcw +LjkwNTQvL0VODQpWRVJTSU9OOjIuMA0KQ0FMU0NBTEU6R1JFR09SSUFODQpNRVRIT0Q6UkVRVUVT +VA0KQkVHSU46VkVWRU5UDQpEVFNUQVJUOjIwMTQwMjI0VDExMDAwMFoNCkRURU5EOjIwMTQwMjI0 +VDEyMDAwMFoNCkRUU1RBTVA6MjAxNDAyMjRUMTAyNzI4Wg0KT1JHQU5JWkVSOm1haWx0bzprZXBq +bGxyNm1jcTdkMDk1OXU0Y2RjNzAwMEBncm91cC5jYWxlbmRhci5nb29nbGUuY29tDQpVSUQ6MEJF +MkY2NDAtNTgxNC00N0M5LUFCQUUtRTdFOTU5MjA0RTc2DQpBVFRFTkRFRTtDVVRZUEU9SU5ESVZJ +RFVBTDtST0xFPVJFUS1QQVJUSUNJUEFOVDtQQVJUU1RBVD1BQ0NFUFRFRDtSU1ZQPVRSVUUNCiA7 +WC1OVU0tR1VFU1RTPTA6bWFpbHRvOmtlcGpsbHI2bWNxN2QwOTU5dTRjZGM3MDAwQGdyb3VwLmNh +bGVuZGFyLmdvb2dsZS5jb20NCkFUVEVOREVFO0NVVFlQRT1JTkRJVklEVUFMO1JPTEU9UkVRLVBB +UlRJQ0lQQU5UO1BBUlRTVEFUPU5FRURTLUFDVElPTjtSU1ZQPQ0KIFRSVUU7WC1OVU0tR1VFU1RT +PTA6bWFpbHRvOnRob21hc0Bicm90aGVybGkuY2gNCkFUVEVOREVFO0NVVFlQRT1JTkRJVklEVUFM +O1JPTEU9UkVRLVBBUlRJQ0lQQU5UO1BBUlRTVEFUPU5FRURTLUFDVElPTjtSU1ZQPQ0KIFRSVUU7 +Q049VGhvbWFzIEJydWVkZXJsaTtYLU5VTS1HVUVTVFM9MDptYWlsdG86cm91bmRjdWJlQGdtYWls +LmNvbQ0KQ1JFQVRFRDoyMDE0MDIyNFQxMDI3MjhaDQpERVNDUklQVElPTjpUZXN0aW5nIE11bHRp +cGFydCBzdHJ1Y3R1cmVcblZpZXcgeW91ciBldmVudCBhdCBodHRwOi8vd3d3Lmdvb2cNCiBsZS5j +b20vY2FsZW5kYXIvZXZlbnQ/YWN0aW9uPVZJRVcmZWlkPVh6WXhNVFJoWTJrMk5tOXhNekJpT1d3 +M01HOXFPR0k1YXpaME0NCiBXcHBZbUV4T0Rrd2EyRmlZVFUyZERKcWFXUTVjRFk0YnpNNGFEbHVO +bThnZEdodmJXRnpRR0p5YjNSb1pYSnNhUzVqYUEmdG9rPU4NCiBUSWphMlZ3YW14c2NqWnRZM0Uz +WkRBNU5UbDFOR05rWXpjd01EQkFaM0p2ZFhBdVkyRnNaVzVrWVhJdVoyOXZaMnhsTG1OdmJUa3oN +CiBOVGN5WVRVMlltVXdOV014TmpZMFpqYzNPVFUwTXpobU1EY3dZMkZoTjJOalpqSXpZV00mY3R6 +PUV1cm9wZS9adXJpY2gmaGw9ZW4NCiAuDQpMQVNULU1PRElGSUVEOjIwMTQwMjI0VDEwMjcyOFoN +CkxPQ0FUSU9OOg0KU0VRVUVOQ0U6NQ0KU1RBVFVTOkNPTkZJUk1FRA0KU1VNTUFSWTppVGlwIGZy +b20gQXBwbGUNClRSQU5TUDpPUEFRVUUNCkVORDpWRVZFTlQNCkVORDpWQ0FMRU5EQVINCg== +--001a11c2ad84243df004f3246bad-- +""" + +itip_application_ics = """MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="=_c8894dbdb8baeedacae836230e3436fd" +From: "Doe, John" <john.doe@example.org> +Date: Fri, 13 Jul 2012 13:54:14 +0100 +Message-ID: <240fe7ae7e139129e9eb95213c101622@example.org> +User-Agent: Roundcube Webmail/0.9-0.3.el6.kolab_3.0 +To: resource-collection-car@example.org +Subject: "test" has been updated + +--=_c8894dbdb8baeedacae836230e3436fd +Content-Transfer-Encoding: quoted-printable +Content-Type: text/plain; charset=UTF-8; format=flowed + +<some text here> + +--=_c8894dbdb8baeedacae836230e3436fd +Content-Type: application/ics; charset=UTF-8; method=REQUEST; + name=event.ics +Content-Transfer-Encoding: quoted-printable + +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Roundcube Webmail 0.9-0.3.el6.kolab_3.0//NONSGML Calendar//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:626421779C777FBE9C9B85A80D04DDFA-A4BF5BBB9FEAA271 +DTSTAMP:20120713T1254140 +DTSTART;TZID=3DEurope/London:20120713T100000 +DTEND;TZID=3DEurope/London:20120713T110000 +SUMMARY:test +DESCRIPTION:test +ORGANIZER;CN=3D"Doe, John":mailto:john.doe@example.org +ATTENDEE;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DNEEDS-ACTION;RSVP=3DTRUE:mailt= +o:resource-collection-car@example.org +TRANSP:OPAQUE +END:VEVENT +END:VCALENDAR + +--=_c8894dbdb8baeedacae836230e3436fd-- +""" + +itip_recurring = """Return-Path: <john.doe@example.org> +Sender: john.doe@example.org +Content-Type: text/calendar; method=REQUEST; charset=UTF-8 +Content-Transfer-Encoding: 8bit +From: john.doe@example.org +Date: Mon, 24 Feb 2014 11:27:28 +0100 +Message-ID: <1a3aa8995e83dd24cf9247e538ac913a@example.org> +Subject: Recurring + +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//Mac OS X 10.9.2//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:dbdb8baeedacae836230e3436fd-5e83dd24cf92 +DTSTAMP:20140213T1254140 +DTSTART;TZID=Europe/London:20120709T100000 +DTEND;TZID=Europe/London:20120709T120000 +RRULE:FREQ=DAILY;INTERVAL=1;COUNT=5 +SUMMARY:Recurring +ORGANIZER;CN="Doe, John":mailto:john.doe@example.org +ATTENDEE;ROLE=REQ-PARTICIPANT;CUTYPE=RESOURCE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:jane@example.com +TRANSP:OPAQUE +END:VEVENT +END:VCALENDAR +""" + +itip_empty = """MIME-Version: 1.0 +Date: Fri, 17 Jan 2014 13:51:50 +0100 +From: <john.doe@example.org> +User-Agent: Roundcube Webmail/0.9.5 +To: john.sample@example.org +Subject: "test" has been sent +Message-ID: <52D92766.5040508@somedomain.com> +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 7bit + +Message plain text goes here... +""" + +conf = pykolab.getConf() + +if not hasattr(conf, 'defaults'): + conf.finalize_conf() + +class TestITip(unittest.TestCase): + + def setUp(self): + # intercept calls to smtplib.SMTP.sendmail() + import smtplib + self.patch(smtplib.SMTP, "__init__", self._mock_smtp_init) + self.patch(smtplib.SMTP, "quit", self._mock_nop) + self.patch(smtplib.SMTP, "sendmail", self._mock_smtp_sendmail) + + self.smtplog = []; + + def _mock_nop(self, domain=None): + pass + + def _mock_smtp_init(self, host=None, port=None, local_hostname=None, timeout=0): + pass + + def _mock_smtp_sendmail(self, from_addr, to_addr, message, mail_options=None, rcpt_options=None): + self.smtplog.append((from_addr, to_addr, message)) + + + def test_001_itip_events_from_message(self): + itips1 = itip.events_from_message(message_from_string(itip_multipart)) + self.assertEqual(len(itips1), 1, "Multipart iTip message with text/calendar") + self.assertEqual(itips1[0]['method'], "REQUEST", "iTip request method property") + + itips2 = itip.events_from_message(message_from_string(itip_non_multipart)) + self.assertEqual(len(itips2), 1, "Detect non-multipart iTip messages") + + itips3 = itip.events_from_message(message_from_string(itip_application_ics)) + self.assertEqual(len(itips3), 1, "Multipart iTip message with application/ics attachment") + + itips4 = itip.events_from_message(message_from_string(itip_google_multipart)) + self.assertEqual(len(itips4), 1, "Multipart iTip message from Google") + + itips5 = itip.events_from_message(message_from_string(itip_empty)) + self.assertEqual(len(itips5), 0, "Simple plain text message") + + # invalid itip blocks + self.assertRaises(Exception, itip.events_from_message, message_from_string(itip_multipart.replace("BEGIN:VEVENT", ""))) + + itips6 = itip.events_from_message(message_from_string(itip_multipart.replace("DTSTART;", "X-DTSTART;"))) + self.assertEqual(len(itips6), 0, "Event with not DTSTART") + + itips7 = itip.events_from_message(message_from_string(itip_non_multipart.replace("METHOD:REQUEST", "METHOD:PUBLISH").replace("method=REQUEST", "method=PUBLISH"))) + self.assertEqual(len(itips7), 0, "Invalid METHOD") + + + def test_002_check_date_conflict(self): + astart = datetime.datetime(2014,7,13, 10,0,0) + aend = astart + datetime.timedelta(hours=2) + + bstart = datetime.datetime(2014,7,13, 10,0,0) + bend = astart + datetime.timedelta(hours=1) + self.assertTrue(itip.check_date_conflict(astart, aend, bstart, bend)) + + bstart = datetime.datetime(2014,7,13, 11,0,0) + bend = astart + datetime.timedelta(minutes=30) + self.assertTrue(itip.check_date_conflict(astart, aend, bstart, bend)) + + bend = astart + datetime.timedelta(hours=2) + self.assertTrue(itip.check_date_conflict(astart, aend, bstart, bend)) + + bstart = datetime.datetime(2014,7,13, 12,0,0) + bend = astart + datetime.timedelta(hours=1) + self.assertFalse(itip.check_date_conflict(astart, aend, bstart, bend)) + + bstart = datetime.datetime(2014,6,13, 10,0,0) + bend = datetime.datetime(2014,6,14, 12,0,0) + self.assertFalse(itip.check_date_conflict(astart, aend, bstart, bend)) + + bstart = datetime.datetime(2014,7,10, 12,0,0) + bend = datetime.datetime(2014,7,14, 14,0,0) + self.assertTrue(itip.check_date_conflict(astart, aend, bstart, bend)) + + + def test_002_check_event_conflict(self): + itip_event = itip.events_from_message(message_from_string(itip_non_multipart))[0] + + event = Event() + event.set_start(datetime.datetime(2012,7,13, 9,30,0, tzinfo=itip_event['start'].tzinfo)) + event.set_end(datetime.datetime(2012,7,13, 10,30,0, tzinfo=itip_event['start'].tzinfo)) + + self.assertTrue(itip.check_event_conflict(event, itip_event), "Conflicting dates") + + event.set_uid(itip_event['uid']) + self.assertFalse(itip.check_event_conflict(event, itip_event), "No conflict for same UID") + + event2 = Event() + event2.set_start(datetime.datetime(2012,7,13, 10,0,0, tzinfo=pytz.timezone("US/Central"))) + event2.set_end(datetime.datetime(2012,7,13, 11,0,0, tzinfo=pytz.timezone("US/Central"))) + + self.assertFalse(itip.check_event_conflict(event, itip_event), "No conflict with timezone shift") + + rrule = kolabformat.RecurrenceRule() + rrule.setFrequency(kolabformat.RecurrenceRule.Weekly) + rrule.setCount(10) + + event3 = Event() + event3.set_recurrence(rrule); + event3.set_start(datetime.datetime(2012,6,29, 9,30,0, tzinfo=pytz.utc)) + event3.set_end(datetime.datetime(2012,6,29, 10,30,0, tzinfo=pytz.utc)) + + self.assertTrue(itip.check_event_conflict(event3, itip_event), "Conflict in (3rd) recurring event instance") + + itip_event = itip.events_from_message(message_from_string(itip_recurring))[0] + self.assertTrue(itip.check_event_conflict(event3, itip_event), "Conflict in two recurring events") + + event4 = Event() + event4.set_recurrence(rrule); + event4.set_start(datetime.datetime(2012,7,1, 9,30,0, tzinfo=pytz.utc)) + 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") + + + def test_003_send_reply(self): + itip_events = itip.events_from_message(message_from_string(itip_non_multipart)) + itip.send_reply("resource-collection-car@example.org", itip_events, "SUMMARY=%(summary)s; STATUS=%(status)s; NAME=%(name)s;") + + self.assertEqual(len(self.smtplog), 1) + self.assertEqual(self.smtplog[0][0], 'resource-collection-car@example.org', "From attendee") + self.assertEqual(self.smtplog[0][1], 'john.doe@example.org', "To organizer") + + message = message_from_string(self.smtplog[0][2]) + self.assertEqual(message.get('Subject'), 'Invitation for test was ACCEPTED') + + text = str(message.get_payload(0)); + self.assertIn('SUMMARY=test', text) + self.assertIn('STATUS=ACCEPTED', text) diff --git a/tests/unit/test-011-wallace_resources.py b/tests/unit/test-011-wallace_resources.py index bb586f8..ccec4b1 100644 --- a/tests/unit/test-011-wallace_resources.py +++ b/tests/unit/test-011-wallace_resources.py @@ -2,6 +2,7 @@ import pykolab import logging import datetime +from pykolab import itip from icalendar import Calendar from email import message from email import message_from_string @@ -87,152 +88,6 @@ END:VEVENT END:VCALENDAR """ -itip_google_multipart = """MIME-Version: 1.0 -Message-ID: <001a11c2ad84243e0604f3246bae@google.com> -Date: Mon, 24 Feb 2014 10:27:28 +0000 -Subject: =?ISO-8859-1?Q?Invitation=3A_iTip_from_Apple_=40_Mon_Feb_24=2C_2014_12pm_?= - =?ISO-8859-1?Q?=2D_1pm_=28Tom_=26_T=E4m=29?= -From: "john.doe" <john.doe@gmail.com> -To: <john.sample@example.org> -Content-Type: multipart/mixed; boundary=001a11c2ad84243df004f3246bad - ---001a11c2ad84243df004f3246bad -Content-Type: multipart/alternative; boundary=001a11c2ad84243dec04f3246bab - ---001a11c2ad84243dec04f3246bab -Content-Type: text/plain; charset=ISO-8859-1; format=flowed; delsp=yes - -<some text content here> - ---001a11c2ad84243dec04f3246bab -Content-Type: text/html; charset=ISO-8859-1 -Content-Transfer-Encoding: quoted-printable - -<div style=3D""><!-- some HTML message content here --></div> ---001a11c2ad84243dec04f3246bab -Content-Type: text/calendar; charset=UTF-8; method=REQUEST -Content-Transfer-Encoding: 7bit - -BEGIN:VCALENDAR -PRODID:-//Google Inc//Google Calendar 70.9054//EN -VERSION:2.0 -CALSCALE:GREGORIAN -METHOD:REQUEST -BEGIN:VEVENT -DTSTART:20140224T110000Z -DTEND:20140224T120000Z -DTSTAMP:20140224T102728Z -ORGANIZER:mailto:kepjllr6mcq7d0959u4cdc7000@group.calendar.google.com -UID:0BE2F640-5814-47C9-ABAE-E7E959204E76 -ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE - ;X-NUM-GUESTS=0:mailto:kepjllr6mcq7d0959u4cdc7000@group.calendar.google.com -ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP= - TRUE;CN=John Sample;X-NUM-GUESTS=0:mailto:john.sample@example.org -CREATED:20140224T102728Z -DESCRIPTION:Testing Multipart structure\\nView your event at http://www.goog - le.com/calendar/event?action=VIEW&eid=XzYxMTRhY2k2Nm9xMzBiOWw3MG9qOGI5azZ0M - WppYmExODkwa2FiYTU2dDJqaWQ5cDY4bzM4aDluNm8gdGhvbWFzQGJyb3RoZXJsaS5jaA&tok=N - TIja2VwamxscjZtY3E3ZDA5NTl1NGNkYzcwMDBAZ3JvdXAuY2FsZW5kYXIuZ29vZ2xlLmNvbTkz - NTcyYTU2YmUwNWMxNjY0Zjc3OTU0MzhmMDcwY2FhN2NjZjIzYWM&ctz=Europe/Zurich&hl=en - . -LAST-MODIFIED:20140224T102728Z -LOCATION: -SEQUENCE:5 -STATUS:CONFIRMED -SUMMARY:iTip from Apple -TRANSP:OPAQUE -END:VEVENT -END:VCALENDAR - ---001a11c2ad84243dec04f3246bab-- ---001a11c2ad84243df004f3246bad -Content-Type: application/ics; name="invite.ics" -Content-Disposition: attachment; filename="invite.ics" -Content-Transfer-Encoding: base64 - -QkVHSU46VkNBTEVOREFSDQpQUk9ESUQ6LS8vR29vZ2xlIEluYy8vR29vZ2xlIENhbGVuZGFyIDcw -LjkwNTQvL0VODQpWRVJTSU9OOjIuMA0KQ0FMU0NBTEU6R1JFR09SSUFODQpNRVRIT0Q6UkVRVUVT -VA0KQkVHSU46VkVWRU5UDQpEVFNUQVJUOjIwMTQwMjI0VDExMDAwMFoNCkRURU5EOjIwMTQwMjI0 -VDEyMDAwMFoNCkRUU1RBTVA6MjAxNDAyMjRUMTAyNzI4Wg0KT1JHQU5JWkVSOm1haWx0bzprZXBq -bGxyNm1jcTdkMDk1OXU0Y2RjNzAwMEBncm91cC5jYWxlbmRhci5nb29nbGUuY29tDQpVSUQ6MEJF -MkY2NDAtNTgxNC00N0M5LUFCQUUtRTdFOTU5MjA0RTc2DQpBVFRFTkRFRTtDVVRZUEU9SU5ESVZJ -RFVBTDtST0xFPVJFUS1QQVJUSUNJUEFOVDtQQVJUU1RBVD1BQ0NFUFRFRDtSU1ZQPVRSVUUNCiA7 -WC1OVU0tR1VFU1RTPTA6bWFpbHRvOmtlcGpsbHI2bWNxN2QwOTU5dTRjZGM3MDAwQGdyb3VwLmNh -bGVuZGFyLmdvb2dsZS5jb20NCkFUVEVOREVFO0NVVFlQRT1JTkRJVklEVUFMO1JPTEU9UkVRLVBB -UlRJQ0lQQU5UO1BBUlRTVEFUPU5FRURTLUFDVElPTjtSU1ZQPQ0KIFRSVUU7WC1OVU0tR1VFU1RT -PTA6bWFpbHRvOnRob21hc0Bicm90aGVybGkuY2gNCkFUVEVOREVFO0NVVFlQRT1JTkRJVklEVUFM -O1JPTEU9UkVRLVBBUlRJQ0lQQU5UO1BBUlRTVEFUPU5FRURTLUFDVElPTjtSU1ZQPQ0KIFRSVUU7 -Q049VGhvbWFzIEJydWVkZXJsaTtYLU5VTS1HVUVTVFM9MDptYWlsdG86cm91bmRjdWJlQGdtYWls -LmNvbQ0KQ1JFQVRFRDoyMDE0MDIyNFQxMDI3MjhaDQpERVNDUklQVElPTjpUZXN0aW5nIE11bHRp -cGFydCBzdHJ1Y3R1cmVcblZpZXcgeW91ciBldmVudCBhdCBodHRwOi8vd3d3Lmdvb2cNCiBsZS5j -b20vY2FsZW5kYXIvZXZlbnQ/YWN0aW9uPVZJRVcmZWlkPVh6WXhNVFJoWTJrMk5tOXhNekJpT1d3 -M01HOXFPR0k1YXpaME0NCiBXcHBZbUV4T0Rrd2EyRmlZVFUyZERKcWFXUTVjRFk0YnpNNGFEbHVO -bThnZEdodmJXRnpRR0p5YjNSb1pYSnNhUzVqYUEmdG9rPU4NCiBUSWphMlZ3YW14c2NqWnRZM0Uz -WkRBNU5UbDFOR05rWXpjd01EQkFaM0p2ZFhBdVkyRnNaVzVrWVhJdVoyOXZaMnhsTG1OdmJUa3oN -CiBOVGN5WVRVMlltVXdOV014TmpZMFpqYzNPVFUwTXpobU1EY3dZMkZoTjJOalpqSXpZV00mY3R6 -PUV1cm9wZS9adXJpY2gmaGw9ZW4NCiAuDQpMQVNULU1PRElGSUVEOjIwMTQwMjI0VDEwMjcyOFoN -CkxPQ0FUSU9OOg0KU0VRVUVOQ0U6NQ0KU1RBVFVTOkNPTkZJUk1FRA0KU1VNTUFSWTppVGlwIGZy -b20gQXBwbGUNClRSQU5TUDpPUEFRVUUNCkVORDpWRVZFTlQNCkVORDpWQ0FMRU5EQVINCg== ---001a11c2ad84243df004f3246bad-- -""" - -itip_application_ics = """MIME-Version: 1.0 -Content-Type: multipart/mixed; - boundary="=_c8894dbdb8baeedacae836230e3436fd" -From: "Doe, John" <john.doe@example.org> -Date: Fri, 13 Jul 2012 13:54:14 +0100 -Message-ID: <240fe7ae7e139129e9eb95213c101622@example.org> -User-Agent: Roundcube Webmail/0.9-0.3.el6.kolab_3.0 -To: resource-collection-car@example.org -Subject: "test" has been updated - ---=_c8894dbdb8baeedacae836230e3436fd -Content-Transfer-Encoding: quoted-printable -Content-Type: text/plain; charset=UTF-8; format=flowed - -<some text here> - ---=_c8894dbdb8baeedacae836230e3436fd -Content-Type: application/ics; charset=UTF-8; method=REQUEST; - name=event.ics -Content-Transfer-Encoding: quoted-printable - -BEGIN:VCALENDAR -VERSION:2.0 -PRODID:-//Roundcube Webmail 0.9-0.3.el6.kolab_3.0//NONSGML Calendar//EN -CALSCALE:GREGORIAN -METHOD:REQUEST -BEGIN:VEVENT -UID:626421779C777FBE9C9B85A80D04DDFA-A4BF5BBB9FEAA271 -DTSTAMP:20120713T1254140 -DTSTART;TZID=3DEurope/London:20120713T100000 -DTEND;TZID=3DEurope/London:20120713T110000 -SUMMARY:test -DESCRIPTION:test -ORGANIZER;CN=3D"Doe, John":mailto:john.doe@example.org -ATTENDEE;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DNEEDS-ACTION;RSVP=3DTRUE:mailt= -o:resource-collection-car@example.org -TRANSP:OPAQUE -END:VEVENT -END:VCALENDAR - ---=_c8894dbdb8baeedacae836230e3436fd-- -""" - -itip_empty = """MIME-Version: 1.0 -Date: Fri, 17 Jan 2014 13:51:50 +0100 -From: <john.doe@example.org> -User-Agent: Roundcube Webmail/0.9.5 -To: john.sample@example.org -Subject: "test" has been sent -Message-ID: <52D92766.5040508@somedomain.com> -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 7bit - -Message plain text goes here... -""" - - conf = pykolab.getConf() if not hasattr(conf, 'defaults'): @@ -301,32 +156,6 @@ class TestWallaceResources(unittest.TestCase): return None - def test_001_itip_events_from_message(self): - itips1 = pykolab.itip.events_from_message(message_from_string(itip_multipart)) - self.assertEqual(len(itips1), 1, "Multipart iTip message with text/calendar") - self.assertEqual(itips1[0]['method'], "REQUEST", "iTip request method property") - - itips2 = pykolab.itip.events_from_message(message_from_string(itip_non_multipart)) - self.assertEqual(len(itips2), 1, "Detect non-multipart iTip messages") - - itips3 = pykolab.itip.events_from_message(message_from_string(itip_application_ics)) - self.assertEqual(len(itips3), 1, "Multipart iTip message with application/ics attachment") - - itips4 = pykolab.itip.events_from_message(message_from_string(itip_google_multipart)) - self.assertEqual(len(itips4), 1, "Multipart iTip message from Google") - - itips5 = pykolab.itip.events_from_message(message_from_string(itip_empty)) - self.assertEqual(len(itips5), 0, "Simple plain text message") - - # invalid itip blocks - self.assertRaises(Exception, pykolab.itip.events_from_message, message_from_string(itip_multipart.replace("BEGIN:VEVENT", ""))) - - itips6 = pykolab.itip.events_from_message(message_from_string(itip_multipart.replace("DTSTART;", "X-DTSTART;"))) - self.assertEqual(len(itips6), 0, "Event with not DTSTART") - - itips7 = pykolab.itip.events_from_message(message_from_string(itip_non_multipart.replace("METHOD:REQUEST", "METHOD:PUBLISH").replace("method=REQUEST", "method=PUBLISH"))) - self.assertEqual(len(itips7), 0, "Invalid METHOD") - def test_002_resource_record_from_email_address(self): res = module_resources.resource_record_from_email_address("doe@example.org") @@ -337,7 +166,7 @@ class TestWallaceResources(unittest.TestCase): def test_003_resource_records_from_itip_events(self): message = message_from_string(itip_multipart) - itips = pykolab.itip.events_from_message(message) + itips = itip.events_from_message(message) res = module_resources.resource_records_from_itip_events(itips) self.assertEqual(len(res), 2, "Return all attendee resources"); @@ -365,7 +194,7 @@ class TestWallaceResources(unittest.TestCase): def test_005_send_response_accept(self): - itip_event = pykolab.itip.events_from_message(message_from_string(itip_non_multipart)) + itip_event = itip.events_from_message(message_from_string(itip_non_multipart)) module_resources.send_response("resource-collection-car@example.org", itip_event) self.assertEqual(len(self.smtplog), 1); @@ -384,7 +213,7 @@ class TestWallaceResources(unittest.TestCase): def test_006_send_response_delegate(self): # delegate resource-collection-car@example.org => resource-car-audi-a4@example.org - itip_event = pykolab.itip.events_from_message(message_from_string(itip_non_multipart))[0] + itip_event = itip.events_from_message(message_from_string(itip_non_multipart))[0] itip_event['xml'].delegate('resource-collection-car@example.org', 'resource-car-audi-a4@example.org') itip_event['xml'].set_attendee_participant_status(itip_event['xml'].get_attendee('resource-car-audi-a4@example.org'), "ACCEPTED") @@ -408,30 +237,3 @@ class TestWallaceResources(unittest.TestCase): self.assertEqual(ical2['attendee'].params['PARTSTAT'], "DELEGATED") - def test_007_check_date_conflict(self): - astart = datetime.datetime(2014,7,13, 10,0,0) - aend = astart + datetime.timedelta(hours=2) - - bstart = datetime.datetime(2014,7,13, 10,0,0) - bend = astart + datetime.timedelta(hours=1) - self.assertTrue(module_resources.check_date_conflict(astart, aend, bstart, bend)) - - bstart = datetime.datetime(2014,7,13, 11,0,0) - bend = astart + datetime.timedelta(minutes=30) - self.assertTrue(module_resources.check_date_conflict(astart, aend, bstart, bend)) - - bend = astart + datetime.timedelta(hours=2) - self.assertTrue(module_resources.check_date_conflict(astart, aend, bstart, bend)) - - bstart = datetime.datetime(2014,7,13, 12,0,0) - bend = astart + datetime.timedelta(hours=1) - self.assertFalse(module_resources.check_date_conflict(astart, aend, bstart, bend)) - - bstart = datetime.datetime(2014,6,13, 10,0,0) - bend = datetime.datetime(2014,6,14, 12,0,0) - self.assertFalse(module_resources.check_date_conflict(astart, aend, bstart, bend)) - - bstart = datetime.datetime(2014,7,10, 12,0,0) - bend = datetime.datetime(2014,7,14, 14,0,0) - self.assertTrue(module_resources.check_date_conflict(astart, aend, bstart, bend)) - diff --git a/wallace/module_resources.py b/wallace/module_resources.py index f398120..7c23995 100644 --- a/wallace/module_resources.py +++ b/wallace/module_resources.py @@ -809,7 +809,7 @@ def get_resource_owner(resource): if not isinstance(collections, list): collections = [ collections ] - for dn,collection in collections: + for collection in collections: if collection.has_key('owner') and isinstance(collection['owner'], list): owners += collection['owner'] elif collection.has_key('owner'): |