8. Workflows verwalten
Workflows verwalten
Eine der vielen Stärken von Plone liegt in seiner Workflow-Komponente. Workflows sind ein zentrales Thema beim Content-Management, in dem es um die Trennung von Anwendungslogik, Inhalt und Präsentation geht. Deswegen wird in diesem Kapitel der Workflow in Plone detailliert behandelt.
Ich beginne mit einigen Schlüsseldefinitionen im Zusammenhang mit Workflows sowie mit den wichtigsten dabei beteiligten Werkzeugen zum Erstellen von Workflows. Nachdem diese Konzepte klar sind, werde ich dann beschreiben, wie Sie Ihre eigenen Workflows hinzufügen und bearbeiten können.
Über das gesamte Kapitel hinweg werde ich Ihnen einfache Änderungen zeigen, die Sie an jenem Workflow vornehmen können, der in Plone von vornherein enthalten ist. Außerdem werde ich auch eine Reihe von Beispielen zeigen, um Ihnen bei Aufgaben wie der Erstellung von Benachrichtigungen, beim Verschieben von Inhalten usw. zu helfen. Und schließlich werde ich einige fortgeschrittenere Eigenschaften bei der Entwicklung von Workflows sowie einige nützliche Werkzeuge dabei vorstellen.
Was ist ein Workflow?
Unter einem Workflow versteht man eine Kette von Aktionen oder Ereignissen, die sich abspielen, um ein bestimmtes Ziel zu erreichen. Oftmals wird eine Geschäftslogik mit einem Workflow ausgedrückt. Alle Geschäftsbereiche haben ihre eigenen Regeln und Vorschriften zu Vorgängen, die sich in einer Firma so ereignen. Hier sind einige Beispiele dafür:
- Bevor die Arbeitsstundenaufstellung eines Mitarbeiters genehmigt wird, muss sie von einem Vorgesetzten angeschaut und bestätigt werden.
- In einer Fabrik, die irgendwelche Teile herstellt, müssen die Benutzer für jedes zusammengesetzte Teil über die Bearbeitungsreihenfolge und Zustandsänderungen auf dem Weg durch die Fabrik benachrichtigt werden.
- Bevor eine Seite auf einer Website veröffentlicht wird, muss sie von der Marketingabteilung und vom Webmaster genehmigt und von einem Linguisten übersetzt werden.
Der Workflow kapselt die Geschäftslogik dieser Regeln und standardisiert die Art und Weise, über diese Vorgänge nachzudenken. Durch diese isolierte Geschäftslogik können Firmen eine Anwendung nun leicht gemäß ihrer Tätigkeit und den entsprechenden Prozessen abwandeln. Normale Anwendungen erzwingen oftmals einen Workflow in einem Geschäftsbereich, weil der Workflow darin fest kodiert ist.
Workflow in Plone
Das Workflow-Werkzeug von Plone bietet gewisse Eigenschaften und Beschränkungen, die man kennen muss, um Workflows in Plone zu verstehen. Das in Plone benutzte Workflow-Produkt ist DCWorkflow, ein Open Source-Produkt der Zope Corporation. Es sind auch weitere Workflow-Systeme verfügbar, und einige davon werden in Plone eingesetzt, z.B. CMFOpenFlow, ein aktivitätsbasierender Workflow (http://www.reflab.it/community/Openprojects/CMFOpenflow). Im Moment ist DCWorkflow jedoch mächtig und einfach genug, um alle von den meisten Benutzern gewünschten Eigenschaften zu bieten.
DCWorkflow geht davon aus, dass im System ein Objekt existiert, das als Ziel des Workflows fungiert, z.B. ein gewisser Inhalt oder ein Widget. Weiterhin wird angenommen, dass alle Objekte desselben Typs vom selben Workflow erfasst werden. Durch das Umwidmen (engl. Repurposing) von Inhalten (Details dazu folgen in Kapitel 11) können Sie ähnliche Inhalte mit verschiedenen Workflows bearbeiten.
Da DCWorkflow in Plone enthalten ist, gibt es nichts zusätzlich zu installieren. Im Zope Management Interface (ZMI) wird es vom Objekt portal_workflow dargestellt.
Konzipieren eines Workflows
Bevor ich einen Workflow erkläre, werde ich erst ein wenig die Terminologie dazu erklären: die Begriffe Zustände und Übergänge.
Ein Zustand (state) ist eine Information über ein Inhaltselement zu einem bestimmten Zeitpunkt. Beispielzustände sind Privat, Veröffentlicht, Offen und Entwurf. Alle Workflows verfügen über einen Ausgangszustand, in dem alle Inhalte starten. Der Workflow verschiebt den Inhalt dann durch eine Reihe von Zuständen, und zwar entweder durch eine Interaktion mit dem Benutzer oder durch einen automatisierten Prozess. Wenn der Inhalt einen Endzustand erreicht hat, bleibt er für lange Zeit in diesem Zustand (normalerweise für immer). Während der Workflow aktiv ist, kann ein Inhalt auch einen von mehreren verschiedenen Endzuständen erreichen.
Damit dieser Inhalt von einem Zustand zum anderen gelangt, muss ein Übergang (engl. Transition) dazwischen vorhanden sein. Ein Übergang verbindet einen Start- mit einem Endzustand. Mit einem Übergang können viele verschiedene Eigenschaften verbunden sein, wie Sie später sehen werden, aber im Moment müssen Sie nur wissen, dass ein Übergang einen Inhalt zwischen zwei Zuständen bewegt. Normalerweise wird ein Übergang durch eine äußere Einwirkung ausgelöst, z.B. von einem Benutzer, der auf einer Webseite einen Button anklickt, oder von einem Skript, das von einer Seite aus aufgerufen wird.
Die Visualisierung eines Workflows kann etwas verwirrend sein, besonders dann, wenn man über etwas so Vages wie einen Inhalt spricht. Daher ist es hilfreich, an ein alltägliches Beispiel zu denken. In diesem Fall zeigt das folgende Beispiel den Workflow meiner Kreditkartenrechnung, die mich einmal im Monat beglückt:
- Die Kreditkartenfirma erstellt eine Rechnung und sendet sie per Post an mich.
- Ich erhalte die Rechnung und lege sie auf meinen Schreibtisch. Manchmal liegt die Rechnung dort eine ganze Weile, während ich bis zum Monatsende warte. Gelegentlich muss ich bei Leuten wegen bestimmter Ausgaben nachfragen, z.B. "Was für Kleider hast du da gekauft?"
- Alle ungeklärten Probleme gehen an die Kreditkartenfirma weiter, die möglicherweise eine neue Rechnung ausstellt (was allerdings sehr selten passiert).
- Am Monatsende, wenn ich normalerweise die ganze Buchhaltung mache, bezahle ich dann die Rechnung.
Aus dieser Beschreibung können Sie nun ein paar Zustände ableiten. Wenn Sie sich die obigen Schritte anschauen, stellen Sie fest, dass Sie wirklich keinen Bedarf für verschiedene Zustände beim Erhalt der Rechnung haben, wozu auch das Öffnen und Ablegen auf meinen Schreibtisch gehört. Ebenso wenig müssen Sie sich mit allen Überprüfungen herumschlagen, die vorgenommen werden. Das sind zwar alles wichtige Schritte, die ausgeführt werden, aber einen Workflow für jeden einzelnen Schritt zu erstellen wäre bei weitem zu umständlich. Sie können stattdessen den Workflow mit den folgenden Zuständen zusammenfassen:
- Entwurf: Die Kreditkartenrechnung wurde erstellt und mir zugeschickt.
- Überprüfung: Die Kreditkartenrechnung wurde empfangen, liegt auf meinem Schreibtisch und wird geprüft.
- Bezahlt: Die Kreditkartenrechnung wurde bezahlt, ins Regal abgelegt und für immer vergessen.
Nun haben Sie die Zustände gefunden und können sich Gedanken zu den notwendigen Übergängen machen. Zu jedem Zustand gibt es mindestens einen Übergang, der die Rechnung von einem Zustand in einen anderen bewegt:
- Verschicken: Die Bank verschickt die Kreditkartenrechnung.
- Bezahlen: Ich bezahle die Kreditkartenrechnung.
- Ablehnen: Etwas auf der Rechnung stimmt nicht, und sie wird nicht genehmigt.
Abbildung 8.1 zeigt diesen Satz von Zuständen und Übergängen. In dieser Abbildung werden Zustände mit Namen von Kästen dargestellt, und Zustandsübergänge werden von Pfeilen mit kursiv geschriebenen Namen dargestllt.
Abbildung 8.1. Einfacher Zustandsautomat bei der Bezahlung von Kreditkartenrechnungen
Jetzt haben Sie den Geschäftsvorgang der Bezahlung einer Kreditkartenrechnung in einem Workflow extrahiert. Der nächste Schritt besteht im Nachdenken über Rollen und Sicherheit für diese Kreditkartenrechnung. Dieser Workflow enthält nun die Geschäftslogik einer Anwendung zur Bearbeitung von Kreditkartenrechnungen.
Rollen und Sicherheit in Workflows
In jedem komplizierten System haben Sie Benutzer mit allen möglichen Rollen und Gruppen. Diese Rollen verleihen Plone eine große Flexibilität bei der Sicherheit, können es aber auch komplizierter machen. Kapitel 9 behandelt lokale Rollen und Gruppen, aber dieser Abschnitt behandelt einige wichtige Punkte dazu, wie diese Themen mit dem Workflow zusammenhängen.
Wenn ein Inhaltselement von einem Workflow-Zustand in einen anderen übergeht, kann der Workflow-Prozess die Sicherheitseinstellungen auf diesem Inhalt ändern. Diese Sicherheitseinstellungen bestimmen, welcher Benutzer welche Aktion auf welchem Inhalt ausführen kann. Durch die Manipulation der Sicherheitseinstellungen über den Workflow kann man die Sicherheit eines Inhaltselements über seinen Lebenszyklus hinweg ändern. Benutzer von statischen Systemen oder von Zope sind oftmals verwirrt, weil in Zope alle Inhaltselemente über ihren gesamten Lebenszyklus die gleichen Sicherheitseinstellungen haben.
Was das Kreditkartenbeispiel angeht, können Sie die Sicherheitseinstellungen für die Kreditkartenrechnung ableiten. Eine Möglichkeit, diese darzustellen, besteht darin, eine Tabelle anzulegen, die die Sicherheit für die Übergänge zwischen verschiedenen Zuständen allgemein erweitert, wie in Tabelle 8.1 zu sehen ist.
Tabelle 8.1. Übergänge und ihre erzeugenden Zustände
| Zustand | Ich | Bank |
|---|---|---|
| Entwurf | Abschicken | |
| Überprüfung | Bezahlen | Ablehnen |
| Bezahlt |
In diesem Stadium sehen Sie in Tabelle 8.1 die Übergänge und wer sie erzeugen kann. Sie haben aber noch nicht über den Zugriff nachgedacht, der immer dann erfolgt, wenn ein Benutzer eine Aktion auf einem Objekt ausführt. Wann kann jemand z.B. die Rechnung bearbeiten, und wann kann sie angezeigt werden? Plone verwendet hierfür den Begriff Aktion, wie in Tabelle 8.2 zu sehen ist. Hoffentlich habe nur ich Zugriff auf meine eigenen Kreditkartenauszüge! Ebenso kann die Bank die Kreditkartenrechnung jederzeit anzeigen und Fragen dazu beantworten.
Tabelle 8.2. Aktionen und ihre erzeugenden Zustände
| Zustand | Ich | Bank |
|---|---|---|
| Entwurf | Anzeigen, Bearbeiten | |
| Überprüfung | Anzeigen | Anzeigen |
| Bezahlt | Anzeigen | Anzeigen |
Tatsächlich stellt sich heraus, dass ich meine Kreditkartenrechnung nicht bearbeiten kann, nur die Bank kann das. Ich kann meine Rechnung ablehnen und zurückschicken, aber die Bank will sicher nicht, dass ich die Rechnung bearbeiten kann. In dieser Situation nehmen Sie an, dass die Bank der Besitzer der Kreditkartenrechnung ist. Hiermit wird das Konzept eines Besitzers (engl. Owner) demonstriert. Ich habe evtl. mehrere Kreditkartenrechnungen von mehreren Banken, und bei jeder können Sie sich die Bank als deren Besitzer vorstellen. Jede Bank besitzt ihre eigenen Kreditkartenrechnungen, aber nicht die anderer Banken. Tabelle 8.3 kombiniert Übergänge und Aktionen, wobei die Begriffe Ich und Bank jeweils in Bezahler und Besitzer geändert wurden.
Tabelle 8.3. Übergänge und Aktionen kombiniert, plus Rollen der Leute
| Zustand | Bezahler | Besitzer |
|---|---|---|
| Entwurf | Abschicken, Anzeigen, Bearbeiten | |
| Überprüfung | Bezahlen, Ablehnen, Anzeigen | Anzeigen |
| Bezahlt | Anzeigen | Anzeigen |
Natürlich ist das ein sehr gestelltes Beispiel, aber es illustriert, wie Sie einen Workflow auf einfache Zustände anwenden können. Es können hier auch weitere Übergänge erfolgen, z.B. wäre ich sehr froh, wenn meine Kreditkartenrechnungen von jemand anderem bezahlt würden, aber das ist leider so unwahrscheinlich, dass Sie das nicht zum Workflow oder zur Sicherheit aufnehmen sollten.
Bevor ich Ihnen zeige, wie Sie Workflows erstellen und bearbeiten, zeige ich Ihnen jetzt noch die Standard-Workflows, die in Plone enthalten sind.
Einführung in Plone-Workflows
Plone enthält bereits eine Reihe von Standard-Workflows für Ihre Plone-Site. Diese Workflows bieten eine logische Art und Weise, Inhalte durch eine Plone-Site zu schleusen. Eine Standard-Plone-Site enthält zwei Workflows: den Default-Workflow und den Ordner-Workflow (Folder-Workflow). In den folgenden Abschnitten werden beide vorgestellt.
Default-Workflow
In Kapitel 3 habe ich den Default-Workflow und die Standardeinstellungen bei der Veröffentlichung von Inhalten behandelt. Dort habe ich für jeden Zustand im Workflow dessen Sicherheit und Einstellungen beschrieben. Aber da ein Bild mehr sagt als tausend Worte, sehen Sie in Abbildung 8.2 diese Workflow-Zustände.
Abbildung 8.2. Default-Workflow in Plone für Inhalte
Abbildung 8.2 zeigt die Hauptzustände und -übergänge. Die grau gepunktete Linie in dieser Abbildung stellt eine Art Trennung zwischen Sicherheitsbereichen dar. Links von dieser Linie sind es die Besitzer von Inhalten, die damit interagieren, und rechts von der Linie interagieren normalerweise die Prüfer mit den Inhalten.
Hinweis
Der Besitzer des Inhalts ist jene Person, die den Inhalt ursprünglich erstellt hat. Ein Besitzer ist ein bestimmtes Mitglied einer Plone-Site. Zwar existieren auf einer Plone-Site viele Mitglieder, aber nur eine Person kann Besitzer eines Inhalts auf einer Plone-Site sein. Diese Besitzerrolle ist insofern speziell, als sie sich erst dann ergibt, wenn ein Objekt angelegt wird.
Wie beim Kreditkartenbeispiel ist auch hier ein zugehöriger Satz an Rechten für den Default-Workflow vorhanden. Tabelle 8.4 gibt alle Rechte und Zustände an.
Tabelle 8.4. Rechte im Default-Workflow
| Zustand | Anonym | Authentifiziert | Besitzer | Manager | Prüfer |
|---|---|---|---|---|---|
| Offen | Anzeigen | Anzeigen | Anzeigen | Bearbeiten | Bearbeiten |
| Privat | Bearbeiten | Bearbeiten | Anzeigen | ||
| Veröffentlicht | Anzeigen | Anzeigen | Anzeigen | Bearbeiten | Anzeigen |
| Sichtbar | Anzeigen | Anzeigen | Bearbeiten | Bearbeiten | Anzeigen |
| Anzeigen bezieht sich auf folgende Rechte: Access, Contents, Information und View | |||||
| Bearbeiten bezieht sich auf folgende Rechte: Modify, Portal und Content | |||||
Wie Sie in Tabelle 8.4 sehen können, werden Inhalte nur dann standardmäßig vor anderen verborgen, wenn sie im Zustand Privat sind. Inhalte im Zustand Veröffentlicht kann nur der Manager bearbeiten. Im Abschnitt "Rechte bearbeiten", der weiter unten folgt, werde ich Ihnen zeigen, wie Sie diese Rechte ganz einfach über das Web ändern können.
Ordner-Workflow
Ebenfalls in Kapitel 3 habe ich den Ordner-Workflow beschrieben, als ich die Veröffentlichung von Inhalten behandelt habe. Aber wie ich dort bemerkt habe, gibt es für Ordner keinen offenen Zustand. Deswegen haben Sie einen etwas einfacheren Workflow, wie in Abbildung 8.3 gezeigt.
Abbildung 8.3. Ordner-Workflow in Plone für Inhalte
Weitere Workflows
Für eine Plone-Website sind zahlreiche Workflows verfügbar, darunter ein privater Workflow, ein Community-Workflow, ein One-Step Publication-Workflow usw. ZopeZen enthält einen Workflow, und PloneCollectorNG enthält ebenfalls einen Workflow. DCWorkflow enthält vier Workflows.
Zurzeit enthält das Produkt PloneWorkflows im Collective-Projekt auf SourceForge (http://sf.net/projects/collective) zwei Workflows: den Community-Workflow und den One-Step Publication-Workflow. Der Community-Workflow ähnelt bis auf ein paar Änderungen dem Plone-Workflow. Der One-Step Publication-Workflow verfügt über zwei Zustände: privat und veröffentlicht.
Im Moment gibt es keine einfache Möglichkeit, Workflows zu installieren bzw. zu deinstallieren, ebenso wenig wie es eine wirklich einfache Methode gibt, den Zustand von Inhalten zu wechseln. Wenn Sie z.B. den One-step Publication-Workflow bei einem vorhandenen Zustand installieren, müssen Sie auch die Zustände für alle Objekte reparieren und sie in einen der neuen Zustände überführen. In diesem Fall ist das wahrscheinlich einfach: Alles im Zustand Veröffentlicht sollte so bleiben, wie es ist, und alles andere sollte in den Zustand Privat wechseln.
Workflows hinzufügen und bearbeiten
Nachdem ich den Default-Workflow beschrieben habe, komme ich zum Hauptpunkt, der Sie wahrscheinlich am meisten interessiert: Wie können Sie die Defaults ändern? Nun, wie bei den meisten Dingen in Plone können Sie alle Workflows über das ZMI erstellen, bearbeiten und löschen. Das Werkzeug, mit dem der Workflow gesteuert wird, lautet portal_workflow. In den folgenden Abschnitten behandle ich, wie Workflows zugewiesen werden, und gehe dann im Detail durch alle Einstellungen bei einem Workflow durch.
Workflows auf Inhaltstypen setzen
Nach einem Klick auf portal_workflow sehen Sie eine Liste von Workflow-Zuweisungen. Ein Merkmal von DCWorkflow ist, das jedem Inhaltstyp genau ein Workflow zugewiesen ist. Abbildung 8.4 zeigt diese Zuweisungen.
Abbildung 8.4. Die Workflow-Liste nach Typ
Auf dieser Seite sehen Sie eine Liste aller Inhaltstypen und des darauf angewendeten Workflows. Falls kein Workflow angegeben ist, d.h. falls der Wert leer ist, wird kein Workflow angewendet. Der Standardwert z.B. für den Typ Portal Site (Plone Site) ist leer. Ganz bestimmt möchten Sie nicht den Zustand der Plone-Site selbst wechseln, sondern nur den Zustand der Objekte darin. Falls der Wert (Default) lautet, wird der Default-Workflow unten auf der Seite auf diesen Inhaltstyp angewendet. In Abbildung 8.4 wird der Workflow folder_workflow für Themen und Ordner benutzt, und bei allen anderen Inhaltstypen wird plone_workflow angewendet. Die Namen eines Workflows beziehen sich auf den Namen von Workflow-Objekten, die innerhalb des Workflow-Werkzeugs importiert oder erstellt werden. Weitere Informationen über verfügbare Workflows finden Sie, wenn Sie auf den Contents-Reiter klicken. Danach wird eine Liste von Workflows geöffnet, die im System geladen sind, wie in Abbildung 8.5 zu sehen ist.
Abbildung 8.5. Verfügbare Workflows
Sie können Workflows hinzufügen, indem Sie auf den Button Add Workflow klicken. Dadurch wird eine Liste verfügbarer Workflows geöffnet. Um einen Workflow zu erstellen, wählen Sie einen Workflow-Typ und geben einen Workflow-Namen ein. Um einen leeren, aber über das Web konfigurierbaren Workflow zu erstellen, wählen Sie dc_workflow und geben einen passenden Namen ein, z.B. mein_workflow.
Bearbeiten eines Workflows
Unter dem Contents-Reiter können Sie auf einen Workflow klicken, um zu den Management-Bildschirmen für alle Zustände, Übergänge und Eigenschaften zu diesem Workflow zu gelangen. Die Reiter oben auf der Seite beschreiben recht gut die Funktionalität eines Workflows: States (Zustände), Transitions (Übergänge), Variables (Variablen), Worklists, Scripts und Permissions (Rechte). Ich werde all diese Reiter und einige andere verfügbare Optionen durchgehen. Falls nichts Gegenteiliges gesagt wird, sind alle folgenden Reiter von der Workflow-Hauptseite aus erreichbar.
Das Erstellen und Bearbeiten von Workflows verlangt mitunter viel Klickerei und kann ein wenig verwirrend sein. Wenn Sie als Entwickler scharf darauf sind, das Dateisystem zu benutzen, können Sie all das aus Python heraus tun, wenn Sie möchten. Ich werde das im Abschnitt "Workflows in Python schreiben" gegen Ende des Kapitels behandeln.
Ausgangszustand setzen
Um den Ausgangszustand zu setzen, gehen Sie zum States-Reiter und prüfen die verfügbaren Zustände. Neben einem der Zustände werden Sie ein Sternchen wie in Abbildung 8.6 sehen.
Abbildung 8.6. Ausgangszustand für diesen Workflow setzen
Auf dieser Seite setzen Sie den Ausgangszustand für Ihren Workflow, indem Sie das Kontrollkästchen neben dem Zustand markieren und dann auf Set Initial State klicken. Alle Inhalte, die diesen Workflow benutzen, werden in diesem Ausgangszustand erzeugt. Alle anderen schon erzeugten Inhalte bleiben in ihrem Zustand. Bei einer späteren Zustandsänderung wird dieser Zustand nicht verändert. Zu jedem Workflow können Sie nur einen Ausgangszustand einstellen.
Zustände bearbeiten
Unter dem States-Reiter werden die in diesem Workflow vorhandenen Zustände aufgelistet. Am Anfang dieses Kapitels habe ich erklärt, dass ein Zustand ein Objekt zu einem bestimmten Zeitpunkt darstellt. Jeder Zustand hat eine eindeutige ID, normalerweise ein einfaches Verb wie pending (offen) oder published (veröffentlicht). Um einen Zustand hinzuzufügen, geben Sie eine ID ein und klicken unten auf der Seite auf Add.
Außerdem werden Sie die folgenden Optionen sehen:
- Title: Der Titel des Zustands wird in Ihrer Plone-Site angezeigt. Er ist ein benutzerfreundlicher Name für den Zustand.
- Description: Dies ist eine längere Beschreibung des Zustands. Momentan können die Benutzer diese Beschreibung nicht sehen, aber das kann sich in Zukunft noch ändern.
- Possible transitions: Hier werden die möglichen Übergänge aufgelistet, die aus diesem Zustand heraus erfolgen können. Diese Liste erscheint nur dann, wenn Sie tatsächlich einen Übergang im System haben. Wählen Sie einfach die Übergänge aus, die aus diesem Zustand erfolgen müssen. Durch die Wahl eines Übergangs für diesen Zustand machen Sie diesen Zustand zum Startpunkt des gewählten Übergangs.
Um einen Zustand zu ändern, geben Sie die Änderungen ein und klicken dann auf Save, um diese zu bestätigen. Der Permissions-Reiter wird geöffnet und zeigt die Rechte an, die auf dem Objekt in diesem Zustand angewendet werden. Das kann bedeuten, dass sich die Rechte des Objekts ändern, wenn es in diesen Zustand übergeht. Das Formular ist ziemlich selbsterklärend. Damit ein anonymer Benutzer das Objekt sehen kann, markieren Sie die Kästchen für View und Anonymous und klicken Sie auf Save, wie in Abbildung 8.7 zu sehen ist.
Abbildung 8.7. Seite für Zustandsrechte
Wenn Sie die Rechte an einem bestimmten Workflow-Zustand ändern, haben Sie ein Problem, das Sie lösen müssen. Diese neuen Workflow-Rechte werden nicht auf den vorhandenen Inhalten in diesem Zustand gesetzt. Diese Inhalte haben weiterhin die alten Workflow-Rechte, und Sie müssen sie aktualisieren. Wenn Sie mit Ihren Änderungen fertig sind, gehen Sie in die Workflow-Ausgangsseite und klicken auf Update Security Settings, wie in Abbildung 8.4 gezeigt wird. Es kann eine Weile dauern, diese Aktualisierung durchzuführen, je nachdem, wie viele Objekte davon betroffen sind.
Der Variables-Reiter gestattet Ihnen die Zuweisung eines Wertes an eine Variable, falls das Objekt in diesem Zustand ist. Der Workflow bestimmt für jeden Zustand die Liste der verfügbaren Variablen. Weitere Informationen dazu finden Sie im Abschnitt "Variablen bearbeiten".
Übergänge bearbeiten
Der Transitions-Reiter listet die Übergänge auf, die in diesem Workflow erfolgen können. Zu Beginn dieses Kapitels habe ich Ihnen gezeigt, wie ein Übergang Änderungen darstellt, die auf dem Objekt erfolgen. Jeder Übergang hat einige Variablen, die auf der Zusammenfassungsseite angezeigt werden. Um einen Übergang hinzuzufügen geben Sie eine ID ein und klicken unten auf der Seite auf Add, wie in Abbildung 8.8 zu sehen ist.
Abbildung 8.8. Seite mit Übergangsdetails
Wenn Sie nun auf einen Übergang klicken, öffnen Sie die Details zu diesem Übergang:
- Title: Dies ist der Titel des Übergangs.
- Description: Dies ist die detaillierte Beschreibung des Übergangs.
- Destination state: Das ist der Zielzustand dieses Übergangs. Der Ursprungszustand wird bei der Zuweisung des Übergangs an einen Zustand definiert.
- Trigger type: Hiermit wird angegeben, wodurch der Übergang ausgelöst wird. Automatic bedeutet, dass er sofort ausgelöst wird, wenn dieser Zustand erreicht wird. Initiated by user action ist die am häufigsten gewählte Einstellung und bedeutet, dass ein Benutzer den Übergang ausgelöst hat, indem er einen Link angeklickt hat.
- Script (before): Dieses Skript wird ausgeführt, bevor der Übergang erfolgt.
- Script (after): Dieses Skript wird ausgeführt, nachdem der Übergang erfolgt ist.
- Guard: Dies ist der Wächter bei diesem Zustand (wird gleich erklärt).
- Display in actions box: Hier wird angegeben, wie dieser Übergang in Plone dargestellt wird. Eine Eingabe an dieser Stelle garantiert, dass der Übergang auch als Aktion eingegeben wird. Sie erhalten diesen Übergang als Aktion, wenn Sie nach Aktionen fragen.
Unter diesen Werten ist der Zielzustand recht interessant. Ich habe zwar schon erwähnt, dass Übergänge normalerweise den Zustand wechseln, aber das muss nicht so sein. Da bei jedem Übergang Skripten ausgeführt werden können und etwas protokolliert werden kann, ist es manchmal nützlich, den Zustand nicht zu wechseln. Betrachten Sie als Beispiel hierfür den Abschnitt "Änderungen mit einem Workflow verfolgen" weiter unten in diesem Kapitel. Wenn Ihr Übergang den Zustand wechselt, wählen Sie den neuen Zustand als Zielzustand.
Ein Übergang kann mehrere Startpunkte, aber nur ein Ziel haben. Wenn Sie mehrere Ziele brauchen, müssen Sie mehrere Übergänge anlegen. Sie können auch Skripten angeben, die vor und nach diesem Übergang ausgeführt werden. Zwei häufige Beispiele hierfür sind das Verschieben eines Objekts im Workflow und das Senden von Benachrichtigungen per E-Mail. Beide Beispiele werden im Abschnitt "Häufige Aufgaben und Beispiele" behandelt.
Bevor ein Übergang erfolgt, wird er von einem Sicherheitswächter (Guard) überprüft, um sicherzustellen, dass der Benutzer auch das Recht hat, den Übergang auszuführen. Dieser Wächter besteht aus den folgenden drei Komponenten:
- Permission(s): Dies sind die notwendigen Rechte. Mehrere Rechte sollten durch ein Semikolon (;) voneinander getrennt sein.
- Role(s): Dies sind die notwendigen Rollen. Mehrere Rollen sollten durch ein Semikolon (;) voneinander getrennt sein.
- Expression: Dies ist ein Workflow-Ausdruck. Weitere Informationen dazu finden Sie im Abschnitt "Workflow-Ausdrücke bearbeiten" weiter unten in diesem Kapitel. Für jeden angegebenen Wert muss der Wächter den Wert logisch wahr ergeben, bevor weitergemacht werden kann. Falls ein Test bei einem der Werte fehlschlägt, wird der Übergang nicht ausgeführt. Meistens sind bei einem Wächter nur ein oder zwei Werte angegeben.
Variablen bearbeiten
Der Variables-Reiter listet die Variablen auf, die im Workflow erzeugt und geändert werden. Bisher habe ich diese Variablen nicht groß erwähnt, sondern habe mich auf Zustände und Übergänge konzentriert. In diesem Abschnitt geht es nun um Variablen.
Es ist nicht immer möglich, alle in einem Workflow benötigten Informationen in Zuständen und Übergängen zu kapseln. Und ich rate Ihnen auch nicht, das unbedingt zu versuchen. Stattdessen können Sie Variablen verwenden, um einige Workflow-bezogene Informationen zu speichern. Im Kreditkartenbeispiel könnte die Rechnung z.B. auf mehrere Arten beglichen werden, z.B. per Online-Banking, Scheck usw. Sie könnten den Betrag (z.B. 100 Euro) in einer Variablen speichern. Sollte die Rechnung abgelehnt oder verändert werden, würde dieser Betrag aktualisiert. Der wesentliche Punkt bei einer Variablen ist der, dass man etwas hat, das sich zwischen den Zuständen und Übergängen ändern kann.
Klicken Sie nun wieder in der Workflow-Hauptseite auf den Variables-Reiter, um eine Liste aller Variablen zu bekommen. Um eine Variable hinzuzufügen, geben Sie eine Variablen-ID ein und klicken unten auf der Seite auf Add. Um zu bestimmen, in welchem Zustand ein Objekt zu einer bestimmten Zeit ist, speichert DCWorkflow den aktuellen Zustand in einer Variablen im Objekt. Standardmäßig lautet der Name dieser Variable review_state.
Hinweis
Sollten Sie diesen Namen ändern müssen, weil es einen Konflikt mit einem anderen Namen gibt, können Sie das unten auf der Seite tun. Dabei geht allerdings der Zustand all Ihrer aktuellen Objekte verloren. Seien Sie also bei einer solchen Änderung vorsichtig.
Alle Workflow-Variablen verfügen über die folgenden Eigenschaften:
- Description: Dies ist eine Beschreibung der Variablen.
- Make available to catalog: Diese Variablen werden in einer Liste platziert, auf die der Katalog zugreifen kann. Dabei werden kein Index oder Metadaten zum Katalog hinzugefügt. Das müssen Sie weiterhin von Hand machen.
- Store in workflow: Hiermit wird bestimmt, ob die Information im Workflow oder im Objekt gespeichert wird.
- Variable update mode: Dies bestimmt, wann die Variable aktualisiert wird.
- Default value: Das gibt einen Standardwert als String an.
- Default expression: Dies ist der Standardwert als Ausdruck. Wenn er vorhanden ist, wird er an Stelle des String-Wertes verwendet (weitere Informationen finden Sie im Abschnitt "Workflow-Ausdrücke bearbeiten" weiter unten in diesem Kapitel).
- Info. guard: Das sind Sicherheitseinstellungen beim Zugriff auf diese Variable. Diese Wächtereinstellungen ähneln jenen eines Übergangs. Hierbei wird der Wächter allerdings dann ausgeführt, wenn auf die Variable zugegriffen wird.
Worklists bearbeiten
Der Worklists-Reiter bietet einen Zugriff auf alle Worklists, die in diesem Workflow zugewiesen sind. Eine Worklist ist eine Methode, den Workflow nach Informationen über die Anzahl von Objekten in diesem Workflow zu fragen. Ich möchte z.B. gern den Workflow einfach nach allen ausstehenden Kreditkartenrechnungen für mich fragen.
Um eine Worklist hinzuzufügen, geben Sie eine ID ein und klicken auf Add. Alle Worklists verfügen über folgende Eigenschaften:
- Description: Dies ist eine Beschreibung der Worklist.
- Cataloged variable matches: Dies ist der Wert, auf den die Workflow-Variable eines Objekts passen muss, damit es zu dieser Worklist hinzugefügt wird. Die passende Variable ist die Workflow-Zustandsvariable, die in der Variablenliste angegeben ist (der Standardname dieser Variablen lautet review_state).
- Display in actions box: Diese Information soll in der Benutzerschnittstelle angezeigt werden. Die Eingabe eines Wertes an dieser Stelle stellt auch sicher, dass der Übergang als Aktion eingetragen wird. Sie erhalten diesen Übergang als Aktion, wenn Sie nach den Aktionen fragen.
- Guard: Dies ist ein Wächter für den Zugriff auf diese Worklist.
Kommen wir wieder zum Kreditkartenbeispiel zurück: Wenn ich gerne wüsste, welche Kreditkartenrechnungen ich alle überprüfen muss, könnte ich diese Information in einer Worklist angeben. Zuerst würde die Variable review_state den aktuellen Zustand jedes Elements enthalten. Alle zu überprüfenden Kreditkartenrechnungen wären im Zustand review (überprüfen). Zweitens würde ich eine Worklist namens review_queue hinzufügen, und der Variablenwert wäre pending (offen). Nun würde ich die Worklist nach allen Elementen in review_queue fragen.
Obwohl Worklists eine bequeme Art sind, diese Information zu speichern, benutzt Plone selbst keine Worklists. Stattdessen benutzt Plone direkt ZCatalog, um Objekte abzufragen, die sich in einem Workflow befinden. Da die DCWorkflow-Worklist das Katalog-Werkzeug verwendet, ist das Ergebnis das gleiche.
Skripten bearbeiten
Der Scripts-Reiter listet die Skripten auf, die in diesem Workflow verfügbar sind. Diese Liste ist eigentlich ein normaler Ordner im ZMI, und Sie können darin fast alles hinzufügen. Der Hauptgrund dafür ist vermutlich der, ein Skript hinzuzufügen, um eine kompliziertere Behandlung von Übergängen zu bewerkstelligen, d.h., Sie sollten an dieser Stelle nur Script (Python)-Objekte hinzufügen.
Um ein Skript unter dem Scripts-Reiter hinzuzufügen, wählen Sie im Add-Dropdown-Menü die Option Script (Python) und geben dem Skript eine ID. Dem Skript wird genau ein Objekt übergeben, nämlich das Ausdrucksobjekt des Basis-Workflows. Weitere Informationen darüber finden Sie im Abschnitt "Workflow-Skripten bearbeiten" weiter unten in diesem Kapitel. Wenn Sie z.B. auf das eigentliche Objekt im Workflow zugreifen müssen, können Sie ein Python-Skript wie folgt benutzen:
##parameters=state_change obj = state_change.object
Was in diesem Skript passiert, entscheidet dessen Entwickler. Sie können hier fast alles machen. Sie können Ereignisse auslösen, und Sie können auf andere Workflows und Übergänge zugreifen. Einige Beispielskripten finden Sie in den Abschnitten "Benachrichtigungen per E-Mail versenden" und "Objekte verschieben" im weiteren Verlauf dieses Kapitels. Wenn das Skript ausgeführt wird, wird es unter dem Benutzer ausgeführt, der den Übergang eingeleitet hat. Sie könnten dem Skript eine Proxy-Rolle zuweisen, wenn es unter einem anderen Benutzer ausgeführt werden muss. Was die Übergänge angeht, so können Sie dieses Skript in den Einstellungen zu script (after) und script (before) an beliebig viele Übergänge zuweisen. Sie können das Skript entweder vor oder nach einem Übergang ausführen.
Rechte bearbeiten
Der Permissions-Reiter listet die von diesem Workflow verwalteten Rechte auf. Diese Rechte haben Sie schon bei der Behandlung von Zuständen gesehen. Unter diesem Reiter setzen Sie die Liste der Rechte, die in diesen Zuständen verwaltet werden. Ein neues Recht fügen Sie hinzu, indem Sie es im Dropdown-Menü auswählen und auf Add klicken.
Workflow-Skripten bearbeiten
Skripten bieten dem Entwickler die Möglichkeit, bei der Ausführung eines Übergangs eine zusätzliche Anwendungslogik auszuführen. Das kann fast alles sein, was Sie tun möchten. Sie könnten z.B prüfen, ob gewisse Bedingungen erfüllt sind (z.B. ob die Rechtschreibung beim Dokument geprüft wurde) oder ob spezielle Aktionen ausgeführt wurden. Wenn ein Objekt seinen Zustand wechselt, wird das Skript aufgerufen.
Wenn ein Skript aufgerufen wird, wird ihm ein zusätzlicher Parameter übergeben. Dieser zusätzliche Parameter ermöglicht den Zugriff auf alle Arten von übergangsbezogenen Elementen und Attributen. Dieser Parameter wird auch state_change-Parameter genannt und hat folgende Attribute:
- status: Dies ist der Status des Workflows.
- object: Dies ist das Objekt, das im Workflow einen Zustandswechsel durchmacht.
- workflow: Dies ist das aktuelle Workflow-Objekt zu dem betroffenen Objekt.
- transition: Dies ist das aktuell ausgeführte Übergangsobjekt.
- old_state: Dies ist der Ursprungszustand des Objekts.
- new_state: Dies ist der Zielzustand des Objekts.
- kwargs: Dies sind die Schlüsselargumente, die an die Methode doActionFor übergeben werden.
- getHistory: Dies ist eine Methode, die keine Parameter hat und eine Kopie der Workflow-Historie des Objekts zurückgibt.
- getPortal: Dies ist eine Methode, die keine Parameter hat und das Plone-Wurzelobjekt zurückgibt.
- ObjectDeleted(ordner): Dies sagt dem Workflow, dass das Objekt, dessen Zustand wechselt, gelöscht wurde. Diese Methode erwartet das Objekt, zu dem der Benutzer zurückkehren soll. Übergeben Sie der Ausnahme den Ordner, zu dem der Benutzer umgeleitet werden soll (siehe den Abschnitt "Objekte verschieben" weiter unten in diesem Kapitel).
- ObjectMoved(neuesObjekt, neuesObjekt): Dies sagt dem Workflow, dass das Objekt, dessen Zustand wechselt, verschoben wurde. Übergeben Sie der Ausnahme den Ordner, zu dem der Benutzer umgeleitet werden soll (siehe den Abschnitt "Objekte verschieben" weiter unten in diesem Kapitel).
- getDateTime: Dies ist eine Methode, die keine Parameter hat und das zum Übergang gehörende DateTime-Objekt zurückgibt.
Um z.B. herauszufinden, zu welchem Zielzustand ein Übergang erfolgt und wann, können Sie das folgende Script (Python)-Objekt verwenden, das Ihnen genau diese Information liefert. Dieses Skript schreibt die Information über den Übergang in die Protokolldatei:
##parameters=state_change
st = 'From %s to %s on %s' % (
state_change.old_state,
state_change.new_state,
state_change.getDateTime())
context.plone_log(st)
Tipp
Wenn Sie ein Script (Python)-Objekt schreiben, müssen Sie eventuell etwas in die Protokolldatei ausgeben, um sich die Fehlersuche leichter zu machen. Ein Skript namens plone_log tut genau das. Es erwartet einen String, den es an die Protokollfunktionen von Plone übergibt. Daher sind Aufrufe von context.plone_log bei der Fehlersuche sehr hilfreich.
Bei der Zuweisung eines Skripts an einen Übergang haben Sie zwei Möglichkeiten: before und after. Wie diese Namen schon besagen, wird ein Skript, das an before zugewiesen wird, ausgeführt, bevor der Übergang erfolgt. Das eignet sich für Skripten, die prüfen, ob etwas noch vor dem Übergang passieren soll, die also z.B. testen, ob ein weiteres abhängiges Objekt oder eine Seite hochgeladen wurde oder ob etwas frei von Tippfehlern ist. Das an after zugewiesene Skript wird ausgeführt, nachdem der Übergang beendet ist. Sollte aber eine irgendwann ausgelöste, nicht abgefangene Ausnahme in einem Skript auftreten, dann führt das dazu, dass der Übergang fehlschlägt, das Objekt in seinem ursprünglichen Zustand bleibt und dem Benutzer die Ausnahme angezeigt wird.
Workflow-Ausdrücke bearbeiten
In diesem Kapitel haben Sie durchgehend Werte gesehen, die als Workflow-Ausdrücke ausgedrückt werden können. Der Wert beispielsweise, der einer Variablen zugewiesen wird, ist das Ergebnis eines Workflow-Ausdrucks. Dieser Ausdruck ist nichts Ungewöhnliches, sondern lediglich ein TAL-Ausdruck (Template Attribute Language) mit einigen anderen verfügbaren Variablen. TAL-Ausdrücke haben Sie bereits in Kapitel 5 kennen gelernt, d.h., Sie sollten mit diesen Ausdrücken und ihren Optionen wie Python-, String- und Pfadausdrücken vertraut sein.
Anders als bei den normalen TAL-Ausdrücken werden einige zusätzliche Parameter mit Bezug auf den konkreten Workflow über den Namespace übergeben. Der Namespace eines Workflow-Ausdrucks enthält Folgendes:
- here: Dies ist das Objekt, das im Workflow einen Zustandswechsel erfährt.
- container: Dies ist der Container des Objekts, das im Workflow den Zustandswechsel erfährt.
- state_change: Dies ist das Zustandswechselobjekt, das im Abschnitt "Workflow-Skripten bearbeiten" erwähnt wurde.
- transition: Dies ist der gerade ausgeführte Übergang; identisch mit state_change.transition.
- status: Dies ist der ursprüngliche Zustand, identisch mit state_change.old_state.
- workflow: Dies ist der Workflow für dieses Objekt.
- scripts: Dies sind die in diesem Workflow verfügbaren Skripten.
- user: Dies ist der Benutzer, der den Übergang ausführt.
Häufige Aufgaben und Beispiele
Ich werde Ihnen nun einige Aufgaben vorstellen, die Sie leicht mit einem Workflow bewerkstelligen können. Wenn ein Benutzer einen Übergang im Workflow bewirkt, wird dieser Übergang mit den Rechten dieses konkreten Benutzers ausgeführt. In vielen dieser Beispiele verfügt ein normaler Benutzer möglicherweise nicht über die notwendigen Rechte, um die Aufgabe auszuführen. Mitglieder haben z.B. normalerweise kein Recht, auf die Liste der Mitglieder zuzugreifen, sofern ihnen dieses Recht nicht explizit gewährt worden ist.
Um dieses Rechteproblem zu lösen, wurde da, wo es vermerkt ist, einigen der folgenden Script (Python)-Objekte eine leicht andere Rolle gegeben. Um auf einem Skript eine Proxy-Rolle zu setzen, greifen Sie auf den Proxy-Reiter eines Objekts zu und wählen dann den Benutzer, der das Skript ausführen soll, wie in Abbildung 8.9 zu sehen ist.
Abbildung 8.9. Proxy-Einstellungen eines Skripts setzen
Natürlich würden Sie dabei dafür sorgen, dass Ihre Skripten mit den minimal notwendigen Rollen ausgeführt werden, je nachdem, was Ihr Skript genau macht.
Einführung in Workflow-Ausdrücke
Im Folgenden sehen Sie einige nützliche Beispiele von Workflow-Ausdrücken, die an verschiedenen Stellen verwendet werden können.
Benutzen Sie Folgendes, um die Kommentare eines Übergangs bzw. einen leeren String zu erhalten:
python:state_change.kwargs.get('comment', '')
Um den Titel eines Ordners zu erhalten, in dem das Objekt enthalten ist, benutzen Sie Folgendes:
container/Title
Um zu testen, ob der alte Zustand gleich Offen (pending) ist, schreiben Sie Folgendes:
python: state_change.old_state == 'pending'
Um an den Benutzer zu kommen, der den Übergang ausführt, benutzen Sie Folgendes:
user/getId
Wenn Sie also mitverfolgen möchten, welcher Benutzer zuletzt den Zustand eines Objekts verändert hat, könnten Sie eine Variable namens last_user zum Workflow hinzufügen. Das machen Sie, indem Sie zum Workflow gehen, dann auf den Variables-Reiter klicken und anschließend die Variable last_user hinzufügen. Wenn Sie die Variable Default expr auf user/getId setzen, würde dieser Wert jedes Mal für Sie gespeichert, wenn das Objekt seinen Zustand ändert.
Änderungen mit einem Workflow verfolgen
Ein Kunde von mir wollte für eine spezielle Anwendung mitverfolgen, wann immer und aus welchem Grund ein Element bearbeitet wurde, so dass bei einer späteren Prüfung des Elements zu jeder Änderung ein Kommentar vorhanden wäre. Mit Hilfe eines Workflows war das recht einfach zu realisieren.
In diesem Fall bestand der Workflow aus nur einem Zustand, aber das würde sogar bei fast allen Workflows funktionieren. Bei diesem speziellen Workflow wurde ein Übergang namens edit hinzugefügt, der nicht wirklich den Objektzustand verändert. Der Zielzustand dieses Übergangs war (Remain in state), d.h., es fand kein Wechsel statt.
Wenn ein Objekt bearbeitet wird, wird eine Methode aufgerufen, die den Übergang ausführt. Wenn z.B. ein Dokument bearbeitet wird, lautet die aufgerufene Methode document_edit.cpy. Dieses Skript finden Sie, wenn Sie nacheinander portal_skins, plone_form_scripts und document_edit anklicken. Sie müssen lediglich eine Zeile vor der letzten Zeile dieses Skripts hinzufügen:
context.portal_workflow.doActionFor(new_context, 'edit', comment='')
Die Methode doActionFor in portal_workflow führt den gegebenen Übergang (in diesem Fall edit) auf dem übergebenen Objekt durch (in diesem Fall context). Jedes Mal, wenn das Objekt bearbeitet wird, wird dieser edit-Übergang ausgelöst. Das führt dann dazu, dass eine Zeile zur Kommentarliste hinzugefügt wird, in der neben einem Kommentar steht, wer das Objekt bearbeitet hat und wann es hinzugefügt wurde.
Eigentlich gibt es keinen Kommentar, wenn ein Objekt bearbeitet wird. Das heißt, um es ganz richtig zu machen, müssten Sie das Bearbeiten-Template des Dokuments so modifizieren, dass es ein Kommentarfeld enthält. Dann könnten Sie mit dem content_status_history-Formular auf diese Kommentarliste zugreifen, wo unten die Liste der Änderungen angezeigt wird. Dieses Formular erreichen Sie, indem Sie im Workflow-Menü auf erweitert klicken.
Objekte verschieben
Eine nützliche Fähigkeit ist die, ein Objekt im Workflow zu verschieben. Sie könnten z.B. immer dann, wenn Sie eine Pressemitteilung veröffentlichen, alle Pressemitteilungen in einen Ordner namens Press Release verschieben. Inhalte könnten irgendwo erstellt und bearbeitet werden, um dann bei ihrer Veröffentlichung in diesen Ordner verschoben zu werden. Das Beispielskript in Listing 8.1 verschiebt das vom Workflow erfasste Objekt in den Members-Ordner. Um dieses Skript hinzuzufügen, gehen Sie im ZMI zum Workflow-Werkzeug und klicken auf den Scripts-Reiter. Dann wählen Sie Script (Python) im Dropdown-Menü aus. Nun geben Sie dem neuen Objekt den Namen moveObject und geben dann den Code aus Listing 8.1 in diesem Skript ein.
Listing 8.1. Ein Objekt verschieben
##parameters=state_change # get the object and its ID obj = state_change.object id = obj.getId() # get the src folder and the destination folder dstFldr = context.portal_url.Members srcFldr = obj.aq_parent # perform the move objs = srcFldr.manage_cutObjects([id,]) dstFldr.manage_pasteObjects(objs) # get the new object new_obj = dstFldr[id] # pass new_obj to the error, *twice* raise state_change.ObjectMoved(new_obj, new_obj)
Sie müssen noch ein paar andere Dinge machen. Zuerst weisen Sie dieses Skript einem Übergang zu. Ich benutze ein solches Skript normalerweise im Publish-Übergang. Dazu gehen Sie zum Übergang und weisen moveObject den Wert script (after) zu.
Zweitens gibt es noch ein kleines Problem: Dieses Skript verschiebt Objekte in den Members-Ordner. Wahrscheinlich schwebt Ihnen ein besserer Ort dafür vor. Um ein solches Verschieben vorzunehmen, muss ein Benutzer die geeigneten Rechte haben, um Objekte zwischen diesen Ordnern zu bewegen. Normalerweise kann nur ein Manager Objekte in den Members-Ordner verschieben. Daher müssen Sie dem Skript die Proxy-Rolle eines Managers geben. Das tun Sie, indem Sie erst auf Scripts und dann auf moveObject klicken und anschließend den Proxy-Reiter wählen. Weisen Sie diesem Skript dann die Manager-Rolle zu. Weitere Informationen über Sicherheit und lokale Rollen finden Sie in Kapitel 9.
Wenn Sie sich den Code anschauen, sehen Sie, dass das Skript zuerst das Objekt und seine Objekt-ID aus dem Namespace des Übergangs holt. Dann holt es sich den Ursprungs- und Zielordner. Danach benutzt es die ObjectManager-API von Zope zum Kopieren und Einfügen. Natürlich könnten Sie diese Ordner auch im Programm selbst bestimmen, beispielsweise abhängig vom Benutzer, der den Übergang durchführt, oder vom Typ des verschobenen Inhalts. Schließlich haben Sie das Objekt und übergeben es an die Ausnahme ObjectMoved.
Die Ausnahme (Exception) ObjectMoved ist eine spezielle Ausnahme in DCWorkflow. Indem das neue Objekt zweimal als Parameter an die Ausnahme übergeben wird, wird dieses neue Objekt an das Plone-Frontend weitergegeben. Hier muss man aufpassen, denn wenn der Benutzer als Folge der Änderung zum Objekt geleitet wird, ist es das Objekt an seinem neuen Zielort und nicht das Objekt am Ursprungsort. Natürlich könnten Sie auch eine Funktion schreiben, die das Objekt wieder zurückbewegt, nachdem es abgelehnt wurde - vielleicht in den Startordner des Benutzers.
Ein weiterer spezieller und eher ungewöhnlicher Fall ist der, ein Objekt im Workflow zu löschen. Normalerweise ist das Löschen eines Objekts eine Aktion des umgebenden Objekts, daher ist es im Workflow ungewöhnlich. Für diese Aufgabe können Sie die Ausnahme ObjectDeleted auslösen. Listing 8.2 zeigt das Skript, mit dem man ein Objekt löschen kann.
Listing 8.2. Ein Objekt löschen
##parameters=state_change # get the object obj = state_change.object id = obj.getId() # get the parent folder, delete the object srcFldr = obj.aq_parent srcFldr.manage_delObjects([id,]) # raise the object deleted method and pass # the folder you want to return to raise state_change.ObjectDeleted(srcFldr)
Dieses Skript könnten Sie deleteObject nennen und Objekte damit erfolgreich im Workflow löschen. Noch einmal: Durch das Auslösen der Ausnahme weiß Plone, was es zu tun hat. In diesem Fall bringt es den Benutzer zu dem Ordner, der das Objekt enthält.
Benachrichtigungen per E-Mail versenden
Wenn Sie eine Website haben, die von ihren Benutzern nicht so oft besucht wird, dann ist es sinnlos, darauf Informationen darüber anzuzeigen, welche Inhalte geprüft werden müssen. Sie können den Workflow aber zu einem einfachen Benachrichtigungssystem machen, indem Sie damit E-Mails an die Benutzer verschicken. Der Nachrichtenkanal über E-Mail ist nur ein Beispiel. Es könnte auch einer mit Instant Messages, SMS-Mitteilungen per Telefon usw. sein. Ich über lasse es Ihnen, sich weitere Möglichkeiten auszudenken.
In diesem Beispiel senden Sie E-Mails über das MailHost-Objekt auf dem Server an alle Benutzer mit der Rolle eines Redakteurs im System. Mit diesen E-Mails teilen Sie ihnen mit, dass neue Elemente für die Überprüfung bereitstehen. Dieses Skript ist etwas komplizierter als die anderen, die ich Ihnen bisher gezeigt habe, da es mehrere Schritte durchmacht: Definieren der Variablen, Finden der Kontonamen aller Redakteure, Finden und Senden einer E-Mail. Sie sehen das Skript in Listing 8.3.
Listing 8.3. Eine Benachrichtigung per E-Mail versenden
##parameters=state_change # the objects we need object = state_change.object mship = context.portal_membership mhost = context.MailHost administratorEmailAddress = context.email_from_address # the message format, %s will be filled in from data message = """ From: %s To: %s Subject: New item submitted for approval - %s %s URL: %s """
Hiermit werden die Nachricht und die benötigten Objekte aufgesetzt. Neben dem Objekt, das einen Zustandswechsel erfährt, benötigen Sie auch eine Referenz auf das Mitglieder-Werkzeug portal_membership und den SMTP-Server (Simple Mail Transfer Protocol) über MailHost. Die Nachricht lässt sich leicht so konfigurieren, dass Sie eine E-Mail in einem beliebigen Format schicken können.
Dann benutzen Sie die Methode listMembers des Objekts portal_membership, um eine Liste der Mitglieder zu erhalten. Bei jedem Mitglied können Sie dann nachprüfen, ob in der Liste der Rollen zu diesem Benutzer die Redakteursrolle enthalten ist, indem Sie die Methode getRoles aufrufen:
for user in mship.listMembers():
if "Reviewer" in mship.getMemberById(user.id).getRoles():
Aufmerksame Leser werden bemerken, dass eine Iteration über alle Mitglieder einer Plone-Site etwas langsam sein könnte, falls Sie Tausende von Benutzern haben sollten. Im nächsten Kapitel werden Sie das Skript modifizieren, um eine Liste von Benutzern aus einer speziellen Gruppe zu erhalten.
Eine E-Mail zu verschicken macht nur dann Sinn, wenn Sie die E-Mail-Adresse eines Benutzers haben, d.h., hier prüfen Sie zuerst, ob es eine gültige E-Mail-Adresse gibt. Nun muss die E-Mail nur noch formatiert und verschickt werden. Dazu können Sie die String-Ersetzungsfunktionen von Python benutzen und vier Parameter übergeben, die dem %s in der Variable message entsprechen, die am Anfang des Skripts gesetzt werden. Nach dieser Ersetzung enthält die Variable msg die E-Mail, die Sie verschicken möchten. Um sie abzuschicken, rufen Sie einfach die Methode send von MailHost auf und übergeben dabei den String mit der E-Mail:
if user.email:
msg = message % (
administratorEmailAddress,
user.email,
object.TitleOrId(),
object.Description(),
object.absolute_url()
)
mhost.send(msg)
Dadurch wird die folgende E-Mail verschickt:
From: administrator@agmweb.ca To: andy@agmweb.ca Subject: New item submitted for approval - Plone's great We all know Plone is a great product, but with the newest release it's gotten even better... URL: http://agmweb.ca/Members/andym/News_Item_123
Anhang B zeigt das vollständige Listing für dieses Skript.
PloneCollectorNG verwenden
PloneCollectorNG ist ein Bugtracking-Programm für Plone. Sie werden noch viele weitere solcher Programme finden, aber dieses eine benutze und empfehle ich im Zusammenhang mit Plone. Tatsächlich scheinen Entwickler sehr häufig solche Fehlerverwaltungsprogramme zu schreiben. Eine sehr nette Eigenschaft von Workflows ist, dass Ihre Benutzer damit ganz wesentlich die Art und Weise ändern können, wie eine Anwendung funktioniert. Die Entwicklung von Produkten, die mit DCWorkflow zusammenarbeiten, ermöglicht es, dass Ihre Anwendung flexibel bleibt. Sie finden PloneCollectorNG unter http://www.zope.org/Members/ajung/PloneCollectorNG.
Das Produkt fügt bei der Installation eine Reihe von Inhaltstypen hinzu, darunter PloneIssueNG, also einen Fehlerbericht (issue). Anstatt genau festzuschreiben, wie der Bericht durch die Datenbank geht, wird ihm ein eigener Workflow zugewiesen. Dieser Workflow enthält die passenden Zustände, Übergänge, Variablen und Worklists.
Sie können zu jedem Zeitpunkt herausfinden, in welchem Zustand ein Objekt ist, indem Sie die Methode getInfoFor in portal_workflow aufrufen. Diese nützliche Methode erwartet ein Objekt und die Variable, die gesucht werden soll. Im Workflow von PloneCollectorNG lautet diese Variable state, und im Plone-Workflow lautet sie review_state. Um z.B. den Zustand eines Objekts herauszufinden, benutzen Sie Folgendes:
portal_workflow.getInfoFor(obj, "state")
Die möglichen Zustände eines Objekts finden Sie heraus, indem Sie das Zustandsobjekt direkt im Workflow wie folgt untersuchen:
portal_workflow['pcng_workflow'].states._mapping.keys()
Wenn Ihre Benutzer ein einfaches Fehlerberichtssystem haben möchten, dann können Sie hiermit recht einfach diesen Workflow über das Web entsprechend anpassen (falls bei der Entwicklung der Anwendung die Workflow-Werkzeuge berücksichtigt wurden). Vergleichen Sie das einmal mit Bugzilla, einem anderen populären Bugtracking-System, wo zum Ändern eines Zustands oder eines Übergangs viele Stunden an Arbeitszeit eines Perl-Programmierers nötig sind, um alle festkodierten Referenzen auf Zustände von Fehlern herauszufinden.
Workflows verteilen und schreiben
Wenn Sie einen tollen Workflow für Ihre Anwendung haben, dann stehen Ihnen einige verschiedene Möglichkeiten offen, den Workflow zu schreiben und zu verteilen. Die folgenden Abschnitte stellen einige dieser Möglichkeiten vor und beschließen damit die Diskussion zu Workflows.
Schreiben über das ZMI
Der vielleicht einfachste, aber arbeitsintensivste Weg, einen Workflow zu schreiben, ist der über das ZMI. Auch, wenn das ZMI viele Leute in den Wahnsinn treibt, ist es doch eine einfach Art, die Optionen einzustellen. Leider ist es aber so, dass Sie, nachdem Sie mit dem Schreiben im ZMI angefangen haben, in diesem Paradigma gefangen sind. Mit anderen Worten: Es gibt keinen einfachen Weg, diesen Workflow im Dateisystem zu bearbeiten oder zu verändern. Natürlich habe ich aber weiter oben in diesem Kapitel beschrieben, wie Sie einen Workflow über das Web bearbeiten können. Eine andere Alternative ist, den Workflow in einem UML-Tool als Zustandsdiagramm zu erstellen und mit ArchGenXML (siehe Kapitel 13) zu generieren.
Um einen Workflow aus dem ZMI zu exportieren, klicken Sie auf portal_workflow und dann auf den Contents-Reiter. Wählen Sie die gewünschten Workflows aus, indem Sie die Kästchen links im ZMI markieren, und klicken Sie dann auf import/export. Im oberen Teil der Exportseite wählen Sie Download to local machine und klicken auf export. Es wird eine Datei mit der Erweiterung .zexp erzeugt, die gespeichert und weiterverteilt werden kann. Bei der Wahl von XML Format hat die Datei das Format XML (Extensible Markup Language) mit der Erweiterung .xml.
Wenn Sie einen Workflow mit der Erweiterung .zexp oder .xml erhalten, können Sie diesen Workflow sehr einfach in Ihr Plone importieren. Kopieren Sie die Datei im Dateisystem ins Import-Verzeichnis von Zope. Das kann das Verzeichnis von der Wurzelinstanz oder von Zope sein.
Klicken Sie dann auf portal_workflow, wählen Sie den Contents-Reiter, und klicken Sie auf import/export. Im unteren Teil der Seite werden Sie ein kleines Formular sehen, in dem man einen Import-Dateinamen angeben kann. Geben Sie hier den Dateinamen ein, und lassen Sie die Option Take ownership of imported objects markiert. Klicken Sie auf den Import-Button, um den Workflow zu importieren. Nun wird der Workflow importiert und bekommt den Namen, der beim Export angegeben wurde.
Workflows in Python schreiben
Der vermutlich beliebteste Weg, Workflows zu schreiben, ist der, es direkt in Python zu tun, weil man dies vollständig in Python machen und leicht verteilen kann. Erstellen Sie zuerst ein Python-Modul im Dateisystem. Ganz oben in der Datei importieren Sie die passenden Werkzeuge wie folgt:
from Products.CMFCore.WorkflowTool import addWorkflowFactory from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition
Als Zweites erstellen Sie eine Funktion, die den Workflow erzeugt. Anhang A listet das API zum Schreiben eines Workflows etwas detaillierter auf. Aber Sie könnten auch mogeln und sich all die tollen Beispiele anschauen, die im PloneWorkflow-Projekt der Collective-Sammlung verfügbar sind (http://sf.net/projects/collective) oder sogar die, die in Plone enthalten sind. Beispiel:
def sample(id):
""" Sample workflow """
ob = DCWorkflowDefinition(id)
ob.states.addState('private')
ob.states.addState('public')
# add transitions
return ob
Und schließlich registrieren Sie den Workflow wie folgt im System:
addWorkflowFactory(sample,
id='sample_workflow',
title='Sample workflow')
Dieses Skript muss nun Teil einer Produkt-Installation werden. Kapitel 12 behandelt das Schreiben und die Installation von Produkten.
Nun gibt es dafür natürlich auch eine Abkürzung namens DCWorkflowDump. Dabei wird für Sie der Code aus dem ZMI genommen und in ein Python-Modul geschrieben. Den Quellcode für DCWorkflowDump finden Sie im Collective-Projekt unter http://sf.net/projects/collective, aber Sie finden auch eine Zip-Datei des Codes auf der Website zum Plone-Buch unter http://plone-book.agmweb.ca.
Um DCWorkflowDump zu installieren, packen Sie die Datei aus und kopieren das Verzeichnis namens DCWorkflowDump in das Products-Verzeichnis Ihrer Plone-Installation. Dass Sie im richtigen Verzeichnis sind, merken Sie, wenn das Products-Verzeichnis auch das DCWorkflow-Verzeichnis und andere Dinge enthält. Dann starten Sie Ihre Plone-Instanz neu.
Nachdem Sie Plone neu gestartet haben, gehen Sie im ZMI zu dem bestimmten Workflow, wo Sie einen neuen Reiter namens dump bemerken werden. Klicken Sie auf diese Seite, um zu diesem Dump-Schirm zu gelangen, und klicken Sie dann auf Dump it!, um den Workflow auf den Bildschirm zu schreiben. Dabei wird Ihr Workflow für Sie in Python formatiert. Speichern Sie die Datei in Ihr Produkt, und Sie haben eine Python-Datei, die Sie manipulieren können. Dieses Produkt ist ein tolles Werkzeug, weil es Ihnen erlaubt, den Workflow im ZMI zu erstellen und dann mit Hilfe von Python zu verteilen und zu ändern.
Andy McKay: Plone. Addison-Wesley 2005
Es wurde zuletzt von sichart am 2006-10-06 14:25 aus der cvs Quelle via
cvs -z3 -d:pserver:anonymous@plone-docs.cvs.sourceforge.net:/cvsroot/plone-docs co -P PloneBook aktualisiert.









