Tag Archives: document management

IT explained

sclable: Das “rapid everything” ERP

Vergangene Woche hatte ich das Vergnügen, an einer sneak peek für ein überraschend neuartiges ERP-System teilzunehmen. Das Wiener Startup sclable tritt an, um das SAP oder Oracle von morgen zu werden. Die Ansage ist natürlich zu stark, um zu halten, aber dennoch ist das Produktkonzept mehr als nur einen Blick wert.

Ich würde sclable als Scaffolding Framework mit Workflows und hübschem UI beschreiben. Sagt vorerst wenig: Man kann damit jedenfalls sehr schnell individuelle Workflows in Software gießen und bleibt überdies flexibel. Es klingt ein wenig nach Heiligem Gral der Softwareentwicklung: Vorteile von Standard- und Individualsoftware vereint in einer Lösung, das Ganze durch geschulte Mitarbeiter in Eigenregie durchführbar.

sclable besetzt mit dieser Idee eine – zumindest für mich – komplett neuartige Nische im Unternehmen irgendwo zwischen zur Unhandhabbarkeit gewachsenen Excels, dem von Haus aus unhandhabbaren Sharepoint, der schwerfälligen Business Class mit SAP Workbench oder Oracle Forms sowie der Plugin-Architektur von WordPress.

Bereits nach der kurzen Einführung würde ich mir zutrauen, beispielsweise einen Bestellworkflow für ein mittleres Unternehmen mit sclable innerhalb weniger Stunden umzusetzen. So schnell, wie ich in sclable editiere, kann ich beim besten Willen nicht programmieren.

hgd
sclable at its best: Im Handumdrehen erstellte Entitäten werden mit beliebig komplexen Workflows verknüpft. Die graphische Darstellung ist bereits der halbe Weg zur Dokumentation.

Damit kommen wir zum wirklichen Vorteil: Durch die enorme Geschwindigkeit wachsen Spezifikation, Umsetzung, Test und Dokumentation zusammen. Es ist also vorstellbar alle Präsentationen, Powerpoints, e-Mails und Telefonate zu skippen und gleich gemeinsam mit dem Kunden loszulegen. Solange also die Aufgabenstellung zum Kern von sclable passt (“Mehrbenutzer-Workflow rund um ER-Modell”), ist’s ein Wahnsinns-Tool.

“Don’t ever fight a framework!”

Den Punkt, wo Customizing zur Vergewaltigung wird, darf man allerdings – wie bei jedem anderen Framework auch – nicht übersehen. Dann endet man schließlich wiederum in der Individualentwicklung, und hier würde ich dann generell zu Python/Django greifen. (Nun ja, da greife ich fast immer hin.)

Was paranoide oder Policy-geplagte CIOs beruhigen dürfte, ist außerdem die Info, dass das Produkt nicht nur als SaaS sondern auch on-premise laufen soll. Dank API sind Daten außerdem exportierbar, was langfristige Abhängigkeiten ohne Ausweg unterbindet.

Nachteil ist womöglich PHP als Runtime. Technisch ist es einfach pfui wegen fehlender Namespaces einer besch*** Standard Library, Patch-Wahnsinn, usw. Entwickler gibt’s jedoch genug. (Und mit Wikipedia oder Facebook gibt’s zugegebenermaßen ziemlich große PHP-Projekte, wo auch niemand über die Programmiersprache schimpft…)

Ich bin gespannt auf den Launch und weitere News von sclable.at!

Edit: Markus Nenning hat mich darauf aufmerksam gemacht, dass ERP eine nicht ganz korrekte Schublade für das Produktkonzept ist. Ich hab’s dennoch beim Titel belassen, da man sich mit bekannten Kategorien einfach leichter tut. Aber klar, mit der Flexibilität von sclable könnte man auch ganz andere Schubladen füllen – von Projektmanagement über CMS bis hin zu einem Universitätsverwaltungssystem.

hacks

Writing emails to a website

Unix’ beauty lies in the fact that you can easily build powerful systems out of simple components. This post describes an email-to-database interface for one of our web applications using Python and some Unix tools.

Users came up with the urgent need to annotate database records with arbitrary content. Rather than bending our application into a document management system (which apparently it is not) I came up with the idea to offer an email-to-website service.

Or as my friend Florian put it: “With a few billion users, email is quite a succesful social network.”

