Do you Lisp Wiki

Das Do you Lisp Wiki ist eine Demoapplikation zum "Do you Lisp?" Framework und zum Lisp-Database-Package. Es handelt sich um eine Wiki-Engine mit folgenden Funktionen:

• Nutzer können sich registrieren, indem sie Name, E-Mail-Adresse und Passwort angeben. Nachdem ein anderer Nutzer dem Beitritt zugestimmt hat, kann ein Nutzer einloggen. Von dieser Regel ausgenommen ist der erste Nutzer des Wikis.
• Nutzer können ihre Registrierung löschen, wenn sie keine Dokumente besitzen.
• Dokumente können nur für den Besitzer, für alle eingeloggten Nutzer oder auch für anonyme Nutzer sichtbar sein.
• Dokumente können nur von ihrem Besitzer geändert oder gelöscht werden.
• Dokumente können Synonyme haben.
• Der Titel und die Synonyme eines Dokuments werden in anderen Dokumenten automatisch verlinkt.
• Der Besitzer kann ein Dokument an einen anderen Nutzer weitergeben. Der Transfer wird abgeschlossen, wenn der andere Nutzer zustimmt.
• Eingeloggte Nutzer können alle Dokumente taggen, die sie sehen können.
• Anhand eines Tags können die Dokumente auf der Index-Seite gefiltert werden.
• Die Funktionen zur Verwaltung der Dokumente können als
JSON Services angesprochen werden.

Das
Do you Lisp Wiki ist eine Weiterentwicklung des Wiki-Package.




Abbildung: Screenshot der Startseite (Wiki mit einigen Dokumenten).


Services

Query Document - Der Service query-document.object liefert eine Liste von Objekten, die jeweils die Felder id und title haben. Dabei handelt es sich um die Ids und Titel der sichtbaren Dokumente: [ { "id": 34, "title": "Abstract Window Toolkit" }, { "id": 24, "title": "Adapter" } ].

Login - Der Service login.object erwartet zwei Argumente, e-mail und password. Wenn mit der E-Mail-Adresse und dem Passwort erfolgreich eingeloggt werden konnte, wird ein
Objekt mit den Feldern first-name und last-name als Ergebnis übermittelt: { "first-name": "Andreas", "last-name": "Motzek" }. Anderenfalls ist das Resultat null. Nach einem erfolgreichen Login können die anderen, im Folgenden beschriebenen Services genutzt werden.

Create Document - Der Service create-document.object legt ein neues Dokument an. Er erwartet drei Argumente, den Titel (title), den Text (text) und die Sichtbarkeit (visibility). Der Service liefert die Id des angelegten Dokuments oder null, wenn das Dokument nicht angelegt werden konnte.

Find Document - Der Service find-document.object erwartet den Titel eines Dokuments als Argument mit Namen title. Wenn ein passendes Dokument existiert und sichtbar ist, dann wird das Dokument als
Objekt zurückgeliefert: { "id": 6, "userid": 1, "visibility": 1, "text": "\"Do you Lisp?\" ist [...]", "title": "Do you Lisp", "normalizedtitle": "do you lisp" }. Ansonsten ist das Resultat null.

Get Document - Der Service get-document.object liefert zu der Id eines Dokuments das zugehörige Dokument als
Objekt. Die Id muss als Wert des Parameters document-id übermittelt werden. Auch bei diesem Service ist das Resultat null, wenn zu der Id kein Dokument existiert, oder das Dokument nicht sichtbar ist.

Update Document - Mit dem Service update-document.object kann ein Dokument geändert werden. Der Service benötigt die document-id, den Titel (als title), die kommaseparierte Liste der Synonyme (als synonyms), den Text (als text) und die Sichtbarkeit (als visibility) als Argumente. Er liefert die document-id, wenn die Änderung des Dokuments übernommen wurde und anderenfalls null.

Delete Document - Der Service delete-document.object löscht ein Dokument, dass durch die document-id identifiziert wird. Das Resultat des Service-Aufrufs ist die document-id im Erfolgsfall oder null, falls ein Fehler aufgetreten ist.


Komponenten

Das
Do you Lisp Wiki besteht aus den folgenden Komponenten:

dojo Toolkit 0.4.0,
Apache
Derby 10.1.3.1,
"
Do you Lisp?" Framework, Lisp-Database-Package und weitere benötigte Packages,
Actions und Libraries.

