User Generated Content mit dem Forum-Modul

In diesem Post möchte ich anhand eines konkreten Szenarios alle Schritte aufzeigen, die zur Inbetriebnahme des Forum-Moduls mit Magnolia 4.5.x notwendig sind.

Das Forum-Modul steht für Magnolia 4.5.x aktuell in der Version 1.3.4 bereit und beherrscht erst die grundlegendsten Forum-Funktionen:

  • Themen anlegen
  • Threads anlegen
  • Beiträge erfassen / Auf Beiträge antworten
    • Keine Zitate
    • Keine Code-Blocks
    • Keine Formatierung wie fettkursivunterstrichen
    • HTML möglich (!!)

Momentan ist eine überarbeitete Version (4.0) des Forums in Planung, die die oben genannten fehlenden Funktionen nachliefern soll. Wie hoch der Release dieser Version priorisiert ist kann ich aber nicht sagen.

Szenario

Ich vermute, dass die am häufigsten anzutreffende Konstellation von Magnolia-Instanzen aus 2 Public- und einer Autor-Instanz besteht. Deshalb wird es unser Ziel sein, das Forum so in diese Umgebung zu integrieren, dass:

  • Content der auf PublicA erfasst wird, automatisch auch auf PublicB erscheint und umgekehrt,
  • Forum-Beiträge von allen 3 Instanz aus moderiert werden können.

Author- und Public-Instanz

Synchronisierung des Contents

Damit Content der auf PublicA erfasst wurde auch auf PublicB gelangt, benötigen wir einen Mechanismus, der diese Synchronisierung immer wieder anstosst. Hier kommt die Clustering-Fähigkeit von Jackrabbit in’s Spiel. Denn Jackrabbit ermöglicht es uns, ein Repository zu konfigurieren, auf das alle unsere Magnolia-Instanzen zugreifen können. Jede Magnolia-Instanz repräsentiert einen Node. In unserem Fall werden wir 3 Nodes, PublicA, PublicB und Autor, anlegen und den Magnolia Forum-Workspace auf dieses spezielle Repository auslagern. Danach werden alle unseren Magnolia-Instanzen für den Forum-Content dieses zentrale Repository abfragen.

Clustering

Cluster einrichten

Voraussetzung für solch ein zentrales Repository ist ein Server der von allen Nodes erreicht werden kann, also aus dem internen Netz für die Autor-Instanz, sowie auch aus der DMZ für die beiden Public-Instanzen PublicA und PublicB. Auf diesem Server sollte eine Datenbank-Applikation installiert sein, da Datenbanken von Natur aus Cluster-fähig sind. Folgende Datenbanken werden von Jackrabbit unterstützt:

In meinem Beispiel installiere ich MySQL, lege eine Datenbank „magnolia“ an und erstelle einen Benutzer „magnolia“ mit Schreib- und Lesezugriff darauf.

Repository Mapping

Nun muss ich die Magnolia Repository-Konfiguration um ein zusätzliches Repository und ein neues Mapping erweitern. Das neue Repository ist unser zentrales Forum-Repository und das neue Mapping wird den Magnolia Forum-Workspace auf eben dieses Repository mappen. So weiss Magnolia, wo es die Forum-Daten abzulegen hat. Um die Konfiguration anzupassen öffne ich die Datei WEB-INF/config/default/repositories.xml und ergänze den Inhalt wie folgt.

Zuerst trage ich unser neues Forum-Repository ein, das unter den Nodes bzw. Magnolia-Instanzen geteilt werden soll:

<Repository name="magnolia_shared" provider="info.magnolia.jackrabbit.ProviderImpl" loadOnStartup="true">
    <!-- Unter dem property magnolia.repositories.jackrabbit.cluster.config wird in der Datei magnolia.properties der Pfad zur Jackrabbit-Konfiguration angegeben -->
    <param name="configFile" value="${magnolia.repositories.jackrabbit.cluster.config}" />
    <param name="repositoryHome" value="${magnolia.repositories.home}/magnolia_shared" />
    <param name="contextFactoryClass" value="org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory" />
    <param name="providerURL" value="localhost" />
    <param name="bindName" value="cluster-${magnolia.webapp}" />
    <workspace name="forum" />