Mailing to a script

In order to write mails to a program rather than a conventional mailbox you need to edit the file /etc/aliases .

booking:        |/opt/wu-wien/roomsmta/bin/booking.sh

Here I’m sending the mail to an address called booking. Every incoming mail invokes the shell script booking.sh.

If you want to forward your mail to other locations simply add mailboxes or addresses after a comma. Don’t forget to run newaliases after the file is saved.

 Shell wrapper

#!/bin/sh

PYTHON_EGG_CACHE=/opt/wu-wien/roomsmta/cache
export PYTHON_EGG_CACHE

exec /opt/wu-wien/roomsmta/bin/booking.py

The incoming mail is passed to a shell script which sets some environment variables needed for virtualenv. The Unix command exec passes standard input on to the Python script. The result will be a custom Python interpreter set up with its very own environment.

The Python script

My script reads the email from STDIN, does some parsing magic and eventually puts the content into a database. (For reasons of clarity I have omitted the latter part in my example.) Since my mail configuration saves the mail in a proper mailbox as well I do not store attachments in the database. If you’re interested in parsing attachments I recommend Ian Lewis’ post.

#!/opt/wu-wien/roomsmta/v_mtapy/bin/python
import email.FeedParser
from email.utils import parseaddr

import sys, os
import base64
import re

import cx_Oracle

def parse_email(email_input):
    """Return message object"""
    
    parser = email.FeedParser.FeedParser()
    msg = None
    for msg_line in email_input:
       msg = parser.feed(msg_line)
    msg = parser.close()
    
    return msg


class Email(object):
    
    
    def __init__(self, msg):
        
        self.msg = msg

        self.subject = msg['Subject']
        self.date = msg['Date']
        (self.from_name, self.from_email) = parseaddr(msg['From'])
        
        self.to_email = parseaddr(msg['To'])
        
        self.has_attachments = 0
        
        msgbody = []


        for part in msg.walk():
            
            if part.get_content_type() == 'text/plain':
                
                if part['Content-Transfer-Encoding'] == 'base64':
                    body = unicode(base64.b64decode(part.get_payload()), part.get_content_charset(), 'replace' )
                
                else:
                    
                    try:
                        body = unicode(part.get_payload(), part.get_content_charset(), 'replace')
                    except TypeError:
                        # if no charset is given
                        body = unicode(part.get_payload())
                msgbody.append(body)
                
            elif part.get_content_type() == 'text/html':
                
                html = unicode(part.get_payload(), part.get_content_charset(), 'replace')
                raw = nltk.clean_html(html)          

                msgbody.append(raw)
                #print raw.encode('utf8', 'replace')

            elif part.get("Content-Disposition"):
                #print part.get("Content-Disposition")

                self.has_attachments = 1
                msgbody.append(u'ATTACHMENT: %s' % (part.get_filename(),))

        self.body = u'\n'.join(msgbody)
    
    def save(self):
        
        print 'GOING on to save'


if __name__ == '__main__':
    
    
    email_input = sys.stdin.readlines()
    msg = parse_email(email_input)
    
    Email(msg).save()

Testing the setup

Testing your code turns out to be a nightmare since you will need a mail client to invoke your script. Fortunately Unix comes with pipes which mock the email behavior:

less my_test_mail.eml | ./booking.py

Addressing records in the database

Did you know that you can have plus signs in a valid mail address?

Until now we have written all our email to booking@servername. But what you need in an application context is the possibility to clearly  attribute incoming email to specific database records. I have seen some solutions carrying the magic in the subject field, but I prefer RFC2822‘s possibility to write content after a plus sign into the address field. In my case this will either be the record’s id and the database instance in use (i.e. test or production).

        tocc = '%s %s' % (self.msg['To'], self.msg['Cc'])

        # has formats:
        #   booking+1234T@localhost
        #   booking+1234P@localhost
        #
        m = re.search('booking\+\d+[PT]', tocc)
        
        try:
            
            tocc = m.group(0)

            instance = tocc[-1:] 
            tid = tocc[:-1].replace('booking+','')
            
            return (instance, tid)
        
        except AttributeError:
            raise NoEventFound

Voilá, I can write mails to booking+1234T@servername.

Mail’s in the database – mission accomplished.

Thanks to Roland and Willi who did the tricky work;-)