Das
dojo Toolkit wird auf der Clientseite vom "Do you Lisp?" Framework benötigt. Apache Derby verwaltet die Datenbank, in der die Angaben über die Nutzer, die Wiki-Dokumente, die Tags und weitere Daten gespeichert werden. Das "Do you Lisp?" Framework und das Lisp-Database-Package dienen als Grundlage für die Realisierung der Actions und Libraries, von denen die Funktionen der Wiki-Engine bereitgestellt werden.


Prinzipielle Funktionsweise

Im Folgenden soll die prinzipielle Funktionsweise des "
Do you Lisp?" Frameworks anhand der Wiki-Startseite erläutert werden. Die Startseite hat die relative URL /index.page. Das bedeutet, dass der Inhalt der Seite von der gleichnamigen Action erzeugt wird.

<action>
<requires-library>/capabilities.library</requires-library>
<requires-library>/tag-cloud.library</requires-library>
<requires-library>/
index.library</requires-library>
<requires-library>/storage.library</requires-library>
<function>
(lambda (request)
(html-from-template
"/
index.html"
(pairlis
(quote (can-login can-create-document
index tags))
(list
(bool-to-string (can-login?))
(bool-to-string (can-create-document?))
(
index "/show-document.script" (visible-document-ids-and-names session-user-id))
(tag-cloud "/show-tag.script" (query-tags session-user-id)))
nil)))
</function>
</action>

Allen Actions ist gemeinsam, dass sie Funktionen sind, die den HTTP Request (beziehungsweise die in ihm enthaltenen Argumente) verarbeiten.

Im Fall von
index.page besteht die Verarbeitung darin, eine Instanz des HTML Templates index.html zu erzeugen. Das Template besteht aus gewöhnlichem HTML mit einigen eingestreuten HTML Kommentaren:

<
html>
<head>
<title>Wiki</title>
<script language="
JavaScript" type="text/javascript">
djConfig = { isDebug: true };
</script>
<script type="text/
javascript" src="/dojo-0.4.0-ajax/dojo.js"></script>
<script language="
JavaScript" type="text/javascript">
dojo.require("dojo.io.*");
dojo.require("dojo.widget.TitlePane");
</script>
</head>
<body>
<table>
<tr height="10" />
<tr>
[...]
<td valign="top">
<div id="content">
<!-- optional name="
can-login" value="true" -->
<a href="
javascript:void dojo.io.bind({preventCache:true, url:&quot;login-enter.script&quot;, mimetype:&quot;text/javascript&quot;})">Login</a><br>
<!-- /optional -->
<!-- optional name="
can-login" value="false" -->
<a href="
javascript:void dojo.io.bind({preventCache:true, url:&quot;member.script&quot;, mimetype:&quot;text/javascript&quot;})">Member</a><br>
<!-- /optional -->
<p>
<div dojoType="TitlePane" label="Tags">
<!-- insert type="list" name="
tags" -->
<!-- head -->
<br /><a href="
javascript:void dojo.io.bind({preventCache:true, url:&quot;index.script&quot;, mimetype:&quot;text/javascript&quot;})"><span style="font-size: 175%;">*</span></a>
<!-- /head -->
<!-- element -->
<a name="tag-link"><span name="tag-style"><!-- insert type="text" name="tag" --><!-- /insert --></span></a>
<!-- /element -->
<!-- tail -->
<br />
<!-- /tail -->
<!-- /insert -->
</div>
<p>
<div id="index-pane">
<div dojoType="TitlePane" label="
Index">
<!-- insert type="list" name="
index" -->
<!-- head -->
<br />
<!-- /head -->
<!-- element -->
<a name="document-link"><!-- insert type="text" name="title" --><!-- /insert --></a>
<!-- /element -->
<!-- tail -->
<!-- /tail -->
<!-- /insert -->
</div>
</div>
<p>
<!-- optional name=
"can-create-document" value="true" -->
<a href="
javascript:void dojo.io.bind({preventCache:true, url:&quot;create-document-enter.script&quot;, mimetype:&quot;text/javascript&quot;})">Neues Dokument anlegen</a>
<!-- /optional -->
</div>
</td>
<td width="10" />
</tr>
</table>
</body>
</
html>

