Files
2026-09-04 17:36:50 +02:00

19 KiB

Paperless-Connector für LibreOffice

Erweiterung, die Dokumente direkt aus einem Paperless-ngx-Archiv öffnet, Bearbeitungen als neue Version desselben Dokuments ablegt, die Klassifizierung bearbeitet und zeitlich begrenzte Freigabelinks erzeugt.

Voraussetzung ist Paperless-ngx 3.0 oder neuer — erst dort gibt es die Dokumentversionierung.


Funktionen

Befehl Wirkung
Aus Paperless öffnen Suche, Trefferliste, Versionsliste — lädt das Original
Als neue Version ablegen hängt die Fassung als Version an das bestehende Dokument
In Paperless ablegen neues Dokument oder neue Version eines beliebigen anderen Dokuments
Klassifizierung bearbeiten Titel, Datum, Korrespondent, Dokumenttyp, Tags
Freigabelink erzeugen zeitlich begrenzter, unauthentifizierter Link, optional mit Kennzeichnung
Status anzeigen Kennung, Titel, Versionsanzahl des aktuellen Dokuments
Verbindung einrichten Basisadresse und API-Token

Erreichbar über das Menü Extras → Paperless und über eine eigene Symbolleiste.


Sprachen

Die Oberfläche liegt in Deutsch, Englisch und Französisch vor. Die Sprache richtet sich nach der Einstellung von LibreOffice, nicht nach der des Betriebssystems — maßgeblich ist die Sprache, in der die Erweiterung erscheint.

Übersetzt wird in pythonpath/paperless_i18n.py. Als Schlüssel dient der deutsche Text selbst; fehlt eine Übersetzung, erscheint das deutsche Original. Eine weitere Sprache ergänzt man, indem man ein Wörterbuch nach dem Muster von EN anlegt und in KATALOG einträgt.

Die Menü- und Symbolleistentexte liegen getrennt davon in Addons.xcu; dort sind sie je Sprache als xml:lang-Werte hinterlegt.

Sicherheit

Ausführlich in SICHERHEIT.md. Die wichtigsten Punkte:

  • Makros werden nie ausgeführt. Heruntergeladene Dateien werden mit MacroExecutionMode = NEVER_EXECUTE geladen — auch eine Rückfrage gibt es nicht. Ein Dokument aus dem Archiv ist fremder Inhalt, selbst aus dem eigenen Bestand.
  • Keine externen Inhalte beim Öffnen. UpdateDocMode = NO_UPDATE.
  • Dateinamen aus der Antwort werden vollständig bereinigt, beide Pfadtrennzeichen, Windows-Gerätenamen, Punkte am Ende.
  • Arbeitsverzeichnis im Benutzerprofil, nicht in /tmp — dort wäre ein Symlink-Angriff möglich.
  • Nur http und https als Basisadresse und bei Weiterleitungen.
  • Größenbegrenzung auf Antworten.

Bewusste Entwurfsentscheidungen

Eigene Schaltflächen statt Speichern-Knopf

Paperless als echtes Speicherziel in die Datei-Dialoge einzuhängen würde einen UCB Content Provider erfordern — C++-UNO-Arbeit in einer sehr dünn dokumentierten Ecke, für ein Einzelprojekt nicht tragfähig.

Eigene Schaltflächen sind ohnehin die ehrlichere Lösung: Es bleibt sichtbar, wann eine neue Version im Archiv entsteht, und ein versehentliches Strg+S erzeugt keine Archivversion.

Prüfungen vor der Freigabe

Ein Link auf einen Stand, der nur lokal existiert, wäre irreführend — der Empfänger bekäme etwas anderes zu sehen als der Absender vor sich hat. Deshalb wird vorher geprüft:

Zustand Reaktion
Dokument nicht in Paperless Angebot, es zuerst abzulegen
lokale Änderungen nicht abgelegt Auswahl: abbrechen, trotzdem teilen, oder erst neue Version ablegen

Zusätzlich lässt sich das Dokument beim Teilen mit einem Tag kennzeichnen, voreingestellt Sharelink. Das macht geteilte Dokumente später gezielt auffindbar — Paperless zeigt zwar die eigenen Freigaben an, aber ein Tag lässt sich in gespeicherten Ansichten und Regeln verwenden.