</Repository>

Danach erweitere ich das Workspace-Mapping mit dem neuen Repository und mappe den Workspace „forum“ darauf:

<RepositoryMapping>
    <!-- bestehende mappings -->
     
    <!-- Mappt den Workspace "forum" auf das soeben konfigurierte Repository "magnolia_shared" -->
    <Map name="forum" repositoryName="magnolia_shared" workspaceName="forum" />
</RepositoryMapping>

Cluster-Konfiguration

Nun benötige ich für jede unserer Magnolia-Instanzen eine Cluster-Konfiguration. Hierfür trage ich zuerst den Pfad zur Konfiguration in die entsprechenden magnolia.properties ein.

  • WEB-INF/config/publicA/magnolia.properties
    magnolia.repositories.jackrabbit.cluster.config=WEB-INF/config/publicA/jackrabbit-bundle-mysql-search.xml
  • WEB-INF/config/publicB/magnolia.properties
    magnolia.repositories.jackrabbit.cluster.config=WEB-INF/config/publicB/jackrabbit-bundle-mysql-search.xml
  • WEB-INF/config/autor/magnolia.properties
    magnolia.repositories.jackrabbit.cluster.config=WEB-INF/config/autor/jackrabbit-bundle-mysql-search.xml

In den nächsten Schritten werden wir nun noch folgende Arbeiten erledigen:

  • Konfiguration für publicA kopieren
  • Konfiguration für publicA cluster-fähig machen
  • Konfiguration nach publicB und autor kopieren
  • Node-IDs in Konfiguration anpassen

Als erstes kopiere ich also eine der vorgefertigten Jackrabbit-Konfigurationen aus dem Ordner WEB-INF/config/repo-conf in meinen Ordner WEB-INF/config/publicA. Es existieren Konfigurationen für MySQL, Ingres und PostgreSQL. Hier die Konfiguration der DB-Applikation, die auch auf dem Server installiert ist, verwenden. Für mich ist das die MySQL-Konfiguration jackrabbit-bundle-mysql-search.xml.

Jetzt muss ich die Konfiguration cluster-fähig machen. Dafür müssen gemäss Jackrabbit-Dokumentation folgende Eigenschaften erfüllt werden:

  • Jeder Node benötigt eine eigene Cluster-Konfiguration (PublicA, PublicB und Autor)
  • Wird ein DataStore verwendet, muss dieser in jedem Fall „shared“ sein.
    • DataStores werden zur Ablage grosser Binaries verwendet.
  • Das globale FileSystem auf Repository level muss „shared“ sein.
    • Das FileSystem, das im XML auf gleicher Ebene mit dem DataStore ist.
  • Das FileSystem unter Workspace und Versioning ist privat.
  • Der SearchIndex unter Workspace ist privat.
  • Jeder Node benötigt eine eindeutige Cluster-ID.
  • Jeder Node muss auf das selbe geteilte Journal zugreifen.

Siehe auch Clustering Requirements.

Den Cluster-Voraussetzungen entsprechend beginne ich also die Konfiguration zu modifizieren. Als erstes konfiguriere ich zuoberst in der Datei meine geteilte Datenbank als DataSource. Somit ist mir möglich, in der Konfiguration stets darauf zu referenzieren.

