pykolab/utils.py pykolab/xml tests/functional tests/unit wallace/module_invitationpolicy.py wallace/module_resources.py

Thomas Brüderli bruederli at kolabsys.com
Mon Nov 24 18:21:53 CET 2014


 pykolab/utils.py                                              |    9 ++++
 pykolab/xml/event.py                                          |   12 +++---
 tests/functional/resource_func.py                             |    3 +
 tests/functional/test_wallace/test_005_resource_invitation.py |    2 -
 tests/unit/test-011-itip.py                                   |   12 +++++-
 tests/unit/test-012-wallace_invitationpolicy.py               |   12 +++++-
 wallace/module_invitationpolicy.py                            |   20 +++++++---
 wallace/module_resources.py                                   |   10 ++++-
 8 files changed, 62 insertions(+), 18 deletions(-)

New commits:
commit d49a7ea6c05521995afa8b73fcf0e638931f83d9
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Wed Nov 19 21:27:09 2014 -0500

    Build iTip response and notification messages with unicode strings (#3926) + adjust tests

diff --git a/pykolab/utils.py b/pykolab/utils.py
index d34daeb..f91ed8d 100644
--- a/pykolab/utils.py
+++ b/pykolab/utils.py
@@ -309,6 +309,15 @@ def stripped_message(message):
 
     return "\n%s\n" % ("\n".join(lines))
 
+def str2unicode(s, encoding='utf-8'):
+    if isinstance(s, unicode):
+        return s
+    try:
+        return unicode(s, encoding)
+    except:
+        pass
+    return s
+
 def normalize(_object):
     if type(_object) == list:
         result = []
diff --git a/pykolab/xml/event.py b/pykolab/xml/event.py
index 2eb1155..0e7c333 100644
--- a/pykolab/xml/event.py
+++ b/pykolab/xml/event.py
@@ -945,7 +945,6 @@ class Event(object):
         from email.MIMEBase import MIMEBase
         from email.MIMEText import MIMEText
         from email.Utils import COMMASPACE, formatdate
-        from email import Encoders
 
         msg = MIMEMultipart()
         organizer = self.get_organizer()
@@ -1030,7 +1029,10 @@ class Event(object):
         from email.MIMEBase import MIMEBase
         from email.MIMEText import MIMEText
         from email.Utils import COMMASPACE, formatdate
-        from email import Encoders
+
+        # encode unicode strings with quoted-printable
+        from email import charset
+        charset.add_charset('utf-8', charset.SHORTEST, charset.QP)
 
         msg = MIMEMultipart()
 
@@ -1093,19 +1095,19 @@ class Event(object):
             else:
                 msg_from = from_address
 
-        msg['From'] = msg_from
+        msg['From'] = utils.str2unicode(msg_from)
 
         msg['Date'] = formatdate(localtime=True)
 
         if subject is None:
             subject = _("Invitation for %s was %s") % (self.get_summary(), participant_status_label(participant_status))
 
-        msg["Subject"] = subject
+        msg['Subject'] = utils.str2unicode(subject)
 
         if message_text is None:
             message_text = _("""This is an automated response to one of your event requests.""")
 
-        msg.attach(MIMEText(utils.stripped_message(message_text)))
+        msg.attach(MIMEText(utils.stripped_message(message_text), _charset='utf-8'))
 
         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 ac80360..a7e4d90 100644
--- a/tests/functional/resource_func.py
+++ b/tests/functional/resource_func.py
@@ -15,7 +15,8 @@ def resource_add(type, cn, members=None, owner=None, **kw):
         'cn': cn,
         'kolabtargetfolder': "shared/Resources/" + cn + "@example.org",
         'uniquemember': members,
-        'owner': owner
+        'owner': owner,
+        'ou': 'ou=resources,dc=example,dc=org'
     }
 
     resource_details.update(kw)