Der zuletzt verwendete Tagname wird gemerkt. Ist er noch nicht vorhanden, wird er nach Rückfrage angelegt. Vorhandene Tags des Dokuments bleiben erhalten.

Drei Wege ins Archiv

Befehl Ergebnis
Als neue Version ablegen eine weitere Fassung desselben Dokuments
In Paperless ablegen → Neues Dokument eigenständiges Dokument mit eigener Versionskette und Seriennummer
In Paperless ablegen → An bestehendes anhängen neue Version eines beliebigen anderen Dokuments

Der dritte Weg deckt eine Lücke, die Dokumentenverwaltungen gern offenlassen:

Die Rechnung kommt als PDF ins Archiv. Später entsteht die bearbeitbare Fassung. Beides gehört zusammen — aber das PDF war zuerst da.

„Als neue Version ablegen" zielt immer auf das eigene Wurzeldokument und hilft hier nicht. Über die Zielauswahl lässt sich dagegen jedes vorhandene Dokument suchen und die geöffnete Datei daran anhängen.

Beim neuen Dokument lässt sich die Klassifizierung des Ursprungs übernehmen — Dokumenttyp, Korrespondent, Tags, Zusatzfelder und Eigentümer. Zusatzfelder mit Herkunftsbezug werden bewusst nicht kopiert — wer aus einem anderen System migriert hat, führt dort oft ein Feld mit der Fremdkennung, und eine Kopie mit derselben Kennung wäre falsch. Welche Feldnamen das betrifft, steht in den Einstellungen unter herkunftsfelder.

In beiden Fällen kann das geöffnete Fenster danach dem Ziel zugeordnet werden. Weitere Versionen landen dann dort.

Der Befehl funktioniert auch mit Dateien, die nicht aus Paperless stammen — dann ist er der Weg, sie überhaupt erst einzuliefern.

Und er funktioniert mit Dokumenten, die noch nie gespeichert wurden. Ein frisch angelegtes „Unbenannt 1" hat keinen Speicherort; es wird dann in dasselbe temporäre Verzeichnis geschrieben, das auch beim Öffnen benutzt wird, im zur Anwendung passenden ODF-Format. Der eingegebene Titel bestimmt dabei den Dateinamen, unter dem Paperless das Original ablegt.

Ein Dialog von oben nach unten

┌─ Suche ──────────────────────────────────────── [Suchen] ─┐
│                                                            │
│  Dokumente          ASN        Datum        Titel          │
│  ┌──────────────────────────────────────────────────────┐  │
│  │ 11263      2024-02-11   Mietvertrag                  │  │
│  │ 11264      2024-03-02   Nebenkostenabrechnung        │  │
│  └──────────────────────────────────────────────────────┘  │
│                                                            │
│  Versionen          Nr.  Datum        Format   Bezeichnung │
│  ┌──────────────────────────────────────────────────────┐  │
│  │ • 3   2026-09-01   PDF        LibreOffice 2026-09-01 │  │
│  │   2   2025-06-04   ODF Text                          │  │
│  │   1   2024-02-11   ODF Text                          │  │
│  └──────────────────────────────────────────────────────┘  │
│  Bearbeitbar. Änderungen können als neue Version …         │
│  ☐ Schreibgeschützt öffnen           [Öffnen] [Abbrechen]  │
└────────────────────────────────────────────────────────────┘

Die Spaltenüberschrift steht jeweils unter der Bezeichnung des Abschnitts und über der Liste, nicht daneben.

Beide Listen verwenden eine dicht laufende Schrift mit festen Spaltenbreiten und senkrechten Strichen als Trenner. Die Schriftgröße wird bewusst nicht festgelegt, sondern vom Dialog geerbt — also die Vorgabe des Systems. Mit der sonst üblichen Proportionalschrift wären mit Leerzeichen aufgefüllte Spalten nicht ausgerichtet — die Überschrift stünde woanders als der Inhalt.

Die Trefferliste zeigt je Dokument einen Eintrag, nämlich das Wurzeldokument. Bei Auswahl füllt sich darunter die Versionsliste mit Nummer, Datum, Dateiformat und Bezeichnung.

