diff --git a/docs/changelog.rst b/docs/changelog.rst index c4443504f..d6ad73ce2 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,6 +5,16 @@ Changelog ********* +paperless-ng 0.9.4 +################## + +* Front end: Clickable tags, correspondents and types allow quick filtering for related documents. +* Front end: Saved views are now editable. +* Front end: Preview documents directly in the browser. +* Fixes: + * A severe error when trying to use post consume scripts. +* The documentation now contains information about bare metal installs. + paperless-ng 0.9.3 ################## @@ -20,7 +30,7 @@ paperless-ng 0.9.3 aware of. * Issue with the automatic classifier not working with only one tag. * A couple issues with the search index being opened to eagerly. - + * Added lots of tests for various parts of the application. paperless-ng 0.9.2 diff --git a/docs/setup.rst b/docs/setup.rst index 4e2826dd6..9853ce2f1 100644 --- a/docs/setup.rst +++ b/docs/setup.rst @@ -208,9 +208,147 @@ Docker Route Bare Metal Route ================ -.. warning:: +Paperless runs on linux only. The following procedure has been tested on a minimal +installation of Debian/Buster, which is the current stable release at the time of +writing. Windows is not and will never be supported. - TBD. User docker for now. +1. Install dependencies. Paperless requires the following packages. + + * ``python3`` 3.6, 3.7, 3.8 (3.9 is untested). + * ``python3-pip``, optionally ``pipenv`` for package installation + * ``python3-dev`` + + * ``imagemagick`` >= 6 for PDF conversion + * ``unpaper`` for cleaning documents before OCR + * ``ghostscript`` + * ``optipng`` for optimising thumbnails + * ``tesseract-ocr`` >= 4.0.0 for OCR + * ``tesseract-ocr`` language packs (``tesseract-ocr-eng``, ``tesseract-ocr-deu``, etc) + * ``gnupg`` for handling encrypted documents + * ``libpoppler-cpp-dev`` for PDF to text conversion + * ``libmagic-dev`` for mime type detection + * ``libpq-dev`` for PostgreSQL + + You will also need ``build-essential``, ``python3-setuptools`` and ``python3-wheel`` + for installing some of the python dependencies. You can remove that + again after installation. + +2. Install ``redis`` >= 5.0 and configure it to start automatically. + +3. Optional. Install ``postgresql`` and configure a database, user and password for paperless. If you do not wish + to use PostgreSQL, SQLite is avialable as well. + +4. Get the release archive. If you pull the git repo as it is, you also have to compile the front end by yourself. + Extract the frontend to a place from where you wish to execute it, such as ``/opt/paperless``. + +5. Configure paperless. See :ref:`configuration` for details. Edit the included ``paperless.conf`` and adjust the + settings to your needs. Required settings for getting paperless running are: + + * ``PAPERLESS_REDIS`` should point to your redis server, such as redis://localhost:6379. + * ``PAPERLESS_DBHOST`` should be the hostname on which your PostgreSQL server is running. Do not configure this + to use SQLite instead. Also configure port, database name, user and password as necessary. + * ``PAPERLESS_CONSUMPTION_DIR`` should point to a folder which paperless should watch for documents. You might + want to have this somewhere else. Likewise, ``PAPERLESS_DATA_DIR`` and ``PAPERLESS_MEDIA_ROOT`` define where + paperless stores its data. If you like, you can point both to the same directory. + * ``PAPERLESS_SECRET_KEY`` should be a random sequence of characters. It's used for authentication. Failure + to do so allows third parties to forge authentication credentials. + + Many more adjustments can be made to paperless, especially the OCR part. The following options are recommended + for everyone: + + * Set ``PAPERLESS_OCR_LANGUAGE`` to the language most of your documents are written in. + * Set ``PAPERLESS_TIME_ZONE`` to your local time zone. + +6. Setup permissions. Create a system users under which you wish to run paperless. Ensure that these directories exist + and that the user has write permissions to the following directories + + * ``/opt/paperless/media`` + * ``/opt/paperless/data`` + * ``/opt/paperless/consume`` + + Adjust as necessary if you configured different folders. + +7. Install python requirements. Paperless comes with both Pipfiles for ``pipenv`` as well as with a ``requirements.txt``. + Both will install exactly the same requirements. It is up to you if you wish to use a virtual environment or not. + +8. Go to ``/opt/paperless/src``, and execute the following commands: + + .. code:: bash + + # This collects static files from paperless and django. + python3 manage.py collectstatic --clear --no-input + + # This creates the database schema. + python3 manage.py migrate + + # This creates your first paperless user + python3 manage.py createsuperuser + +9. Optional: Test that paperless is working by executing + + .. code:: bash + + # This collects static files from paperless and django. + python3 manage.py runserver + + and pointing your browser to http://localhost:8000/. + + .. warning:: + + This is a development server which should not be used in + production. + + .. hint:: + + This will not start the consumer. Paperless does this in a + separate process. + +10. Setup systemd services to run paperless automatically. You may + use the service definition files included in the ``scripts`` folder + as a starting point. + + Paperless needs the ``webserver`` script to run the webserver, the + ``consumer`` script to watch the input folder, and the ``scheduler`` + script to run tasks such as email checking and document consumption. + + These services rely on redis and optionally the database server, but + don't need to be started in any particular order. The example files + depend on redis being started. If you use a database server, you should + add additinal dependencies. + + .. hint:: + + You may optionally set up your preferred web server to serve + paperless as a wsgi application directly instead of running the + ``webserver`` service. The module containing the wsgi application + is named ``paperless.wsgi``. + + .. caution:: + + The included scripts run a ``gunicorn`` standalone server, + which is fine for running paperless. It does support SSL, + however, the documentation of GUnicorn states that you should + use a proxy server in front of gunicorn instead. + +11. Optional: Install a samba server and make the consumption folder + available as a network share. + +12. Configure ImageMagick to allow processing of PDF documents. Most distributions have + this disabled by default, since PDF documents can contain malware. If + you don't do this, paperless will fall back to ghostscript for certain steps + such as thumbnail generation. + + Edit ``/etc/ImageMagick-6/policy.xml`` and adjust + + .. code:: + + + + to + + .. code:: + + Migration to paperless-ng ######################### diff --git a/scripts/make-release.sh b/scripts/make-release.sh index 3c3892aed..0a7bc7a9b 100755 --- a/scripts/make-release.sh +++ b/scripts/make-release.sh @@ -42,6 +42,7 @@ fi mkdir "$PAPERLESS_DIST" mkdir "$PAPERLESS_DIST_APP" mkdir "$PAPERLESS_DIST_APP/docker" +mkdir "$PAPERLESS_DIST_APP/scripts" mkdir "$PAPERLESS_DIST_DOCKERFILES" # setup dependencies. @@ -104,6 +105,11 @@ cp "$PAPERLESS_ROOT/docker/gunicorn.conf.py" "$PAPERLESS_DIST_APP/docker/" cp "$PAPERLESS_ROOT/docker/imagemagick-policy.xml" "$PAPERLESS_DIST_APP/docker/" cp "$PAPERLESS_ROOT/docker/supervisord.conf" "$PAPERLESS_DIST_APP/docker/" +# auxiliary files for bare metal installs +cp "$PAPERLESS_ROOT/scripts/paperless-webserver.service" "$PAPERLESS_DIST_APP/scripts/" +cp "$PAPERLESS_ROOT/scripts/paperless-consumer.service" "$PAPERLESS_DIST_APP/scripts/" +cp "$PAPERLESS_ROOT/scripts/paperless-scheduler.service" "$PAPERLESS_DIST_APP/scripts/" + # try to make the docker build. cd "$PAPERLESS_DIST_APP" diff --git a/scripts/paperless-consumer.service b/scripts/paperless-consumer.service index 79a27d3ce..04512b719 100644 --- a/scripts/paperless-consumer.service +++ b/scripts/paperless-consumer.service @@ -1,10 +1,12 @@ [Unit] Description=Paperless consumer +Requires=redis.service [Service] User=paperless Group=paperless -ExecStart=/home/paperless/project/virtualenv/bin/python /home/paperless/project/src/manage.py document_consumer +WorkingDirectory=/opt/paperless/src +ExecStart=python3 manage.py document_consumer [Install] WantedBy=multi-user.target diff --git a/scripts/paperless-scheduler.service b/scripts/paperless-scheduler.service new file mode 100644 index 000000000..c565d8af4 --- /dev/null +++ b/scripts/paperless-scheduler.service @@ -0,0 +1,12 @@ +[Unit] +Description=Paperless consumer +Requires=redis.service + +[Service] +User=paperless +Group=paperless +WorkingDirectory=/opt/paperless/src +ExecStart=python3 manage.py qcluster + +[Install] +WantedBy=multi-user.target diff --git a/scripts/paperless-webserver.service b/scripts/paperless-webserver.service index 8ff746be2..a43110be2 100644 --- a/scripts/paperless-webserver.service +++ b/scripts/paperless-webserver.service @@ -2,11 +2,13 @@ Description=Paperless webserver After=network.target Wants=network.target +Requires=redis.service [Service] User=paperless Group=paperless -ExecStart=/home/paperless/project/virtualenv/bin/gunicorn --pythonpath=/home/paperless/project/src paperless.wsgi -w 2 +WorkingDirectory=/opt/paperless/src +ExecStart=/opt/paperless/.local/bin/gunicorn paperless.wsgi -w 2 -b 0.0.0.0:8000 [Install] WantedBy=multi-user.target diff --git a/src-ui/src/app/components/common/tag/tag.component.html b/src-ui/src/app/components/common/tag/tag.component.html index a83c53c77..8b9632a65 100644 --- a/src-ui/src/app/components/common/tag/tag.component.html +++ b/src-ui/src/app/components/common/tag/tag.component.html @@ -1,2 +1,2 @@ {{tag.name}} -{{tag.name}} \ No newline at end of file +{{tag.name}} \ No newline at end of file diff --git a/src-ui/src/app/components/common/tag/tag.component.ts b/src-ui/src/app/components/common/tag/tag.component.ts index ec59e86f3..c032c51db 100644 --- a/src-ui/src/app/components/common/tag/tag.component.ts +++ b/src-ui/src/app/components/common/tag/tag.component.ts @@ -14,10 +14,10 @@ export class TagComponent implements OnInit { tag: PaperlessTag @Input() - clickable: boolean = false + linkTitle: string = "" - @Output() - click = new EventEmitter() + @Input() + clickable: boolean = false ngOnInit(): void { } diff --git a/src-ui/src/app/components/document-detail/document-detail.component.ts b/src-ui/src/app/components/document-detail/document-detail.component.ts index 21ed6a4a5..7c396692e 100644 --- a/src-ui/src/app/components/document-detail/document-detail.component.ts +++ b/src-ui/src/app/components/document-detail/document-detail.component.ts @@ -1,4 +1,3 @@ -import { DatePipe, formatDate } from '@angular/common'; import { Component, OnInit } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; @@ -7,17 +6,14 @@ import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'; import { PaperlessDocument } from 'src/app/data/paperless-document'; import { PaperlessDocumentMetadata } from 'src/app/data/paperless-document-metadata'; import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'; -import { TAG_COLOURS, PaperlessTag } from 'src/app/data/paperless-tag'; import { DocumentListViewService } from 'src/app/services/document-list-view.service'; import { OpenDocumentsService } from 'src/app/services/open-documents.service'; import { CorrespondentService } from 'src/app/services/rest/correspondent.service'; import { DocumentTypeService } from 'src/app/services/rest/document-type.service'; import { DocumentService } from 'src/app/services/rest/document.service'; -import { TagService } from 'src/app/services/rest/tag.service'; import { DeleteDialogComponent } from '../common/delete-dialog/delete-dialog.component'; import { CorrespondentEditDialogComponent } from '../manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component'; import { DocumentTypeEditDialogComponent } from '../manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component'; -import { TagEditDialogComponent } from '../manage/tag-list/tag-edit-dialog/tag-edit-dialog.component'; @Component({ selector: 'app-document-detail', @@ -140,8 +136,8 @@ export class DocumentDetailComponent implements OnInit { close() { this.openDocumentService.closeDocument(this.document) - if (this.documentListViewService.viewId) { - this.router.navigate(['view', this.documentListViewService.viewId]) + if (this.documentListViewService.savedViewId) { + this.router.navigate(['view', this.documentListViewService.savedViewId]) } else { this.router.navigate(['documents']) } diff --git a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html index 305cb37d2..63a8bf710 100644 --- a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html +++ b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html @@ -7,7 +7,12 @@
-
{{document.correspondent ? document.correspondent.name + ': ' : ''}}{{document.title}}
+
+ + {{document.correspondent.name}}: + + {{document.title}} +
#{{document.archive_serial_number}}

@@ -24,6 +29,13 @@ Edit + + + + + + View + diff --git a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.ts b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.ts index 1c1e110c0..4a44909ec 100644 --- a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.ts +++ b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.ts @@ -1,6 +1,7 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; import { PaperlessDocument } from 'src/app/data/paperless-document'; +import { PaperlessTag } from 'src/app/data/paperless-tag'; import { DocumentService } from 'src/app/services/rest/document.service'; @Component({ @@ -18,6 +19,12 @@ export class DocumentCardLargeComponent implements OnInit { @Input() details: any + @Output() + clickTag = new EventEmitter() + + @Output() + clickCorrespondent = new EventEmitter() + ngOnInit(): void { } @@ -41,4 +48,8 @@ export class DocumentCardLargeComponent implements OnInit { getDownloadUrl() { return this.documentService.getDownloadUrl(this.document.id) } + + getPreviewUrl() { + return this.documentService.getPreviewUrl(this.document.id) + } } diff --git a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html index 022b92a4d..4da5cdf9b 100644 --- a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html +++ b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html @@ -2,26 +2,34 @@

- +
-