Branch 'dev/boddie' - 8 commits - pykolab/auth pykolab/utils.py pykolab/xml tests/functional tests/unit wallace/__init__.py wallace/module_resources.py

Paul Boddie boddie at kolabsys.com
Wed Mar 19 00:00:01 CET 2014


 pykolab/auth/ldap/__init__.py                                 |    6 
 pykolab/utils.py                                              |   11 -
 pykolab/xml/attendee.py                                       |    4 
 pykolab/xml/event.py                                          |    4 
 tests/functional/resource_func.py                             |    5 
 tests/functional/test_wallace/test_005_resource_invitation.py |   70 +++++++
 tests/functional/user_add.py                                  |    2 
 tests/unit/test-011-wallace_resources.py                      |   23 ++
 wallace/__init__.py                                           |   10 -
 wallace/module_resources.py                                   |   91 ++++++++--
 10 files changed, 190 insertions(+), 36 deletions(-)

New commits:
commit 43500498bb0026a1df32c40f3fa3a0d945880dfa
Merge: 195864c 99262c3
Author: Paul Boddie <paul at boddie.org.uk>
Date:   Wed Mar 19 00:04:32 2014 +0100

    Merge branch 'paul-fix' into dev/boddie



commit 99262c3f1198c1dcd14cec7f2ed416150b0f50a7
Author: Paul Boddie <paul at boddie.org.uk>
Date:   Wed Mar 19 00:01:28 2014 +0100

    Fixed refactoring error.

diff --git a/pykolab/auth/ldap/__init__.py b/pykolab/auth/ldap/__init__.py
index 952af86..a9070b8 100644
--- a/pykolab/auth/ldap/__init__.py
+++ b/pykolab/auth/ldap/__init__.py
@@ -455,7 +455,7 @@ class LDAP(pykolab.base.Base):
 
         return recipient_address_attrs, result_attributes
 