Vorausgewählt ist die aktuellste Version. Ein Punkt markiert Fassungen, die LibreOffice nach der Formattabelle nicht bearbeiten kann — etwa ein PDF, während eine ältere Version noch das ODT ist.

Öffnungsart

Unten im Dialog wird die Öffnungsart gewählt. Die Vorbelegung ist ein Vorschlag, keine Vorschrift — die Formaterkennung kann danebenliegen, und dann soll der Anwender trotzdem bearbeitbar öffnen können.

Fall Vorbelegung Hinweis
bekannt und bearbeitbar Bearbeitbar
nicht erkannt Bearbeitbar zeigt Dateiname und MIME-Typ, damit das Format gemeldet und ergänzt werden kann
bekannt, nicht bearbeitbar (PDF, E-Mail) Schreibgeschützt bearbeitbar bleibt wählbar

Beim Zurückschreiben eines unbekannten Formats kommt eine Rückfrage: Es gibt dann keinen passenden Speicherfilter, LibreOffice speichert im eigenen Format, und die Dateiendung passt danach möglicherweise nicht mehr zum Inhalt.

Welche Formate als bearbeitbar gelten, steht in pythonpath/paperless_formats.py. Die Tabelle lässt sich dort ergänzen — wenn im Hinweistext regelmäßig derselbe MIME-Typ auftaucht, gehört er hinein.

Die Formatangabe steht nicht in der eingebetteten versions-Liste, deshalb ruft die Erweiterung je Version einen Datensatz ab. Die Ergebnisse werden zwischengespeichert, damit das Blättern in der Trefferliste nicht bei jedem Tastendruck erneut abfragt.

Immer das Original laden

Der Download erfolgt mit ?original=true. Bei ZUGFeRD bleibt damit die eingebettete XML erhalten, bei E-Mails die Anhänge. Die von Paperless erzeugte Archivfassung wäre eine Ableitung.

Kennung in den Dokumenteigenschaften

Die Paperless-ID wird in den benutzerdefinierten Dokumenteigenschaften abgelegt (PaperlessDocumentId). Diese überleben einen ODF-Speichervorgang und wandern sogar mit, wenn die Datei kopiert wird.

Als Rückfallebene dient eine lokale Zuordnungsdatei über den Datei-URL — für Formate, die keine solchen Eigenschaften kennen.

Betriebssystemneutral

Die Erweiterung läuft unter Linux, Windows und macOS. Was dafür nötig war:

Punkt Umsetzung
Konfigurationsort %APPDATA% unter Windows, sonst XDG_CONFIG_HOME bzw. ~/.config
Pfade durchgehend os.path.join, nie feste Trennzeichen
Datei-URLs unohelper.systemPathToFileUrl statt eigener Zusammensetzung
Dateinamen Windows-Verbotszeichen und Gerätenamen werden auch unter Linux entfernt

Eine Einschränkung: chmod ist unter Windows weitgehend wirkungslos. Die Einstellungsdatei mit dem Token liegt dort im Benutzerprofil, auf das andere Benutzer standardmäßig keinen Zugriff haben — der Schutz kommt also vom Betriebssystem statt von den Dateirechten.

build.sh ist ein Shell-Skript und läuft nur unter Linux und macOS. Es wird ausschließlich zur Entwicklung gebraucht; die fertige .oxt lässt sich überall installieren.

Ohne requests

Die in LibreOffice mitgelieferte Python-Laufzeit bringt nur die Standardbibliothek mit. Alles läuft über urllib, inklusive selbstgebautem Multipart-Upload.


Bauen und installieren

./build.sh
unopkg add --force paperless-libreoffice-1.1.0.oxt

Zur Versionsabhängigkeit: OpenOffice.org-minimal-version in description.xml bezieht sich auf die OpenOffice-Referenzversion, und die ist bei LibreOffice dauerhaft auf 4.1 eingefroren — unabhängig davon, ob die installierte Version 7, 24 oder 25 heißt. Ein Wert wie 7.0 schließt dort jede Installation aus und führt zu „Die Erweiterung benötigt mindestens OpenOffice.org Referenzversion 7.0".