diff --git a/tests/functional/test_wallace/test_005_resource_invitation.py b/tests/functional/test_wallace/test_005_resource_invitation.py
index 4e69f2f..885f4ba 100644
--- a/tests/functional/test_wallace/test_005_resource_invitation.py
+++ b/tests/functional/test_wallace/test_005_resource_invitation.py
@@ -574,7 +574,7 @@ class TestResourceInvitation(unittest.TestCase):
     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")
+        itip_other = itip_invitation.replace("mailto:%s", "mailto:some-other-resource at example.org\nCOMMENT: Sent to %s")
         self.send_itip_invitation(self.audi['mail'], datetime.datetime(2014,3,22, 8,0,0), template=itip_other)
 
         time.sleep(1)
diff --git a/tests/unit/test-011-itip.py b/tests/unit/test-011-itip.py
index cb1b760..e5edee5 100644
--- a/tests/unit/test-011-itip.py
+++ b/tests/unit/test-011-itip.py
@@ -465,5 +465,13 @@ class TestITip(unittest.TestCase):
         self.assertEqual(message.get('Subject'), _("Invitation for %(summary)s was %(status)s") % { 'summary':'test', 'status':_accepted })
 
         text = str(message.get_payload(0));
-        self.assertIn('SUMMARY=test', text)
-        self.assertIn('STATUS=' + _accepted, text)
+        self.assertIn('SUMMARY=3Dtest', text)
+        self.assertIn('STATUS=3D' + _accepted, text)
+
+    def test_004_send_reply_unicode(self):
+        itip_events = itip.events_from_message(message_from_string(itip_non_multipart.replace('SUMMARY:test', "SUMMARY:With äöü")))
+        itip.send_reply("resource-collection-car at example.org", itip_events, "SUMMARY=%(summary)s; STATUS=%(status)s; NAME=%(name)s;")
+
+        self.assertEqual(len(self.smtplog), 1)
+        self.assertIn("Subject: =?utf-8?q?Invitation_for_With_=C3=A4=C3=B6=C3=BC_was_Accepted?=", self.smtplog[0][2])
+        self.assertIn('SUMMARY=3DWith =C3=A4=C3=B6=C3=BC', self.smtplog[0][2])
diff --git a/tests/unit/test-012-wallace_invitationpolicy.py b/tests/unit/test-012-wallace_invitationpolicy.py
index 3366950..20e139d 100644
--- a/tests/unit/test-012-wallace_invitationpolicy.py
+++ b/tests/unit/test-012-wallace_invitationpolicy.py
@@ -1,3 +1,5 @@
+# -*- coding: utf-8 -*-
+
 import os
 import pykolab
 import logging
@@ -160,4 +162,12 @@ class TestWallaceInvitationpolicy(unittest.TestCase):
         self.assertFalse( MIP.is_auto_reply({ 'kolabinvitationpolicy':accept_some },  'sam at example.org', 'event'))
         self.assertFalse( MIP.is_auto_reply({ 'kolabinvitationpolicy':accept_avail }, 'user at domain.com', 'event'))
         self.assertTrue(  MIP.is_auto_reply({ 'kolabinvitationpolicy':accept_avail }, 'john at example.org', 'event'))
-        
\ No newline at end of file
+
+    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 at 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])
+
diff --git a/wallace/module_invitationpolicy.py b/wallace/module_invitationpolicy.py
index 753547c..6adf82d 100644
--- a/wallace/module_invitationpolicy.py
+++ b/wallace/module_invitationpolicy.py
@@ -970,6 +970,10 @@ def send_update_notification(object, receiving_user, old=None, reply=True):
     from email.MIMEText import MIMEText
     from email.Utils import formatdate
 
+    # encode unicode strings with quoted-printable
+    from email import charset
+    charset.add_charset('utf-8', charset.SHORTEST, charset.QP)
+
     organizer = object.get_organizer()
     orgemail = organizer.email()
     orgname = organizer.name()
