#pragma supplementation-page on
#pragma section-numbers on
{{{#!wiki blue
This text was written for a [[http://www.rrzn.uni-hannover.de/buecher.html?&no_cache=1&tx_rrznbuecher_pi1[showUid]=215|german python book]]. The idea was to give an advertice in learning python with examples of popular python projects. Two chapter of the book were about python learning and the last chapter describes first steps for three python projects. At last the publisher decided to drop the third chapter for several reasons. 

@copyright: 2007-2008 MoinMoin:ReimarBauer

@license: GPL
}}}

{{{#!wiki yellow 
 . <<Hits>> times read
}}}

<<TableOfContents>>
== MoinMoin (1.6) - Erweiterungen und Anpassungen (Reimar Bauer) ==
##der text der hier hin soll steckt noch im Buch
== Einleitung ==
MoinMoin ist eine Wiki-Software, welche in Python geschrieben ist. Zur Drucklegung dieses Buches befindet sich die Version 1.7 kurz vor der Veröffentlichung -- auf der Homepage ({{{http://moinmo.in}}}) können Sie Aktuelles zum Entwicklungsstand erfahren. MoinMoin ist Freie Software (Open Source Software) unter der GNU General Public License. Diese Beschreibung setzt voraus, dass Sie die aktuelle Version dieser Software von der Homepage herunterladen.

Ein Wiki ist eine im World Wide Web verfügbare Seitensammlung, die von den Benutzern nicht nur gelesen, sondern auch in Echtzeit online geändert werden kann. Wie bei Hypertexten üblich, sind die einzelnen Seiten und Artikel eines Wikis durch Querverweise (Links) miteinander verbunden.

Ab der Version 1.6 enthält MoinMoin ein vorkonfiguriertes Wiki, das in Verbindung mit dem in der Python-Standardbibliothek enthaltenen Webserver gut für ein persönliches Wiki auf dem lokalem Desktop geeignet ist. Diese Kombination ermöglicht es ebenso, in einer Entwicklungsumgebung (z.B. Eclipse/PyDev),  komfortabel zu debuggen. Folgen Sie daher bitte den Hinweisen in der Installationsanleitung für das vorkonfigurierte Wiki. Dieses Wiki enthält auch die Hilfeseiten; /* Verweise auf das Hilfesystem sind im Text mit einer Hinterlegung markiert. */

Nahezu alles an MoinMoin kann durch ein ausgeklügeltes Plugin-Konzept verändert werden. Das Aussehen könnnen Sie durch ein eigenes ''Theme'' (siehe Kapitel [[#plugintheme|theme]]) umgestalten. Mit einem ''Parser'' (siehe [[#pluginparser|parser plugins]] können Sie Inhalte interpretieren und diese dann darstellen. Ein ''Macro'' (siehe [[#pluginmacro|macro plugins]]) dient dazu,  in Form eines Kommandos etwas auf einer Seite einzufügen, während Sie mit einer ''Action'' (siehe Kapitel [[#pluginaction|action plugins]]) bestimmen, was auf "Knopfdruck" geschehen soll. Ein ''Formatter'' siehe Kapitel [[#pluginformatter|formatter plugins]]) und Kapitel [[#formatter|formatter]]) erlaubt eine Ausgabe in einem beliebigen Format. ''Filter'' ([[#pluginfilter|filter plugins]]) werden zum Erstellen des Suchindex am Beispiel von Dateianhängen benutzt. Mit ''XMLRPC'' (siehe Kapitel [[#xmlrpc|xmlrpc]] und [[#pluginxmlrpc|xmlrpc plugins]]) können Sie über eine Netzwerkverbindung mit MoinMoin kommunizieren.


Falls Sie Verbesserungswünsche haben, können Sie einen Feature Request <<FootNote(FeatureRequest)>>  erstellen - eventuell sogar mit einem Patch, wenn Sie das Feature bereits implementiert haben.

Im Nachfolgenden beziehen sich alle Beschreibungen auf den Standalone-Server und das vorkonfigurierte Wiki. <<Anchor(wikistarten)>> Um dieses zu starten, gehen Sie in das Verzeichnis {{{moin-1.6}}} und rufen Sie das Programm {{{moin.py}}} auf. Ihr lokales Wiki erreichen Sie dann über die URL ''http://localhost:8080/'' (siehe [[#perswiki|Abbildung]]). Falls Einstellungen geändert werden müssen, werden diese in der Konfigurationsdatei {{{wikiconfig.py}}} im gleichen Verzeichnis vorgenommen  /* (siehe HilfeZurKonfiguration). */

<<Anchor(perswiki)>>
||{{attachment:StartSeite.png}}||
||Das persönliche Wiki||

== Referenz der Klassen und Methoden von MoinMoin ==
Das nachfolgende Schaubild<<FootNote(mit freundlicher Genehmigung von Nir Soffer)>> zeigt die wesentlichen Klassen, die beim Ablauf des Programms {{{moin.py}}} eine Wiki-Seite in Ihrem Browser ausgeben. Die einzelnen Klassen stellen einzelne Schritte dar. Beispielsweise wird über eine {{{Action}}} eine Seite durch {{{Page}}} angefordert. Diese Seite wird durch das {{{Theme}}}  mit weiteren Inhalten ausgestattet und dann als HTML-Seite auf ihrem Browser ausgegeben.
<<Anchor(Schaubild)>>
||{{attachment:MoinMoinArchitecture.png}}||
||Prinzipieller Aufbau von MoinMoin||

Diesen Klassen ist gemeinsam, dass sie über ein {{{request}}}-Objekt miteinander kommunizieren. Mit einem eigenem {{{request}}}-Objekt (siehe Kapitel [[#request|request]]) können Sie aus einer anderen Applikation MoinMoin nutzen, um ein Wiki in Ihre Applikation zu integrieren.

Damit das Arbeiten mit dem MoinMoin-Code einfacher fällt, stelle ich Ihnen zunächst einige Klassen aus der Bibliothek vor, jedoch kann ich deren Methoden nicht komplett aufführen und auch nicht alle Parameter beschreiben. Ich beschränke mich hier auf jene, die wir dann auch in Beispielen verwenden werden. Da Sie den Sourcecode vorliegen haben, werden Sie noch viele andere interessante Klassen und Methoden finden. Gerne können Sie die Entwickler auch in ihrem chatroom {{{#moin}}} auf {{{chat.freenode.net}}} besuchen, wenn etwas unklar ist oder Sie über weitere Möglichkeiten diskutieren wollen.

Anhand des nachfolgenden Beispiels sehen Sie, wie Sie einige Funktionen zum Ausgeben einer Seite anwenden können.

{{{{{#!python
from MoinMoin.Page import Page
from MoinMoin.request import request_cli
request = request_cli.Request()
pagename = u'StartSeite'
text = Page(request, pagename).get_raw_body()
print text
}}}}}
##||Ausgabe der StartSeite||

Zunächst werden von {{{MoinMoin.Page}}} die {{{Page}}}-Klasse und von {{{MoinMoin.request}}} das Modul {{{request_cli}}} importiert. Die {{{Page}}} Klasse (siehe Kapitel [[#Page|Page]]) benötigen Sie für den lesenden Zugriff auf eine Wiki-Seite. Die Klasse {{{request_cli}}} (siehe Kapitel [[#request|request]]) benötigen Sie für alle Zugriffe auf das Wiki, die von der Python shell erfolgen.

Der Variablen {{{request}}} wird mit {{{request = request_cli.Request()}}} ein frisch erzeugtes {{{request}}}-Objekt zugewiesen.

Die Variable {{{pagename}}} bekommt als unicode String z.B. mit {{{u'StartSeite'}}} den Namen der Seite zugewiesen, die Sie ausgeben möchten.

Die nachfolgende Zeile {{{text = Page(request, pagename).get_raw_body()}}} wendet aus der Klasse {{{Page}}} die Methode {{{get_raw_body}}} (siehe Kapitel [[#pagegetrawbody|page.get_raw_body]]) an. Diese liest den Inhalt der Seite und speichert deren Rückgabewert in der Variablen {{{text}}}.

Mit {{{print text}}} wird der Inhalt von {{{text}}} ausgegeben.


{{{{{#!wiki comment
Um die Beispiele im Python-Interpreter ausprobieren zu können, sollten Sie in das Verzeichnis {{{moin-1.6}}} wechseln. In diesem Verzeichnis können Sie durch {{{moin.py}}} den Standalone-Server starten, um Ihre Änderungen mitzuverfolgen.

In den Beispielen, die auf eine Wiki-Seite oder deren Dateianhänge (attachments) zugreifen, werden immer auch die Zugriffsrechte des ausführenden Benutzers geprüft. Daher gewährleisten Sie bitte auch, dass in Ihrer Wiki-Konfiguration dem entsprechenden Benutzer diese Rechte erteilt werden.


In der Konfigurationsdatei wikiconfig.py sollte daher folgende Zeile enthalten sein: 

acl_rights_default = u``All:read,write,delete,revert,admin'

Diese Zeile regelt, dass in den nachfolgenden Beispielen alle Benutzer auf jeder Seite des Wikis die Rechte zum Lesen, Schreiben, Löschen, Wiederherstellen und zur Administration der Seite haben.
}}}}}

<<Anchor(request)>>
=== request ===

Den Klassen (siehe [[#Schaubild|Abbildung]]) ist das zentrale {{{request}}}-Objekt gemeinsam. Dieses enthält Daten und Objekte, die für die Bearbeitung in den einzelnen Programmen benötigt werden; u.a. den Zugriff auf die Konfigurationsdatei.

Neben einem  {{{request}}}-Objekt ({{{request_cli}}}), dass Sie zum Arbeiten in der Python-Shell verwenden können, unterstützt MoinMoin auch {{{cgi}}}, {{{fcgi}}}, {{{mod_python}}}, {{{standalone}}}, {{{twisted}}} und {{{wsgi}}}. /* (siehe HilfeZurInstallation) */

Sehr praktisch ist, dass Sie mit diesem {{{request}}}-Objekt in der Python-Shell viele der Methoden, die für die Plugin-Entwicklung (siehe Kapitel [[#Plugins|Plugins]]) wichtig sind, ausprobieren und kennen lernen können.

Falls Sie bereits eine in Python entwickelte Applikation haben, können Sie unter anderem mit diesem {{{request}}}-Objekt auch mit einem MoinMoin-Wiki kommunizieren oder die Wiki- Funktionalitäten anwenden. Das nachfolgende Beispiel zeigt, wie Sie ein {{{request}}}-Objekt in der Python-Shell bilden können, und wie Sie von der Shell aus auf das Wiki zugreifen können.

{{{{{#!python 
from MoinMoin.request import request_cli
request = request_cli.Request()
}}}}}
##[caption=request abgeleitet von request_cli]{request Object}

Sie können sich mit {{{help(request)}}} die Docstrings von {{{request}}} ausgeben lassen. Die Ausgabe beginnt mit dem folgendem Text:
{{{{{

Help on Request in module MoinMoin.request.request_cli object:

class Request(MoinMoin.request.RequestBase)
 |  specialized on command line interface and script requests
 |
 |  Method resolution order:
 |      Request
....
}}}}}
==== request.getText ====

Die Methode {{{request.getText}}} ermöglicht die Übersetzung von Text (z.B. die Beschriftung der Navigationselemente) in die voreingestellte Sprache des Benutzers.
{{{{{#!python [caption=Internationalisierung]{getText}
request.lang = 'de'
_ = request.getText
print _("Mail me my account data")
}}}}}
Für das cli-{{{request}}}-Objekt (command line interface) wird diese Funktionalität derzeit nicht unterstützt.
Daher sind die Ausgaben, der in der Beschreibung verwendeten Beispiele auf der Basis von {{{request_cli.Request()}}} in englisch.

MoinMoin wird englischsprachig entwickelt und der Text dann in die jeweilige Benutzersprache übersetzt. Sie finden unter ''moin-1.6/MoinMoin/i18'' in der Datei ''de.MoinMoin.po'' die deutschen Übersetzungen. Evtl. finden Sie in dieser Datei dort einen passenden Ausgabetext für Ihre Erweiterung. Dann können Sie direkt von den vorhandenen Übersetzungen profitieren. Die Übersetzungsarbeit wird gemeinschaftlich von vielen Nutzern auf dem Wiki [[MoinMaster:AktuelleÄnderungen|MoinMaster]] <<FootNote(EditingOnMoinMaster)>> durchgeführt. Dieses Wiki dient auch der Entwicklung der Hilfeseiten, die Sie in Ihrem Wiki vorfinden.

<<Anchor(requestusermay)>>
==== request.user.may ====
Mit den Methoden von {{{request.user.may}}} werden die Rechte des Benutzers für eine Seite überprüft.
{{{{{#!python 
pagename = u'StartSeite'
print request.user.may.read(pagename)
print request.user.may.write(pagename)
print request.user.may.delete(pagename)
print request.user.may.revert(pagename)
print request.user.may.admin(pagename)
}}}}}
##[caption=Abfrage der Zugriffsrechte]{request.user.may}
<<Anchor(Page)>>
=== Page ===
Die Klasse {{{Page}}} wird für den {{{readonly}}}-Zugriff auf eine Seite verwendet. Sie können damit auch auf ältere Versionen einer Seite als die aktuelle zugreifen. Bei Operationen, die auf Wiki-Seiten oder deren Attachments vorgenommen werden, werden die Zugriffsrechte des Benutzers überprüft /* (mit sog. ACLs, siehe HilfeZuAccessControlLists). */

{{{{{#!python
from MoinMoin.Page import Page
}}}}}
##[caption=import Page]{Page Object}
==== Page.exists() ====
Mit der Methode {{{Page.exists()}}} stellen Sie fest, ob eine Seite bereits existiert, z.B.:
{{{{{#!python [caption=Zeige ob die Seite existiert]{Page exists}
pagename = u'StartSeite'
print Page(request, pagename).exists()
}}}}}
Ausgabe:
{{{{{
True
}}}}}
==== Page.getRevList() ====
Die Methode {{{Page.getRevList()}}} gibt eine Liste der Revisionen einer Seite zurück. Die aktuelle Revision wird als erste angezeigt.
{{{{{#!python
pagename = u'StartSeite'
print Page(request, pagename).getRevList()
}}}}}
##[caption=Zeige die Revisionen einer Seite]{Page getRevList}
Ausgabe:
{{{{{
[2, 1]
}}}}}

==== Page.current_rev() ====
Die Methode {{{Page.current_rev()}}} zeigt die aktuelle Revision einer Seite an.
{{{{{#!python 
pagename = u'StartSeite'
print Page(request, pagename).current_rev()
}}}}}
##[caption=Zeige die aktuelle Revision einer Seite]
Ausgabe:
{{{{{
2
}}}}}

##==== Page.getPagePath() ====
## this method will be removed soon
##Wenn Sie den Dateipfad zu einer Wiki-Seite wissen möchten, wenden Sie die Methode {{{Page.getPagePath()}}} an.
##{{{{{#!python
##pagename = u'StartSeite'
##print Page(request, pagename).getPagePath()
##}}}}}
##[caption=Zeige den Pfad zu einer Seite im Dateisystem]{Page getPagePath}
##Ausgabe:
##{{{{{
##/home/workspace/moin-1.6/wiki/underlay/pages/StartSeite
##}}}}}

<<Anchor(pagegetrawbody)>>
==== Page.get_raw_body() ====
Um den Seiteninhalt auszulesen, wenden Sie {{{Page.get_raw_body()}}} an.

{{{{{#!python 
pagename = u'StartSeite'
text = Page(request, pagename).get_raw_body()
print text
}}}}}
##[caption=Zeige den Inhalt einer Wiki Seite]{Page getrawbody}

{{{{{
Worum geht es in diesem Wiki?

Wichtige Einstiegsseiten:
 * AktuelleÄnderungen: Sehen Sie, woran gerade gearbeitet wird
 * SeiteFinden: Durchsuchen Sie das Wiki
 * WegWeiser: Finden Sie sich im Wiki zurecht
 * WikiSandkasten: Probieren Sie das Editieren im Wiki aus
 * SyntaxReferenz: Schnellübersicht der Darstellungs- und
Textauszeichnungsmöglichkeiten

'''Beachten Sie auch die englische Startseite: FrontPage.'''

== Wie man diese Seiten benutzt ==

Ein Wiki wird von einer gemeinschaftlichen Idee getragen, jeder
kann seinen Beitrag leisten und daran teilhaben:
 * Bearbeiten Sie jede Seite, indem Sie auf "<<GetText(Edit)>>"
in der oberen oder unteren Leiste klicken
 * Erstellen Sie einen Link zu einer anderen Seite durch das
Aneinanderreihen von groß geschriebenen Worten (z. B.
AktuelleÄnderungen)
 * Suchen Sie nach Seiten mit dem Suchfeld oben auf
der Seite (Titel- oder Volltextsuche)
 * Auf HilfeFürAnfänger stehen weitere Hinweise;
HilfeInhalt verlinkt auf alle Hilfeseiten.

Um mehr darüber zu erfahren, was ein WikiWikiWeb ist, können
Sie DseWiki:WarumWikiFunktioniert lesen. Antworten auf häufig
gestellte Fragen finden Sie auch auf der Seite HilfeAllgemein/
FragenUndAntworten.

Dieses Wiki basiert auf [[http://moinmo.in/|MoinMoin]]
}}}}}


==== Page.send_page() ====

Mit {{{Page.send_page()}}} senden Sie die formatierte Seite an das Ausgabegerät (meistens an den Browser). Optional können Sie eine Nachricht über den {{{msg}}}-Parameter ausgeben. Diese Nachricht wird dann in einer Box oberhalb der Seite angezeigt.
Wird diese Methode nicht für einen Browser angewendet, sollte auch kein {{{http_header}}} verschickt werden.

{{{{{#!python
pagename = u'StartSeite'
Page(request, pagename).send_page(msg=u'Done', emit_headers=False)
}}}}}
##[caption=Sende eine Seite an das Ausgabegerät]{Page sendpage}
Die Ausgabe in der Konsole beginnt mit:
{{{{{
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<meta name="robots" content="index,nofollow">

<title>StartSeite - MoinMoin DesktopEdition</title>
<script type="text/javascript" src="/moin_static160/common/js/common.js">
</script>

<script type="text/javascript">
<!--
var search_hint = "Search";
//-->
</script>
}}}}}

=== PageEditor ===
Die Klasse {{{PageEditor}}} wird für alle Schreiboperationen auf eine Seite des Wikis verwendet. Bei Operationen, die auf Wiki-Seiten oder deren Attachments vorgenommen werden, werden die Zugriffsrechte des Benutzers überprüft. /* (siehe HilfeZuAccessControlLists) */
{{{{{#!python [caption=import PageEditor]{import PageEditor}
from MoinMoin.PageEditor import PageEditor
}}}}}

==== PageEditor.saveText() ====

{{{PageEditor.saveText()}}} wird verwendet, um Text auf einer Seite zu speichern. Neben dem Text, den Sie speichern wollen, müssen Sie auch noch die Revision der Seite als Parameter angeben.
{{{{{#!python 
pagename = u'TestSeite'
text = u'Das ist ein Beispiel'
print PageEditor(request, pagename).saveText(text, 0)
}}}}}
##[caption=Speichere eine Seite im Wiki]{PageEditor saveText}

Die Bestätigung für das erfolgreiche Speichern lautet:
{{{{{
'Thank you for your changes. Your attention to detail is
 appreciated.'
}}}}}

Diese Seite befindet sich jetzt im Wiki, wie Sie leicht mit einem Web-Browser überprüfen können.
''http://localhost:8080/TestSeite''

Wenn Sie den Aufruf {{{PageEditor(request, pagename).saveText(text, 0)}}} wiederholen, ohne eine Änderung am {{{text}}} durchzuführen. wird das Speichern verweigert und Sie erhalten eine Fehlermeldung ausgelöst durch eine Ausnahme.
{{{{{
MoinMoin.PageEditor.Unchanged: You did not change the page
content, not saved!
}}}}}

Diese Fehlermeldung sollte immer mit einem {{{try ... except:}}}-Block abgefangen werden, siehe nachfolgendes Beispiel:
{{{{{#!python
pagename = u'TestSeite'
page = PageEditor(request, pagename)
text = u'Das ist ein Beispiel'
try:
    page.saveText(text, 0)
except page.Unchanged:
    print "You did not change the page content, not saved!"
}}}}}
##[caption=Umgang mit ungeänderten Inhalt]
<<Anchor(PageEditordeletePage)>>
==== PageEditor.deletePage() ====
Die Methode {{{PageEditor.deletePage}}} wird verwendet, um eine Seite zu löschen. Wird eine Seite gelöscht, wird eine neue Revision ohne Datendatei erzeugt -- die alten Versionen der Seite bleiben aber erhalten und können auch wieder hergestellt werden.
{{{{{#!python
pagename = u'TestSeite'
print PageEditor(request, pagename).deletePage()
}}}}}
## [caption=Lösche eine Seite]{PageEditor deletePage}
Die Bestätigung für das erfolgreiche Löschen lautet:
{{{{{
(True, u'Page "TestSeite" was successfully deleted!')
}}}}}

=== AttachFile ===
Das Modul {{{AttachFile}}} enthält die Funktionen, die benötigt werden, um Attachments auf Wiki-Seiten abzulegen /* (siehe HilfeZuAktionen/DateiAnhänge) */ oder von dort zu laden. Es ist geplant in einer zukünftigen MoinMoin-Version, dass Attachments ähnlich wie Wiki-Seiten behandelt werden (und damit dann auch versionierbar werden). Dadurch wird dann diese Klasse entfallen.
{{{{{#!python
from MoinMoin.action import AttachFile
}}}}}
## [caption=import AttachFile]{import AttachFile}
==== AttachFile.exists() ====

Die Methode {{{AttachFile.exists()}}} stellt fest, ob ein bestimmter Dateianhang schon auf der Seite existiert.
{{{{{#!python
pagename = u'WikiSandkasten'
attachment = u'dateianhang.png'
print AttachFile.exists(request, pagename, attachment)
}}}}}
## [caption=Zeige ob das Attachment existiert]{AttachFile exists}
Ausgabe:
{{{{{
True
}}}}}

==== AttachFile.getAttachDir() ====

Die Methode {{{AttachFile.getAttachDir()}}} gibt den Pfad zu dem Attachment zurück.
{{{{{#!python 
pagename = u'WikiSandkasten'
attachment = u'dateianhang.png'
print AttachFile.getAttachDir(request, pagename)
}}}}}
##  [caption=Zeige den Pfad eines Attachments im Dateisystem]
Ausgabe:
{{{{{
/home/workspace/moin-1.6/wiki/underlay/pages/
  WikiSandkasten/attachments
}}}}}

==== AttachFile.getAttachUrl() ====

Mit der Methode {{{AttachFile.getAttachUrl()}}} erhalten Sie die URL Ihres Attachments.
{{{{{#!python
pagename = u'WikiSandkasten'
attachment = u'dateianhang.png'
print AttachFile.getAttachUrl(pagename, attachment, request)
}}}}}
## [caption=Zeige die URL eines Attachments]{AttachFile getAttachUrl}
Ausgabe:
{{{{{
./WikiSandkasten?action=AttachFile&do=get&target=dateianhang.png
}}}}}

=== logfile ===

MoinMoin unterscheidet zwei Logging-Systeme: Mit {{{eventlog}}} werden hauptsächlich Ereignisse, wie mit dem Wiki umgegangen wird, für statistische Auswertungen festgehalten, z.B. welcher Browser eingesetzt wird oder welche Seiten an einem Tag angeschaut wurden. Das {{{editlog}}} speichert Ereignisse, wann eine Seite erstellt, bearbeitet oder gelöscht wurde, und diese Information werden auf der Seite ''Aktuelle Änderungen'' oder im ''Info'' Bereich der Seite angezeigt.
<<Anchor(eventlog)>>
==== logfile.eventlog ====
Die Klasse {{{eventlog}}} verwaltet Zugriffe auf Wiki-Seiten. Sie haben die Möglichkeit zwischen zwei Filtern zu wählen. {{{'VIEWPAGE'}}} kennzeichnet die angesehenen Seiten und {{{'SAVEPAGE'}}} die gespeicherten. Das nachfolgende Beispiel zählt die Zugriffe auf die ''StartSeite''. Bevor die Seitenzugriffe gezählt werden, wird überprüft, ob der Benutzer die zu zählende Seite lesen darf. Ist dies nicht der Fall, wird der Wert {{{0}}} ausgegeben.
{{{{{#!python
from MoinMoin.logfile import eventlog
event_type = u'VIEWPAGE'
pagename = u'StartSeite'
event_log = eventlog.EventLog(request)
count = 0
if request.user.may.read(pagename):
    test = filter(lambda line: line[1] in event_type and line[2]['pagename'] == pagename, event_log)
    count = len(test)

print count
}}}}}
## [caption=Zeige wie häufig eine Seite angeschaut wurde]{logfile eventlog}
Ausgabe:
{{{{{
8
}}}}}

==== logfile.editlog ====
Mit Hilfe der Klasse {{{logfile.editlog}}} erfahren Sie etwas über die Bearbeitungsgeschichte einer Wiki-Seite.
Wiki-Seiten können erstellt, umbenannt und gelöscht werden. Dies wird im {{{editlog}}} vermerkt.
{{{u'SAVENEW'}}} für neu angelegte Seiten, {{{u'SAVE/RENAME'}}} für Seiten die umbenannt wurden, {{{u'SAVE'}}} für gelöschte Seiten, (siehe Kapitel [[#PageEditordeletepage|PageEditor.deletePage]]). Das nachfolgende Beispiel zeigt die neu erstellten Wiki-Seiten in Ihrem Wiki und das Erstellungsdatum der Seiten. Es werden durch den Vergleich {{{line.action == 'SAVENEW'}}} nur Seiten ausgegeben, die in Ihrem Wiki neu angelegt wurden.
{{{{{#!python
from MoinMoin import wikiutil
from MoinMoin.logfile import editlog
edit_log = editlog.EditLog(request)
for line in edit_log.reverse():
    if (request.user.may.read(line.pagename) and line.action == 'SAVENEW'):
        timestamp = request.user.getTime(wikiutil.version2timestamp(line.ed_time_usecs))
        year, month, day = timestamp[0:3]
        print "%s %s.%s.%s" % (line.pagename, day, month, year)
}}}}}
## [caption=Zeige die letzten Änderungen]{logfile editlog}
Ausgabe:
{{{{{
ExamplePage1 2007-11-3
ExamplePage2 2007-11-3
ExamplePage3 2007-11-4
}}}}}

<<Anchor(wikidicts)>>
=== wikidicts ===
Mit den Methoden der Klasse {{{wikidicts}}} erhalten Sie Zugriff auf verschiedene Dictionaries, die Sie mit  Wiki-Seiten anlegen können. Es gibt ein Dictionary für Gruppen, mit denen Sie u.a. Benutzer zuordnen können, und eins für die Verarbeitung von Variablen, wie sie in {{{dicts}}} verwendet werden. Diese erlauben es Ihnen zu je einem Schlüssel einen Wert zu definieren.
{{{{{#!python
from MoinMoin import wikidicts
}}}}}
##[caption=import wikidicts]{import wikidicts}

{{{{{#!wiki comment

In {{{HelpOnConfiguration}}} sind die beiden Variablen {{{page_group_regex}}} und {{{page_dict_regex}}} beschrieben. Mit der Definition der Variablen {{{page_group_regex}}} legen Sie fest, welche Seiten als Group-Dictionaries verwendet werden sollen ({{{wikidicts.Group()}}}). Mit der Variablen {{{page_dict_regex}}} legen Sie fest, welche Seiten durch {{{wikidicts.Dict()}}} auswertbar werden.

Die Voreinstellungen sind:

page_group_regex = u'$[a-z0-9]$Group$'

page_dict_regex = u'$[a-z0-9]$Dict$'
}}}}}

==== wikidicts.Group() ====

Mit der Methode {{{wikidicts.Group()}}} können Sie feststellen, wer oder was in einer bestimmten Gruppe ist. Durch die Default-Einstellungen enden diese Seiten auf ''Group''.
Um das folgende Beispiel auszuprobieren sollten, Sie eine Seite die mit Group endet in Ihrem Wiki anlegen. Im Beispiel heißt die Seite {{{UserGroup}}}. Dort speichern Sie in Form einer Punkte-Liste /* (siehe HilfeZuListen) */ einige Benutzer. Diese Gruppen finden u.a. Verwendung bei der Zuweisung von Zugriffsrechten. Sie können diese Definition dazu verwenden, um ''plugins'' so zu schreiben, dass bestimmte Funktionen nur Mitgliedern einer Gruppe zugänglich sind. /* siehe HilfeZuAccessControlLists */

{{{{{#!python
pagename = u'UserGroup'
user_group = wikidicts.Group(request, pagename)
members = user_group.members()
print members
print "Ist der Benutzer in der Gruppe: %s" % request.user.name in members
}}}}}
##[caption=Zeige die Mitglieder einer "GroupSeite"]{wikidicts.Group}
Ausgabe:
{{{{{
[u'ExampleUser', u'TestUser']
Ist der Benutzer in der Gruppe: False
}}}}}
==== wikidicts.Dict() ====
Mit der Methode {{{wikidicts.Dict()}}} können Sie Daten von Seiten, die auf ''Dict'' enden auslesen. /* siehe HelpOnDictionaries */ Wenn Sie auf einer Seite ''!MyDict'' als Unterseite Ihrer Homepage in Ihrem Wiki in der Syntax einer Defintions-Liste /* (siehe HilfeZuListen) */ einen Key ''var1'' mit dem Wert ''Wert1'' anlegen, zeigt Ihnen das folgende Beispiel, wie Sie darauf zugreifen können.
{{{{{#!python
pagename = u'MyDict'
key = u'var1'
d = wikidicts.Dict(request, pagename)
result = d.get(key, '')
print result
}}}}}
## [caption=Auslesen von Variablen einer "Dict" Seite]{wikidicts.Dict}
Ausgabe:
{{{{{
Wert1
}}}}}
Das Macro `GetVal` wendet diese Methode an. Sie können den {{{Wert1}}} überall dort einfügen, wo Sie das Macro `<<GetVal(MyDict,var1)>>` in den Wiki-Text schreiben. Diese Variable lässt sich damit auch von einer anderen Wiki-Seite benutzen. /* (siehe HelpOnVariables) */ 

=== wikiutil ===

Die Klasse {{{wikiutil}}} enthält diverse Utility-Funktionen.
{{{{{#!python
from MoinMoin import wikiutil
}}}}}
## [caption=import wikiutil]{import wikiutil}
==== wikiutil.escape() ====

Mit der Methode {{{wikiutil.escape()}}} maskieren Sie mögliche HTML-Sonderzeichen. Alles, was HTML-Sonderzeichen enthält, muss vor der Ausgabe escaped werden. Diese Methode wendet auch der Formatter (siehe Seite [[#formatter|formatter]]) an.
{{{{{#!python
print wikiutil.escape(u'<html>')
}}}}}
##[caption=Maskieren von HTML-Steuerzeichen]{wikiutil escape}
Ausgabe:
{{{{{
&lt;html&gt
}}}}}
<<Anchor(wikiutilcreateTicket)>>
==== wikiutil.createTicket() ====
Durch Anwendung der Methode {{{wikiutil.createTicket()}}} erstellen Sie ein Ticket, das Sie zur Verifikation von Formularen verwenden können. Dadurch können Sie überprüfen, ob die eingehenden Formulardaten aus einem von Ihnen erstellten Formular stammen (siehe [[#ticket|Beispiel]]).
{{{{{#!python
print wikiutil.createTicket(request)
}}}}}
##[caption=Schlüsselwort für Formularoperationen generieren]{wikiutil createTicket}
Ausgabe:
{{{{{
0046e8506e.None.show.8ea03fb9d6e50bf60721aa
}}}}}
==== wikiutil.checkTicket() ====

Mit der Methode {{{wikiutil.checkTicket()}}} wird überprüft, ob das Ticket dem System bekannt ist (siehe [[#ticket|Beispiel]]).
{{{{{#!python
print wikiutil.checkTicket(request,
   '0046e8506e.None.show.8ea03fb9d6e50bf60721aa')
}}}}}
##[caption=Ticket überprüfen]{wikiutil checkTicket}

Ausgabe:
{{{{{
True
}}}}}

<<Anchor(wikiutilinvokeextensionfunction)>>
==== wikiutil.invoke_extension_function() ====

Die Anwendung der Methode {{{wikiutil.invoke_extension_function()}}} ermöglicht es Ihnen, komfortabel Parameter Ihrer Macros (siehe Kapitel [[#pluginmacro|Plugins macro]]) auszuwerten. Durch die Definition eines Defaultwerts wird der Datentyp des Parameters festgelegt. Durch Vorgabe einer Liste möglicher Eingaben werden nur Eingaben aus dieser Liste zugelassen. Auf abweichende Eingaben wird mit einer Fehlermeldung hingewiesen.

==== wikiutil.version2timestamp() ====
Mit der Methode {{{wikiutil.version2timestamp()}}} wird die Zeitinformation, die in MoinMoin verwendet wird in die UNIX Zeitinformation umgerechnet.

==== wikiutil.timestamp2version() ====
Mit der Methode {{{wikiutil.timestamp2version()}}} wird die UNIX Zeitinformation, in die in MoinMoin verwendete Zeit umgerechnet.


=== user ===

Die Klasse {{{User}}} repräsentiert einen Benutzer und gibt Zugriff auf sein Profil.
{{{{{#!python 
from MoinMoin.user import User
}}}}}
##[caption=import User]{import User}

==== user.name ====
Auf der Variablen {{{user.name}}} ist der Benutzername gespeichert. Wenn Sie einen Benutzer in ihrem Wiki mit dem Namen ''!ExampleUser'' haben, wird dieser Name im nachfolgendem Beispiel ausgegeben.
{{{{{#!python
user = User(request, name=u'ExampleUser')
print user.name
}}}}}
## [caption=Zeige den Benutzernamen]{User exists}
==== user.exists() ====

Die Methode {{{user.exists()}}} wird verwendet, um festzustellen ob der Benutzer existiert.
{{{{{#!python
user = User(request, name=u'ExampleUser')
print user.exists()
}}}}}
## [caption=Zeige ob der Benutzername definiert ist]
Ausgabe:
{{{{{
False
}}}}}

==== user.isSuperUser() ====

Die Methode {{{user.isSuperUser()}}} Überprüft, ob der Benutzer ein Superuser ist. Superuser haben einige besondere Rechte. /* (siehe HelpOnSuperUser) */
{{{{{#!python
user = User(request, name=u'ExampleUser')
print user.isSuperUser()
}}}}}
##[caption=Zeige ob der Benutzername als SuperUser definiert ist]{User isSuperUser}
Ausgabe:
{{{{{
0
}}}}}

==== user.save() ====
Mit der Methode {{{user.save()}}} wird das Benutzer-Profil gespeichert.
{{{{{#!python 
user = User(request, name=u'ExampleUser')
if user.exists():
    user.save()
}}}}}
## [caption=Speichere die Benutzereinstellungen ]

==== user.getSubscriptionList() ====

Die Methode {{{user.getSubscriptionList()}}} gibt die abonnierten Seiten des Benutzers aus.
{{{{{#!python 
user = User(request, name=u'ExampleUser')
print user.getSubscriptionList()
}}}}}
##[caption=Zeige die Liste der abonnierten Seiten des Benutzers]{User getSubscriptionList}
==== user.subscribe() ====

Die Methode {{{user.subscribe()}}} wird verwendet, um eine Seite zu abonnieren. Mit {{{True}}} wird das erfolgreiche Abonnement einer Seite bestätigt. Ändert ein anderer Benutzer diese Seite bekommt der Abonnement eine Benachrichtigung per email der Änderungen.
{{{{{#!python
user = User(request, name=u'ExampleUser')
pagename = u'StartSeite'
print user.subscribe(pagename)
}}}}}
## [caption=Abonniere eine Seite]
==== user.unsubscribe() ====

Die Methode {{{user.unsubscribe()}}} wird verwendet, um das Abonnement einer Seite zu beenden.
{{{{{#!python 
user = User(request, name=u'ExampleUser')
pagename = u'StartSeite'
print user.unsubscribe(pagename)
}}}}}
##[caption=Entferne das Abonnement einer Seite]
==== user.getTime() ====

Die Methode {{{user.getTime()}}} wird verwendet, um die Zeit in der Zeitzone des Benutzers umzurechnen.
Wenn Sie den Wert {{{0}}} angeben, wird die aktuelle Zeit ausgegeben.
{{{{{#!python
user = User(request, name=u'ExampleUser')
print user.getTime(0)
}}}}}
## [caption=Zeige die Zeit in der Zeitzone des Benutzers]
Ausgabe:
{{{{{
(2007, 11, 27, 23, 43, 52, 1, 331, 0)
}}}}}

<<Anchor(formatter)>>
=== formatter ===
Ein Formatter ist für die Ausgabe-Erzeugung zuständig. Für die HTML-Ausgabe ist eine Formatter-Instanz von {{{formatter.text_html}}} im {{{request}}}-Objekt enthalten.

{{{{{#!wiki comment

Wenn Sie alles, was Sie ausgeben, durch den {{{formatter}}} schicken, ist gewährleistet, dass kein Benutzer Ihres Programms in der Lage ist, irgendwelche HTML- oder Javascript-Befehle in Ihre Anwendung einzuschleusen. Ist dies für einen Anwender möglich, spricht man von Cross Site Scripting (XSS). Durch die Anwendung von XSS kann jemand Ihre Benutzerdaten  stehlen.

Durch die Eingabe von <script>alert("XSS!")</script> (in input Felder) können Sie jede HTML-Anwendung auf XSS-Probleme testen.
}}}}}

Das nachfolgende Beispiel importiert den HTML-Formatter und weist eine Instanz des Formatters der Variablen {{{html_formatter}}} zu:
{{{{{#!python 
from MoinMoin.formatter.text_html import Formatter
html_formatter = Formatter(request)
}}}}}
## [caption=import formatter]{import formatter}

==== formatter.text() ====

Wenn Sie Text mit einem {{{Macro}}} ausgeben, sollten Sie darauf achten, dass HTML-Steuerzeichen maskiert werden. Die Formatter-Methode text berücksichtigt dies, wie Sie am zweiten Beispiel sehen können.
{{{{{#!python
print html_formatter.text('Hello World')
}}}}}
##[caption=Ausgabe von Text mit dem formatter]{formatter text}
Ausgabe:
{{{{{
Hello World
}}}}}

{{{{{#!python
print html_formatter.text('<BR>Hello World<BR>')
}}}}}
## [caption=HTML Steuerzeichen durch Anwendung des Text formatters maskieren]{formatter text escapen}
Ausgabe:
{{{{{
&lt;BR&gt;Hello World&lt;BR&gt;
}}}}}
==== formatter.img() ====

Wenn Sie mit dem {{{formatter}}} ein Bild ausgeben möchten, verwenden Sie die Methode  {{{formatter.img()}}}.
{{{{{#!python 
src = "http://static.moinmo.in/logos/moinmoin.png"
print html_formatter.image(src=src)
}}}}}
##caption=Ausgabe eines Bildes mit dem formatter]{formatter image}
Ausgabe:
{{{{{
<img src="http://static.wikiwikiweb.de/logos/moinmoin.png" />
}}}}}

==== formatter.number_list() ====
Die Methode {{{formatter.number_list()}}} ermöglicht es, eine Aufzählung auszugeben (siehe [[#listitem|Beispiel]]).


==== formatter.bullet_list() ====
Die Methode {{{formatter.bullet_list()}}} ermöglicht es, eine Punkte-Liste auszugeben (siehe [[#listitem|Beispiel]]).

<<Anchor(listitem)>>
==== formatter.listitem() ====

Die Methode {{{formatter.listitem()}}} ermöglicht es, in einer Nummerierten- oder Punkte- Liste Elemente auszugeben.

{{{{{#!python
txt = html_formatter.bullet_list(True)
txt += html_formatter.listitem(True)
txt += 'erstes bullet der Zeile'
txt += html_formatter.listitem(False)
txt += html_formatter.bullet_list(False)
print txt
}}}}}
##[caption=Ausgabe einer Punkte Liste]{formatter bullet listitem()}
Ausgabe:
{{{{{
<ul><li>erstes bullet der Zeile</li></ul>
}}}}}

{{{{{#!python
txt = html_formatter.number_list(True)
txt += html_formatter.listitem(True)
txt += 'erste nummerierte Zeile'
txt += html_formatter.listitem(False)
txt += html_formatter.number_list(False)
print txt
}}}}}
##[caption=Ausgabe einer Aufzählungs Liste]{formatter number listitem()}
Ausgabe:
{{{{{
<ol><li>erste nummerierte Zeile</li></ol>
}}}}}


<<Anchor(xmlrpc)>>
=== xmlrpc ===
In den bisherigen Beispielen sind Ihnen einige Klassen und Methoden von MoinMoin vorgestellt worden. Sie haben gesehen, wie Sie interaktiv in der Python-Kommandozeile oder aus anderen Programmen heraus Wiki-Seiten erstellen können. Diese Programme müssen auf der gleichen Maschine ausgeführt werden, auf der sich das Wiki befindet. Diese Einschränkung wird durch die Anwendung des {{{xmlrpc}}}-Protokolls aufgehoben. Damit können Daten von anderen Rechnern in ein Wiki eingefügt werden. Damit Sie {{{xmlrpc}}} nutzen können, empfiehlt es sich neben der nötigen Konfiguration, in der Konfigurationsdatei {{{wikiconfig.py}}} die Rechte für den Schreibzugriff auf die Wiki Seiten auf eine bekannte Gruppe von Benutzern zu begrenzen. Die Zugriffsverwaltung geschieht durch die Anwendung von Access Control Lists (ACLs). Wenn Sie z.B. einen Benutzer ''!TestUser'' in Ihrem Wiki angelegt haben, könnte der Eintrag in {{{wikiconfig.py}}} wie folgt lauten:
{{{{{
actions_excluded = []
acl_rights_default = u"TestUser:read,write,delete All:read"
}}}}}

{{{{{#!wiki comment
Die ACL-Zeile regelt, dass nur der Benutzer ''!TestUser'' die Rechte Lesen, Schreiben und Löschen auf allen Seiten des Wikis hat, auf denen keine anderen ACLs definiert sind. Andere User haben nur das Recht, alle Seiten zu Lesen. Sind auf einzelnen Seiten andere ACLs definiert, wird die Default-ACL überschrieben. Weitere Informationen finden Sie unter HilfeZuAccessControllLists.
}}}}}

Damit Sie mit {{{xmlrpc}}} auf Ihr Wiki zugreifen können, muss das Wiki gestartet werden (siehe [[#wikistarten|Beispiel]]).
Derzeit wird das Wiki nur standalone betrieben. Ist es auf einem Server installiert (siehe HilfeZurInstallation), verwenden Sie als {{{wikiurl}}} die Adresse des wikis das Sie ansprechen wollen. Mit dem nachfolgendem Beispiel wird gezeigt, wie die Anmeldung des Benutzers ''!TestUser'' mit Benutzername und Passwort erfolgt:
{{{{{
name = "TestUser"
password = "geheimeswort"
wikiurl = "http://localhost:8080"
homewiki = xmlrpclib.ServerProxy(wikiurl + "?action=xmlrpc2", allow_none=True)
auth_token = homewiki.getAuthToken(name, password)
}}}}}
Durch das {{{getAuthToken}}} wird das User Object initialisiert.

==== xmlrpc.putPage() ====
Mit der {{{xmlrpc.putPage()}}}-Methode übertragen Sie neue Inhalte auf eine Seite. Das nachfolgende Beispiel erstellt die Seite "!TestSeite" in Ihrem Wiki. Bitte verwenden Sie einen Benutzer, der in Ihrem Wiki durch die Konfiguration in {{{wikiconfig.py}}} Schreibrechte hat. Im Beispiel ist es der User ''!TestUser''.
Mit der {{{xmlrpclib.MultiCall()}}}-Methode können Sie das Verarbeiten der {{{xmlrpc}}}-Befehle dadurch beschleunigen, dass Sie {{{xmlrpc}}}-Befehle bündeln, um diese dann als einen {{{xmlrpc}}}-Befehl abzuschicken.


{{{{{#!python
import xmlrpclib
name = "TestUser"
password = "geheimeswort"
wikiurl = "http://localhost:8080"
homewiki = xmlrpclib.ServerProxy(wikiurl + "?action=xmlrpc2", allow_none=True)
auth_token = homewiki.getAuthToken(name, password)
mc = xmlrpclib.MultiCall(homewiki)
mc.applyAuthToken(auth_token)
pagename = 'TestSeite'
text = 'Dies ist eine Zeile Text'
mc.putPage(pagename, text)
result = mc()
}}}}}
## [caption=Mit XMLRPC eine Seite speichern]{xmlrpc putPage}

==== xmlrpc.getPage() ====

Ebenso wie Sie Seiten in das Wiki schreiben können, können Sie auch Seiten auslesen.
Anstelle der {{{xmlrpc.putPage()}}}-Methode verwenden Sie dann die {{{xmlrpc.getPage()}}}-Methode.
{{{{{#!python
import xmlrpclib
wikiurl = "http://localhost:8080"
homewiki = xmlrpclib.ServerProxy(wikiurl + "?action=xmlrpc2", allow_none=True)
pagename = 'TestSeite'
raw_text = homewiki.getPage(pagename)
print raw_text
Dies ist eine Zeile Text
}}}}}
##[caption=Mit XMLRPC eine Seite holen]{xmlrpc getPage}

oder 

{{{{{#!python
import xmlrpclib
name = "TestUser"
password = "sgeheimeswort"
wikiurl = "http://localhost:8080/"
homewiki = xmlrpclib.ServerProxy(wikiurl + "?action=xmlrpc2", allow_none=True)
auth_token = homewiki.getAuthToken(name, password)
mc = xmlrpclib.MultiCall(homewiki)
mc.applyAuthToken(auth_token)
pagename = u'TestSeite'
mc.getPage(pagename)
result = mc()
success, raw = tuple(result)
if success:
    print raw
}}}}}

==== xmlrpc.putAttachment() ====

Mit {{{xmlrpc.putAttachment()}}} können Sie eine Datei als Attachment auf eine Wiki-Seite laden.

{{{{{#!python 
import xmlrpclib
name = "TestUser"
password = "secret"
wikiurl = "http://localhost:8080"
homewiki = xmlrpclib.ServerProxy(wikiurl + "?action=xmlrpc2", allow_none=True)
mc = xmlrpclib.MultiCall(homewiki)
auth_token = homewiki.getAuthToken(name, password)
mc.applyAuthToken(auth_token)
attachname = 'beispiel.txt'
text = file(attachname, 'rb+').read()
data = xmlrpclib.Binary(text)
mc.putAttachment(pagename, attachname, data)
result = mc()
}}}}}
##[caption=Mit XMLRPC ein Attachment speichern]{xmlrpc putAttachment}
==== xmlrpc.getAttachment() ====

Mit {{{xmlrpc.getAttachment()}}} können Sie ein Attachment einer Wiki-Seite als Datei auslesen (und dann z.B. auf Ihren Rechner speichern). Mit der vorgegebenen ACL-Definition darf ein anonymer Benutzer Wiki-Seiten und Attachments lesen. Das Beispiel beschreibt das Auslesen einer Datei "Beispiel.txt" auf der Seite !TestSeite.
{{{{{#!python 
import xmlrpclib
wikiurl = "http://localhost:8080"
homewiki = xmlrpclib.ServerProxy(wikiurl + "?action=xmlrpc2", allow_none=True)
pagename = 'TestSeite'
attachname = 'Beispiel.txt'
data = homewiki.getAttachment(pagename, attachname)
file(attachname, 'wb+').write(data.data)
}}}}}
##[caption=Mit XMLRPC ein Attachment holen]{xmlrpc getAttachment}

<<Anchor(Plugins)>>
== Plugins ==
Reicht der Umfang von MoinMoin nicht aus, kann man ihn sehr einfach durch ein eigenes Plugin erweitern. Wiki Seiten von MoinMoin werden in Form von HTML in einem Cache system zwischengespeichert. Solange Seiten sich nicht ändern können komplexe Seiten daher sehr schnell nach der ersten Generierung wieder dargestellt werden. Machmal ist das aber nicht gewünscht. Für alle Plugins können daher Abhängigkeiten definiert werden, wenn sich die Ausgabe des Plugins abhängig von diesen ändert. Mit der Variable {{{Dependencies = []}}} können Sie bestimmen, welche Abhängigkeiten bestehen (wenn keine bestehen, wird die Ausgabe als statisch angesehen). Neben einem einfachem {{{[]}}}, werden folgende Abhängigkeiten {{{["time"]}}}, {{{["user"]}}}, {{{["language"]}}},  {{{["pages"]}}}, {{{["namespace"]}}} verwendet.

Dem Typ eines Plugins entsprechend gibt es unterhalb von {{{moin-1.6/wiki/data/plugin}}} jeweils ein zugeordnetes Verzeichnis, in dem Sie das Plugin für die Verwendung speichern müssen.

Z.B. ein ''Action''-Plugin gehört in das Verzeichnis {{{moin-1.6/wiki/data/plugin/action}}}.

{{{{{#!wiki comment
Das Programm {{{moin.py}}} müssen Sie neu starten, nachdem Sie Änderungen an einem Plugin durchgeführt haben, sonst werden diese Änderungen nicht wirksam.
}}}}}


Achten Sie bei der Ausgabe bitte darauf, dass Sie diese mit dem {{{formatter}}} bewerkstelligen, um Anfälligkeit gegen XSS vorzubeugen (siehe [[#formatter|formatter]]).

Bei Plugins kann es nötig sein, Berechtigungen über das {{{request}}}-Objekt abzufragen (siehe [[#Save|Beispiel]]).

Die nachfolgenden Sektion-Überschriften beschreiben den Ort, wo Sie Ihre plugins unterhalb von ''moin-1.6/wiki/data/plugin'' ablegen müssen, damit diese von MoinMoin erkannt werden.

<<Anchor(pluginmacro)>>
=== macro ===

Ein ''Macro'' wird im Wiki-Text durch zwei Kleiner-Zeichen und zwei Größer-Zeichen dem ''Parser'' kenntlich gemacht. z.B.: {{{<<HelloWorld>>}}} /* (siehe HilfeZuMakros) */
==== Hello World ====
Das nachfolgende Beispiel beschreibt ein typisches HelloWorld Programm zum Kennenlernen eines ''Macro'' Aufrufs. {{{<<HelloWorld>>}}}
{{{{{#!python
def execute(macro, args):
    return macro.request.formatter.text('Hello World')
}}}}}
## [caption=macro HelloWorld.py]{Hello world}
Das obige Beispiel verwendet keine Argumente. Ab der Version 1.6 ist es möglich, Argumente durch einen Argumentparser auszuwerten. Damit können Sie explizit in der Definition des Makros festlegen, welche Eingabe erlaubt ist (siehe Kapitel [[#wikiutilinvokeextensionfunction|wikiutil.invoke_extension_function]]).

{{{{{#!python
from MoinMoin import wikiutil

def macro_HelloWorld(macro, color=(u'red', u'blue')):
    return macro.request.formatter.text('Hello World', style="color:%s" % color)

def execute(macro, args):
    try:
        return wikiutil.invoke_extension_function(macro.request, macro_HelloWorld, args, [macro])
    except ValueError, err:
        return macro.request.formatter.text("<<HelloWorld: %s>>" % err.args[0])
}}}}}
##[caption=Vorstellung des Argument Parsers]
Mit {{{<<HelloWorld>>}}} wird der erste Wert der Definition von color angewandt und der Text in rot geschrieben.
{{{<<HelloWorld(color="blue")>>}}} schreibt Hello World in blau. Wogegen {{{<<HelloWorld(color="green")>>}}} die
Fehlermeldung ausgibt:
{{{
<<HelloWorld: Argument "color" muss eins von "red", "blue"  sein, nicht "green">>
}}}
==== Attachments verarbeiten ====
Das nachfolgende Beispiel zeigt Ihnen die Möglichkeit Wiki-Text im Programm zu verwenden um daraus dann HTML für die Darstellung zu generieren. Es verarbeitet dabei CSV-Daten, die als Dateianhänge auf einer Seite abgespeichert sind.
## wird mit 1.7 kürzer, da der csv parser dann verwendbar ist
{{{{{#!python 
# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - ShowCSV shows csv file as table
    @copyright: 2007 MoinMoin:ReimarBauer
    @license: GNU GPL, see COPYING for details.
"""
Dependencies = ['time'] # do not cache

import codecs, csv, os
from MoinMoin import config, wikiutil
from MoinMoin.action import AttachFile
from MoinMoin.parser.text_moin_wiki import Parser

def utf_8_encoder(unicode_csv_data):
    for line in unicode_csv_data:
        yield line.encode('utf-8')

def execute(macro, args):
    request = macro.request
    formatter = macro.formatter
    extension = '.csv'
    pagename = formatter.page.page_name
    files = AttachFile._get_files(request, pagename)
    attach_dir = AttachFile.getAttachDir(request, pagename)
    for file in files:
        if file.lower().endswith(extension):
            file_id = codecs.open(os.path.join(attach_dir, file), 'rb', config.charset)
            reader = csv.reader(utf_8_encoder(file_id))
            result = "|| '''%s''' ||\n" % ("''' || '''".join(reader.next()))

            for row in reader:
                result += "|| %s ||\n" % " || ".join(row)
            result = wikiutil.url_unquote(result)
            result += '. \n[[attachment:%s]]' % file
            result = wikiutil.escape(result)
            Parser(result, request).format(request.formatter)
    return ""
}}}}}
##[caption=CSV-Daten darstellen]
Dieses Programm stellt nun bei der Verwendung als {{{<<ShowCSV>>}}} auf einer Wiki-Seite alle attachments, die auf dieser Seite gespeichert sind und auf {{{.csv}}} enden als Tabellen dar. Unterhalb der Tabelle befindet sich ein Link zu der Datei.


||{{attachment:ShowCSV.png}}||
||Ausgabe des Makros ShowCSV.py||


==== Logeintragungen auf einer Seite verwenden ====
Makros sind auch hervorragend geeignet, um z.B. Information aus der event-log Datei auf einer Seite auszugeben. Das nachfolgende Beispiel zeigt die Zugriffe auf der Seite an. Sobald es als {{{<<Hits>>}}} auf die Seite geschrieben wird.
Wird die {{{filter}}} Variable verwendet, können Sie {{{u'VIEWPAGE'}}} bzw. {{{u'SAVEPAGE'}}} verwenden (siehe Kapitel [[#eventlog|eventlog]]. Mit der Variablen {{{all}}} können Sie festlegen, ob die Ausgabe der Analyse nur für die aktuelle Seite oder alle Seiten des Wikis erfolgen soll. Sie können dort nur boolsche Variablen eingeben, z.B.: {{{<<HIT(all=True)>>}}}, {{{<<HITS(filter='SAVEPAGE')>>}}}.


{{{{{#!python
# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - Hits Macro shows hits of a page
    @copyright: 2004-2007 MoinMoin:ReimarBauer,
                2005 BenjaminVrolijk
    @license: GNU GPL, see COPYING for details.
"""
Dependencies = ['time'] # do not cache
from MoinMoin import wikiutil
from MoinMoin.logfile import eventlog

def macro_Hits(macro, all=False, event_type=(u'VIEWPAGE', u'SAVEPAGE')):
    pagename = macro.formatter.page.page_name
    event_log = eventlog.EventLog(macro.request)
    count = 0
    if not all:
        test = filter(lambda line: line[1] in event_type and line[2]['pagename'] == pagename, event_log)
    else:
        test = filter(lambda line: line[1] in event_type, event_log)

    return u'%d' % len(test)


def execute(macro, args):
    try:
        return wikiutil.invoke_extension_function(macro.request, macro_Hits, args, [macro])
    except ValueError, err:
        return macro.request.formatter.text(err.args[0])
}}}}}
##[caption=Seitenzugriffe anzeigen]

<<Anchor(pluginaction)>>
=== action ===
Eine ''Action'' wird über das "Weitere Aktionen"-Menü angeboten, sofern Sie den Dateinamen mit einem Grossbuchstaben beginnen. Eine Aktion ist durch die Anordnung im ''Theme'' nicht an eine Wiki-Seite gebunden im Unterschied zu einem ''Macro''. /* (siehe HilfeZuAktionen) */ Das nachfolgende Beispiel stellt die {{{Save}}}-''Action'' dar. Wählt man diese Aktion für eine Seite aus, wird der Quelltext dieser Seite gespeichert.

z.B.: ''http://localhost:8080/FrontPage?action=Save''.
<<Anchor(Save)>>
{{{{{#!python
# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - Action for saving a page
    @copyright: 2007 MoinMoin:ReimarBauer
    @license: GNU GPL, see COPYING for details.
"""

from MoinMoin.Page import Page

def execute(pagename, request):
    if not request.user.may.read(pagename):
        Page(request, pagename).send_page()
    else:
        rev = request.rev or 0
        Page(request, pagename,rev=rev).send_raw(content_disposition='attachment')
}}}}}
## [caption={action Save.py}, label=Save]
In diesem Beispiel sehen Sie auch die Überprüfung des Lese-Zugriffsrechts, das durch ACLs eingeschränkt sein kann:
{{{if not request.user.may.read(pagename):}}}

Diese Abfrage hat den Zweck, dass Sie einen Hinweis mit einer Fehlermeldung bekommen, wenn Sie versuchen, eine Seite abzuspeichern, die Sie nicht lesen dürfen. Eine Aktion muss mit einer Message abgeschlossen werden. Wenn Sie einen eigenen Wert zurückgeben wollen, verwenden Sie den msg Parameter, z.B.:
{{{Page(request, pagename).send_page(msg= u'Mein Wert')}}}.

Neben dem {{{read}}}-Recht können Sie auch die anderen ACL-Rechte, wie: {{{write}}}, {{{delete}}}, {{{revert}}} und {{{admin}}} abfragen (siehe Kapitel [[#requestusermay|request.user.may]]).

==== Mit einer Action POST oder GET Parameter verarbeiten ====
Eine ''Action'' kann Variablen verarbeiten, die über die Formularmethode {{{GET}}} oder {{{POST}}} verschickt werden.
Das nachfolgende Beispiel zeigt, wie Sie eine ''Action'' benutzen können, um eine Seite mit Informationen zu ergänzen. Z.B. kann das Verwendung finden, wenn Sie ein Programm in einer beliebigen Programmiersprache haben, das Status-Informationen in ein Wiki schreiben soll.

Damit nicht jeder diese ''Action'' ausführen kann, muss noch eine geheime Information mitübertragen werden. Dies geschieht in diesem Beispiel durch eine Variable, deren Wert in dem Programm vorgegeben ist. Es ist auch abwandelbar, so dass diese Variable z.B. auf einer geschützten Wiki-Seite steht und ausgelesen wird (siehe Kapitel [[#wikidicts|wikidicts]]).

Die gesendeten Daten können von einem anderen Rechner stammen. Die Action kann sowohl POST- als auch GET-Parameter verarbeiten. Die URL mit GET-Parametern für die Benutzung lautet: {{{http://localhost:8080?action=log&date=200701129&comment=System on&ticket=Geheim!}}}
Sie sollten nur POST verwenden, wenn die Daten über das internet geschickt werden, je nachdem wie schützenswert Ihnen die Daten sind sollten Sie diese dann auch verschlüsseln. 


{{{{{#!python 
# -*- coding: iso-8859-1 -*-
"""
    log - add log entry
    @license: GNU GPL, see COPYING for details.
    @copyright:  2007 MoinMoin:ReimarBauer
"""
from MoinMoin import wikiutil
from MoinMoin.PageEditor import PageEditor
from MoinMoin.Page import Page

def execute(pagename, request):
    _ = request.getText()
    ticket = 'Geheim!'
    esc = wikiutil.escape
    date = esc(request.form.get('date', ['None'])[0])
    comment = esc(request.form.get('comment', ['None'])[0])
    secret = esc(request.form.get('ticket', ['wrong'])[0])

    if (ticket != secret or  date == 'None' or
        comment == 'None'):
        Page(request, pagename).send_page(_(u"A severe error occured:"))
        return

    pagename = u'LogPage'
    page = Page(request, pagename)
    raw = u''

    if page.exists():
        raw = page.get_raw_body()

    result = "|| %s || %s ||" % (date, comment)
    newtext = "%s%s\n" % (raw, result)
    try:
        PageEditor(request, pagename).saveText(newtext, 0)
        Page(request, pagename).send_page(_(u"OK!"))
    except:
        Page(request, pagename).send_page(_(u"A severe error occured:"))
}}}}}
##[caption=Log Seite über eine Action erstellen]{log}
Das nachfolgende Beispiel zeigt Ihnen, wie Sie Daten mit dieser ''Action'' aus einem anderen Python-Programm übertragen können. Auf {{{result}}} bekommen Sie die HTML-Ausgabe der Seite zurück.

{{{{{#!python 
import urllib
params = urllib.urlencode({'date':'20070928', 'comment': 'System on', 'ticket': 'Geheim!'})
f = urllib.urlopen('http://localhost:8080/StartSeite?action=log&%s' % params)
result = f.read()
}}}}}
##[caption=Logeintrag mit log.py aus einem anderen Programm tätigen]{log eintragen}
<<Anchor(ticket)>>
==== Ausschließlich Formulare, die vom eigenem Server stammen, verarbeiten ====

Sollen Daten ausschließlich von dem Wiki-Server verarbeitet werden, sollten Sie {{{wikiutil.createTicket()}}} und {{{wikiutil.checkTicket()}}} (siehe Kapitel [[#wikiutilcreateTicket|wikiutil.createTicket]]) verwenden.
Dadurch können Sie auf dem Server eine geheime Information ablegen, die das Programm für die Eingabe der Daten angeben muss.

Sinnvollerweise verwendet man diese Daten dann nur mit der Methode POST. Wenn Sie ein Formular verwenden, dann können Sie in einem versteckten Textfeld das Ticket mit übertragen. Sobald das Formular ausgefüllt ist und die Daten an den Server geschickt werden, überprüft ihr Programm dann mit {{{wikiutil.checkTicket()}}}, ob das richtige Ticket enthalten ist. Ist dies der Fall, wird die ''Action'' ausgeführt. Auch bei diesem Beispiel ist es sinnvoll zu überprüfen, ob der Benutzer berechtigt ist, die ''Action'' auf der Seite auszuführen.
Das nachfolgende Beispiel erstellt ein Listenfeld, in dem die einzelnen Revisionen der Seite gelistet werden. Mit Auswahl einer Revision wird die zugehörige Seite dargestellt.


{{{{{#!python 
# -*- coding: iso-8859-1 -*-
"""
    ShowRev - action to select a page revision
    @license: GNU GPL, see COPYING for details.
    @copyright:  2007 MoinMoin:ReimarBauer
"""
from MoinMoin import wikiutil
from MoinMoin.Page import Page

def form_html(ticket, revlist):
    html = []
    for rev in revlist:
        html.append("<OPTION>%d</OPTION>" % rev)
    return '''
<form method="post" >
<p>select a revision</P>
<select name="revision" size="%(len)s">
%(option)s
</select>
<input type="hidden" name="action" value="ShowRev">
<input type="submit" name="button" value="Select">
<input type="hidden" name="ticket" value="%(ticket)s">
</form>''' % {
    'ticket' : ticket,
    'option': ''.join(html),
    'len': min(len(revlist), 5)}

def execute(pagename, request):
    _ = request.getText
    page = Page(request, pagename)
    if not request.user.may.read(pagename):
        return page.send_page(
                msg= _('''You are not allowed to read this page.'''))

    if (request.form.has_key('button')
        and request.form.has_key('ticket')):
        if not wikiutil.checkTicket(request, request.form['ticket'][0]):
            return page.send_page(request,
             msg = _('''Please use the interactive user interface!'''))
        rev =  long((request.form.get('revision', ['-1'])[0]))
        return Page(request, pagename, rev=rev).send_page()
    ticket = wikiutil.createTicket(request)
    revlist = page.getRevList()
    msg = form_html(ticket, revlist)
    page.send_page(msg=msg)
}}}}}
## [caption=ShowRev.py (Wähle die Revision einer Seite)]

<<Anchor(pluginparser)>>
=== parser ===
Ein ''Parser'' analysiert die Eingabedaten und gibt sie in einer gewünschten Form aus. Zum einen werden ''Parser'' verwendet, um Quellcode farbig darzustellen und zum anderen, um z.B. Inhalte zu analysieren, damit sie dann strukturiert ausgegeben werden können.
Werden die {{{Parser}}}-Programm-Dateien in Kleinbuchstaben geschrieben, können Sie für den kompletten Inhalt einer Seite angewendet werden, z.B. {{{#format plain}}} am Seitenanfang. /* (siehe HilfeZuParsern) */ Ansonsten muss der Text, der geparsed werden soll, mit drei offenen und drei geschlossenen geschweiften Klammern umschlossen werden. Der Name des Parsers muss dann mit dem Hash-Bang {{{#!}}} kenntlich gemacht werden, z.B.:
{{{{{
{{{#!plain
Das ist ein Beispiel
    Zeile 2
}}}
## [caption=Anwendung eines Parsers]{Parser plain auf einer Seite}
}}}}}

Das nachfolgende Beispiel zeigt die Anwendung des {{{#format}}} Befehls.
{{{{{
#format plain

Alles
was
jetzt
auf
dieser
Seite
geschrieben
wird,
wird
genauso
ausgegeben.
}}}}}
##[caption=Anwendung eines Parsers mit dem format Befehl]

Der Parser, der die plain Text Ausgabe bewerkstelligt, ist wie folgt aufgebaut.
{{{{{#!python
# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - Plain Text Parser, fallback for text/*
    @copyright: 2000-2002 Juergen Hermann <jh@web.de>
    @license: GNU GPL, see COPYING for details.
"""

Dependencies = []

class Parser:
    """
        Send plain text in a HTML <pre> element.
    """
    extensions = '*'
    Dependencies = []

    def __init__(self, raw, request, **kw):
        self.raw = raw
        self.request = request
        self.form = request.form
        self._ = request.getText

    def format(self, formatter):
        """ Send the text. """
        self.request.write(formatter.preformatted(1))
        self.request.write(formatter.text(self.raw.expandtabs()))
        self.request.write(formatter.preformatted(0))

}}}}}
## [caption=parser text]
Eigene Parser sollten mit dem Namen {{{text_x_}}} beginnen, sonst werden sie nicht erkannt. Die Namensgebung ist angelehnt an den MIME-Type der Daten, die geparsed werden sollen.

<<Anchor(pluginformatter)>>
=== formatter ===
Ein {{{Formatter}}} hat den Zweck, den Inhalt einer Seite in einer anderen Form auszugeben. Der Wiki-Text kann z.B. anstatt im HTML- auch in DocBook-Format ausgegeben werden, oder jedem anderem Format, das Sie anwenden möchten (und für das ein Formatter existiert).

Der Aufruf erfolgt über die url ''http://localhost:8080/FrontPage?mimetype=text/plain''

Dazu müssen Sie die Ausgaben für die jeweiligen Methoden definieren.

In der folgenden Auflistung sehen Sie einen Auszug einiger möglicher Definitionen. Sehen Sie bitte in die Datei
{{{MoinMoin/formatter/__init__.py}}} für eine komplette Liste.

{{{
def startDocument(self, pagename): 
def startContent(self, content_id="content", **kw):
def endContent(self): 
def text(self, text, **kw): 
def table(self, on, attrs={}, **kw): 
def table_row(self, on, attrs={}, **kw): 
def table_cell(self, on, attrs={}, **kw): 
}}}


Das nachfolgende Beispiel zeigt einige der Methoden und die Ableitung der FormatterBase von dem text_plain formatter.
Es zeigt die Abwandlung der Ausgabe von Tabellen als Komma separierte Liste. Der Dateiname Ihres Formatters sollte demnach {{{text_csv.py}}} lauten und dann im fromatter Verzeichnis gespeichert werden.

{{{{{#!python 
from MoinMoin.formatter.text_plain import Formatter as FBase

class Formatter(FBase):
    def __init__(self, request, **kw):
        FBase.__init__(self, request, **kw)
        self._text = []
        self._table_rows = []

    def text(self, text, **kw):
        if text:
            self._text.append(text)
        return ""

    def table_row(self, on, attrs={}, **kw):
        if len(self._text) > 0:
            self._table_rows.append(u','.join(self._text))
            self._text = []
        return ""

    def table(self, on, attrs={}, **kw):
        if len(self._table_rows) > 0:
            result = u'\n'.join(self._table_rows)
            return "%s\n\n" % result
        return ""
}}}}}
##[caption=formatter (Tabellen als CSV Dateien speichern)]{formatter}

Evtl. möchten Sie noch weitere Methoden anpassen. Die Ausgabe einer Wiki-Seite wird mit ''http://localhost:8080/FrontPage?mimetype=text/csv'' aufgerufen. Falls Sie eine Applikation in Ihrem Browser für diesen MIME-Type definiert haben, wird die Ausgabe dahin umgeleitet.

<<Anchor(pluginfilter)>>
=== filter ===
''Filter'' werden zur Indizierung von Datei-Anhängen benutzt, d.h. sie extrahieren die Text-Informationen aus Datei-Anhängen.

{{{{{#!python 
# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - PDF filter
    Depends on: pdftotext command from
                xpdf-utils package

    @copyright: 2006 MoinMoin:ThomasWaldmann
    @license: GNU GPL, see COPYING for details.
"""

from MoinMoin.filter import execfilter

def execute(indexobj, filename):
     return execfilter("pdftotext -enc UTF-8 '%s' -", filename)
}}}}}
##[caption=filter PDF filter]{filter}
=== xmlrpc ===
<<Anchor(xmlrpc)>>

Für den Fall, dass Sie weitere ''xmlrpc''-Methoden benötigen, können Sie auch diese erweitern.
Das nachfolgende Beispiel gibt aus, wer die Abfrage ausgeführt hat.

{{{{{#!python 
"""
    MoinMoin - Tells who you are
          and whether the wiki trusts you.

    @copyright: 2005 MoinMoin:ThomasWaldmann
    @license: GNU GPL, see COPYING for details.
"""

def execute(xmlrpcobj, *args):
    request = xmlrpcobj.request
    username = request.user.name
    if not username:
        username = "<unknown user>"
    valid = request.user.valid
    result = "You are %s. valid=%d." % (username.encode("utf-8"), valid)
    return xmlrpcobj._outstr(result)
}}}}}
##[caption=xmlrpc plugin whoami]{xmlrpc}

<<Anchor(plugintheme)>>
=== theme ===
Mit einem Theme bestimmen Sie, wie die Benutzeroberfläche von MoinMoin dargestellt wird. Derzeit werden mit MoinMoin standardmäßig drei ''Themes'' (modern, classic und rightsidebar) zur Verfügung gestellt. Eine ganze Reihe von Benutzern entwickelte ''Themes'' finden Sie unter ''http://moinmo.in/ThemeMarket''. /* (siehe HelpOnThemes) */

Ein Theme besteht aus einem Python Programm, CSS und Bildern. Der prinzipielle Aufbau des Themes {{{modern.py}}} wird durch nachfolgendes Beispiel wiedergegeben. Bitte schauen Sie in die eigentliche Programmdatei für eine vollständige Listung des Aufbaus. Mit Hilfe der Variablen {{{name}}} wird bekannt gegeben, wo die zu dem Theme zugehörigen CSS Dateien und Bilder liegen.

Für das modern-Theme liegen diese daher unter {{{moin-1.6/wiki/htdocs/modern}}} in den Verzeichnissen {{{css}}} und {{{img}}}.

Im {{{css}}} Verzeichnis gibt es die Dateien


||common.css ||legt die Default styles fest||
||msie.css ||MoinMoin MS Internet explorer bug workarounds ||
||print.css || legt die Styles für eine Druckausgabe fest ||
||projection.css || legt die Styles für eine Slide-Show fest ||
||screen.css || legt die Styles für die Darsellung im Browser fest||


Im {{{img}}} Verzeichnis liegen alle Bilder die im {{{modern}}} Theme Verwendung finden.


Das Theme {{{modern}}} ist von der ThemeBase abgeleitet. Es verändert header, editorheader und footer durch die Anordnung einzelner Elemente.


{{{{{#!python 
# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - modern theme
    @copyright: 2003-2005 Nir Soffer, Thomas Waldmann
    @license: GNU GPL, see COPYING for details.
"""
from MoinMoin.theme import ThemeBase

class Theme(ThemeBase):
    name = "modern"

    def header(self, d, **kw):
        html = [
            self.emit_custom_html(self.cfg.page_header1),]


    def editorheader(self, d, **kw):
        html = [
            self.emit_custom_html(self.cfg.page_header1),]


    def footer(self, d, **keywords):
        page = d['page']
        html = [
            self.pageinfo(page),]


def execute(request):
    """ Generate and return a theme object """
    return Theme(request)
}}}}}
##[caption=theme (prinzipieller Aufbau)]{theme}

Das nachfolgende Beispiel ist von dem {{{modern_cms}}}-''Theme'' abgeleitet, das von Nir Soffer entwickelt wurde.

{{{{{#!python 
"""
@copyright (c) 2005 Nir Soffer <nirs@freeshell.org>
@copyright (c) 2006 Thomas Waldmann
@license: GNU GPL, see COPYING for details
"""
from MoinMoin.theme import modern

class Theme(modern.Theme):

    name = "modern" # uses "modern" CSS and images

    def shouldShowEditbar(self, page):
        """ Hide the edit bar if you can't edit """
        if self.request.user.may.write(page.page_name):
            return modern.Theme.shouldShowEditbar(
                   self, page)
        return False

}}}}}
##[caption=theme modern_cms (Ein CMS Theme aus modern abgeleitet)]{theme}
Dieses ''Theme'' unterdrückt für nicht angemeldete Benutzer die Anzeige des editbars, wenn in {{{wikiconfig.py}}} folgendes eingetragen ist:
{{{{{
acl_rights_default = u"Known:read,write,delete,revert"
theme_default = 'modern_cms'
theme_force = True
}}}}}

{{{{{#!wiki comment 


acl_rights_default definiert für Benutzer, die dem Wiki bekannt sind, dass sie lesen, schreiben, löschen und alte Versionen wieder herstellen dürfen. Mit theme_default wird das neue ''Theme'' ausgewählt und mit theme_force erzwungen, dass es immer geladen wird. Der Benutzer hat dadurch nicht die Möglichkeit das ''Theme'' zu wechseln.}}}}}


Wenn Sie ein neues {{{Theme}}} erstellen wollen, gehen Sie am besten so vor, dass Sie eines der mitgelieferten Themes kopieren und ihren Wünschen nach abändern. Sie finden die vorhandenen Themes unter {{{moin-1.6/MoinMoin/theme/}}}.

Das nachfolgende Beispiel basiert auf einer Kopie des {{{modern}}} Themes. Es ändert das Aussehen des headers. Alle anderen Einstellungen von {{{modern}}} werden übernommen.
{{{{{#!python
# -*- coding: iso-8859-1 -*-
"""
    exampletheme
    @license: GNU GPL, see COPYING for details.
"""
from MoinMoin.theme import modern

class Theme(modern.Theme):

    name = "modern"

    def header(self, d, **kw):
        html = [
            u'<div id="header">',
            self.searchform(d),
            self.username(d),
            self.navibar(d),
            u'<div id="pageline">',
            u'<hr style="display:none;"></div>',
            u'</div>',
            self.startPage(),
        ]


def execute(request):
    return Theme(request)
}}}}}
## [caption=theme (Veränderter Header im exampletheme abgeleitet von modern)]{theme}
Diese Änderungen geben dem Wiki ein anderes Aussehen( zum Vergleich siehe Abbildung [[#perswiki|perswiki]].


||{{attachment:exampletheme.png}}||
||ein modifiziertes Theme auf Basis des modern Themes||

Im nachfolgenden einige Beispiel Themes (SimpleMente <<FootNote(Mit freundlicher Genehmigung von Oliver Siemoneit)>> , classic_dark <<FootNote(Mit freundlicher Genehmigung von Heather Stern)>> , Explorer <<FootNote(Mit freundlicher Genehmigung von Wolfgang Fischer)>> , Green Mist <<FootNote(Mit freundlicher Genehmigung von Radomir Dopieralski)>> ),  die Gestaltungsmöglichkeiten aufzeigen. Diese Themes finden Sie auf ThemeMarket.


||{{attachment:simplemente-chico.png}}||
||SimpleMente||

||{{attachment:classic_dark.jpg}}||
||classic dark||

||{{attachment:explorer_theme.png}}||
||Explorer||

||{{attachment:greenmist.png}}||
||Green Mist||
-----