Für echte LibreOffice-Versionen gibt es lo:LibreOffice-minimal-version im Namensraum http://libreoffice.org/extensions/description/2011.

LibreOffice danach vollständig beenden, auch den Schnellstarter:

pkill soffice

Entfernen:

unopkg remove org.example.paperless.libreoffice

Alternativ über Extras → Extension Manager.


Einrichten

  1. Extras → Paperless → Verbindung einrichten
  2. Basisadresse eintragen, etwa https://dms.example.org — ohne abschließenden Schrägstrich
  3. API-Token eintragen. Erzeugt wird er im Benutzerprofil von Paperless, nicht in der allgemeinen Verwaltung
  4. Speichern — die Verbindung wird sofort geprüft

Die Einstellungen liegen unter ~/.config/paperless-libreoffice/settings.json mit Modus 600.

Zum Token: Er liegt im Klartext in dieser Datei. Das entspricht dem, was andere Desktop-Anwendungen tun, ist aber kein Geheimnisspeicher. Wer es strenger will, müsste die Erweiterung an den Systemschlüsselbund anbinden — über com.sun.star.task.PasswordContainer oder libsecret.


Ablauf im Alltag

Extras → Paperless → Aus Paperless öffnen…
   Suchbegriff oder Archiv-Seriennummer eingeben
   Dokument auswählen → öffnet sich in LibreOffice

… bearbeiten, zwischendurch normal mit Strg+S speichern
   (bleibt lokal, das Archiv bleibt unberührt)

Extras → Paperless → Als neue Version ablegen
   Rückfrage bestätigen → Upload → Bestätigung mit Versions-ID

Die bisherige Fassung bleibt als Version erhalten. In Paperless entsteht kein neuer Eintrag, sondern eine Version am bestehenden Dokument.


Fehlersuche

Die Erweiterung erscheint nicht im Menü:

unopkg list | grep -i paperless

Fehlt sie, wurde LibreOffice nicht vollständig beendet. Python-Fehler beim Laden erscheinen auf der Konsole:

soffice --writer

Ausführlichere Meldungen mit:

SAL_LOG="+WARN+INFO.extensions" soffice --writer

Bekannte Stolpersteine

Dokument ohne Speicherort. Ein noch nie gespeichertes Dokument wird für die Ablage automatisch temporär geschrieben. In LibreOffice bleibt es danach weiterhin ungespeichert — das ist Absicht, damit nicht ungefragt eine Datei im Dateisystem entsteht, von der niemand weiß.

„Dieses Dokument stammt nicht aus Paperless." Die Kennung wurde nicht gefunden. Das passiert, wenn die Datei über den normalen Öffnen-Dialog geladen wurde oder das Format keine benutzerdefinierten Dokumenteigenschaften kennt.

Speichern in Fremdformaten. Beim Zurückspeichern eines DOCX oder XLSX wird der passende Filter gewählt (siehe FORMATS in pythonpath/paperless_formats.py). Fehlt ein Format dort, speichert LibreOffice als ODF — dann stimmt die Endung nicht mehr zum Inhalt.

Freigabelinks. Der Endpunkt heißt je nach Paperless-Version share_links/ oder sharelinks/. Beide werden probiert.

HTTP 403 nur über die Domain, nicht über die IP. Klassisches Zeichen dafür, dass ein Schutzsystem vor der Anwendung den User-Agent abweist. urllib sendet ohne Zutun Python-urllib/3.x, und diese Kennung steht in den Sperrlisten von CrowdSec, fail2ban und gängigen WAF-Regelwerken.

Die Erweiterung setzt deshalb eine eigene Kennung. Wird auch die abgewiesen, lässt sie sich in paperless_client.py über die Konstante USER_AGENT ändern.

Zum Nachstellen:

curl -s -o /dev/null -w '%{http_code}\n' -A "Python-urllib/3.10" \
  -H "Authorization: Token $PT" https://dms.example.org/api/documents/

403 gegenüber 200 mit der curl-Vorgabe bestätigt die Ursache. Die Fehlermeldung kann dabei von einem völlig anderen Dienst stammen als dem, den man ansprechen wollte.


Symbole