@@ -1053,12 +1057,12 @@ def send_update_notification(object, receiving_user, old=None, reply=True):
     message_text += "\n" + _("*** This is an automated message. Please do not reply. ***")
 
     # compose mime message
-    msg = MIMEText(utils.stripped_message(message_text))
+    msg = MIMEText(utils.stripped_message(message_text), _charset='utf-8')
 
     msg['To'] = receiving_user['mail']
     msg['Date'] = formatdate(localtime=True)
-    msg['Subject'] = _('"%s" has been updated') % (object.get_summary())
-    msg['From'] = '"%s" <%s>' % (orgname, orgemail) if orgname else orgemail
+    msg['Subject'] = utils.str2unicode(_('"%s" has been updated') % (object.get_summary()))
+    msg['From'] = utils.str2unicode('"%s" <%s>' % (orgname, orgemail) if orgname else orgemail)
 
     smtp = smtplib.SMTP("localhost", 10027)
 
@@ -1081,6 +1085,10 @@ def send_cancel_notification(object, receiving_user):
     from email.MIMEText import MIMEText
     from email.Utils import formatdate
 
+    # encode unicode strings with quoted-printable
+    from email import charset
+    charset.add_charset('utf-8', charset.SHORTEST, charset.QP)
+
     log.debug(_("Send cancellation notification for %s %r to user %r") % (
         object.type, object.uid, receiving_user['mail']
     ), level=8)
@@ -1111,12 +1119,12 @@ def send_cancel_notification(object, receiving_user):
     message_text += "\n" + _("*** This is an automated message. Please do not reply. ***")
 
     # compose mime message
-    msg = MIMEText(utils.stripped_message(message_text))
+    msg = MIMEText(utils.stripped_message(message_text), _charset='utf-8')
 
     msg['To'] = receiving_user['mail']
     msg['Date'] = formatdate(localtime=True)
-    msg['Subject'] = _('"%s" has been cancelled') % (object.get_summary())
-    msg['From'] = '"%s" <%s>' % (orgname, orgemail) if orgname else orgemail
+    msg['Subject'] = utils.str2unicode(_('"%s" has been cancelled') % (object.get_summary()))
+    msg['From'] = utils.str2unicode('"%s" <%s>' % (orgname, orgemail) if orgname else orgemail)
 
     smtp = smtplib.SMTP("localhost", 10027)
 
diff --git a/wallace/module_resources.py b/wallace/module_resources.py
index 0b4d811..d1833eb 100644
--- a/wallace/module_resources.py
+++ b/wallace/module_resources.py
@@ -1197,6 +1197,10 @@ def send_owner_notification(resource, owner, itip_event, success=True):
     from email.MIMEText import MIMEText
     from email.Utils import formatdate
 
+    # encode unicode strings with quoted-printable
+    from email import charset
+    charset.add_charset('utf-8', charset.SHORTEST, charset.QP)
+
     notify = False
     status = itip_event['xml'].get_attendee_by_email(resource['mail']).get_participant_status(True)
 
@@ -1223,12 +1227,14 @@ def send_owner_notification(resource, owner, itip_event, success=True):
 
         message_text = owner_notification_text(resource, owner, itip_event['xml'], success)
 
-        msg = MIMEText(utils.stripped_message(message_text))
+        msg = MIMEText(utils.stripped_message(message_text), _charset='utf-8')
 
         msg['To'] = owner['mail']
         msg['From'] = resource['mail']
         msg['Date'] = formatdate(localtime=True)
-        msg['Subject'] = _('Booking for %s has been %s') % (resource['cn'], participant_status_label(status) if success else _('failed'))
+        msg['Subject'] = utils.str2unicode(_('Booking for %s has been %s') % (
+            resource['cn'], participant_status_label(status) if success else _('failed')
+        ))
 
         smtp = smtplib.SMTP("localhost", 10027)
 




More information about the commits mailing list