Die fertige Konfiguration sieht wie folgt aus:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 2.0//EN" ">
<Repository>
  <DataSources>
    <DataSource name="magnolia">
      <param name="driver" value="com.mysql.jdbc.Driver" />
      <param name="url" value="jdbc:mysql://localhost:3306/magnolia" />
      <param name="user" value="root" />
      <param name="password" value="root" />
      <param name="databaseType" value="mysql"/>
      <param name="validationQuery" value="select 1"/>
    </DataSource>
  </DataSources>
  <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
     <!-- shared -->
     <param name="path" value="/Users/cbalaguer/projects/crisi-ch/magnolia-work_shared/repositories/magnolia_shared/repository" />
  </FileSystem>
  <Security appName="magnolia">
    <SecurityManager class="org.apache.jackrabbit.core.DefaultSecurityManager"/>
    <AccessManager class="org.apache.jackrabbit.core.security.DefaultAccessManager">
    </AccessManager>
    <!-- login module defined here is used by the repo to authenticate every request. not by the webapp to authenticate user against the webapp context (this one has to be passed before thing here gets invoked -->
    <LoginModule class="info.magnolia.jaas.sp.jcr.JackrabbitAuthenticationModule">
    </LoginModule>
  </Security>
  <DataStore class="org.apache.jackrabbit.core.data.FileDataStore">
    <!-- shared -->
    <param name="path" value="/Users/cbalaguer/projects/crisi-ch/magnolia-work_shared/repositories/magnolia_shared/repository/datastore"/>
    <param name="minRecordLength" value="1024"/>
  </DataStore>
  <Workspaces rootPath="${rep.home}/workspaces" defaultWorkspace="default" />
  <Workspace name="default">
    <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
      <param name="path" value="${wsp.home}/default" />
    </FileSystem>
    <PersistenceManager class="org.apache.jackrabbit.core.persistence.pool.MySqlPersistenceManager">
      <param name="dataSourceName" value="magnolia"/>
      <param name="schemaObjectPrefix" value="pm_${wsp.name}_" />
    </PersistenceManager>
    <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
      <param name="path" value="${wsp.home}/index" />
      <param name="useCompoundFile" value="true" />
      <param name="minMergeDocs" value="100" />
      <param name="volatileIdleTime" value="3" />
      <param name="maxMergeDocs" value="100000" />
      <param name="mergeFactor" value="10" />
      <param name="maxFieldLength" value="10000" />
      <param name="bufferSize" value="10" />
      <param name="cacheSize" value="1000" />
      <param name="forceConsistencyCheck" value="false" />
      <param name="autoRepair" value="true" />
      <param name="queryClass" value="org.apache.jackrabbit.core.query.QueryImpl" />
      <param name="respectDocumentOrder" value="true" />
      <param name="resultFetchSize" value="2147483647" />
      <param name="extractorPoolSize" value="3" />
      <param name="extractorTimeout" value="100" />
      <param name="extractorBackLogSize" value="100" />
    </SearchIndex>
    <WorkspaceSecurity>
      <AccessControlProvider class="info.magnolia.cms.core.MagnoliaAccessProvider" />
    </WorkspaceSecurity>
  </Workspace>
  <Versioning rootPath="${rep.home}/version">
    <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
      <param name="path" value="${rep.home}/workspaces/version" />
    </FileSystem>
    <PersistenceManager class="org.apache.jackrabbit.core.persistence.pool.MySqlPersistenceManager">
      <param name="dataSourceName" value="magnolia"/>
      <param name="schemaObjectPrefix" value="version_" />
    </PersistenceManager>
  </Versioning>
    <Cluster id="cid-publicA" syncDelay="2000">
        <Journal class="org.apache.jackrabbit.core.journal.DatabaseJournal">
            <param name="dataSourceName" value="magnolia"/>
            <param name="revision" value="${rep.home}/revision.log" />
            <param name="schemaObjectPrefix" value="journal_"/>
        </Journal>
    </Cluster>
</Repository>

Somit wäre die Konfiguration für die PublicA-Instanz fertig. Jetzt können wir die gleiche Datei auch in die Ordner WEB-INF/config/publicB und WEB-INF/config/autor kopieren. Danach muss jeweils noch die Cluster-ID angepasst werden. Aus cid-publicA wird also cid-publicB und cid-autor.

Die Konfigurations-Arbeiten sind abgeschlossen und die Instanzen können gestartet werden.

Forum Setup

Das Forum ist zurzeit noch nicht im STK integriert, was bedeutet, dass wir von Hand ein neues Forum-Template anlegen müssen und darauf die Forum-Komponenten freischalten, damit wir das Forum fertig einrichten können.

Welche Komponenten existieren und wie man die miteinander Verknüpfen muss, ist sehr gut in der Forum-Dokumentation von Magnolia beschrieben. Auch ein Schritt-für-Schritt-Tutorial findet ihr in der Dokumentation.

Nach dem Erstellen der Forum-Pages sollten die Unterseiten des Forums von der Navigation ausgeschlossen werden, um diesen Bug hier zu vermeiden. Danach sollte die Einstiegs-Seite für das Forum so aussehen:

Magnolia Forum Einstiegsseite

Workflow unseres Szenarios

Nachdem die Forum-Komponenten gemäss Anleitung erstellt und konfiguriert wurden, sieht der Workflow zur Erfassung und Freischaltung von neuem Content wie folgt aus.

Beitrag erstellen

Standardmässig haben anonyme Benutzer keinen Zugriff auf das Forum. Um anonymen Benutzern Leserechte und/oder Schreibrechte auf das Forum zu geben, muss dem Benutzer die Rolle forum-base für Leserechte und zusätzlich forum-user für Schreibrechte zugewiesen werden.

Magnolia Forum Neuer Thread

Anmerkung:
Ist in der Forum-Konfiguration unter /modules/forum/config das Property createRolesForNewForums auf true gesetzt, werden für jedes Forum-Thema folgende Rollen kreiert:

  • forum-<topicName>-user
  • forum-<topicName>-moderator
  • forum-<topicName>-admin

Dies erlaubt eine feinstufigere Rechte-Vergabe. Ist das Property hingegen auf false kann mit den 3 Rollen forum_ALL-userforum_ALL-moderator undforum_ALL-admin gearbeitet werden. Bei Unsicherheiten in den Rechten einer Rolle, können die ACLs des Forum- und Config-Workspaces kurz überprüft werden. Anhand der dort eingestellten Optionen sieht man sehr schnell was für konkrete Rechte eine Rolle hat:

  • forum-moderator-base
    Rechte im Config WorkspaceRechte im Forum Workspace

Weitere Informationen findet man in der Magnolia Forum-Dokumentation.

Moderation

Alle berechtigten User können nun den vorher erfassten Beitrag auf einer beliebigen Instanz unter Forums | Moderation sehen und nach der Überprüfung aktivieren.

Magnolia Forum Moderation

Mit einem Klick auf „Validate“ wird der Forum-Beitrag dann freigeschaltet und erscheint fortan auf allen Magnolia Instanzen.

Magnolia Forum Beitrag validieren

Anmerkung:
Das Forum hat in der aktuellen Version einen Bug in der Moderation-Page, die Seite ist immer leer. Dies ist nicht weiter tragisch, da die Beiträge ohnehin über eine andere Ansicht validiert werden. Ohne die Moderation-Page müssen die zu validierenden Beiträge aber in der Forum-Struktur gesucht werden.

Magnolia Forum Moderation-Page

Ein JIRA-Ticket zu diesem Issue existiert bereits. Ein Workaround für diesen Bug ist hier beschrieben. Kurz zusammengefasst müsste man:

  • info.magnolia.module.forum.admin.moderation.ModerationList extenden und in getModel()-Methode das eigene ModerationListModel zurückgeben.
  • info.magnolia.module.forum.admin.moderation.ModerationListModel kopieren und die getQuery()-Methode überschreiben (return null).
  • Unter /modules/forum/pages/forumModeration das class-Property mit der eigenen ModerationList-Klasse überschreiben.

Fazit

Das aktuelle Forum-Modul besitzt einen minimalen Funktionsumfang. Der Text kann nicht mit Rich-Text-Elementen wie Bildern, Links und Zitaten angereichert werden. Für ein ausgereiftes Forum-Modul müssen wir wohl auf die Version 4.0 warten. Gemäss Magnolia-Entwickler Grégory Joseph wird es dann möglich sein Bilder, Schrift-Formatierung, Zitate etc. einzubinden. Zusätzlich erschwert der ModerationPage-Bug das Auffinden der zu validierenden Beiträge. Bei einem Forum mit vielen Topics und hoher Aktivität kann dies sehr mühsam sein.
Wer also eine Community-Page aufbauen möchte, ist momentan mit der Integration einer ausgewachsenen Forum-Plattform sicher besser bedient. Die Integration des Forums über ein iFrame wäre z.B. eine Möglichkeit.

Resourcen

Update
Das Forum-Modul existiert nun in der Version 3 und wurde für Magnolia 5 kompatibel gemacht.

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

*

*

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>