# -*- coding: utf-8 -*- import os import pykolab import logging import time from icalendar import Calendar from email import message from email import message_from_string from wallace import module_invitationpolicy as MIP from twisted.trial import unittest from pykolab.auth.ldap import LDAP from pykolab.constants import * # define some iTip MIME messages itip_multipart = """MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=_c8894dbdb8baeedacae836230e3436fd" From: "Doe, John" 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: jane.doe@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 1.0.1//NONSGML Calendar//EN CALSCALE:GREGORIAN METHOD:REQUEST BEGIN:VEVENT UID:626421779C777FBE9C9B85A80D04DDFA-A4BF5BBB9FEAA271 DTSTAMP:20120713T125414Z 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:jane.doe@example.org ATTENDEE;ROLE=3DOPT-PARTICIPANT;PARTSTAT=3DNEEDS-ACTION;RSVP=3DTRUE:mailt= user.external@example.com SEQUENCE:1 TRANSP:OPAQUE END:VEVENT END:VCALENDAR --=_c8894dbdb8baeedacae836230e3436fd-- """ conf = pykolab.getConf() if not hasattr(conf, 'defaults'): conf.finalize_conf() class TestWallaceInvitationpolicy(unittest.TestCase): def setUp(self): # monkey-patch the pykolab.auth module to check API calls # without actually connecting to LDAP self.patch(pykolab.auth.Auth, "connect", self._mock_nop) self.patch(pykolab.auth.Auth, "disconnect", self._mock_nop) self.patch(pykolab.auth.Auth, "find_user_dn", self._mock_find_user_dn) self.patch(pykolab.auth.Auth, "get_entry_attributes", self._mock_get_entry_attributes) self.patch(pykolab.auth.Auth, "list_domains", self._mock_list_domains) # 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, "connect", self._mock_smtp_init) self.patch(smtplib.SMTP, "sendmail", self._mock_smtp_sendmail) self.smtplog = [] def _mock_find_user_dn(self, value, kolabuser=False): (prefix, domain) = value.split('@') return "uid=" + prefix + ",ou=People,dc=" + ",dc=".join(domain.split('.')) def _mock_get_entry_attributes(self, domain, entry, attributes): (_, uid) = entry.split(',')[0].split('=') return {'cn': uid, 'mail': uid + "@example.org", '_attrib': attributes} def _mock_list_domains(self): return {'example.org': 'example.org'} 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)) return [] def test_001_itip_events_from_message(self): itips = pykolab.itip.events_from_message(message_from_string(itip_multipart)) self.assertEqual(len(itips), 1, "Multipart iTip message with text/calendar") self.assertEqual(itips[0]['method'], "REQUEST", "iTip request method property") self.assertEqual(len(itips[0]['attendees']), 2, "List attendees from iTip") self.assertEqual(itips[0]['attendees'][0], "mailto:jane.doe@example.org", "First attendee from iTip") def test_002_user_dn_from_email_address(self): res = MIP.user_dn_from_email_address("doe@example.org") self.assertEqual("uid=doe,ou=People,dc=example,dc=org", res) def test_003_get_matching_invitation_policy(self): user = {'kolabinvitationpolicy': [ 'TASK_REJECT:*', 'EVENT_ACCEPT:example.org', 'EVENT_REJECT:gmail.com', 'ALL_UPDATE:outlook:com', 'ALL_MANUAL:*' ]} self.assertEqual(MIP.get_matching_invitation_policies(user, 'a@fastmail.net', MIP.COND_TYPE_EVENT), [MIP.ACT_MANUAL]) self.assertEqual(MIP.get_matching_invitation_policies(user, 'b@example.org', MIP.COND_TYPE_EVENT), [MIP.ACT_ACCEPT, MIP.ACT_MANUAL]) self.assertEqual(MIP.get_matching_invitation_policies(user, 'c@gmail.com', MIP.COND_TYPE_EVENT), [MIP.ACT_REJECT, MIP.ACT_MANUAL]) self.assertEqual(MIP.get_matching_invitation_policies(user, 'd@somedomain.net', MIP.COND_TYPE_TASK), [MIP.ACT_REJECT, MIP.ACT_MANUAL]) user = {'kolabinvitationpolicy': ['ALL_SAVE_TO_FOLDER:maya.foo@example.org', 'ACT_REJECT:others']} self.assertEqual(MIP.get_matching_invitation_policies(user, 'maya.foo@example.org', MIP.COND_TYPE_ALL), [MIP.ACT_SAVE_TO_FOLDER]) self.assertEqual(MIP.get_matching_invitation_policies(user, 'd@somedomain.net', MIP.COND_TYPE_ALL), [MIP.ACT_MANUAL]) # def test_004_write_locks(self): # user = { 'cn': 'John Doe', 'mail': "doe@example.org" } # # lock_key = MIP.get_lock_key(user, '1234567890-abcdef') # lock_file = os.path.join(MIP.mybasepath, 'locks', lock_key + '.lock') # MIP.set_write_lock(lock_key) # # time.sleep(1) # self.assertTrue(os.path.isfile(lock_file)) # self.assertFalse(MIP.set_write_lock(lock_key, False)) # # MIP.remove_write_lock(lock_key) # self.assertFalse(os.path.isfile(lock_file)) def test_005_is_auto_reply(self): all_manual = ['ACT_MANUAL'] accept_none = ['ACT_REJECT'] accept_all = ['ACT_ACCEPT', 'ACT_UPDATE'] accept_cond = ['ACT_ACCEPT_IF_NO_CONFLICT', 'ACT_REJECT_IF_CONFLICT'] accept_some = ['ACT_ACCEPT_IF_NO_CONFLICT', 'ACT_SAVE_TO_CALENDAR:example.org', 'ACT_REJECT_IF_CONFLICT'] accept_avail = ['ACT_ACCEPT_IF_NO_CONFLICT', 'ACT_REJECT_IF_CONFLICT:example.org'] self.assertFalse( MIP.is_auto_reply({'kolabinvitationpolicy': all_manual}, 'user@domain.org', 'event')) self.assertTrue( MIP.is_auto_reply({'kolabinvitationpolicy': accept_none}, 'user@domain.org', 'event')) self.assertTrue( MIP.is_auto_reply({'kolabinvitationpolicy': accept_all}, 'user@domain.com', 'event')) self.assertTrue( MIP.is_auto_reply({'kolabinvitationpolicy': accept_cond}, 'user@domain.com', 'event')) self.assertTrue( MIP.is_auto_reply({'kolabinvitationpolicy': accept_some}, 'user@domain.com', 'event')) self.assertFalse( MIP.is_auto_reply({'kolabinvitationpolicy': accept_some}, 'sam@example.org', 'event')) self.assertFalse( MIP.is_auto_reply({'kolabinvitationpolicy': accept_avail}, 'user@domain.com', 'event')) self.assertTrue( MIP.is_auto_reply({'kolabinvitationpolicy': accept_avail}, 'john@example.org', 'event')) def test_006_send_update_notification(self): itips = pykolab.itip.events_from_message(message_from_string(itip_multipart.replace('SUMMARY:test', 'SUMMARY:with äöü'))) MIP.send_update_notification(itips[0]['xml'], {'mail': 'sender@example.org'}, old=None, reply=True) self.assertEqual(len(self.smtplog), 1) self.assertIn("Subject: =?utf-8?", self.smtplog[0][2]) self.assertIn("The event 'with =C3=A4=C3=B6=C3=BC' at", self.smtplog[0][2])