-    def get_filter_for_addresses(self, attrs, prefix, suffix):
+    def get_filter_for_addresses(self, address, attrs, prefix, suffix):
         """
             Return the filter string for addresses provided by the given
             attributes, using the specified prefix and suffix.
@@ -544,7 +544,7 @@ class LDAP(pykolab.base.Base):
 
         recipient_address_attrs, result_attributes = self.get_search_attributes()
 
-        _filter = self.get_filter_for_addresses(recipient_address_attrs, __filter_prefix, __filter_suffix)
+        _filter = self.get_filter_for_addresses(address, recipient_address_attrs, __filter_prefix, __filter_suffix)
 
         log.debug(_("Finding recipient with filter %r") % (_filter), level=8)
 
@@ -569,7 +569,7 @@ class LDAP(pykolab.base.Base):
 
         recipient_address_attrs, result_attributes = self.get_search_attributes()
 
-        _filter = self.get_filter_for_addresses(recipient_address_attrs, __filter_prefix, __filter_suffix)
+        _filter = self.get_filter_for_addresses(address, recipient_address_attrs, __filter_prefix, __filter_suffix)
 
         log.debug(_("Finding resource with filter %r") % (_filter), level=8)
 


commit 195864ce212314e2a09637512597f05d540858e8
Merge: 01735f3 e9634cf
Author: Paul Boddie <paul at boddie.org.uk>
Date:   Mon Mar 17 23:21:25 2014 +0100

    Merge branch 'master' of git://git.kolab.org/git/pykolab into dev/boddie

diff --cc pykolab/utils.py
index a623323,d552bff..1c492b1
--- a/pykolab/utils.py
+++ b/pykolab/utils.py
@@@ -293,16 -279,7 +293,14 @@@ def generate_password()
  
      return output
  
 +def setup_status(service, condition):
 +    print "%-25s - %s" % (service, condition)
 +
 +def message(text):
 +    progname = os.path.split(sys.argv[0])[-1]
 +    print >> sys.stderr, "%s: %s" % (progname, text)
 +
  def multiline_message(message):
-     _msg = ""
- 
      column_width = 80
  
      # First, replace all occurences of "\n"
diff --cc wallace/__init__.py
index 7b55f99,aeb1ccc..e37f76f
--- a/wallace/__init__.py
+++ b/wallace/__init__.py
@@@ -23,8 -24,10 +23,9 @@@ import gr
  import multiprocessing
  import os
  import pwd
+ import traceback
  from smtpd import SMTPChannel
  import socket
 -import struct
  import sys
  import tempfile
  import time


commit e9634cff74a53a653b2581b771e0b8a7cafe02ec
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Wed Mar 5 19:44:04 2014 -0500

    Fix ROLE parameter mapping according to RFC 2445

diff --git a/pykolab/xml/attendee.py b/pykolab/xml/attendee.py
index 68e9d9b..c62bbb1 100644
--- a/pykolab/xml/attendee.py
+++ b/pykolab/xml/attendee.py
@@ -23,9 +23,9 @@ class Attendee(kolabformat.Attendee):
         }
 
     role_map = {
-            "REQ-PARTICIPANT": kolabformat.Required,
             "CHAIR": kolabformat.Chair,
-            "OPTIONAL": kolabformat.Optional,
+            "REQ-PARTICIPANT": kolabformat.Required,
+            "OPT-PARTICIPANT": kolabformat.Optional,
             "NON-PARTICIPANT": kolabformat.NonParticipant,
         }
 


commit 5e9e21061bfe45f05c4e0f2567f3838ec57e9a19
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Wed Mar 5 12:44:09 2014 -0500

    Test owner assignment for resources and mentions in reservation request responses

diff --git a/pykolab/utils.py b/pykolab/utils.py
index b7ff468..d552bff 100644
--- a/pykolab/utils.py
+++ b/pykolab/utils.py
@@ -280,8 +280,6 @@ def generate_password():
     return output
 
 def multiline_message(message):
-    _msg = ""
-
     column_width = 80
 
     # First, replace all occurences of "\n"
@@ -289,8 +287,6 @@ def multiline_message(message):
     message = message.replace("\n", " ")
 
     lines = []
-    line_length = 0
-
     line = ""
     for word in message.split():
         if (len(line) + len(word)) > column_width:
@@ -306,6 +302,13 @@ def multiline_message(message):
 
     return "\n%s\n" % ("\n".join(lines))
 
+def stripped_message(message):
+    lines = []
+    for line in message.strip().split("\n"):
+        lines.append(multiline_message(line).strip())
+
+    return "\n%s\n" % ("\n".join(lines))
+
 def normalize(_object):
     if type(_object) == list:
         result = []
diff --git a/pykolab/xml/event.py b/pykolab/xml/event.py
index a165bcf..2218400 100644
--- a/pykolab/xml/event.py
+++ b/pykolab/xml/event.py
@@ -779,14 +779,14 @@ class Event(object):
         msg['Date'] = formatdate(localtime=True)
 
         if subject is None:
-            subject = _("Reservation Request for %s was %s") % (self.get_summary(), participant_status)
+            subject = _("Reservation Request for %s was %s") % (self.get_summary(), _(participant_status))
 
         msg["Subject"] = subject
 
         if message_text is None:
             message_text = _("""This is an automated response to one of your event requests.""")
 
-        msg.attach(MIMEText(utils.multiline_message(message_text)))
+        msg.attach(MIMEText(utils.stripped_message(message_text)))
 
         part = MIMEBase('text', 'calendar', charset='UTF-8', method=method)
         del part['MIME-Version']  # mime parts don't need this
diff --git a/tests/functional/resource_func.py b/tests/functional/resource_func.py
index e3519d1..43aca96 100644
--- a/tests/functional/resource_func.py
+++ b/tests/functional/resource_func.py
@@ -4,7 +4,7 @@ from pykolab import wap_client
 
 conf = pykolab.getConf()
 
-def resource_add(type, cn, members=None):
+def resource_add(type, cn, members=None, owner=None):
     if type == None or type == '':
         raise Exception
 
@@ -14,7 +14,8 @@ def resource_add(type, cn, members=None):
     resource_details = {
         'cn': cn,
         'kolabtargetfolder': "shared/Resources/" + cn + "@example.org",
-        'uniquemember': members
+        'uniquemember': members,
+        'owner': owner
     }
 
     result = wap_client.authenticate(conf.get('ldap', 'bind_dn'), conf.get('ldap', 'bind_pw'), conf.get('kolab', 'primary_domain'))
diff --git a/tests/functional/test_wallace/test_005_resource_invitation.py b/tests/functional/test_wallace/test_005_resource_invitation.py
index 53ed2ec..8a1d844 100644
--- a/tests/functional/test_wallace/test_005_resource_invitation.py
+++ b/tests/functional/test_wallace/test_005_resource_invitation.py
@@ -194,11 +194,21 @@ class TestResourceInvitation(unittest.TestCase):
             'displayname': 'John Doe',
             'mail': 'john.doe at example.org',
             'sender': 'John Doe <john.doe at example.org>',
-            'mailbox': 'user/john.doe at example.org'
+            'mailbox': 'user/john.doe at example.org',
+            'dn': 'uid=doe,ou=People,dc=example,dc=org'
+        }
+
+        self.jane = {
+            'displayname': 'Jane Manager',
+            'mail': 'jane.manager at example.org',
+            'sender': 'Jane Manager <jane.manager at example.org>',
+            'mailbox': 'user/jane.manager at example.org',
+            'dn': 'uid=manager,ou=People,dc=example,dc=org'
         }
 
         from tests.functional.user_add import user_add
         user_add("John", "Doe")
+        user_add("Jane", "Manager")
 
         funcs.purge_resources()
         self.audi = funcs.resource_add("car", "Audi A4")
@@ -206,6 +216,10 @@ class TestResourceInvitation(unittest.TestCase):
         self.boxter = funcs.resource_add("car", "Porsche Boxter S")
         self.cars = funcs.resource_add("collection", "Company Cars", [ self.audi['dn'], self.passat['dn'], self.boxter['dn'] ])
 
+        self.room1 = funcs.resource_add("confroom", "Room 101", owner=self.jane['dn'])
+        self.room2 = funcs.resource_add("confroom", "Conference Room B-222")
+        self.rooms = funcs.resource_add("collection", "Rooms", [ self.room1['dn'], self.room2['dn'] ], self.jane['dn'])
+
         time.sleep(1)
         from tests.functional.synchronize import synchronize_once
         synchronize_once()
@@ -267,11 +281,14 @@ class TestResourceInvitation(unittest.TestCase):
         return uid
 
 
-    def check_message_received(self, subject, from_addr=None):
+    def check_message_received(self, subject, from_addr=None, mailbox=None):
+        if mailbox is None:
+            mailbox = self.john['mailbox']
+
         imap = IMAP()
         imap.connect()
-        imap.set_acl(self.john['mailbox'], "cyrus-admin", "lrs")
-        imap.imap.m.select(self.john['mailbox'])
+        imap.set_acl(mailbox, "cyrus-admin", "lrs")
+        imap.imap.m.select(mailbox)
 
         found = None
         retries = 10
@@ -520,3 +537,33 @@ class TestResourceInvitation(unittest.TestCase):
 
         self.assertEqual(self.check_message_received("Reservation Request for test was ACCEPTED", self.audi['mail']), None)
 
+
+    def test_011_owner_info(self):
+        self.purge_mailbox(self.john['mailbox'])
+
+        self.send_itip_invitation(self.room1['mail'], datetime.datetime(2014,6,19, 16,0,0))
+
+        accept = self.check_message_received("Reservation Request for test was ACCEPTED", self.room1['mail'])
+        self.assertIsInstance(accept, email.message.Message)
+        respose_text = str(accept.get_payload(0))
+        self.assertIn(self.jane['mail'], respose_text)
+        self.assertIn(self.jane['displayname'], respose_text)
+
+
+    def TODO_test_012_owner_notification(self):
+        self.purge_mailbox(self.john['mailbox'])
+        self.purge_mailbox(self.jane['mailbox'])
+
+        self.send_itip_invitation(self.room1['mail'], datetime.datetime(2014,5,4, 13,0,0))
+
+        # check notification message sent to resource owner (jane)
+        notify = self.check_message_received("Reservation Request for test was ACCEPTED", self.room1['mail'], self.jane['mailbox'])
+        self.assertIsInstance(notify, email.message.Message)
+        self.assertEqual(notify['From'], self.room1['mail'])
+        self.assertEqual(notify['Cc'], self.jane['mail'])
+
+        # check notification sent to collection owner (jane)
+        self.send_itip_invitation(self.rooms['mail'], datetime.datetime(2014,5,4, 12,30,0))
+
+        notify = self.check_message_received("Reservation Request for test was ACCEPTED", self.room2['mail'], self.jane['mailbox'])
+        self.assertIsInstance(notify, email.message.Message)
diff --git a/tests/functional/user_add.py b/tests/functional/user_add.py
index 6af0419..4939f93 100644
--- a/tests/functional/user_add.py
+++ b/tests/functional/user_add.py
@@ -49,7 +49,7 @@ def user_add(givenname, sn, preferredlanguage='en_US'):
         attr_details = user_type_info['form_fields'][attribute]
 
         if isinstance(attr_details, dict):
-            if not attr_details.has_key('optional') or attr_details['optional'] == False:
+            if not attr_details.has_key('optional') or attr_details['optional'] == False or user_details.has_key(attribute):
                 params[attribute] = user_details[attribute]
         elif isinstance(attr_details, list):
             params[attribute] = user_details[attribute]
diff --git a/tests/unit/test-011-wallace_resources.py b/tests/unit/test-011-wallace_resources.py
index 50fdc6b..6198a6f 100644
--- a/tests/unit/test-011-wallace_resources.py
+++ b/tests/unit/test-011-wallace_resources.py
@@ -245,6 +245,7 @@ class TestWallaceResources(unittest.TestCase):
         self.patch(pykolab.auth.Auth, "connect", self._mock_nop)
         self.patch(pykolab.auth.Auth, "disconnect", self._mock_nop)
         self.patch(pykolab.auth.Auth, "find_resource", self._mock_find_resource)
+        self.patch(pykolab.auth.Auth, "get_entry_attributes", self._mock_get_entry_attributes)
 
         # intercept calls to smtplib.SMTP.sendmail()
         import smtplib
@@ -262,6 +263,10 @@ class TestWallaceResources(unittest.TestCase):
         entry_dn = "uid=" + prefix + ",dc=" + ",dc=".join(domain.split('.'))
         return [ entry_dn ];
 
+    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_smtp_init(self, host=None, port=None, local_hostname=None, timeout=0):
         pass
 
@@ -334,7 +339,21 @@ class TestWallaceResources(unittest.TestCase):
         self.assertEqual("uid=resource-collection-car,dc=example,dc=org", res[0]);
 
 
-    def test_004_send_response_accept(self):
+    def test_004_get_resource_owner(self):
+        owner1 = module_resources.get_resource_owner({ 'owner': "uid=foo,ou=People,cd=example,dc=org" })
+        self.assertIsInstance(owner1, dict)
+        self.assertEqual("foo at example.org", owner1['mail'])
+        self.assertIn("telephoneNumber", owner1['_attrib'])
+
+        owner2 = module_resources.get_resource_owner({ 'owner': ["uid=john,ou=People,cd=example,dc=org", "uid=jane,ou=People,cd=example,dc=org"] })
+        self.assertIsInstance(owner2, dict)
+        self.assertEqual("john at example.org", owner2['mail'])
+
+        owner3 = module_resources.get_resource_owner({ 'dn': "uid=cars,ou=Resources,cd=example,dc=org" })
+        self.assertEqual(owner3, None)
+
+
+    def test_005_send_response_accept(self):
         itip_event = module_resources.itip_events_from_message(message_from_string(itip_non_multipart))
         module_resources.send_response("resource-collection-car at example.org", itip_event)
 
@@ -352,7 +371,7 @@ class TestWallaceResources(unittest.TestCase):
         self.assertEqual(ics_part.get_param('method'), "REPLY")
 
 
-    def test_005_send_response_delegate(self):
+    def test_006_send_response_delegate(self):
         # delegate resource-collection-car at example.org => resource-car-audi-a4 at example.org
         itip_event = module_resources.itip_events_from_message(message_from_string(itip_non_multipart))[0]
         itip_event['xml'].delegate('resource-collection-car at example.org', 'resource-car-audi-a4 at example.org')
diff --git a/wallace/module_resources.py b/wallace/module_resources.py
index ee63e85..d861614 100644
--- a/wallace/module_resources.py
+++ b/wallace/module_resources.py
@@ -234,6 +234,8 @@ def execute(*args, **kw):
                     if 'kolabsharedfolder' in [x.lower() for x in resource_attrs['objectclass']]:
                         resources[uniquemember] = resource_attrs
                         resources[uniquemember]['memberof'] = resource_dn
+                        if not resource_attrs.has_key('owner') and resources[resource_dn].has_key('owner'):
+                            resources[uniquemember]['owner'] = resources[resource_dn]['owner']
                         resource_dns.append(uniquemember)
         else:
             resources[resource_dn] = resource_attrs
@@ -528,7 +530,7 @@ def accept_reservation_request(itip_event, resource, delegator=None):
         level=9
     )
 
-    send_response(delegator['mail'] if delegator else resource['mail'], itip_event)
+    send_response(delegator['mail'] if delegator else resource['mail'], itip_event, get_resource_owner(resource))
 
 
 def decline_reservation_request(itip_event, resource):
@@ -542,7 +544,7 @@ def decline_reservation_request(itip_event, resource):
         "DECLINED"
     )
 
-    send_response(resource['mail'], itip_event)
+    send_response(resource['mail'], itip_event, get_resource_owner(resource))
 
 
 def save_resource_event(itip_event, resource):
@@ -550,9 +552,8 @@ def save_resource_event(itip_event, resource):
         Append the given event object to the resource's calendar
     """
     try:
-        # TODO: The Cyrus IMAP (or Dovecot) Administrator login
-        # name comes from configuration.
-        imap.imap.m.setacl(resource['kolabtargetfolder'], "cyrus-admin", "lrswipkxtecda")
+        # Administrator login name comes from configuration.
+        imap.imap.m.setacl(resource['kolabtargetfolder'], conf.get(conf.get('kolab', 'imap_backend'), 'admin_login'), "lrswipkxtecda")
         result = imap.imap.m.append(
             resource['kolabtargetfolder'],
             None,
@@ -573,7 +574,7 @@ def delete_resource_event(uid, resource):
     """
         Removes the IMAP object with the given UID from a resource's calendar folder
     """
-    imap.imap.m.setacl(resource['kolabtargetfolder'], "cyrus-admin", "lrswipkxtecda")
+    imap.imap.m.setacl(resource['kolabtargetfolder'], conf.get(conf.get('kolab', 'imap_backend'), 'admin_login'), "lrswipkxtecda")
     imap.imap.m.select(resource['kolabtargetfolder'])
 
     typ, data = imap.imap.m.search(None, '(HEADER SUBJECT "%s")' % uid)
@@ -861,7 +862,33 @@ def resource_records_from_itip_events(itip_events, recipient_email=None):
     return resource_records
 
 
-def send_response(from_address, itip_events):
+def get_resource_owner(resource):
+    """
+        Get this resource's owner record
+    """
+    global auth
+
+    if not auth:
+        auth = Auth()
+        auth.connect()
+
+    if resource.has_key('owner'):
+        if not isinstance(resource['owner'], list):
+            resource['owner'] = [ resource['owner'] ]
+
+        for dn in resource['owner']:
+            owner = auth.get_entry_attributes(None, dn, ['cn','mail','telephoneNumber'])
+            if owner is not None:
+                return owner
+
+    else:
+        # TODO: get owner attribute from collection
+        pass
+
+    return None
+
+
+def send_response(from_address, itip_events, owner=None):
     """
         Send the given iCal events as a valid iTip response to the organizer.
         In case the invited resource coolection was delegated to a concrete
@@ -880,14 +907,20 @@ def send_response(from_address, itip_events):
     for itip_event in itip_events:
         attendee = itip_event['xml'].get_attendee_by_email(from_address)
         participant_status = itip_event['xml'].get_ical_attendee_participant_status(attendee)
-        message_text = None
+
+        message_text = reservation_response_text(participant_status, owner)
 
         if participant_status == "DELEGATED":
             # Extra actions to take
             delegator = itip_event['xml'].get_attendee_by_email(from_address)
             delegatee = [a for a in itip_event['xml'].get_attendees() if from_address in [b.email() for b in a.get_delegated_from()]][0]
+            delegatee_status = itip_event['xml'].get_ical_attendee_participant_status(delegatee)
 
-            message = itip_event['xml'].to_message_itip(delegatee.get_email(), method="REPLY", participant_status=itip_event['xml'].get_ical_attendee_participant_status(delegatee))
+            message = itip_event['xml'].to_message_itip(delegatee.get_email(),
+                method="REPLY",
+                participant_status=delegatee_status,
+                message_text=reservation_response_text(delegatee_status, owner)
+            )
             smtp.sendmail(message['From'], message['To'], message.as_string())
 
             # restore list of attendees after to_message_itip()
@@ -896,11 +929,32 @@ def send_response(from_address, itip_events):
 
             participant_status = "DELEGATED"
             message_text = _("""
-                Your reservation was delegated to "%s"
-                which is available for the requested time.
+                *** This is an automated response, please do not reply! ***
+
+                Your reservation was delegated to "%s" which is available for the requested time.
             """) % (delegatee.get_name())
 
-        message = itip_event['xml'].to_message_itip(from_address, method="REPLY", participant_status=participant_status, message_text=message_text)
+        message = itip_event['xml'].to_message_itip(from_address,
+            method="REPLY",
+            participant_status=participant_status,
+            message_text=message_text
+        )
         smtp.sendmail(message['From'], message['To'], message.as_string())
 
     smtp.quit()
+
+
+def reservation_response_text(status, owner):
+    message_text = _("""
+        *** This is an automated response, please do not reply! ***
+        
+        We hereby inform you that your reservation was %s.
+    """) % (_(status))
+
+    if owner:
+        message_text += _("""
+            If you have questions about this reservation, please contact
+            %s <%s> %s
+        """) % (owner['cn'], owner['mail'], owner['telephoneNumber'] if owner.has_key('telephoneNumber') else '')
+    
+    return message_text


commit b3afa468579586b62aee849779c89d0104c3d21e
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Wed Mar 5 07:14:13 2014 -0500

    Test handling of (some) invalid iTip messages to resources

diff --git a/tests/functional/test_wallace/test_005_resource_invitation.py b/tests/functional/test_wallace/test_005_resource_invitation.py
index 1800e19..53ed2ec 100644
--- a/tests/functional/test_wallace/test_005_resource_invitation.py
+++ b/tests/functional/test_wallace/test_005_resource_invitation.py
@@ -505,3 +505,18 @@ class TestResourceInvitation(unittest.TestCase):
         uid3 = self.send_itip_invitation(self.audi['mail'], datetime.datetime(2014,2,22, 8,0,0), template=itip_recurring)
         accept = self.check_message_received("Reservation Request for test was ACCEPTED")
         self.assertIsInstance(accept, email.message.Message)
+
+
+    def test_010_invalid_bookings(self):
+        self.purge_mailbox(self.john['mailbox'])
+
+        itip_other = itip_invitation.replace("mailto:%s", "mailto:some-other-resource at example.org\nDESCRIPTION: Sent to %s")
+        self.send_itip_invitation(self.audi['mail'], datetime.datetime(2014,3,22, 8,0,0), template=itip_other)
+
+        time.sleep(1)
+
+        itip_invalid = itip_invitation.replace("DTSTART;", "X-DTSTART;")
+        self.send_itip_invitation(self.audi['mail'], datetime.datetime(2014,3,24, 19,30,0), template=itip_invalid)
+
+        self.assertEqual(self.check_message_received("Reservation Request for test was ACCEPTED", self.audi['mail']), None)
+
diff --git a/wallace/module_resources.py b/wallace/module_resources.py
index 302f276..ee63e85 100644
--- a/wallace/module_resources.py
+++ b/wallace/module_resources.py
@@ -206,6 +206,13 @@ def execute(*args, **kw):
     # iTip events
     resource_dns = resource_records_from_itip_events(itip_events, resource_recipient)
 
+    # check if resource attendees match the envelope recipient
+    if len(resource_dns) == 0:
+        log.info(_("No resource attendees matching envelope recipient %s, Reject message") % (resource_recipient))
+        reject(filepath)
+        return False
+
+
     # Get the resource details, which includes details on the IMAP folder
     resources = {}
     for resource_dn in list(set(resource_dns)):


commit cfe5378af4eb9bbe6c210f85263c23842f6ca490
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Wed Mar 5 06:42:11 2014 -0500

    Catch and log unexpected exceptions from wallace modules; abort loop if a module 'consumed' a message

diff --git a/wallace/__init__.py b/wallace/__init__.py
index 6b1b96c..aeb1ccc 100644
--- a/wallace/__init__.py
+++ b/wallace/__init__.py
@@ -24,6 +24,7 @@ import grp
 import multiprocessing
 import os
 import pwd
+import traceback
 from smtpd import SMTPChannel
 import socket
 import struct
@@ -62,9 +63,16 @@ def pickup_message(filepath, *args, **kw):
             modules.execute(kw['module'], filepath)
 
     for module in wallace_modules:
-        result_filepath = modules.execute(module, filepath)
+        try:
+            result_filepath = modules.execute(module, filepath)
+        except:
+            log.error(_("Module %s.execute() failed on message %r with error: %s" % (module, filepath, traceback.format_exc())))
+            result_filepath = False
+
         if not result_filepath == None and not result_filepath == False:
             filepath = result_filepath
+        else:
+            break
 
 def worker_process(*args, **kw):
     log.debug(_("Worker process %s initializing") % (multiprocessing.current_process().name), level=1)


commit 7bd1d324254b08e1366f734cf168422d08b297c7
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Thu Mar 6 06:17:54 2014 -0500

    Optimization: only connect to LDAP and IMAP when actually necessary

diff --git a/wallace/module_resources.py b/wallace/module_resources.py
index 4202098..302f276 100644
--- a/wallace/module_resources.py
+++ b/wallace/module_resources.py
@@ -96,10 +96,7 @@ def execute(*args, **kw):
     log.debug(_("Resource Management called for %r, %r") % (args, kw), level=9)
 
     auth = Auth()
-    auth.connect()
-
     imap = IMAP()
-    imap.connect()
 
     # TODO: Test for correct call.
     filepath = args[0]
@@ -182,6 +179,8 @@ def execute(*args, **kw):
             possibly_any_resources = False
 
     if possibly_any_resources:
+        auth.connect()
+
         for recipient in recipients:
             if not len(resource_record_from_email_address(recipient)) == 0:
                 resource_recipient = recipient
@@ -234,6 +233,7 @@ def execute(*args, **kw):
 
     log.debug(_("Resources: %r; %r") % (resource_dns, resources), level=8)
 
+    imap.connect()
 
     done = False
     receiving_resource = resources[resource_dns[0]]




More information about the commits mailing list