Wenn eine Instanz des Templates erzeugt wird, dann bedeutet das, dass die vier Platzhalter can-login, can-create-document,
index und tags durch konkrete Werte ersetzt werden. Bei can-login und can-create-document werden dabei optionale Teile der Seite ein- oder ausgeblendet. Im Falle von tags und index werden Listen von Links erzeugt. Die Liste für den Index wird von der Library index.library anhand der URL url und der Dokumentenliste list aufgebaut:

<library>
<requires-library>/documents.library</requires-library>
<provides>
(setq
index
(lambda (url list)
(mapcar
(lambda (document)
(pairlis
(quote (document-link title))
(list2
(
dojo-link
url
(acons (quote document-id) (get-document-id document) nil))
(get-document-title document))
nil))
list)))
</provides>
</library>

Die von der Library definierte Funktion
index erzeugt eine Liste von Assoziationslisten, jeweils mit einem Link unter dem Namen document-link und den Dokumententitel unter dem Namen title. Der Link wird durch die Funktion dojo-link aus dem "Do you Lisp?" Framework gebildet, er verweist auf die URL /show-document.script und enthält außerdem die Id des Dokuments.

Wenn der Link geklickt wird, dann wird die Action show-document.script aktiv. Sie ermittelt aus dem Request die Id des Dokuments (document-id) und liest das betreffende Dokument aus der Datenbank (get-document-by-id). Zunächst wird daraufhin überprüft, ob der ggf. anonyme oder eingeloggte Nutzer das Dokument sehen darf (can-see-document?). Ist das der Fall, wird der Content-Bereich der Seite durch eine Instanz des Templates /show-document.
html ersetzt (replace-node-from-template), wobei die Daten des Dokuments Titel, E-Mail Adresse des Besitzers, Text) eingefüllt werden:

<action>
<requires-library>/capabilities.library</requires-library>
<requires-library>/wiki-text.library</requires-library>
<requires-library>/storage.library</requires-library>
<function>
(lambda (request)
(let
((
document-id (read-from-string (get-valueq document-id request))))
(let
((document (
get-document-by-id document-id)))
(if
(or
(null? document)
(not (
can-see-document? document)))
nil
(list
(
replace-node-from-template
(quote content)
"/show-document.
html"
(pairlis
(quote (title owner-e-mail text
can-login can-create-document can-edit-document can-tag-document can-offer-document can-accept-document can-delete-document
edit-link tag-link offer-link accept-link delete-link))
(list
(get-document-title document)
(get-user-e-mail (get-user-by-id (get-document-owner-id document)))
(make-wiki-text (get-document-text document))
(bool-to-string (can-login?))
(bool-to-string (can-create-document?))
(bool-to-string (can-edit-document? document))
(bool-to-string (can-tag-document? document))
(bool-to-string (can-offer-document? document))
(bool-to-string (can-accept-document? document))
(bool-to-string (can-delete-document? document))
(dojo-link "/edit-document-enter.script" (acons (quote document-id) document-id nil))
(dojo-link "/tag-document-enter.script" (acons (quote document-id) document-id nil))
(dojo-link "/offer-document-enter.script" (acons (quote document-id) document-id nil))
(dojo-link "/accept-document-enter.script" (acons (quote document-id) document-id nil))
(dojo-link "/delete-document-enter.script" (acons (quote document-id) document-id nil)))
nil)))))))
</function>
</action>


Download

Die Quelltexte des
Do you Lisp Wiki unterliegen der Modified Artistic License v1 finden sich in der Version v8 zusammen mit allen weiteren benötigten Dateien in der ZIP-Datei unter dieser URL: http://www.qrst.de/downloads/doyoulispwiki.zip

Nach dem Download und dem Entpacken des ZIPs kann das Wiki mit dem Shellscript startwiki.sh aus dem Installationsverzeichnis gestartet werden. Es wird eine Installation von
Java 1.4.2 oder neuer vorausgesetzt. Die Hauptseite des Wikis ist unter der URL http://localhost:8080/index.page zu erreichen. Nach dem ersten Start muss ein Nutzer angelegt werden (Login > Hier registrieren). Der erste Nutzer kann unmittelbar nach der Registrierung mit seiner E-Mail-Adresse und seinem Passwort einloggen. Bei allen weiteren frisch registrierten Nutzern ist erst eine Bestätigung durch einen alten Nutzer nötig (Member > Aufgaben bearbeiten).