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