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