Alle Symbole teilen dieselbe Grundform — ein Blatt mit umgeknickter Ecke in Paperless-Grün — damit die Leiste als zusammengehörige Gruppe erkennbar bleibt. Unterschieden wird über eine farbige Scheibe unten rechts:

Befehl Beizeichen
Markensymbol gefüllte grüne Fläche mit weißem Blatt, ganz links in der Leiste
Öffnen blauer Pfeil nach unten
Neue Version oranger Pfeil nach oben mit Plus
In Paperless ablegen oranger Pfeil nach oben mit Sternchen, zweites Blatt dahinter
Klassifizierung violettes Etikett
Teilen türkise verbundene Punkte
Einstellungen graues Zahnrad

Das Markensymbol steht am Anfang der Leiste, durch einen Trenner von den Befehlen abgesetzt. Es ist mit Status anzeigen belegt, also nicht nur Zierde. Durch die gefüllte Fläche unterscheidet es sich deutlich von den Bordmitteln von LibreOffice — man sieht auf einen Blick, wo die Paperless-Leiste beginnt und endet.

Format

Registriert sind SVG. LibreOffice skaliert sie auf die eingestellte Symbolgröße (Extras → Optionen → Ansicht → Symbolgröße: Klein, Groß, Sehr groß). Mit PNG wären nur zwei feste Größen möglich, und bei „Sehr groß" würde hochgerechnet.

Erzeugt werden die Symbole mit make_icons.py aus einer gemeinsamen Geometriebeschreibung — SVG und PNG können deshalb nicht auseinanderlaufen. Das Skript braucht Pillow für die PNG-Ausgabe und wird nur zur Entwicklung gebraucht; die fertigen Dateien liegen unter icons/ und sind im Paket.

Zusätzlich zu den SVG enthält das Paket PNG in 16, 26 und 32 Pixeln als Rückfallebene. Sollte die SVG-Unterstützung in einer LibreOffice-Version nicht greifen und gar kein Symbol erscheinen, in Addons.xcu umstellen:

ImageSmallURL → %origin%/icons/paperless-NAME_16.png
ImageBigURL   → %origin%/icons/paperless-NAME_26.png

Reihenfolge in der Leiste

[Paperless] │ [Öffnen] [Neue Version] [Ablegen unter] [Klassifizierung] [Teilen] │ [Verbindung]

Aufbau

paperless_addon.py            Protokoll-Handler, Befehlslogik
make_icons.py                 erzeugt die Symbole (nur zur Entwicklung)
pythonpath/
  paperless_client.py         REST-Client, nur Standardbibliothek
  paperless_config.py         Einstellungen, Dokumentzuordnung
  paperless_dialogs.py        UNO-Dialoge, programmatisch aufgebaut
  paperless_formats.py        Formate, Filter, Bearbeitbarkeit
Addons.xcu                    Menü, Symbolleiste, Symbole
icons/                        16x16 und 26x26 PNG je Befehl
ProtocolHandler.xcu           Registrierung von paperless.Command:*

Der Protokoll-Handler ist der Kern: Menüeinträge lösen URLs wie paperless.Command:Open aus, die LibreOffice an die registrierte Klasse weiterreicht.


Stand und Grenzen

Version 1.1.0. Das Gerüst ist vollständig und die Client-Logik getestet, aber die Erweiterung ist an einer echten Instanz noch nicht über längere Zeit erprobt.

Nicht enthalten:

  • Zusatzfelder im Klassifizierungsdialog — nur die Grundfelder
  • Fortschrittsanzeige beim Upload — bei großen Dateien wirkt LibreOffice währenddessen eingefroren
  • Übersetzungen über die Oberflächentexte hinaus
  • Konfliktbehandlung, wenn dasselbe Dokument parallel anderswo geändert wurde

Der letzte Punkt ist der relevanteste für den Mehrbenutzerbetrieb. Paperless kennt keine Sperren; wer zeitgleich arbeitet, erzeugt zwei Versionen statt eines Konflikts. Bei einem kleinen Kreis ist das verschmerzbar.

Die Software wird ohne jegliche Gewähr oder Haftungsübernahme bereitgestellt. Die Nutzung erfolgt auf eigene Gefahr.