Initial Commit
This commit is contained in:
29
LICENSE
29
LICENSE
@@ -1,18 +1,21 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2026 marco.morath
|
Copyright (c) 2026 Marco Morath
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
in the Software without restriction, including without limitation the rights
|
||||||
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
following conditions:
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
The above copyright notice and this permission notice shall be included in all
|
||||||
portions of the Software.
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|||||||
466
README.md
466
README.md
@@ -1,3 +1,465 @@
|
|||||||
# libreoffice-paperless-connector
|
# Paperless-Connector für LibreOffice
|
||||||
|
|
||||||
Addon für Libreoffice um Paperless-NGX anzubinden.
|
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](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
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pkill soffice
|
||||||
|
```
|
||||||
|
|
||||||
|
Entfernen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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ü:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
unopkg list | grep -i paperless
|
||||||
|
```
|
||||||
|
|
||||||
|
Fehlt sie, wurde LibreOffice nicht vollständig beendet. Python-Fehler beim
|
||||||
|
Laden erscheinen auf der Konsole:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
soffice --writer
|
||||||
|
```
|
||||||
|
|
||||||
|
Ausführlichere Meldungen mit:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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.
|
||||||
|
|||||||
Reference in New Issue
Block a user