4 commits - conf/kolab.conf tests/functional wallace/module_footer.py
Jeroen van Meeuwen
vanmeeuwen at kolabsys.com
Sat Dec 29 19:27:48 CET 2012
conf/kolab.conf | 5
tests/functional/test_wallace/test_002_footer.py | 285 +++++++++++++++++++++++
tests/functional/user_add.py | 2
wallace/module_footer.py | 172 +++++++++++++
4 files changed, 464 insertions(+)
New commits:
commit 2e28430d8444e316655d214372a7bdafe98dbad7
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Sat Dec 29 19:27:34 2012 +0100
Set the correct password for new users
diff --git a/tests/functional/user_add.py b/tests/functional/user_add.py
index 0271d43..2fc44cf 100644
--- a/tests/functional/user_add.py
+++ b/tests/functional/user_add.py
@@ -64,5 +64,7 @@ def user_add(givenname, sn, preferredlanguage='en_US'):
for attribute in user_type_info['auto_form_fields'].keys():
params[attribute] = retval[attribute]
+ params['userpassword'] = user_details['userpassword']
+
result = wap_client.user_add(params)
commit ff0ad690e034f742b954d1b445969a1f3eefbbb9
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Sat Dec 29 19:27:25 2012 +0100
Add tests for the footer module
diff --git a/tests/functional/test_wallace/test_002_footer.py b/tests/functional/test_wallace/test_002_footer.py
new file mode 100644
index 0000000..f9568c2
--- /dev/null
+++ b/tests/functional/test_wallace/test_002_footer.py
@@ -0,0 +1,285 @@
+from email import message_from_string
+from email.MIMEMultipart import MIMEMultipart
+from email.MIMEBase import MIMEBase
+from email.MIMEImage import MIMEImage
+from email.MIMEText import MIMEText
+from email.Utils import COMMASPACE, formatdate
+from email import Encoders
+import os
+import smtplib
+import time
+import unittest
+
+import pykolab
+from pykolab import wap_client
+from pykolab.auth import Auth
+from pykolab.imap import IMAP
+
+conf = pykolab.getConf()
+
+class TestWallaceFooter(unittest.TestCase):
+
+ @classmethod
+ def setup_class(self, *args, **kw):
+ from tests.functional.purge_users import purge_users
+ purge_users()
+
+ self.user = {
+ 'local': 'john.doe',
+ 'domain': 'example.org'
+ }
+
+ self.footer = {}
+
+ footer_html_file = conf.get('wallace', 'footer_html')
+ footer_text_file = conf.get('wallace', 'footer_text')
+
+ if os.path.isfile(footer_text_file):
+ self.footer['plain'] = open(footer_text_file, 'r').read()
+
+ if not os.path.isfile(footer_html_file):
+ self.footer['html'] = '<p>' + self.footer['plain'] + '</p>'
+ else:
+ self.footer['html'] = open(footer_html_file, 'r').read()
+
+ self.send_to = 'john.doe at example.org'
+ self.send_from = 'john.doe at example.org'
+
+ self.message_to = '"Doe, John" <%s>' % (self.send_to)
+ self.message_from = '"Doe, John" <%s>' % (self.send_from)
+
+ from tests.functional.user_add import user_add
+ user_add("John", "Doe")
+ time.sleep(2)
+ from tests.functional.synchronize import synchronize_once
+ synchronize_once()
+
+# @classmethod
+# def teardown_class(self, *args, **kw):
+# from tests.functional.purge_users import purge_users
+# purge_users()
+
+ def check_message_delivered(self, subject):
+ imap = IMAP()
+ imap.connect()
+ imap.set_acl("user/john.doe at example.org", "cyrus-admin", "lrs")
+ imap.imap.m.select("user/john.doe at example.org")
+
+ found = False
+ max_tries = 20
+
+ while not found and max_tries > 0:
+ max_tries -= 1
+
+ typ, data = imap.imap.m.search(None, 'ALL')
+ for num in data[0].split():
+ typ, msg = imap.imap.m.fetch(num, '(RFC822)')
+ _msg = message_from_string(msg[0][1])
+ if _msg['Subject'] == subject:
+ found = True
+
+ time.sleep(1)
+
+ return found
+
+ def html_attachment(self):
+ html_body = "<html><body><p>This is an HTML attachment</p></body></html>"
+ html_part = MIMEBase("text", "html")
+ html_part.add_header("Content-Disposition", "attachment", filename="html_attachment.html")
+ html_part.set_payload(html_body)
+ return html_part
+
+ def image_attachment(self):
+ image_file = '/usr/share/kolab-webadmin/public_html/skins/default/images/logo_kolab.png'
+ image_part = MIMEImage(open(image_file, 'r').read())
+ image_part.add_header("Content-Disposition", "attachment", filename=os.path.basename(image_file))
+ return image_part
+
+ def message_standard_params(self, subject, msg):
+ msg['From'] = self.message_from
+ msg['To'] = self.message_to
+
+ msg['Subject'] = subject
+ msg['Date'] = formatdate(localtime=True)
+
+ return msg
+
+ def send_message(self, msg, _to=None, _from=None):
+ smtp = smtplib.SMTP('localhost', 10026)
+
+ if _to == None:
+ _to = self.send_to
+
+ if _from == None:
+ _from = self.send_from
+
+ smtp.sendmail(_from, _to, msg.as_string())
+
+ def test_001_inbox_created(self):
+ imap = IMAP()
+ imap.connect()
+
+ folders = imap.lm('user/%(local)s@%(domain)s' % (self.user))
+ self.assertEqual(len(folders), 1)
+
+ def test_002_send_plaintext(self):
+ subject = "test_002_send_plaintext"
+ body = "This is a test message"
+ msg = MIMEBase("text", "plain")
+ msg = self.message_standard_params(subject, msg)
+
+ msg.set_payload(body)
+
+ self.send_message(msg)
+
+ if not self.check_message_delivered(subject):
+ raise Exception
+
+ def test_003_send_plaintext_with_attachment(self):
+ subject = "test_003_send_plaintext_with_attachment"
+ body = "This is a test message"
+ msg = MIMEMultipart()
+ msg = self.message_standard_params(subject, msg)
+
+ msg.attach(MIMEText(body))
+ msg.attach(self.image_attachment())
+
+ self.send_message(msg)
+
+ if not self.check_message_delivered(subject):
+ raise Exception
+
+ def test_004_send_html(self):
+ subject = "test_004_send_html"
+ body = "<html><body><p>This is a test message</p></body></html>"
+ msg = MIMEBase("text", "html")
+ msg = self.message_standard_params(subject, msg)
+ msg.set_payload(body)
+
+ self.send_message(msg)
+
+ if not self.check_message_delivered(subject):
+ raise Exception
+
+ def test_005_send_html_with_plaintext_alternative(self):
+ subject = "test_005_send_html_with_plaintext_alternative"
+ html_body = "<html><body><p>This is the HTML part</p></body></html>"
+ plain_body = "This is the plaintext part"
+
+ msg = MIMEMultipart("alternative")
+ msg = self.message_standard_params(subject, msg)
+
+ html_part = MIMEBase("text", "html")
+ html_part.set_payload(html_body)
+ msg.attach(html_part)
+
+ plain_part = MIMEText(plain_body)
+ msg.attach(plain_part)
+
+ self.send_message(msg)
+
+ if not self.check_message_delivered(subject):
+ raise Exception
+
+ def test_006_send_html_with_attachment(self):
+ subject = "test_006_send_html_with_attachment"
+ html_body = "<html><body><p>This is the HTML part</p></body></html>"
+ plain_body = "This is the plaintext part"
+
+ msg = MIMEMultipart()
+ msg = self.message_standard_params(subject, msg)
+
+ html_part = MIMEBase("text", "html")
+ html_part.set_payload(html_body)
+ msg.attach(html_part)
+
+ msg.attach(self.image_attachment())
+
+ self.send_message(msg)
+
+ if not self.check_message_delivered(subject):
+ raise Exception
+
+ def test_007_send_html_with_plaintext_alternative_and_attachment(self):
+ subject = "test_007_send_html_with_plaintext_alternative_and_attachment"
+ html_body = "<html><body><p>This is the HTML part</p></body></html>"
+ plain_body = "This is the plaintext part"
+
+ msg = MIMEMultipart("mixed")
+ msg = self.message_standard_params(subject, msg)
+
+ message_part = MIMEMultipart("alternative")
+
+ html_part = MIMEBase("text", "html")
+ html_part.set_payload(html_body)
+ message_part.attach(html_part)
+
+ plain_part = MIMEText(plain_body)
+ message_part.attach(plain_part)
+
+ msg.attach(message_part)
+
+ msg.attach(self.image_attachment())
+
+ self.send_message(msg)
+
+ if not self.check_message_delivered(subject):
+ raise Exception
+
+ def test_008_send_plaintext_with_html_attachment(self):
+ subject = "test_008_send_plaintext_with_html_attachment"
+ body = "This is a plaintext message"
+ msg = MIMEMultipart()
+ msg = self.message_standard_params(subject, msg)
+
+ msg.attach(MIMEText(body))
+
+ msg.attach(self.html_attachment())
+
+ self.send_message(msg)
+
+ if not self.check_message_delivered(subject):
+ raise Exception
+
+ def test_009_send_plaintext_forwarded(self):
+ subject = "test_009_send_plaintext_forwarded"
+ body = "This is a plaintext message"
+
+ from tests.functional.user_add import user_add
+ user_add("Jane", "Doe")
+
+ from tests.functional.synchronize import synchronize_once
+ synchronize_once()
+
+ admin_login = conf.get('cyrus-imap', 'admin_login')
+ admin_password = conf.get('cyrus-imap', 'admin_password')
+
+ import sievelib.factory
+ script = sievelib.factory.FiltersSet("test_wallace_test_009_forward")
+ script.require("copy")
+ script.addfilter("forward", ["true"], [("redirect", ":copy", "john.doe at example.org")])
+
+ import sievelib.managesieve
+ sieveclient = sievelib.managesieve.Client('localhost', 4190, True)
+ sieveclient.connect(None, None, True)
+ sieveclient._plain_authentication(admin_login, admin_password, 'jane.doe at example.org')
+ sieveclient.authenticated = True
+
+ script_str = script.__str__()
+
+ print script_str
+
+ sieveclient.putscript("test_wallace_test_009_forward", script_str)
+
+ sieveclient.setactive("test_wallace_test_009_forward")
+
+ msg = MIMEText(body)
+ msg['From'] = self.message_from
+ msg['To'] = '"Doe, Jane" <jane.doe at example.org>'
+
+ msg['Subject'] = subject
+ msg['Date'] = formatdate(localtime=True)
+
+ self.send_message(msg, _to='jane.doe at example.org', _from='john.doe at example.org')
+
+ raise Exception
commit 1272272c07f6ff08b80064e3ecf7be435880afd8
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Sat Dec 29 19:26:37 2012 +0100
Add a Wallace module that can add footers to messages
Note currently this module also adds footers to inbound messages from external senders
diff --git a/wallace/module_footer.py b/wallace/module_footer.py
new file mode 100644
index 0000000..550e58f
--- /dev/null
+++ b/wallace/module_footer.py
@@ -0,0 +1,172 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+import json
+import os
+import tempfile
+import time
+
+from email import message_from_string
+from email.MIMEBase import MIMEBase
+from email.MIMEText import MIMEText
+from email.utils import formataddr
+from email.utils import getaddresses
+
+import modules
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.wallace')
+conf = pykolab.getConf()
+
+mybasepath = '/var/spool/pykolab/wallace/footer/'
+
+def __init__():
+ modules.register('footer', execute, description=description())
+
+def description():
+ return """Append a footer to messages."""
+
+def execute(*args, **kw):
+ if not os.path.isdir(mybasepath):
+ os.makedirs(mybasepath)
+
+ for stage in ['incoming', 'ACCEPT' ]:
+ if not os.path.isdir(os.path.join(mybasepath, stage)):
+ os.makedirs(os.path.join(mybasepath, stage))
+
+ # TODO: Test for correct call.
+ filepath = args[0]
+
+ if kw.has_key('stage'):
+ log.debug(_("Issuing callback after processing to stage %s") % (kw['stage']), level=8)
+ log.debug(_("Testing cb_action_%s()") % (kw['stage']), level=8)
+ if hasattr(modules, 'cb_action_%s' % (kw['stage'])):
+ log.debug(_("Attempting to execute cb_action_%s()") % (kw['stage']), level=8)
+ exec('modules.cb_action_%s(%r, %r)' % (kw['stage'],'optout',filepath))
+ return
+
+ log.debug(_("Executing module footer for %r, %r") % (args, kw), level=8)
+
+ new_filepath = os.path.join('/var/spool/pykolab/wallace/footer/incoming', os.path.basename(filepath))
+ os.rename(filepath, new_filepath)
+ filepath = new_filepath
+
+ _message = json.load(open(filepath, 'r'))
+ message = message_from_string("%s" % (str(_message['data'])))
+
+ # Possible footer answers are limited to ACCEPT only
+ answers = [ 'ACCEPT' ]
+
+ footer = {}
+
+ footer_html_file = conf.get('wallace', 'footer_html')
+ footer_text_file = conf.get('wallace', 'footer_text')
+
+ if not os.path.isfile(footer_text_file) and not os.path.isfile(footer_html_file):
+ exec('modules.cb_action_%s(%r, %r)' % ('ACCEPT','footer', filepath))
+ return
+
+ if os.path.isfile(footer_text_file):
+ footer['plain'] = open(footer_text_file, 'r').read()
+
+ if not os.path.isfile(footer_html_file):
+ footer['html'] = '<p>' + self.footer['plain'] + '</p>'
+ else:
+ footer['html'] = open(footer_html_file, 'r').read()
+ if footer['html'] == "":
+ footer['html'] = '<p>' + self.footer['plain'] + '</p>'
+
+ if footer['plain'] == "" and footer['html'] == "<p></p>":
+ exec('modules.cb_action_%s(%r, %r)' % ('ACCEPT','footer', filepath))
+ return
+
+ footer_added = False
+
+ try:
+ _footer_added = message.get("X-Wallace-Footer")
+ except:
+ pass
+
+ if _footer_added == "YES":
+ exec('modules.cb_action_%s(%r, %r)' % ('ACCEPT','footer', filepath))
+ return
+
+ if message.is_multipart():
+ if message.get_content_type() == "multipart/alternative":
+ log.debug("The message content type is multipart/alternative.")
+
+ for part in message.walk():
+ disposition = None
+
+ try:
+ content_type = part.get_content_type()
+ except:
+ continue
+
+ try:
+ disposition = part.get("Content-Disposition")
+ except:
+ pass
+
+ if not disposition == None:
+ continue
+
+ if content_type == "text/plain":
+ content = part.get_payload()
+ content += "\n\n--\n%s" % (footer['plain'])
+ part.set_payload(content)
+ footer_added = True
+
+ elif content_type == "text/html":
+ content = part.get_payload()
+ content += "\n<!-- footer appended by Wallace -->\n"
+ content += "\n<html><body><hr />%s</body></html>\n" % (footer['html'])
+ part.set_payload(content)
+ footer_added = True
+
+ else:
+ # Check the main content-type.
+ if message.get_content_type() == "text/html":
+ content = message.get_payload()
+ content += "\n<!-- footer appended by Wallace -->\n"
+ content += "\n<html><body><hr />%s</body></html>\n" % (footer['html'])
+ message.set_payload(content)
+ footer_added = True
+
+ else:
+ content = message.get_payload()
+ content += "\n\n--\n%s" % (footer['plain'])
+ message.set_payload(content)
+ footer_added = True
+
+ if footer_added:
+ log.debug("Footer attached.")
+ message.add_header("X-Wallace-Footer", "YES")
+
+ _message['data'] = "%s" % (str(message.as_string()))
+
+ (fp, new_filepath) = tempfile.mkstemp(dir="/var/spool/pykolab/wallace/footer/ACCEPT")
+ os.write(fp, json.dumps(_message))
+ os.close(fp)
+ os.unlink(filepath)
+
+ exec('modules.cb_action_%s(%r, %r)' % ('ACCEPT','footer', new_filepath))
commit b8c06cb6db8e6125b02bdaa9b712fccacb11a896
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Sat Dec 29 19:16:57 2012 +0100
Add a [wallace] section with valid options for the new footer module
diff --git a/conf/kolab.conf b/conf/kolab.conf
index 339ec33..e0f64c3 100644
--- a/conf/kolab.conf
+++ b/conf/kolab.conf
@@ -202,6 +202,11 @@ admin_password = Welcome123
; The user canonification result attribute.
result_attribute = mail
+[wallace]
+modules = resources, footer
+footer_text = /etc/kolab/footer.text
+footer_html = /etc/kolab/footer.html
+
; This is a domain name space specific section, that enables us to override
; all settings, for example, the LDAP URI, base and bind DNs, scopes, filters,
; etc. Note that overriding the LDAP settings for the primary domain name space
More information about the commits
mailing list