mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			feature-ma
			...
			feature-rt
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 292d7762c4 | 
							
								
								
									
										14
									
								
								.codecov.yml
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								.codecov.yml
									
									
									
									
									
								
							| @@ -14,9 +14,6 @@ flag_management: | ||||
| # codecov will only comment if coverage changes | ||||
| comment: | ||||
|   require_changes: true | ||||
|   # https://docs.codecov.com/docs/javascript-bundle-analysis | ||||
|   require_bundle_changes: true | ||||
|   bundle_change_threshold: "50Kb" | ||||
| coverage: | ||||
|   status: | ||||
|     project: | ||||
| @@ -25,12 +22,7 @@ coverage: | ||||
|         threshold: 1% | ||||
|     patch: | ||||
|       default: | ||||
|         # For the changed lines only, target 100% covered, but | ||||
|         # allow as low as 75% | ||||
|         target: 100% | ||||
|         # For the changed lines only, target 75% covered, but | ||||
|         # allow as low as 50% | ||||
|         target: 75% | ||||
|         threshold: 25% | ||||
| # https://docs.codecov.com/docs/javascript-bundle-analysis | ||||
| bundle_analysis: | ||||
|   # Fail if the bundle size increases by more than 1MB | ||||
|   warning_threshold: "1MB" | ||||
|   status: true | ||||
|   | ||||
| @@ -1,3 +1,3 @@ | ||||
| [codespell] | ||||
| write-changes = True | ||||
| ignore-words-list = criterias,afterall,valeu,ureue,equest,ure,assertIn | ||||
| ignore-words-list = criterias,afterall,valeu,ureue,equest,ure | ||||
|   | ||||
| @@ -1,180 +0,0 @@ | ||||
| # syntax=docker/dockerfile:1 | ||||
|  | ||||
| FROM --platform=$BUILDPLATFORM docker.io/node:20-bookworm-slim as main-app | ||||
|  | ||||
| ARG DEBIAN_FRONTEND=noninteractive | ||||
|  | ||||
| # Buildx provided, must be defined to use though | ||||
| ARG TARGETARCH | ||||
|  | ||||
| # Can be workflow provided, defaults set for manual building | ||||
| ARG JBIG2ENC_VERSION=0.29 | ||||
| ARG QPDF_VERSION=11.9.0 | ||||
| ARG GS_VERSION=10.03.1 | ||||
|  | ||||
| # Set Python environment variables | ||||
| ENV PYTHONDONTWRITEBYTECODE=1 \ | ||||
|     PYTHONUNBUFFERED=1 \ | ||||
|     # Ignore warning from Whitenoise | ||||
|     PYTHONWARNINGS="ignore:::django.http.response:517" \ | ||||
|     PNGX_CONTAINERIZED=1 | ||||
|  | ||||
| # | ||||
| # Begin installation and configuration | ||||
| # Order the steps below from least often changed to most | ||||
| # | ||||
|  | ||||
| # Packages need for running | ||||
| ARG RUNTIME_PACKAGES="\ | ||||
|   # General utils | ||||
|   curl \ | ||||
|   # Docker specific | ||||
|   gosu \ | ||||
|   # Timezones support | ||||
|   tzdata \ | ||||
|   # fonts for text file thumbnail generation | ||||
|   fonts-liberation \ | ||||
|   gettext \ | ||||
|   ghostscript \ | ||||
|   gnupg \ | ||||
|   icc-profiles-free \ | ||||
|   imagemagick \ | ||||
|   # PostgreSQL | ||||
|   postgresql-client \ | ||||
|   # MySQL / MariaDB | ||||
|   mariadb-client \ | ||||
|   # OCRmyPDF dependencies | ||||
|   tesseract-ocr \ | ||||
|   tesseract-ocr-eng \ | ||||
|   tesseract-ocr-deu \ | ||||
|   tesseract-ocr-fra \ | ||||
|   tesseract-ocr-ita \ | ||||
|   tesseract-ocr-spa \ | ||||
|   unpaper \ | ||||
|   pngquant \ | ||||
|   jbig2dec \ | ||||
|   # lxml | ||||
|   libxml2 \ | ||||
|   libxslt1.1 \ | ||||
|   # itself | ||||
|   qpdf \ | ||||
|   # Mime type detection | ||||
|   file \ | ||||
|   libmagic1 \ | ||||
|   media-types \ | ||||
|   zlib1g \ | ||||
|   # Barcode splitter | ||||
|   libzbar0 \ | ||||
|   poppler-utils \ | ||||
|   htop \ | ||||
|   sudo" | ||||
|  | ||||
| # Install basic runtime packages. | ||||
| # These change very infrequently | ||||
| RUN set -eux \ | ||||
|   echo "Installing system packages" \ | ||||
|     && apt-get update \ | ||||
|     && apt-get install --yes --quiet --no-install-recommends ${RUNTIME_PACKAGES} | ||||
|  | ||||
| ARG PYTHON_PACKAGES="\ | ||||
|   python3 \ | ||||
|   python3-pip \ | ||||
|   python3-wheel \ | ||||
|   pipenv \ | ||||
|   ca-certificates" | ||||
|  | ||||
| RUN set -eux \ | ||||
|   echo "Installing python packages" \ | ||||
|     && apt-get update \ | ||||
|     && apt-get install --yes --quiet ${PYTHON_PACKAGES} | ||||
|  | ||||
| RUN set -eux \ | ||||
|   && echo "Installing pre-built updates" \ | ||||
|     && echo "Installing qpdf ${QPDF_VERSION}" \ | ||||
|       && curl --fail --silent --show-error --location \ | ||||
|         --output libqpdf29_${QPDF_VERSION}-1_${TARGETARCH}.deb \ | ||||
|         https://github.com/paperless-ngx/builder/releases/download/qpdf-${QPDF_VERSION}/libqpdf29_${QPDF_VERSION}-1_${TARGETARCH}.deb \ | ||||
|       && curl --fail --silent --show-error --location \ | ||||
|         --output qpdf_${QPDF_VERSION}-1_${TARGETARCH}.deb \ | ||||
|         https://github.com/paperless-ngx/builder/releases/download/qpdf-${QPDF_VERSION}/qpdf_${QPDF_VERSION}-1_${TARGETARCH}.deb \ | ||||
|       && dpkg --install ./libqpdf29_${QPDF_VERSION}-1_${TARGETARCH}.deb \ | ||||
|       && dpkg --install ./qpdf_${QPDF_VERSION}-1_${TARGETARCH}.deb \ | ||||
|     && echo "Installing Ghostscript ${GS_VERSION}" \ | ||||
|       && curl --fail --silent --show-error --location \ | ||||
|           --output libgs10_${GS_VERSION}.dfsg-1_${TARGETARCH}.deb \ | ||||
|           https://github.com/paperless-ngx/builder/releases/download/ghostscript-${GS_VERSION}/libgs10_${GS_VERSION}.dfsg-1_${TARGETARCH}.deb \ | ||||
|       && curl --fail --silent --show-error --location \ | ||||
|           --output ghostscript_${GS_VERSION}.dfsg-1_${TARGETARCH}.deb \ | ||||
|           https://github.com/paperless-ngx/builder/releases/download/ghostscript-${GS_VERSION}/ghostscript_${GS_VERSION}.dfsg-1_${TARGETARCH}.deb \ | ||||
|       && curl --fail --silent --show-error --location \ | ||||
|           --output libgs10-common_${GS_VERSION}.dfsg-1_all.deb \ | ||||
|           https://github.com/paperless-ngx/builder/releases/download/ghostscript-${GS_VERSION}/libgs10-common_${GS_VERSION}.dfsg-1_all.deb \ | ||||
|         && dpkg --install ./libgs10-common_${GS_VERSION}.dfsg-1_all.deb \ | ||||
|         && dpkg --install ./libgs10_${GS_VERSION}.dfsg-1_${TARGETARCH}.deb \ | ||||
|         && dpkg --install ./ghostscript_${GS_VERSION}.dfsg-1_${TARGETARCH}.deb \ | ||||
|     && echo "Installing jbig2enc" \ | ||||
|       && curl --fail --silent --show-error --location \ | ||||
|         --output jbig2enc_${JBIG2ENC_VERSION}-1_${TARGETARCH}.deb \ | ||||
|         https://github.com/paperless-ngx/builder/releases/download/jbig2enc-${JBIG2ENC_VERSION}/jbig2enc_${JBIG2ENC_VERSION}-1_${TARGETARCH}.deb \ | ||||
|       && dpkg --install ./jbig2enc_${JBIG2ENC_VERSION}-1_${TARGETARCH}.deb | ||||
|  | ||||
| # setup docker-specific things | ||||
| # These change sometimes, but rarely | ||||
| WORKDIR /usr/src/paperless/src/docker/ | ||||
|  | ||||
| COPY [ \ | ||||
|   "docker/rootfs/etc/ImageMagick-6/paperless-policy.xml", \ | ||||
|   "./" \ | ||||
| ] | ||||
|  | ||||
| RUN set -eux \ | ||||
|   && echo "Configuring ImageMagick" \ | ||||
|     && mv paperless-policy.xml /etc/ImageMagick-6/policy.xml | ||||
|  | ||||
| # Packages needed only for building a few quick Python | ||||
| # dependencies | ||||
| ARG BUILD_PACKAGES="\ | ||||
|   build-essential \ | ||||
|   git \ | ||||
|   # https://www.psycopg.org/docs/install.html#prerequisites | ||||
|   libpq-dev \ | ||||
|   # https://github.com/PyMySQL/mysqlclient#linux | ||||
|   default-libmysqlclient-dev \ | ||||
|   pkg-config \ | ||||
|   pre-commit" | ||||
|  | ||||
| # hadolint ignore=DL3042 | ||||
| RUN --mount=type=cache,target=/root/.cache/pip/,id=pip-cache \ | ||||
|   set -eux \ | ||||
|   && echo "Installing build system packages" \ | ||||
|     && apt-get update \ | ||||
|     && apt-get install --yes --quiet ${BUILD_PACKAGES} | ||||
|  | ||||
| RUN set -eux \ | ||||
|   && npm update npm -g | ||||
|  | ||||
| # add users, setup scripts | ||||
| # Mount the compiled frontend to expected location | ||||
| RUN set -eux \ | ||||
|   && echo "Setting up user/group" \ | ||||
|     && groupmod --new-name paperless node \ | ||||
|     && usermod --login paperless --home /usr/src/paperless node \ | ||||
|     && usermod -s /bin/bash paperless \ | ||||
|     && echo "paperless ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers \ | ||||
|   && echo "Creating volume directories" \ | ||||
|     && mkdir --parents --verbose /usr/src/paperless/paperless-ngx/data \ | ||||
|     && mkdir --parents --verbose /usr/src/paperless/paperless-ngx/media \ | ||||
|     && mkdir --parents --verbose /usr/src/paperless/paperless-ngx/consume \ | ||||
|     && mkdir --parents --verbose /usr/src/paperless/paperless-ngx/export \ | ||||
|     && mkdir --parents --verbose /usr/src/paperless/paperless-ngx/.venv \ | ||||
|   && echo "Adjusting all permissions" \ | ||||
|     && chown --from root:root --changes --recursive paperless:paperless /usr/src/paperless | ||||
| #  && echo "Collecting static files" \ | ||||
| #    && gosu paperless python3 manage.py collectstatic --clear --no-input --link \ | ||||
| #    && gosu paperless python3 manage.py compilemessages | ||||
|  | ||||
| VOLUME ["/usr/src/paperless/paperless-ngx/data", \ | ||||
|         "/usr/src/paperless/paperless-ngx/media", \ | ||||
|         "/usr/src/paperless/paperless-ngx/consume", \ | ||||
|         "/usr/src/paperless/paperless-ngx/export", \ | ||||
|         "/usr/src/paperless/paperless-ngx/.venv"] | ||||
| @@ -1,28 +0,0 @@ | ||||
| { | ||||
|     "name": "Paperless Development", | ||||
|     "dockerComposeFile": "docker-compose.devcontainer.sqlite-tika.yml", | ||||
|     "service": "paperless-development", | ||||
|     "workspaceFolder": "/usr/src/paperless/paperless-ngx", | ||||
|     "postCreateCommand": "pipenv install --dev && pipenv run pre-commit install", | ||||
|     "customizations": { | ||||
|         "vscode": { | ||||
|           "extensions": [ | ||||
|             "mhutchie.git-graph", | ||||
|             "ms-python.python", | ||||
|             "ms-vscode.js-debug-nightly", | ||||
|             "eamodio.gitlens", | ||||
|             "yzhang.markdown-all-in-one" | ||||
|           ], | ||||
|           "settings": { | ||||
|             "python.defaultInterpreterPath": "/usr/src/paperless/paperless-ngx/.venv/bin/python", | ||||
|             "python.pythonPath": "/usr/src/paperless/paperless-ngx/.venv/bin/python", | ||||
|             "python.terminal.activateEnvInCurrentTerminal": true, | ||||
|             "editor.formatOnPaste": false, | ||||
|             "editor.formatOnSave": true, | ||||
|             "editor.formatOnType": true, | ||||
|             "files.trimTrailingWhitespace": true | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "remoteUser": "paperless" | ||||
|     } | ||||
| @@ -1,83 +0,0 @@ | ||||
| # Docker Compose file for developing Paperless NGX in VSCode DevContainers. | ||||
| # This file contains everything Paperless NGX needs to run. | ||||
| # Paperless supports amd64, arm, and arm64 hardware. | ||||
| # All compose files of Paperless configure it in the following way: | ||||
| # | ||||
| # - Paperless is (re)started on system boot if it was running before shutdown. | ||||
| # - Docker volumes for storing data are managed by Docker. | ||||
| # - Folders for importing and exporting files are created in the same directory | ||||
| #   as this file and mounted to the correct folders inside the container. | ||||
| # - Paperless listens on port 8000. | ||||
| # | ||||
| # SQLite is used as the database. The SQLite file is stored in the data volume. | ||||
| # | ||||
| # In addition, this Docker Compose file adds the following optional | ||||
| # configurations: | ||||
| # | ||||
| # - Apache Tika and Gotenberg servers are started with Paperless NGX and Paperless | ||||
| #   is configured to use these services. These provide support for consuming | ||||
| #   Office documents (Word, Excel, PowerPoint, and their LibreOffice counterparts). | ||||
| # | ||||
| # This file is intended only to be used through VSCOde devcontainers. See README.md | ||||
| # in the folder .devcontainer. | ||||
|  | ||||
|  | ||||
| services: | ||||
|   broker: | ||||
|     image: docker.io/library/redis:7 | ||||
|     restart: unless-stopped | ||||
|     volumes: | ||||
|       - ./redisdata:/data | ||||
|  | ||||
|   # No ports need to be exposed; the VSCode DevContainer plugin manages them. | ||||
|   paperless-development: | ||||
|     image: paperless-ngx | ||||
|     build: | ||||
|       context: ../    # Dockerfile cannot access files from parent directories if context is not set. | ||||
|       dockerfile: ./.devcontainer/Dockerfile | ||||
|     restart: unless-stopped | ||||
|     depends_on: | ||||
|       - broker | ||||
|       - gotenberg | ||||
|       - tika | ||||
|     volumes: | ||||
|       - ..:/usr/src/paperless/paperless-ngx:delegated | ||||
|       - ../.devcontainer/vscode:/usr/src/paperless/paperless-ngx/.vscode:delegated # VSCode config files | ||||
|       - pipenv:/usr/src/paperless/paperless-ngx/.venv | ||||
|       - /usr/src/paperless/paperless-ngx/src/documents/static/frontend # Static frontend files exist only in container | ||||
|       - /usr/src/paperless/paperless-ngx/src/.pytest_cache | ||||
|       - /usr/src/paperless/paperless-ngx/.ruff_cache | ||||
|       - /usr/src/paperless/paperless-ngx/htmlcov | ||||
|       - /usr/src/paperless/paperless-ngx/.coverage | ||||
|       - ./data:/usr/src/paperless/paperless-ngx/data | ||||
|       - ./media:/usr/src/paperless/paperless-ngx/media | ||||
|       - ./consume:/usr/src/paperless/paperless-ngx/consume | ||||
|       - ~/.gitconfig:/usr/src/paperless/.gitconfig:ro | ||||
|     environment: | ||||
|       PAPERLESS_REDIS: redis://broker:6379 | ||||
|       PAPERLESS_TIKA_ENABLED: 1 | ||||
|       PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000 | ||||
|       PAPERLESS_TIKA_ENDPOINT: http://tika:9998 | ||||
|       PAPERLESS_STATICDIR: ./src/documents/static | ||||
|       PAPERLESS_DEBUG: true | ||||
|  | ||||
|     # Overrides default command so things don't shut down after the process ends. | ||||
|     command: /bin/sh -c "chown -R paperless:paperless /usr/src/paperless/paperless-ngx/src/documents/static/frontend && chown -R paperless:paperless /usr/src/paperless/paperless-ngx/.ruff_cache && while sleep 1000; do :; done" | ||||
|  | ||||
|   gotenberg: | ||||
|     image: docker.io/gotenberg/gotenberg:8.17 | ||||
|     restart: unless-stopped | ||||
|  | ||||
|     # The Gotenberg Chromium route is used to convert .eml files. We do not | ||||
|     # want to allow external content like tracking pixels or even JavaScript. | ||||
|     command: | ||||
|       - "gotenberg" | ||||
|       - "--chromium-disable-javascript=true" | ||||
|       - "--chromium-allow-list=file:///tmp/.*" | ||||
|  | ||||
|   tika: | ||||
|     image: docker.io/apache/tika:latest | ||||
|     restart: unless-stopped | ||||
|  | ||||
| volumes: | ||||
|   pipenv: | ||||
| @@ -1,58 +0,0 @@ | ||||
| { | ||||
|     "version": "0.2.0", | ||||
|     "configurations": [ | ||||
|         { | ||||
|             "name": "Chrome: Debug Angular Frontend", | ||||
| 						"description": "Debug the Angular Dev Frontend in Chrome", | ||||
|             "type": "chrome", | ||||
|             "request": "launch", | ||||
|             "url": "http://localhost:4200", | ||||
|             "webRoot": "${workspaceFolder}/src-ui", | ||||
|             "preLaunchTask": "Start: Frontend Angular" | ||||
|         }, | ||||
|         { | ||||
|             "name": "Debug: Backend Server (manage.py runserver)", | ||||
| 						"description": "Debug the Django Backend Server", | ||||
|             "type": "python", | ||||
|             "request": "launch", | ||||
|             "program": "${workspaceFolder}/src/manage.py", | ||||
|             "args": [ | ||||
|                 "runserver" | ||||
|             ], | ||||
|             "django": true, | ||||
|             "console": "integratedTerminal", | ||||
|             "env": { | ||||
|                 "PYTHONPATH": "${workspaceFolder}/src" | ||||
|             }, | ||||
|             "python": "${workspaceFolder}/.venv/bin/python" | ||||
|         }, | ||||
|         { | ||||
|             "name": "Debug: Consumer Service (manage.py document_consumer)", | ||||
| 						"description": "Debug the Consumer Service which processes files from a directory", | ||||
|             "type": "python", | ||||
|             "request": "launch", | ||||
|             "program": "${workspaceFolder}/src/manage.py", | ||||
|             "args": [ | ||||
|                 "document_consumer" | ||||
|             ], | ||||
|             "django": true, | ||||
|             "console": "integratedTerminal", | ||||
|             "env": { | ||||
|                 "PYTHONPATH": "${workspaceFolder}/src" | ||||
|             }, | ||||
|             "python": "${workspaceFolder}/.venv/bin/python" | ||||
|         } | ||||
|     ], | ||||
|     "compounds": [ | ||||
|         { | ||||
|             "name": "Debug: FullStack", | ||||
| 						"description": "Debug run the Angular dev frontend, Django backend, and consumer service", | ||||
|             "configurations": [ | ||||
|                 "Chrome: Debug Angular Frontend", | ||||
|                 "Debug: Backend Server (manage.py runserver)", | ||||
|                 "Debug: Consumer Service (manage.py document_consumer)" | ||||
|             ], | ||||
|             "preLaunchTask": "Start: Celery Worker" | ||||
|         } | ||||
|     ] | ||||
| } | ||||
| @@ -1,11 +0,0 @@ | ||||
| { | ||||
|     "python.testing.pytestArgs": [ | ||||
|         "src" | ||||
|     ], | ||||
|     "python.testing.unittestEnabled": false, | ||||
|     "python.testing.pytestEnabled": true, | ||||
|     "files.watcherExclude": { | ||||
|         "**/.venv/**": true, | ||||
|         "**/pytest_cache/**": true | ||||
|     } | ||||
| } | ||||
| @@ -1,223 +0,0 @@ | ||||
| { | ||||
| 	"version": "2.0.0", | ||||
| 	"tasks": [ | ||||
| 		{ | ||||
| 			"label": "Start: Celery Worker", | ||||
| 			"description": "Start the Celery Worker which processes background and consume tasks", | ||||
| 			"type": "shell", | ||||
| 			"command": "pipenv run celery --app paperless worker -l DEBUG", | ||||
| 			"isBackground": true, | ||||
| 			"options": { | ||||
| 				"cwd": "${workspaceFolder}/src" | ||||
| 			}, | ||||
| 			"problemMatcher": [ | ||||
| 				{ | ||||
| 					"owner": "custom", | ||||
| 					"pattern": [ | ||||
| 						{ | ||||
| 							"regexp": ".", | ||||
| 							"file": 1, | ||||
| 							"location": 2, | ||||
| 							"message": 3 | ||||
| 						} | ||||
| 					], | ||||
| 					"background": { | ||||
| 						"activeOnStart": true, | ||||
| 						"beginsPattern": "celery.*", | ||||
| 						"endsPattern": "ready" | ||||
| 					} | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| 			"label": "Start: Frontend Angular", | ||||
| 			"description": "Start the Frontend Angular Dev Server", | ||||
| 			"type": "shell", | ||||
| 			"command": "npm start", | ||||
| 			"isBackground": true, | ||||
| 			"options": { | ||||
| 				"cwd": "${workspaceFolder}/src-ui" | ||||
| 			}, | ||||
| 			"problemMatcher": [ | ||||
| 				{ | ||||
| 					"owner": "custom", | ||||
| 					"pattern": [ | ||||
| 						{ | ||||
| 							"regexp": ".", | ||||
| 							"file": 1, | ||||
| 							"location": 2, | ||||
| 							"message": 3 | ||||
| 						} | ||||
| 					], | ||||
| 					"background": { | ||||
| 						"activeOnStart": true, | ||||
| 						"beginsPattern": ".*", | ||||
| 						"endsPattern": "Compiled successfully" | ||||
| 					} | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| 			"label": "Start: Consumer Service (manage.py document_consumer)", | ||||
| 			"description": "Start the Consumer Service which processes files from a directory", | ||||
| 			"type": "shell", | ||||
| 			"command": "pipenv run python manage.py document_consumer", | ||||
| 			"group": "build", | ||||
| 			"presentation": { | ||||
| 				"echo": true, | ||||
| 				"reveal": "always", | ||||
| 				"focus": false, | ||||
| 				"panel": "shared", | ||||
| 				"showReuseMessage": false, | ||||
| 				"clear": true, | ||||
| 				"revealProblems": "onProblem" | ||||
| 			}, | ||||
| 			"options": { | ||||
| 				"cwd": "${workspaceFolder}/src" | ||||
| 			} | ||||
| 		}, | ||||
| 		{ | ||||
| 			"label": "Start: Backend Server (manage.py runserver)", | ||||
| 			"description": "Start the Backend Server which serves the Django API and the compiled Angular frontend", | ||||
| 			"type": "shell", | ||||
| 			"command": "pipenv run python manage.py runserver", | ||||
| 			"group": "build", | ||||
| 			"presentation": { | ||||
| 				"echo": true, | ||||
| 				"reveal": "always", | ||||
| 				"focus": false, | ||||
| 				"panel": "shared", | ||||
| 				"showReuseMessage": false, | ||||
| 				"clear": true, | ||||
| 				"revealProblems": "onProblem" | ||||
| 			}, | ||||
| 			"options": { | ||||
| 				"cwd": "${workspaceFolder}/src" | ||||
| 			} | ||||
| 		}, | ||||
| 		{ | ||||
| 			"label": "Maintenance: manage.py migrate", | ||||
| 			"description": "Apply database migrations", | ||||
| 			"type": "shell", | ||||
| 			"command": "pipenv run python manage.py migrate", | ||||
| 			"group": "none", | ||||
| 			"presentation": { | ||||
| 				"echo": true, | ||||
| 				"reveal": "always", | ||||
| 				"focus": true, | ||||
| 				"panel": "shared", | ||||
| 				"showReuseMessage": false, | ||||
| 				"clear": true, | ||||
| 				"revealProblems": "onProblem" | ||||
| 			}, | ||||
| 			"options": { | ||||
| 				"cwd": "${workspaceFolder}/src" | ||||
| 			} | ||||
| 		}, | ||||
| 		{ | ||||
| 			"label": "Maintenance: Build Documentation", | ||||
| 			"description": "Build the documentation with MkDocs", | ||||
| 			"type": "shell", | ||||
| 			"command": "pipenv run mkdocs build --config-file mkdocs.yml && pipenv run mkdocs serve", | ||||
| 			"group": "none", | ||||
| 			"presentation": { | ||||
| 				"echo": true, | ||||
| 				"reveal": "always", | ||||
| 				"focus": true, | ||||
| 				"panel": "shared", | ||||
| 				"showReuseMessage": false, | ||||
| 				"clear": true, | ||||
| 				"revealProblems": "onProblem" | ||||
| 			}, | ||||
| 			"options": { | ||||
| 				"cwd": "${workspaceFolder}" | ||||
| 			} | ||||
| 		}, | ||||
| 		{ | ||||
| 			"label": "Maintenance: manage.py createsuperuser", | ||||
| 			"description": "Create a superuser", | ||||
| 			"type": "shell", | ||||
| 			"command": "pipenv run python manage.py createsuperuser", | ||||
| 			"group": "none", | ||||
| 			"presentation": { | ||||
| 				"echo": true, | ||||
| 				"reveal": "always", | ||||
| 				"focus": true, | ||||
| 				"panel": "shared", | ||||
| 				"showReuseMessage": false, | ||||
| 				"clear": true, | ||||
| 				"revealProblems": "onProblem" | ||||
| 			}, | ||||
| 			"options": { | ||||
| 				"cwd": "${workspaceFolder}/src" | ||||
| 			} | ||||
| 		}, | ||||
| 		{ | ||||
| 			"label": "Maintenance: recreate .venv", | ||||
| 			"description": "Recreate the python virtual environment and install python dependencies", | ||||
| 			"type": "shell", | ||||
| 			"command": "rm -R -v .venv/* || pipenv install --dev", | ||||
| 			"group": "none", | ||||
| 			"presentation": { | ||||
| 				"echo": true, | ||||
| 				"reveal": "always", | ||||
| 				"focus": true, | ||||
| 				"panel": "shared", | ||||
| 				"showReuseMessage": false, | ||||
| 				"clear": true, | ||||
| 				"revealProblems": "onProblem" | ||||
| 			}, | ||||
| 			"options": { | ||||
| 				"cwd": "${workspaceFolder}" | ||||
| 			} | ||||
| 		}, | ||||
| 		{ | ||||
| 			"label": "Maintenance: Install Frontend Dependencies", | ||||
| 			"description": "Install frontend (npm) dependencies", | ||||
| 			"type": "npm", | ||||
| 			"script": "install", | ||||
| 			"path": "src-ui", | ||||
| 			"group": "clean", | ||||
| 			"problemMatcher": [], | ||||
| 			"detail": "install dependencies from package" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"description": "Clean install frontend dependencies and build the frontend for production", | ||||
| 			"label": "Maintenance: Compile frontend for production", | ||||
| 			"type": "shell", | ||||
| 			"command": "npm ci && ./node_modules/.bin/ng build --configuration production", | ||||
| 			"group": "none", | ||||
| 			"presentation": { | ||||
| 				"echo": true, | ||||
| 				"reveal": "always", | ||||
| 				"focus": true, | ||||
| 				"panel": "shared", | ||||
| 				"showReuseMessage": false, | ||||
| 				"clear": true, | ||||
| 				"revealProblems": "onProblem" | ||||
| 			}, | ||||
| 			"options": { | ||||
| 				"cwd": "${workspaceFolder}/src-ui" | ||||
| 			} | ||||
| 		}, | ||||
| 		{ | ||||
| 			"label": "Project Setup: Run all Init Tasks", | ||||
| 			"description": "Runs all init tasks to setup the project including migrate the database, create a superuser and compile the frontend for production", | ||||
| 			"dependsOrder": "sequence", | ||||
| 			"dependsOn": [ | ||||
| 				"Maintenance: manage.py migrate", | ||||
| 				"Maintenance: manage.py createsuperuser", | ||||
| 				"Maintenance: Compile frontend for production" | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| 			"label": "Project Start: Run all Services", | ||||
| 			"description": "Runs all services required to start the project including the Celery Worker, the Consumer Service and the Backend Server", | ||||
| 			"dependsOn": [ | ||||
| 				"Start: Celery Worker", | ||||
| 				"Start: Consumer Service (manage.py document_consumer)", | ||||
| 				"Start: Backend Server (manage.py runserver)" | ||||
| 			] | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| @@ -26,5 +26,3 @@ | ||||
| ./dist | ||||
| ./scripts | ||||
| ./resources | ||||
| # Other stuff | ||||
| **/*.drawio.png | ||||
|   | ||||
							
								
								
									
										17
									
								
								.github/ISSUE_TEMPLATE/bug-report.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								.github/ISSUE_TEMPLATE/bug-report.yml
									
									
									
									
										vendored
									
									
								
							| @@ -9,7 +9,7 @@ body: | ||||
|         ### ⚠️ Please remember: issues are for *bugs* | ||||
|         That is, something you believe affects every single user of Paperless-ngx, not just you. If you're not sure, start with one of the other options below. | ||||
|  | ||||
|         Also, note that **Paperless-ngx does not perform OCR or archive file creation itself**, those are handled by other tools. Problems with OCR or archive versions of specific files should likely be raised 'upstream', see https://github.com/ocrmypdf/OCRmyPDF/issues or https://github.com/tesseract-ocr/tesseract/issues | ||||
|         Also, note that **Paperless-ngx does not perform OCR itself**, that is handled by other tools. Problems with OCR of specific files should likely be raised 'upstream', see https://github.com/ocrmypdf/OCRmyPDF/issues or https://github.com/tesseract-ocr/tesseract/issues | ||||
|   - type: markdown | ||||
|     attributes: | ||||
|       value: | | ||||
| @@ -86,23 +86,22 @@ body: | ||||
|       description: Note there are significant differences from the official image and linuxserver.io, please check if your issue is specific to the third-party image. | ||||
|     validations: | ||||
|       required: true | ||||
|   - type: textarea | ||||
|     id: system-status | ||||
|     attributes: | ||||
|       label: System status | ||||
|       description: If available, copy & paste the system status output from Settings > System Status > Copy | ||||
|       render: json | ||||
|   - type: input | ||||
|     id: browser | ||||
|     attributes: | ||||
|       label: Browser | ||||
|       description: Which browser you are using, if relevant. | ||||
|       placeholder: e.g. Chrome, Safari | ||||
|   - type: textarea | ||||
|   - type: input | ||||
|     id: config-changes | ||||
|     attributes: | ||||
|       label: Configuration changes | ||||
|       description: Any configuration changes you made in `docker-compose.yml`, `docker-compose.env` or `paperless.conf`. | ||||
|   - type: input | ||||
|     id: other | ||||
|     attributes: | ||||
|       label: Other | ||||
|       description: Any other relevant details. | ||||
|   - type: checkboxes | ||||
|     id: required-checks | ||||
|     attributes: | ||||
| @@ -110,8 +109,6 @@ body: | ||||
|       options: | ||||
|         - label: I believe this issue is a bug that affects all users of Paperless-ngx, not something specific to my installation. | ||||
|           required: true | ||||
|         - label: This issue is not about the OCR or archive creation of a specific file(s). Otherwise, please see above regarding OCR tools. | ||||
|           required: true | ||||
|         - label: I have already searched for relevant existing issues and discussions before opening this report. | ||||
|           required: true | ||||
|         - label: I have updated the title field above with a concise description. | ||||
|   | ||||
							
								
								
									
										4
									
								
								.github/ISSUE_TEMPLATE/config.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/ISSUE_TEMPLATE/config.yml
									
									
									
									
										vendored
									
									
								
							| @@ -2,10 +2,10 @@ blank_issues_enabled: false | ||||
| contact_links: | ||||
|   - name: 🤔 Questions and Help | ||||
|     url: https://github.com/paperless-ngx/paperless-ngx/discussions | ||||
|     about: General questions or support for using Paperless-ngx. | ||||
|     about: This issue tracker is not for support questions. Please refer to our Discussions. | ||||
|   - name: 💬 Chat | ||||
|     url: https://matrix.to/#/#paperlessngx:matrix.org | ||||
|     about: Want to discuss Paperless-ngx with others? Check out our chat. | ||||
|   - name: 🚀 Feature Request | ||||
|     url: https://github.com/paperless-ngx/paperless-ngx/discussions/new?category=feature-requests | ||||
|     about: Remember to search for existing feature requests and "up-vote" those that you like. | ||||
|     about: Remember to search for existing feature requests and "up-vote" any you like | ||||
|   | ||||
							
								
								
									
										1
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							| @@ -53,6 +53,7 @@ updates: | ||||
|       development: | ||||
|         patterns: | ||||
|           - "*pytest*" | ||||
|           - "black" | ||||
|           - "ruff" | ||||
|           - "mkdocs-material" | ||||
|       django: | ||||
|   | ||||
							
								
								
									
										76
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										76
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -16,9 +16,9 @@ on: | ||||
| env: | ||||
|   # This is the version of pipenv all the steps will use | ||||
|   # If changing this, change Dockerfile | ||||
|   DEFAULT_PIP_ENV_VERSION: "2024.4.1" | ||||
|   DEFAULT_PIP_ENV_VERSION: "2023.12.1" | ||||
|   # This is the default version of Python to use in most steps which aren't specific | ||||
|   DEFAULT_PYTHON_VERSION: "3.11" | ||||
|   DEFAULT_PYTHON_VERSION: "3.10" | ||||
|  | ||||
| jobs: | ||||
|   pre-commit: | ||||
| @@ -30,7 +30,7 @@ jobs: | ||||
|       github.repository | ||||
|  | ||||
|     name: Linting Checks | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-22.04 | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout repository | ||||
| @@ -46,7 +46,7 @@ jobs: | ||||
|  | ||||
|   documentation: | ||||
|     name: "Build & Deploy Documentation" | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-22.04 | ||||
|     needs: | ||||
|       - pre-commit | ||||
|     steps: | ||||
| @@ -95,12 +95,12 @@ jobs: | ||||
|  | ||||
|   tests-backend: | ||||
|     name: "Backend Tests (Python ${{ matrix.python-version }})" | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-22.04 | ||||
|     needs: | ||||
|       - pre-commit | ||||
|     strategy: | ||||
|       matrix: | ||||
|         python-version: ['3.10', '3.11', '3.12'] | ||||
|         python-version: ['3.9', '3.10', '3.11'] | ||||
|       fail-fast: false | ||||
|     steps: | ||||
|       - | ||||
| @@ -131,7 +131,7 @@ jobs: | ||||
|       - | ||||
|         name: Configure ImageMagick | ||||
|         run: | | ||||
|           sudo cp docker/rootfs/etc/ImageMagick-6/paperless-policy.xml /etc/ImageMagick-6/policy.xml | ||||
|           sudo cp docker/imagemagick-policy.xml /etc/ImageMagick-6/policy.xml | ||||
|       - | ||||
|         name: Install Python dependencies | ||||
|         run: | | ||||
| @@ -170,7 +170,7 @@ jobs: | ||||
|  | ||||
|   install-frontend-depedendencies: | ||||
|     name: "Install Frontend Dependencies" | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-22.04 | ||||
|     needs: | ||||
|       - pre-commit | ||||
|     steps: | ||||
| @@ -201,7 +201,7 @@ jobs: | ||||
|  | ||||
|   tests-frontend: | ||||
|     name: "Frontend Tests (Node ${{ matrix.node-version }} - ${{ matrix.shard-index }}/${{ matrix.shard-count }})" | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-22.04 | ||||
|     needs: | ||||
|       - install-frontend-depedendencies | ||||
|     strategy: | ||||
| @@ -260,8 +260,8 @@ jobs: | ||||
|           retention-days: 7 | ||||
|  | ||||
|   tests-coverage-upload: | ||||
|     name: "Upload to Codecov" | ||||
|     runs-on: ubuntu-24.04 | ||||
|     name: "Upload Coverage" | ||||
|     runs-on: ubuntu-22.04 | ||||
|     needs: | ||||
|       - tests-backend | ||||
|       - tests-frontend | ||||
| @@ -283,7 +283,7 @@ jobs: | ||||
|           merge-multiple: true | ||||
|       - | ||||
|         name: Upload frontend coverage to Codecov | ||||
|         uses: codecov/codecov-action@v5 | ||||
|         uses: codecov/codecov-action@v4 | ||||
|         with: | ||||
|           # not required for public repos, but intermittently fails otherwise | ||||
|           token: ${{ secrets.CODECOV_TOKEN }} | ||||
| @@ -299,41 +299,17 @@ jobs: | ||||
|           path: src/ | ||||
|       - | ||||
|         name: Upload coverage to Codecov | ||||
|         uses: codecov/codecov-action@v5 | ||||
|         uses: codecov/codecov-action@v4 | ||||
|         with: | ||||
|           # not required for public repos, but intermittently fails otherwise | ||||
|           token: ${{ secrets.CODECOV_TOKEN }} | ||||
|           # future expansion | ||||
|           flags: backend | ||||
|           directory: src/ | ||||
|       - | ||||
|         name: Use Node.js 20 | ||||
|         uses: actions/setup-node@v4 | ||||
|         with: | ||||
|           node-version: 20.x | ||||
|           cache: 'npm' | ||||
|           cache-dependency-path: 'src-ui/package-lock.json' | ||||
|       - | ||||
|         name: Cache frontend dependencies | ||||
|         id: cache-frontend-deps | ||||
|         uses: actions/cache@v4 | ||||
|         with: | ||||
|           path: | | ||||
|             ~/.npm | ||||
|             ~/.cache | ||||
|           key: ${{ runner.os }}-frontenddeps-${{ hashFiles('src-ui/package-lock.json') }} | ||||
|       - | ||||
|         name: Re-link Angular cli | ||||
|         run: cd src-ui && npm link @angular/cli | ||||
|       - | ||||
|         name: Build frontend and upload analysis | ||||
|         env: | ||||
|           CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | ||||
|         run: cd src-ui && ng build --configuration=production | ||||
|  | ||||
|   build-docker-image: | ||||
|     name: Build Docker image for ${{ github.ref_name }} | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-22.04 | ||||
|     if: github.event_name == 'push' && (startsWith(github.ref, 'refs/heads/feature-') || startsWith(github.ref, 'refs/heads/fix-') || github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/beta' || contains(github.ref, 'beta.rc') || startsWith(github.ref, 'refs/tags/v')) | ||||
|     concurrency: | ||||
|       group: ${{ github.workflow }}-build-docker-image-${{ github.ref_name }} | ||||
| @@ -406,7 +382,7 @@ jobs: | ||||
|       - | ||||
|         name: Login to Docker Hub | ||||
|         uses: docker/login-action@v3 | ||||
|         # Don't attempt to login if not pushing to Docker Hub | ||||
|         # Don't attempt to login is not pushing to Docker Hub | ||||
|         if: steps.push-other-places.outputs.enable == 'true' | ||||
|         with: | ||||
|           username: ${{ secrets.DOCKERHUB_USERNAME }} | ||||
| @@ -414,7 +390,7 @@ jobs: | ||||
|       - | ||||
|         name: Login to Quay.io | ||||
|         uses: docker/login-action@v3 | ||||
|         # Don't attempt to login if not pushing to Quay.io | ||||
|         # Don't attempt to login is not pushing to Quay.io | ||||
|         if: steps.push-other-places.outputs.enable == 'true' | ||||
|         with: | ||||
|           registry: quay.io | ||||
| @@ -422,7 +398,7 @@ jobs: | ||||
|           password: ${{ secrets.QUAY_ROBOT_TOKEN }} | ||||
|       - | ||||
|         name: Build and push | ||||
|         uses: docker/build-push-action@v6 | ||||
|         uses: docker/build-push-action@v5 | ||||
|         with: | ||||
|           context: . | ||||
|           file: ./Dockerfile | ||||
| @@ -430,8 +406,6 @@ jobs: | ||||
|           push: ${{ github.event_name != 'pull_request' }} | ||||
|           tags: ${{ steps.docker-meta.outputs.tags }} | ||||
|           labels: ${{ steps.docker-meta.outputs.labels }} | ||||
|           build-args: | | ||||
|             PNGX_TAG_VERSION=${{ steps.docker-meta.outputs.version }} | ||||
|           # Get cache layers from this branch, then dev | ||||
|           # This allows new branches to get at least some cache benefits, generally from dev | ||||
|           cache-from: | | ||||
| @@ -461,7 +435,7 @@ jobs: | ||||
|     needs: | ||||
|       - build-docker-image | ||||
|       - documentation | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-22.04 | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
| @@ -482,6 +456,12 @@ jobs: | ||||
|         name: Install Python dependencies | ||||
|         run: | | ||||
|           pipenv --python ${{ steps.setup-python.outputs.python-version }} sync --dev | ||||
|       - | ||||
|         name: Patch whitenoise | ||||
|         run: | | ||||
|           curl --fail --silent --show-error --location --output 484.patch https://github.com/evansd/whitenoise/pull/484.patch | ||||
|           patch -d $(pipenv --venv)/lib/python3.10/site-packages --verbose -p2 < 484.patch | ||||
|           rm 484.patch | ||||
|       - | ||||
|         name: Install system dependencies | ||||
|         run: | | ||||
| @@ -569,7 +549,7 @@ jobs: | ||||
|  | ||||
|   publish-release: | ||||
|     name: "Publish Release" | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-22.04 | ||||
|     outputs: | ||||
|       prerelease: ${{ steps.get_version.outputs.prerelease }} | ||||
|       changelog: ${{ steps.create-release.outputs.body }} | ||||
| @@ -619,7 +599,7 @@ jobs: | ||||
|  | ||||
|   append-changelog: | ||||
|     name: "Append Changelog" | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-22.04 | ||||
|     needs: | ||||
|       - publish-release | ||||
|     if: needs.publish-release.outputs.prerelease == 'false' | ||||
| @@ -649,9 +629,7 @@ jobs: | ||||
|           git checkout ${{ needs.publish-release.outputs.version }}-changelog | ||||
|           echo -e "# Changelog\n\n${{ needs.publish-release.outputs.changelog }}\n" > changelog-new.md | ||||
|           echo "Manually linking usernames" | ||||
|           sed -i -r 's|@([a-zA-Z0-9_]+) \(\[#|[@\1](https://github.com/\1) ([#|g' changelog-new.md | ||||
|           echo "Removing unneeded comment tags" | ||||
|           sed -i -r 's|@<!---->|@|g' changelog-new.md | ||||
|           sed -i -r 's|@(.+?) \(\[#|[@\1](https://github.com/\1) ([#|ig' changelog-new.md | ||||
|           CURRENT_CHANGELOG=`tail --lines +2 changelog.md` | ||||
|           echo -e "$CURRENT_CHANGELOG" >> changelog-new.md | ||||
|           mv changelog-new.md changelog.md | ||||
|   | ||||
							
								
								
									
										8
									
								
								.github/workflows/cleanup-tags.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/cleanup-tags.yml
									
									
									
									
										vendored
									
									
								
							| @@ -21,7 +21,7 @@ jobs: | ||||
|   cleanup-images: | ||||
|     name: Cleanup Image Tags for ${{ matrix.primary-name }} | ||||
|     if: github.repository_owner == 'paperless-ngx' | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-22.04 | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|       matrix: | ||||
| @@ -33,7 +33,7 @@ jobs: | ||||
|       - | ||||
|         name: Clean temporary images | ||||
|         if: "${{ env.TOKEN != '' }}" | ||||
|         uses: stumpylog/image-cleaner-action/ephemeral@v0.9.0 | ||||
|         uses: stumpylog/image-cleaner-action/ephemeral@v0.5.0 | ||||
|         with: | ||||
|           token: "${{ env.TOKEN }}" | ||||
|           owner: "${{ github.repository_owner }}" | ||||
| @@ -47,7 +47,7 @@ jobs: | ||||
|   cleanup-untagged-images: | ||||
|     name: Cleanup Untagged Images Tags for ${{ matrix.primary-name }} | ||||
|     if: github.repository_owner == 'paperless-ngx' | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-22.04 | ||||
|     needs: | ||||
|       - cleanup-images | ||||
|     strategy: | ||||
| @@ -61,7 +61,7 @@ jobs: | ||||
|       - | ||||
|         name: Clean untagged images | ||||
|         if: "${{ env.TOKEN != '' }}" | ||||
|         uses: stumpylog/image-cleaner-action/untagged@v0.9.0 | ||||
|         uses: stumpylog/image-cleaner-action/untagged@v0.5.0 | ||||
|         with: | ||||
|           token: "${{ env.TOKEN }}" | ||||
|           owner: "${{ github.repository_owner }}" | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/codeql-analysis.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/codeql-analysis.yml
									
									
									
									
										vendored
									
									
								
							| @@ -23,7 +23,7 @@ on: | ||||
| jobs: | ||||
|   analyze: | ||||
|     name: Analyze | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-22.04 | ||||
|     permissions: | ||||
|       actions: read | ||||
|       contents: read | ||||
|   | ||||
							
								
								
									
										5
									
								
								.github/workflows/crowdin.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.github/workflows/crowdin.yml
									
									
									
									
										vendored
									
									
								
							| @@ -15,14 +15,13 @@ on: | ||||
| jobs: | ||||
|   synchronize-with-crowdin: | ||||
|     name: Crowdin Sync | ||||
|     if: github.repository_owner == 'paperless-ngx' | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-latest | ||||
|  | ||||
|     steps: | ||||
|     - name: Checkout | ||||
|       uses: actions/checkout@v4 | ||||
|     - name: crowdin action | ||||
|       uses: crowdin/github-action@v2 | ||||
|       uses: crowdin/github-action@v1 | ||||
|       with: | ||||
|         upload_translations: false | ||||
|         download_translations: true | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/project-actions.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/project-actions.yml
									
									
									
									
										vendored
									
									
								
							| @@ -15,7 +15,7 @@ permissions: | ||||
| jobs: | ||||
|   pr_opened_or_reopened: | ||||
|     name: pr_opened_or_reopened | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-22.04 | ||||
|     permissions: | ||||
|       # write permission is required for autolabeler | ||||
|       pull-requests: write | ||||
|   | ||||
							
								
								
									
										33
									
								
								.github/workflows/repo-maintenance.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								.github/workflows/repo-maintenance.yml
									
									
									
									
										vendored
									
									
								
							| @@ -16,14 +16,13 @@ concurrency: | ||||
| jobs: | ||||
|   stale: | ||||
|     name: 'Stale' | ||||
|     if: github.repository_owner == 'paperless-ngx' | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/stale@v9 | ||||
|         with: | ||||
|           days-before-stale: 7 | ||||
|           days-before-close: 14 | ||||
|           any-of-labels: 'stale,cant-reproduce,not a bug' | ||||
|           any-of-labels: 'cant-reproduce,not a bug' | ||||
|           stale-issue-label: stale | ||||
|           stale-pr-label: stale | ||||
|           stale-issue-message: > | ||||
| @@ -32,8 +31,7 @@ jobs: | ||||
|             for your contributions. See our [contributing guidelines](https://github.com/paperless-ngx/paperless-ngx/blob/dev/CONTRIBUTING.md#automatic-repository-maintenance) for more details. | ||||
|   lock-threads: | ||||
|     name: 'Lock Old Threads' | ||||
|     if: github.repository_owner == 'paperless-ngx' | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: dessant/lock-threads@v5 | ||||
|         with: | ||||
| @@ -58,8 +56,7 @@ jobs: | ||||
|             See our [contributing guidelines](https://github.com/paperless-ngx/paperless-ngx/blob/dev/CONTRIBUTING.md#automatic-repository-maintenance) for more details. | ||||
|   close-answered-discussions: | ||||
|     name: 'Close Answered Discussions' | ||||
|     if: github.repository_owner == 'paperless-ngx' | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/github-script@v7 | ||||
|         with: | ||||
| @@ -115,8 +112,7 @@ jobs: | ||||
|             } | ||||
|   close-outdated-discussions: | ||||
|     name: 'Close Outdated Discussions' | ||||
|     if: github.repository_owner == 'paperless-ngx' | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/github-script@v7 | ||||
|         with: | ||||
| @@ -207,8 +203,7 @@ jobs: | ||||
|             } | ||||
|   close-unsupported-feature-requests: | ||||
|     name: 'Close Unsupported Feature Requests' | ||||
|     if: github.repository_owner == 'paperless-ngx' | ||||
|     runs-on: ubuntu-24.04 | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/github-script@v7 | ||||
|         with: | ||||
| @@ -217,20 +212,15 @@ jobs: | ||||
|               return new Promise(resolve => setTimeout(resolve, ms)); | ||||
|             } | ||||
|  | ||||
|             const CUTOFF_MAX_COUNT = 80; | ||||
|             const CUTOFF_1_DAYS = 180; | ||||
|             const CUTOFF_1_COUNT = 5; | ||||
|             const CUTOFF_2_DAYS = 365; | ||||
|             const CUTOFF_2_COUNT = 20; | ||||
|             const CUTOFF_3_DAYS = 730; | ||||
|             const CUTOFF_3_COUNT = 40; | ||||
|             const CUTOFF_2_COUNT = 10; | ||||
|  | ||||
|             const cutoff1Date = new Date(); | ||||
|             cutoff1Date.setDate(cutoff1Date.getDate() - CUTOFF_1_DAYS); | ||||
|             const cutoff2Date = new Date(); | ||||
|             cutoff2Date.setDate(cutoff2Date.getDate() - CUTOFF_2_DAYS); | ||||
|             const cutoff3Date = new Date(); | ||||
|             cutoff3Date.setDate(cutoff3Date.getDate() - CUTOFF_3_DAYS); | ||||
|  | ||||
|             const query = `query( | ||||
|                 $owner:String!, | ||||
| @@ -260,12 +250,9 @@ jobs: | ||||
|             const result = await github.graphql(query, variables); | ||||
|  | ||||
|             for (const discussion of result.repository.discussions.nodes) { | ||||
|               const discussionUpdatedDate = new Date(discussion.updatedAt); | ||||
|               const discussionCreatedDate = new Date(discussion.createdAt); | ||||
|               if ((discussionUpdatedDate < cutoff1Date && discussion.upvoteCount < CUTOFF_MAX_COUNT) || | ||||
|                   (discussionCreatedDate < cutoff1Date && discussion.upvoteCount < CUTOFF_1_COUNT) || | ||||
|                   (discussionCreatedDate < cutoff2Date && discussion.upvoteCount < CUTOFF_2_COUNT) || | ||||
|                   (discussionCreatedDate < cutoff3Date && discussion.upvoteCount < CUTOFF_3_COUNT)) { | ||||
|               const discussionDate = new Date(discussion.updatedAt); | ||||
|               if ((discussionDate < cutoff1Date && discussion.upvoteCount < CUTOFF_1_COUNT) || | ||||
|                   (discussionDate < cutoff2Date && discussion.upvoteCount < CUTOFF_2_COUNT)) { | ||||
|                 console.log(`Closing discussion #${discussion.number} (${discussion.id}), last updated at ${discussion.updatedAt} with votes ${discussion.upvoteCount}`); | ||||
|                 const addCommentMutation = `mutation($discussion:ID!, $body:String!) { | ||||
|                   addDiscussionComment(input:{discussionId:$discussion, body:$body}) { | ||||
|   | ||||
							
								
								
									
										9
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -22,7 +22,6 @@ var/ | ||||
| *.egg-info/ | ||||
| .installed.cfg | ||||
| *.egg | ||||
| /src/paperless_mail/templates/node_modules | ||||
|  | ||||
| # PyInstaller | ||||
| #  Usually these files are written by a python script from a template | ||||
| @@ -66,8 +65,6 @@ target/ | ||||
| .vscode | ||||
| /src-ui/.vscode | ||||
| /docs/.vscode | ||||
| .vscode-server | ||||
| *CommandMarker | ||||
|  | ||||
| # Other stuff that doesn't belong | ||||
| .virtualenv | ||||
| @@ -100,9 +97,3 @@ scripts/nuke | ||||
|  | ||||
| # celery schedule file | ||||
| celerybeat-schedule* | ||||
|  | ||||
| # ignore .devcontainer sub folders | ||||
| /.devcontainer/consume/ | ||||
| /.devcontainer/data/ | ||||
| /.devcontainer/media/ | ||||
| /.devcontainer/redisdata/ | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| repos: | ||||
|   # General hooks | ||||
|   - repo: https://github.com/pre-commit/pre-commit-hooks | ||||
|     rev: v5.0.0 | ||||
|     rev: v4.6.0 | ||||
|     hooks: | ||||
|       - id: check-docstring-first | ||||
|       - id: check-json | ||||
| @@ -29,16 +29,15 @@ repos: | ||||
|       - id: check-case-conflict | ||||
|       - id: detect-private-key | ||||
|   - repo: https://github.com/codespell-project/codespell | ||||
|     rev: v2.4.0 | ||||
|     rev: v2.2.6 | ||||
|     hooks: | ||||
|       - id: codespell | ||||
|         exclude: "(^src-ui/src/locale/)|(^src-ui/e2e/)|(^src/paperless_mail/tests/samples/)" | ||||
|         exclude_types: | ||||
|           - pofile | ||||
|           - json | ||||
|   # See https://github.com/prettier/prettier/issues/15742 for the fork reason | ||||
|   - repo: https://github.com/rbubley/mirrors-prettier | ||||
|     rev: 'v3.3.3' | ||||
|   - repo: https://github.com/pre-commit/mirrors-prettier | ||||
|     rev: 'v3.1.0' | ||||
|     hooks: | ||||
|       - id: prettier | ||||
|         types_or: | ||||
| @@ -46,15 +45,15 @@ repos: | ||||
|           - ts | ||||
|           - markdown | ||||
|         exclude: "(^Pipfile\\.lock$)" | ||||
|         additional_dependencies: | ||||
|           - prettier@3.3.3 | ||||
|           - 'prettier-plugin-organize-imports@4.1.0' | ||||
|   # Python hooks | ||||
|   - repo: https://github.com/astral-sh/ruff-pre-commit | ||||
|     rev: v0.9.6 | ||||
|     rev: 'v0.4.1' | ||||
|     hooks: | ||||
|       - id: ruff | ||||
|       - id: ruff-format | ||||
|   - repo: https://github.com/psf/black-pre-commit-mirror | ||||
|     rev: 24.4.0 | ||||
|     hooks: | ||||
|       - id: black | ||||
|   # Dockerfile hooks | ||||
|   - repo: https://github.com/AleksaC/hadolint-py | ||||
|     rev: v2.12.0.3 | ||||
| @@ -65,8 +64,6 @@ repos: | ||||
|     rev: v6.2.1 | ||||
|     hooks: | ||||
|       - id: beautysh | ||||
|         additional_dependencies: | ||||
|           - setuptools | ||||
|         args: | ||||
|           - "--tab" | ||||
|   - repo: https://github.com/shellcheck-py/shellcheck-py | ||||
|   | ||||
							
								
								
									
										16
									
								
								.prettierrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								.prettierrc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| { | ||||
|     # https://prettier.io/docs/en/options.html#semicolons | ||||
|     "semi": false, | ||||
|     # https://prettier.io/docs/en/options.html#quotes | ||||
|     "singleQuote": true, | ||||
|     # https://prettier.io/docs/en/options.html#trailing-commas | ||||
|     "trailingComma": "es5", | ||||
|     "overrides": [ | ||||
|         { | ||||
|             "files": ["index.md", "administration.md"], | ||||
|             "options": { | ||||
|                 "tabWidth": 4 | ||||
|             } | ||||
|         } | ||||
|     ] | ||||
| } | ||||
| @@ -1,19 +0,0 @@ | ||||
| const config = { | ||||
| 	// https://prettier.io/docs/en/options.html#semicolons | ||||
| 	semi: false, | ||||
| 	// https://prettier.io/docs/en/options.html#quotes | ||||
| 	singleQuote: true, | ||||
| 	// https://prettier.io/docs/en/options.html#trailing-commas | ||||
| 	trailingComma: 'es5', | ||||
| 	overrides: [ | ||||
| 		{ | ||||
| 			files: ['docs/*.md'], | ||||
| 			options: { | ||||
| 				tabWidth: 4, | ||||
| 			}, | ||||
| 		}, | ||||
| 	], | ||||
| 	plugins: [require('prettier-plugin-organize-imports')], | ||||
| } | ||||
|  | ||||
| module.exports = config | ||||
| @@ -1 +1 @@ | ||||
| 3.10.15 | ||||
| 3.9.18 | ||||
|   | ||||
							
								
								
									
										48
									
								
								.ruff.toml
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								.ruff.toml
									
									
									
									
									
								
							| @@ -2,7 +2,7 @@ fix = true | ||||
| line-length = 88 | ||||
| respect-gitignore = true | ||||
| src = ["src"] | ||||
| target-version = "py310" | ||||
| target-version = "py39" | ||||
| output-format = "grouped" | ||||
| show-fixes = true | ||||
|  | ||||
| @@ -31,57 +31,17 @@ extend-select = [ | ||||
|   "PLE",   # https://docs.astral.sh/ruff/rules/#pylint-pl | ||||
|   "RUF",   # https://docs.astral.sh/ruff/rules/#ruff-specific-rules-ruf | ||||
|   "FLY",   # https://docs.astral.sh/ruff/rules/#flynt-fly | ||||
|   "PTH",   # https://docs.astral.sh/ruff/rules/#flake8-use-pathlib-pth | ||||
|   "FBT",   # https://docs.astral.sh/ruff/rules/#flake8-boolean-trap-fbt | ||||
| ] | ||||
| # TODO PTH https://docs.astral.sh/ruff/rules/#flake8-use-pathlib-pth | ||||
| ignore = ["DJ001", "SIM105", "RUF012"] | ||||
|  | ||||
| [lint.per-file-ignores] | ||||
| ".github/scripts/*.py" = ["E501", "INP001", "SIM117"] | ||||
| "docker/wait-for-redis.py" = ["INP001", "T201"] | ||||
| "src/documents/file_handling.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/management/commands/document_consumer.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/management/commands/document_exporter.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/migrations/0012_auto_20160305_0040.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/migrations/0014_document_checksum.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/migrations/1003_mime_types.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/migrations/1012_fix_archive_files.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/models.py" = ["SIM115", "PTH"]  # TODO PTH Enable & remove | ||||
| "src/documents/parsers.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/signals/handlers.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/tasks.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/tests/test_api_app_config.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/tests/test_classifier.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/tests/test_consumer.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/tests/test_file_handling.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/tests/test_management.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/tests/test_management_consumer.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/tests/test_management_exporter.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/tests/test_management_thumbnails.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/tests/test_migration_archive_files.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/tests/test_migration_document_pages_count.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/tests/test_migration_mime_type.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/tests/test_sanity_check.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/tests/test_tasks.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/tests/test_views.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/documents/views.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/paperless/checks.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/paperless/settings.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/paperless/tests/test_checks.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/paperless/urls.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/paperless/views.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/paperless_mail/mail.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/paperless_mail/preprocessor.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/paperless_tesseract/parsers.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/paperless_tesseract/tests/test_parser.py" = ["RUF001", "PTH"]  # TODO PTH Enable & remove | ||||
| "src/paperless_tika/tests/test_live_tika.py" = ["PTH"]  # TODO Enable & remove | ||||
| "src/paperless_tika/tests/test_tika_parser.py" = ["PTH"]  # TODO Enable & remove | ||||
| # Testing | ||||
| "*/tests/*.py" = ["E501", "SIM117"] | ||||
| # Migrations | ||||
| "*/migrations/*.py" = ["E501", "SIM", "T201"] | ||||
| # Docker specific | ||||
| "docker/rootfs/usr/local/bin/wait-for-redis.py" = ["INP001", "T201"] | ||||
| "src/paperless_tesseract/tests/test_parser.py" = ["RUF001"] | ||||
| "src/documents/models.py" = ["SIM115"] | ||||
|  | ||||
| [lint.isort] | ||||
| force-single-line = true | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| We as members, contributors, and leaders pledge to make participation in our | ||||
| community a harassment-free experience for everyone, regardless of age, body | ||||
| size, visible or invisible disability, ethnicity, sex characteristics, gender | ||||
| identity and expression, level of experience, education, socioeconomic status, | ||||
| identity and expression, level of experience, education, socio-economic status, | ||||
| nationality, personal appearance, race, religion, or sexual identity | ||||
| and orientation. | ||||
|  | ||||
|   | ||||
| @@ -11,7 +11,7 @@ If you want to implement something big: | ||||
|  | ||||
| ## Python | ||||
|  | ||||
| Paperless supports python 3.10 - 3.12 at this time. We format Python code with [ruff](https://docs.astral.sh/ruff/formatter/). | ||||
| Paperless supports python 3.9 - 3.11. We format Python code with [Black](https://github.com/psf/black). | ||||
|  | ||||
| ## Branches | ||||
|  | ||||
| @@ -147,7 +147,7 @@ community members. That said, in an effort to keep the repository organized and | ||||
| - Issues, pull requests and discussions that are closed will be locked after 30 days of inactivity. | ||||
| - Discussions with a marked answer will be automatically closed. | ||||
| - Discussions in the 'General' or 'Support' categories will be closed after 180 days of inactivity. | ||||
| - Feature requests that do not meet the following thresholds will be closed: 180 days of inactivity, < 5 "up-votes" after 180 days, < 20 "up-votes" after 1 year or < 80 "up-votes" at 2 years. | ||||
| - Feature requests that do not meet the following thresholds will be closed: 5 "up-votes" after 180 days of inactivity or 10 "up-votes" after 365 days. | ||||
|  | ||||
| In all cases, threads can be re-opened by project maintainers and, of course, users can always create a new discussion for related concerns. | ||||
| Finally, remember that all information remains searchable and 'closed' feature requests can still serve as inspiration for new features. | ||||
|   | ||||
							
								
								
									
										187
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										187
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -13,16 +13,6 @@ WORKDIR /src/src-ui | ||||
| RUN set -eux \ | ||||
|   && npm update npm -g \ | ||||
|   && npm ci | ||||
|  | ||||
| ARG PNGX_TAG_VERSION= | ||||
| # Add the tag to the environment file if its a tagged dev build | ||||
| RUN set -eux && \ | ||||
| case "${PNGX_TAG_VERSION}" in \ | ||||
|   dev|beta|fix*|feature*) \ | ||||
|     sed -i -E "s/version: '([0-9\.]+)'/version: '\1 #${PNGX_TAG_VERSION}'/g" /src/src-ui/src/environments/environment.prod.ts \ | ||||
|     ;; \ | ||||
| esac | ||||
|  | ||||
| RUN set -eux \ | ||||
|   && ./node_modules/.bin/ng build --configuration production | ||||
|  | ||||
| @@ -31,7 +21,7 @@ RUN set -eux \ | ||||
| # Comments: | ||||
| #  - pipenv dependencies are not left in the final image | ||||
| #  - pipenv can't touch the final image somehow | ||||
| FROM --platform=$BUILDPLATFORM docker.io/python:3.12-alpine AS pipenv-base | ||||
| FROM --platform=$BUILDPLATFORM docker.io/python:3.11-alpine as pipenv-base | ||||
|  | ||||
| WORKDIR /usr/src/pipenv | ||||
|  | ||||
| @@ -39,70 +29,15 @@ COPY Pipfile* ./ | ||||
|  | ||||
| RUN set -eux \ | ||||
|   && echo "Installing pipenv" \ | ||||
|     && python3 -m pip install --no-cache-dir --upgrade pipenv==2024.4.1 \ | ||||
|     && python3 -m pip install --no-cache-dir --upgrade pipenv==2023.12.1 \ | ||||
|   && echo "Generating requirement.txt" \ | ||||
|     && pipenv requirements > requirements.txt | ||||
|  | ||||
| # Stage: s6-overlay-base | ||||
| # Purpose: Installs s6-overlay and rootfs | ||||
| # Comments: | ||||
| #  - Don't leave anything extra in here either | ||||
| FROM docker.io/python:3.12-slim-bookworm AS s6-overlay-base | ||||
|  | ||||
| WORKDIR /usr/src/s6 | ||||
|  | ||||
| # https://github.com/just-containers/s6-overlay#customizing-s6-overlay-behaviour | ||||
| ENV \ | ||||
|     S6_BEHAVIOUR_IF_STAGE2_FAILS=2 \ | ||||
|     S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \ | ||||
|     S6_VERBOSITY=1 \ | ||||
|     PATH=/command:$PATH | ||||
|  | ||||
| # Buildx provided, must be defined to use though | ||||
| ARG TARGETARCH | ||||
| ARG TARGETVARIANT | ||||
| # Lock this version | ||||
| ARG S6_OVERLAY_VERSION=3.2.0.2 | ||||
|  | ||||
| ARG S6_BUILD_TIME_PKGS="curl \ | ||||
|                         xz-utils" | ||||
|  | ||||
| RUN set -eux \ | ||||
|     && echo "Installing build time packages" \ | ||||
|       && apt-get update \ | ||||
|       && apt-get install --yes --quiet --no-install-recommends ${S6_BUILD_TIME_PKGS} \ | ||||
|     && echo "Determining arch" \ | ||||
|       && S6_ARCH="" \ | ||||
|       && if [ "${TARGETARCH}${TARGETVARIANT}" = "amd64" ]; then S6_ARCH="x86_64"; \ | ||||
|       elif [ "${TARGETARCH}${TARGETVARIANT}" = "arm64" ]; then S6_ARCH="aarch64"; fi\ | ||||
|       && if [ -z "${S6_ARCH}" ]; then { echo "Error: Not able to determine arch"; exit 1; }; fi \ | ||||
|     && echo "Installing s6-overlay for ${S6_ARCH}" \ | ||||
|       && curl --fail --silent --no-progress-meter --show-error --location --remote-name-all --parallel --parallel-max 4 \ | ||||
|         "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz" \ | ||||
|         "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz.sha256" \ | ||||
|         "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.xz" \ | ||||
|         "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.xz.sha256" \ | ||||
|       && echo "Validating s6-archive checksums" \ | ||||
|         && sha256sum --check ./*.sha256 \ | ||||
|       && echo "Unpacking archives" \ | ||||
|         && tar --directory / -Jxpf s6-overlay-noarch.tar.xz \ | ||||
|         && tar --directory / -Jxpf s6-overlay-${S6_ARCH}.tar.xz \ | ||||
|       && echo "Removing downloaded archives" \ | ||||
|         && rm ./*.tar.xz \ | ||||
|         && rm ./*.sha256 \ | ||||
|     && echo "Cleaning up image" \ | ||||
|       && apt-get --yes purge ${S6_BUILD_TIME_PKGS} \ | ||||
|       && apt-get --yes autoremove --purge \ | ||||
|       && rm -rf /var/lib/apt/lists/* | ||||
|  | ||||
| # Copy our service defs and filesystem | ||||
| COPY ./docker/rootfs / | ||||
|  | ||||
| # Stage: main-app | ||||
| # Purpose: The final image | ||||
| # Comments: | ||||
| #  - Don't leave anything extra in here | ||||
| FROM s6-overlay-base AS main-app | ||||
| FROM docker.io/python:3.11-slim-bookworm as main-app | ||||
|  | ||||
| LABEL org.opencontainers.image.authors="paperless-ngx team <hello@paperless-ngx.com>" | ||||
| LABEL org.opencontainers.image.documentation="https://docs.paperless-ngx.com/" | ||||
| @@ -116,9 +51,9 @@ ARG DEBIAN_FRONTEND=noninteractive | ||||
| ARG TARGETARCH | ||||
|  | ||||
| # Can be workflow provided, defaults set for manual building | ||||
| ARG JBIG2ENC_VERSION=0.30 | ||||
| ARG JBIG2ENC_VERSION=0.29 | ||||
| ARG QPDF_VERSION=11.9.0 | ||||
| ARG GS_VERSION=10.03.1 | ||||
| ARG GS_VERSION=10.02.1 | ||||
|  | ||||
| # Set Python environment variables | ||||
| ENV PYTHONDONTWRITEBYTECODE=1 \ | ||||
| @@ -148,6 +83,7 @@ ARG RUNTIME_PACKAGES="\ | ||||
|   icc-profiles-free \ | ||||
|   imagemagick \ | ||||
|   # PostgreSQL | ||||
|   libpq5 \ | ||||
|   postgresql-client \ | ||||
|   # MySQL / MariaDB | ||||
|   mariadb-client \ | ||||
| @@ -182,39 +118,91 @@ RUN set -eux \ | ||||
|     && apt-get update \ | ||||
|     && apt-get install --yes --quiet --no-install-recommends ${RUNTIME_PACKAGES} \ | ||||
|     && echo "Installing pre-built updates" \ | ||||
|       && curl --fail --silent --no-progress-meter --show-error --location --remote-name-all --parallel --parallel-max 4 \ | ||||
|         https://github.com/paperless-ngx/builder/releases/download/qpdf-${QPDF_VERSION}/libqpdf29_${QPDF_VERSION}-1_${TARGETARCH}.deb \ | ||||
|         https://github.com/paperless-ngx/builder/releases/download/qpdf-${QPDF_VERSION}/qpdf_${QPDF_VERSION}-1_${TARGETARCH}.deb \ | ||||
|         https://github.com/paperless-ngx/builder/releases/download/ghostscript-${GS_VERSION}/libgs10_${GS_VERSION}.dfsg-1_${TARGETARCH}.deb \ | ||||
|         https://github.com/paperless-ngx/builder/releases/download/ghostscript-${GS_VERSION}/ghostscript_${GS_VERSION}.dfsg-1_${TARGETARCH}.deb \ | ||||
|         https://github.com/paperless-ngx/builder/releases/download/ghostscript-${GS_VERSION}/libgs10-common_${GS_VERSION}.dfsg-1_all.deb \ | ||||
|         https://github.com/paperless-ngx/builder/releases/download/jbig2enc-${JBIG2ENC_VERSION}/jbig2enc_${JBIG2ENC_VERSION}-1_${TARGETARCH}.deb \ | ||||
|       && echo "Installing qpdf ${QPDF_VERSION}" \ | ||||
|         && curl --fail --silent --show-error --location \ | ||||
|           --output libqpdf29_${QPDF_VERSION}-1_${TARGETARCH}.deb \ | ||||
|           https://github.com/paperless-ngx/builder/releases/download/qpdf-${QPDF_VERSION}/libqpdf29_${QPDF_VERSION}-1_${TARGETARCH}.deb \ | ||||
|         && curl --fail --silent --show-error --location \ | ||||
|           --output qpdf_${QPDF_VERSION}-1_${TARGETARCH}.deb \ | ||||
|           https://github.com/paperless-ngx/builder/releases/download/qpdf-${QPDF_VERSION}/qpdf_${QPDF_VERSION}-1_${TARGETARCH}.deb \ | ||||
|         && dpkg --install ./libqpdf29_${QPDF_VERSION}-1_${TARGETARCH}.deb \ | ||||
|         && dpkg --install ./qpdf_${QPDF_VERSION}-1_${TARGETARCH}.deb \ | ||||
|       && echo "Installing Ghostscript ${GS_VERSION}" \ | ||||
|         && dpkg --install ./libgs10-common_${GS_VERSION}.dfsg-1_all.deb \ | ||||
|         && dpkg --install ./libgs10_${GS_VERSION}.dfsg-1_${TARGETARCH}.deb \ | ||||
|         && dpkg --install ./ghostscript_${GS_VERSION}.dfsg-1_${TARGETARCH}.deb \ | ||||
|         && curl --fail --silent --show-error --location \ | ||||
|           --output libgs10_${GS_VERSION}.dfsg-2_${TARGETARCH}.deb \ | ||||
|           https://github.com/paperless-ngx/builder/releases/download/ghostscript-${GS_VERSION}/libgs10_${GS_VERSION}.dfsg-1_${TARGETARCH}.deb \ | ||||
|         && curl --fail --silent --show-error --location \ | ||||
|           --output ghostscript_${GS_VERSION}.dfsg-2_${TARGETARCH}.deb \ | ||||
|           https://github.com/paperless-ngx/builder/releases/download/ghostscript-${GS_VERSION}/ghostscript_${GS_VERSION}.dfsg-1_${TARGETARCH}.deb \ | ||||
|         && curl --fail --silent --show-error --location \ | ||||
|           --output libgs10-common_${GS_VERSION}.dfsg-2_all.deb \ | ||||
|           https://github.com/paperless-ngx/builder/releases/download/ghostscript-${GS_VERSION}/libgs10-common_${GS_VERSION}.dfsg-1_all.deb \ | ||||
|         && dpkg --install ./libgs10-common_${GS_VERSION}.dfsg-2_all.deb \ | ||||
|         && dpkg --install ./libgs10_${GS_VERSION}.dfsg-2_${TARGETARCH}.deb \ | ||||
|         && dpkg --install ./ghostscript_${GS_VERSION}.dfsg-2_${TARGETARCH}.deb \ | ||||
|       && echo "Installing jbig2enc" \ | ||||
|         && curl --fail --silent --show-error --location \ | ||||
|           --output jbig2enc_${JBIG2ENC_VERSION}-1_${TARGETARCH}.deb \ | ||||
|           https://github.com/paperless-ngx/builder/releases/download/jbig2enc-${JBIG2ENC_VERSION}/jbig2enc_${JBIG2ENC_VERSION}-1_${TARGETARCH}.deb \ | ||||
|         && dpkg --install ./jbig2enc_${JBIG2ENC_VERSION}-1_${TARGETARCH}.deb \ | ||||
|       && echo "Configuring imagemagick" \ | ||||
|         && cp /etc/ImageMagick-6/paperless-policy.xml /etc/ImageMagick-6/policy.xml \ | ||||
|       && echo "Cleaning up image layer" \ | ||||
|         && rm --force --verbose *.deb \ | ||||
|     && rm --recursive --force --verbose /var/lib/apt/lists/* | ||||
|     && rm --recursive --force --verbose /var/lib/apt/lists/* \ | ||||
|   && echo "Installing supervisor" \ | ||||
|     && python3 -m pip install --default-timeout=1000 --upgrade --no-cache-dir supervisor==4.2.5 | ||||
|  | ||||
| # Copy gunicorn config | ||||
| # Changes very infrequently | ||||
| WORKDIR /usr/src/paperless/ | ||||
|  | ||||
| COPY --chown=1000:1000 gunicorn.conf.py /usr/src/paperless/gunicorn.conf.py | ||||
| COPY gunicorn.conf.py . | ||||
|  | ||||
| # setup docker-specific things | ||||
| # These change sometimes, but rarely | ||||
| WORKDIR /usr/src/paperless/src/docker/ | ||||
|  | ||||
| COPY [ \ | ||||
|   "docker/imagemagick-policy.xml", \ | ||||
|   "docker/supervisord.conf", \ | ||||
|   "docker/docker-entrypoint.sh", \ | ||||
|   "docker/docker-prepare.sh", \ | ||||
|   "docker/paperless_cmd.sh", \ | ||||
|   "docker/wait-for-redis.py", \ | ||||
|   "docker/env-from-file.sh", \ | ||||
|   "docker/management_script.sh", \ | ||||
|   "docker/flower-conditional.sh", \ | ||||
|   "docker/install_management_commands.sh", \ | ||||
|   "/usr/src/paperless/src/docker/" \ | ||||
| ] | ||||
|  | ||||
| RUN set -eux \ | ||||
|   && echo "Configuring ImageMagick" \ | ||||
|     && mv imagemagick-policy.xml /etc/ImageMagick-6/policy.xml \ | ||||
|   && echo "Configuring supervisord" \ | ||||
|     && mkdir /var/log/supervisord /var/run/supervisord \ | ||||
|     && mv supervisord.conf /etc/supervisord.conf \ | ||||
|   && echo "Setting up Docker scripts" \ | ||||
|     && mv docker-entrypoint.sh /sbin/docker-entrypoint.sh \ | ||||
|     && chmod 755 /sbin/docker-entrypoint.sh \ | ||||
|     && mv docker-prepare.sh /sbin/docker-prepare.sh \ | ||||
|     && chmod 755 /sbin/docker-prepare.sh \ | ||||
|     && mv wait-for-redis.py /sbin/wait-for-redis.py \ | ||||
|     && chmod 755 /sbin/wait-for-redis.py \ | ||||
|     && mv env-from-file.sh /sbin/env-from-file.sh \ | ||||
|     && chmod 755 /sbin/env-from-file.sh \ | ||||
|     && mv paperless_cmd.sh /usr/local/bin/paperless_cmd.sh \ | ||||
|     && chmod 755 /usr/local/bin/paperless_cmd.sh \ | ||||
|     && mv flower-conditional.sh /usr/local/bin/flower-conditional.sh \ | ||||
|     && chmod 755 /usr/local/bin/flower-conditional.sh \ | ||||
|   && echo "Installing management commands" \ | ||||
|     && chmod +x install_management_commands.sh \ | ||||
|     && ./install_management_commands.sh | ||||
|  | ||||
| WORKDIR /usr/src/paperless/src/ | ||||
|  | ||||
| # Python dependencies | ||||
| # Change pretty frequently | ||||
| COPY --chown=1000:1000 --from=pipenv-base /usr/src/pipenv/requirements.txt ./ | ||||
| COPY --from=pipenv-base /usr/src/pipenv/requirements.txt ./ | ||||
|  | ||||
| # Packages needed only for building a few quick Python | ||||
| # dependencies | ||||
| @@ -227,32 +215,27 @@ ARG BUILD_PACKAGES="\ | ||||
|   default-libmysqlclient-dev \ | ||||
|   pkg-config" | ||||
|  | ||||
| ARG ZXING_VERSION=2.3.0 | ||||
| ARG PSYCOPG_VERSION=3.2.4 | ||||
|  | ||||
| # hadolint ignore=DL3042 | ||||
| RUN --mount=type=cache,target=/root/.cache/pip/,id=pip-cache \ | ||||
|   set -eux \ | ||||
|   && echo "Installing build system packages" \ | ||||
|     && apt-get update \ | ||||
|     && apt-get install --yes --quiet --no-install-recommends ${BUILD_PACKAGES} \ | ||||
|     && python3 -m pip install --upgrade wheel \ | ||||
|     && python3 -m pip install --no-cache-dir --upgrade wheel \ | ||||
|   && echo "Installing Python requirements" \ | ||||
|     && curl --fail --silent --no-progress-meter --show-error --location --remote-name-all --parallel --parallel-max 4 \ | ||||
|       https://github.com/paperless-ngx/builder/releases/download/psycopg-${PSYCOPG_VERSION}/psycopg_c-${PSYCOPG_VERSION}-cp312-cp312-linux_x86_64.whl \ | ||||
|       https://github.com/paperless-ngx/builder/releases/download/psycopg-${PSYCOPG_VERSION}/psycopg_c-${PSYCOPG_VERSION}-cp312-cp312-linux_aarch64.whl \ | ||||
|       https://github.com/paperless-ngx/builder/releases/download/zxing-${ZXING_VERSION}/zxing_cpp-${ZXING_VERSION}-cp312-cp312-linux_aarch64.whl \ | ||||
|       https://github.com/paperless-ngx/builder/releases/download/zxing-${ZXING_VERSION}/zxing_cpp-${ZXING_VERSION}-cp312-cp312-linux_x86_64.whl \ | ||||
|     && python3 -m pip install --default-timeout=1000 --find-links . --requirement requirements.txt \ | ||||
|     && python3 -m pip install --default-timeout=1000 --requirement requirements.txt \ | ||||
|   && echo "Patching whitenoise for compression speedup" \ | ||||
|     && curl --fail --silent --show-error --location --output 484.patch https://github.com/evansd/whitenoise/pull/484.patch \ | ||||
|     && patch -d /usr/local/lib/python3.11/site-packages --verbose -p2 < 484.patch \ | ||||
|     && rm 484.patch \ | ||||
|   && echo "Installing NLTK data" \ | ||||
|     && python3 -W ignore::RuntimeWarning -m nltk.downloader -d "/usr/share/nltk_data" snowball_data \ | ||||
|     && python3 -W ignore::RuntimeWarning -m nltk.downloader -d "/usr/share/nltk_data" stopwords \ | ||||
|     && python3 -W ignore::RuntimeWarning -m nltk.downloader -d "/usr/share/nltk_data" punkt_tab \ | ||||
|     && python3 -W ignore::RuntimeWarning -m nltk.downloader -d "/usr/share/nltk_data" punkt \ | ||||
|   && echo "Cleaning up image" \ | ||||
|     && apt-get --yes purge ${BUILD_PACKAGES} \ | ||||
|     && apt-get --yes autoremove --purge \ | ||||
|     && apt-get clean --yes \ | ||||
|     && rm --recursive --force --verbose *.whl \ | ||||
|     && rm --recursive --force --verbose /var/lib/apt/lists/* \ | ||||
|     && rm --recursive --force --verbose /tmp/* \ | ||||
|     && rm --recursive --force --verbose /var/tmp/* \ | ||||
| @@ -276,21 +259,21 @@ RUN set -eux \ | ||||
|     && mkdir --parents --verbose /usr/src/paperless/media \ | ||||
|     && mkdir --parents --verbose /usr/src/paperless/consume \ | ||||
|     && mkdir --parents --verbose /usr/src/paperless/export \ | ||||
|   && echo "Creating gnupg directory" \ | ||||
|     && mkdir -m700 --verbose /usr/src/paperless/.gnupg \ | ||||
|   && echo "Adjusting all permissions" \ | ||||
|     && chown --from root:root --changes --recursive paperless:paperless /usr/src/paperless \ | ||||
|   && echo "Collecting static files" \ | ||||
|     && s6-setuidgid paperless python3 manage.py collectstatic --clear --no-input --link \ | ||||
|     && s6-setuidgid paperless python3 manage.py compilemessages | ||||
|     && gosu paperless python3 manage.py collectstatic --clear --no-input --link \ | ||||
|     && gosu paperless python3 manage.py compilemessages | ||||
|  | ||||
| VOLUME ["/usr/src/paperless/data", \ | ||||
|         "/usr/src/paperless/media", \ | ||||
|         "/usr/src/paperless/consume", \ | ||||
|         "/usr/src/paperless/export"] | ||||
|  | ||||
| ENTRYPOINT ["/init"] | ||||
| ENTRYPOINT ["/sbin/docker-entrypoint.sh"] | ||||
|  | ||||
| EXPOSE 8000 | ||||
|  | ||||
| CMD ["/usr/local/bin/paperless_cmd.sh"] | ||||
|  | ||||
| HEALTHCHECK --interval=30s --timeout=10s --retries=5 CMD [ "curl", "-fs", "-S", "--max-time", "2", "http://localhost:8000" ] | ||||
|   | ||||
							
								
								
									
										36
									
								
								Pipfile
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								Pipfile
									
									
									
									
									
								
							| @@ -7,42 +7,37 @@ name = "pypi" | ||||
| dateparser = "~=1.2" | ||||
| # WARNING: django does not use semver. | ||||
| #          Only patch versions are guaranteed to not introduce breaking changes. | ||||
| django = "~=5.1.5" | ||||
| django-allauth = {extras = ["mfa", "socialaccount"], version = "*"} | ||||
| django = "~=4.2.11" | ||||
| django-allauth = "*" | ||||
| django-auditlog = "*" | ||||
| django-celery-results = "*" | ||||
| django-compression-middleware = "*" | ||||
| django-cors-headers = "*" | ||||
| django-extensions = "*" | ||||
| django-filter = "~=25.1" | ||||
| django-filter = "~=24.2" | ||||
| django-guardian = "*" | ||||
| django-multiselectfield = "*" | ||||
| django-soft-delete = "*" | ||||
| djangorestframework = "~=3.15.2" | ||||
| djangorestframework = "==3.14.0" | ||||
| djangorestframework-guardian = "*" | ||||
| drf-spectacular = "*" | ||||
| drf-spectacular-sidecar = "*" | ||||
| drf-writable-nested = "*" | ||||
| bleach = "*" | ||||
| celery = {extras = ["redis"], version = "*"} | ||||
| channels = "~=4.2" | ||||
| channels = "~=4.1" | ||||
| channels-redis = "*" | ||||
| concurrent-log-handler = "*" | ||||
| filelock = "*" | ||||
| flower = "*" | ||||
| gotenberg-client = "*" | ||||
| gunicorn = "*" | ||||
| httpx-oauth = "*" | ||||
| imap-tools = "*" | ||||
| inotifyrecursive = "~=0.3" | ||||
| jinja2 = "~=3.1" | ||||
| langdetect = "*" | ||||
| mysqlclient = "*" | ||||
| nltk = "*" | ||||
| ocrmypdf = "~=16.9" | ||||
| ocrmypdf = "~=15.4" | ||||
| pathvalidate = "*" | ||||
| pdf2image = "*" | ||||
| psycopg = {version = "*", extras = ["c"]} | ||||
| psycopg2 = "*" | ||||
| python-dateutil = "*" | ||||
| python-dotenv = "*" | ||||
| python-gnupg = "*" | ||||
| @@ -51,24 +46,23 @@ python-magic = "*" | ||||
| pyzbar = "*" | ||||
| rapidfuzz = "*" | ||||
| redis = {extras = ["hiredis"], version = "*"} | ||||
| scikit-learn = "~=1.6" | ||||
| scikit-learn = "~=1.4" | ||||
| setproctitle = "*" | ||||
| tika-client = "*" | ||||
| tqdm = "*" | ||||
| # See https://github.com/paperless-ngx/paperless-ngx/issues/5494 | ||||
| uvicorn = {extras = ["standard"], version = "==0.25.0"} | ||||
| watchdog = "~=6.0" | ||||
| whitenoise = "~=6.9" | ||||
| whoosh = "~=2.7" | ||||
| zxing-cpp = "*" | ||||
|  | ||||
| watchdog = "~=4.0" | ||||
| whitenoise = "~=6.6" | ||||
| whoosh="~=2.7" | ||||
| zxing-cpp = {version = "*", platform_machine = "== 'x86_64'"} | ||||
|  | ||||
| [dev-packages] | ||||
| # Linting | ||||
| black = "*" | ||||
| pre-commit = "*" | ||||
| ruff = "*" | ||||
| factory-boy = "*" | ||||
| # Testing | ||||
| factory-boy = "*" | ||||
| pytest = "*" | ||||
| pytest-cov = "*" | ||||
| pytest-django = "*" | ||||
| @@ -76,7 +70,6 @@ pytest-httpx = "*" | ||||
| pytest-env = "*" | ||||
| pytest-sugar = "*" | ||||
| pytest-xdist = "*" | ||||
| pytest-mock = "*" | ||||
| pytest-rerunfailures = "*" | ||||
| imagehash = "*" | ||||
| daphne = "*" | ||||
| @@ -99,4 +92,5 @@ types-tqdm = "*" | ||||
| types-Markdown = "*" | ||||
| types-Pygments = "*" | ||||
| types-colorama = "*" | ||||
| types-psycopg2 = "*" | ||||
| types-setuptools = "*" | ||||
|   | ||||
							
								
								
									
										6423
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6423
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										12
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								README.md
									
									
									
									
									
								
							| @@ -30,14 +30,14 @@ Thanks to the generous folks at [DigitalOcean](https://m.do.co/c/8d70b916d462), | ||||
|   - [Translation](#translation) | ||||
|   - [Feature Requests](#feature-requests) | ||||
|   - [Bugs](#bugs) | ||||
| - [Related Projects](#related-projects) | ||||
| - [Affiliated Projects](#affiliated-projects) | ||||
| - [Important Note](#important-note) | ||||
|  | ||||
| <p align="right">This project is supported by:<br/> | ||||
|   <a href="https://m.do.co/c/8d70b916d462" style="padding-top: 4px; display: block;"> | ||||
|     <picture> | ||||
|       <source media="(prefers-color-scheme: dark)" srcset="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_white.svg" width="140px"> | ||||
|       <source media="(prefers-color-scheme: light)" srcset="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="140px"> | ||||
|       <source media="(prefers-color-scheme: light)" srcset="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_black_.svg" width="140px"> | ||||
|       <img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_black_.svg" width="140px"> | ||||
|     </picture> | ||||
|   </a> | ||||
| @@ -55,7 +55,7 @@ A full list of [features](https://docs.paperless-ngx.com/#features) and [screens | ||||
|  | ||||
| # Getting started | ||||
|  | ||||
| The easiest way to deploy paperless is `docker compose`. The files in the [`/docker/compose` directory](https://github.com/paperless-ngx/paperless-ngx/tree/main/docker/compose) are configured to pull the image from the GitHub container registry. | ||||
| The easiest way to deploy paperless is `docker compose`. The files in the [`/docker/compose` directory](https://github.com/paperless-ngx/paperless-ngx/tree/main/docker/compose) are configured to pull the image from GitHub Packages. | ||||
|  | ||||
| If you'd like to jump right in, you can configure a `docker compose` environment with our install script: | ||||
|  | ||||
| @@ -63,7 +63,7 @@ If you'd like to jump right in, you can configure a `docker compose` environment | ||||
| bash -c "$(curl -L https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)" | ||||
| ``` | ||||
|  | ||||
| More details and step-by-step guides for alternative installation methods can be found in [the documentation](https://docs.paperless-ngx.com/setup/#installation). | ||||
| Alternatively, you can install the dependencies and setup apache and a database server yourself. The [documentation](https://docs.paperless-ngx.com/setup/#installation) has a step by step guide on how to do it. | ||||
|  | ||||
| Migrating from Paperless-ng is easy, just drop in the new docker image! See the [documentation on migrating](https://docs.paperless-ngx.com/setup/#migrating-to-paperless-ngx) for more details. | ||||
|  | ||||
| @@ -93,9 +93,9 @@ Feature requests can be submitted via [GitHub Discussions](https://github.com/pa | ||||
|  | ||||
| For bugs please [open an issue](https://github.com/paperless-ngx/paperless-ngx/issues) or [start a discussion](https://github.com/paperless-ngx/paperless-ngx/discussions) if you have questions. | ||||
|  | ||||
| # Related Projects | ||||
| # Affiliated Projects | ||||
|  | ||||
| Please see [the wiki](https://github.com/paperless-ngx/paperless-ngx/wiki/Related-Projects) for a user-maintained list of related projects and software that is compatible with Paperless-ngx. | ||||
| Please see [the wiki](https://github.com/paperless-ngx/paperless-ngx/wiki/Affiliated-Projects) for a user-maintained list of affiliated projects and software that is compatible with Paperless-ngx. | ||||
|  | ||||
| # Important Note | ||||
|  | ||||
|   | ||||
| @@ -3,9 +3,10 @@ | ||||
| # Can be used locally or by the CI to start the necessary containers with the | ||||
| # correct networking for the tests | ||||
|  | ||||
| version: "3.7" | ||||
| services: | ||||
|   gotenberg: | ||||
|     image: docker.io/gotenberg/gotenberg:8.17 | ||||
|     image: docker.io/gotenberg/gotenberg:7.10 | ||||
|     hostname: gotenberg | ||||
|     container_name: gotenberg | ||||
|     network_mode: host | ||||
| @@ -19,7 +20,7 @@ services: | ||||
|       - "--log-level=warn" | ||||
|       - "--log-format=text" | ||||
|   tika: | ||||
|     image: docker.io/apache/tika:latest | ||||
|     image: ghcr.io/paperless-ngx/tika:latest | ||||
|     hostname: tika | ||||
|     container_name: tika | ||||
|     network_mode: host | ||||
|   | ||||
| @@ -1,17 +1,26 @@ | ||||
| ############################################################################### | ||||
| # Paperless-ngx settings                                                      # | ||||
| ############################################################################### | ||||
|  | ||||
| # See http://docs.paperless-ngx.com/configuration/ for all available options. | ||||
|  | ||||
| # The UID and GID of the user used to run paperless in the container. Set this | ||||
| # to your UID and GID on the host so that you have write access to the | ||||
| # consumption directory. | ||||
| #USERMAP_UID=1000 | ||||
| #USERMAP_GID=1000 | ||||
|  | ||||
| # See the documentation linked above for all options. A few commonly adjusted settings | ||||
| # are provided below. | ||||
| # Additional languages to install for text recognition, separated by a | ||||
| # whitespace. Note that this is | ||||
| # different from PAPERLESS_OCR_LANGUAGE (default=eng), which defines the | ||||
| # language used for OCR. | ||||
| # The container installs English, German, Italian, Spanish and French by | ||||
| # default. | ||||
| # See https://packages.debian.org/search?keywords=tesseract-ocr-&searchon=names&suite=buster | ||||
| # for available languages. | ||||
| #PAPERLESS_OCR_LANGUAGES=tur ces | ||||
|  | ||||
| ############################################################################### | ||||
| # Paperless-specific settings                                                 # | ||||
| ############################################################################### | ||||
|  | ||||
| # All settings defined in the paperless.conf.example can be used here. The | ||||
| # Docker setup does not use the configuration file. | ||||
| # A few commonly adjusted settings are provided below. | ||||
|  | ||||
| # This is required if you will be exposing Paperless-ngx on a public domain | ||||
| # (if doing so please consider security measures such as reverse proxy) | ||||
| @@ -21,17 +30,13 @@ | ||||
| # be a very long sequence of random characters. You don't need to remember it. | ||||
| #PAPERLESS_SECRET_KEY=change-me | ||||
|  | ||||
| # Use this variable to set a timezone for the Paperless Docker containers. Defaults to UTC. | ||||
| # Use this variable to set a timezone for the Paperless Docker containers. If not specified, defaults to UTC. | ||||
| #PAPERLESS_TIME_ZONE=America/Los_Angeles | ||||
|  | ||||
| # The default language to use for OCR. Set this to the language most of your | ||||
| # documents are written in. | ||||
| #PAPERLESS_OCR_LANGUAGE=eng | ||||
|  | ||||
| # Additional languages to install for text recognition, separated by a whitespace. | ||||
| # Note that this is different from PAPERLESS_OCR_LANGUAGE (default=eng), which defines | ||||
| # the language used for OCR. | ||||
| # The container installs English, German, Italian, Spanish and French by default. | ||||
| # See https://packages.debian.org/search?keywords=tesseract-ocr-&searchon=names&suite=buster | ||||
| # for available languages. | ||||
| #PAPERLESS_OCR_LANGUAGES=tur ces | ||||
| # Set if accessing paperless via a domain subpath e.g. https://domain.com/PATHPREFIX and using a reverse-proxy like traefik or nginx | ||||
| #PAPERLESS_FORCE_SCRIPT_NAME=/PATHPREFIX | ||||
| #PAPERLESS_STATIC_URL=/PATHPREFIX/static/ # trailing slash required | ||||
|   | ||||
| @@ -30,6 +30,7 @@ | ||||
| # For more extensive installation and update instructions, refer to the | ||||
| # documentation. | ||||
|  | ||||
| version: "3.4" | ||||
| services: | ||||
|   broker: | ||||
|     image: docker.io/library/redis:7 | ||||
| @@ -38,7 +39,7 @@ services: | ||||
|       - redisdata:/data | ||||
|  | ||||
|   db: | ||||
|     image: docker.io/library/mariadb:11 | ||||
|     image: docker.io/library/mariadb:10 | ||||
|     restart: unless-stopped | ||||
|     volumes: | ||||
|       - dbdata:/var/lib/mysql | ||||
| @@ -77,7 +78,7 @@ services: | ||||
|       PAPERLESS_TIKA_ENDPOINT: http://tika:9998 | ||||
|  | ||||
|   gotenberg: | ||||
|     image: docker.io/gotenberg/gotenberg:8.17 | ||||
|     image: docker.io/gotenberg/gotenberg:7.10 | ||||
|     restart: unless-stopped | ||||
|     # The gotenberg chromium route is used to convert .eml files. We do not | ||||
|     # want to allow external content like tracking pixels or even javascript. | ||||
| @@ -87,7 +88,7 @@ services: | ||||
|       - "--chromium-allow-list=file:///tmp/.*" | ||||
|  | ||||
|   tika: | ||||
|     image: docker.io/apache/tika:latest | ||||
|     image: ghcr.io/paperless-ngx/tika:latest | ||||
|     restart: unless-stopped | ||||
|  | ||||
| volumes: | ||||
|   | ||||
| @@ -26,6 +26,7 @@ | ||||
| # For more extensive installation and update instructions, refer to the | ||||
| # documentation. | ||||
|  | ||||
| version: "3.4" | ||||
| services: | ||||
|   broker: | ||||
|     image: docker.io/library/redis:7 | ||||
| @@ -34,7 +35,7 @@ services: | ||||
|       - redisdata:/data | ||||
|  | ||||
|   db: | ||||
|     image: docker.io/library/mariadb:11 | ||||
|     image: docker.io/library/mariadb:10 | ||||
|     restart: unless-stopped | ||||
|     volumes: | ||||
|       - dbdata:/var/lib/mysql | ||||
|   | ||||
| @@ -19,8 +19,6 @@ | ||||
| # | ||||
| # - Open portainer Stacks list and click 'Add stack' | ||||
| # - Paste the contents of this file and assign a name, e.g. 'paperless' | ||||
| # - Upload 'docker-compose.env' by clicking on 'Load variables from .env file' | ||||
| # - Modify the environment variables as needed | ||||
| # - Click 'Deploy the stack' and wait for it to be deployed | ||||
| # - Open the list of containers, select paperless_webserver_1 | ||||
| # - Click 'Console' and then 'Connect' to open the command line inside the container | ||||
| @@ -30,6 +28,7 @@ | ||||
| # For more extensive installation and update instructions, refer to the | ||||
| # documentation. | ||||
|  | ||||
| version: "3.4" | ||||
| services: | ||||
|   broker: | ||||
|     image: docker.io/library/redis:7 | ||||
| @@ -38,7 +37,7 @@ services: | ||||
|       - redisdata:/data | ||||
|  | ||||
|   db: | ||||
|     image: docker.io/library/postgres:16 | ||||
|     image: docker.io/library/postgres:15 | ||||
|     restart: unless-stopped | ||||
|     volumes: | ||||
|       - pgdata:/var/lib/postgresql/data | ||||
| @@ -63,8 +62,28 @@ services: | ||||
|     environment: | ||||
|       PAPERLESS_REDIS: redis://broker:6379 | ||||
|       PAPERLESS_DBHOST: db | ||||
|     env_file: | ||||
|       - stack.env | ||||
| # The UID and GID of the user used to run paperless in the container. Set this | ||||
| # to your UID and GID on the host so that you have write access to the | ||||
| # consumption directory. | ||||
|       USERMAP_UID: 1000 | ||||
|       USERMAP_GID: 100 | ||||
| # Additional languages to install for text recognition, separated by a | ||||
| # whitespace. Note that this is | ||||
| # different from PAPERLESS_OCR_LANGUAGE (default=eng), which defines the | ||||
| # language used for OCR. | ||||
| # The container installs English, German, Italian, Spanish and French by | ||||
| # default. | ||||
| # See https://packages.debian.org/search?keywords=tesseract-ocr-&searchon=names&suite=buster | ||||
| # for available languages. | ||||
|       #PAPERLESS_OCR_LANGUAGES: tur ces | ||||
| # Adjust this key if you plan to make paperless available publicly. It should | ||||
| # be a very long sequence of random characters. You don't need to remember it. | ||||
|       #PAPERLESS_SECRET_KEY: change-me | ||||
| # Use this variable to set a timezone for the Paperless Docker containers. If not specified, defaults to UTC. | ||||
|       #PAPERLESS_TIME_ZONE: America/Los_Angeles | ||||
| # The default language to use for OCR. Set this to the language most of your | ||||
| # documents are written in. | ||||
|       #PAPERLESS_OCR_LANGUAGE: eng | ||||
|  | ||||
| volumes: | ||||
|   data: | ||||
|   | ||||
| @@ -30,6 +30,7 @@ | ||||
| # For more extensive installation and update instructions, refer to the | ||||
| # documentation. | ||||
|  | ||||
| version: "3.4" | ||||
| services: | ||||
|   broker: | ||||
|     image: docker.io/library/redis:7 | ||||
| @@ -38,7 +39,7 @@ services: | ||||
|       - redisdata:/data | ||||
|  | ||||
|   db: | ||||
|     image: docker.io/library/postgres:16 | ||||
|     image: docker.io/library/postgres:15 | ||||
|     restart: unless-stopped | ||||
|     volumes: | ||||
|       - pgdata:/var/lib/postgresql/data | ||||
| @@ -71,7 +72,7 @@ services: | ||||
|       PAPERLESS_TIKA_ENDPOINT: http://tika:9998 | ||||
|  | ||||
|   gotenberg: | ||||
|     image: docker.io/gotenberg/gotenberg:8.17 | ||||
|     image: docker.io/gotenberg/gotenberg:7.10 | ||||
|     restart: unless-stopped | ||||
|  | ||||
|     # The gotenberg chromium route is used to convert .eml files. We do not | ||||
| @@ -82,7 +83,7 @@ services: | ||||
|       - "--chromium-allow-list=file:///tmp/.*" | ||||
|  | ||||
|   tika: | ||||
|     image: docker.io/apache/tika:latest | ||||
|     image: ghcr.io/paperless-ngx/tika:latest | ||||
|     restart: unless-stopped | ||||
|  | ||||
| volumes: | ||||
|   | ||||
| @@ -26,6 +26,7 @@ | ||||
| # For more extensive installation and update instructions, refer to the | ||||
| # documentation. | ||||
|  | ||||
| version: "3.4" | ||||
| services: | ||||
|   broker: | ||||
|     image: docker.io/library/redis:7 | ||||
| @@ -34,7 +35,7 @@ services: | ||||
|       - redisdata:/data | ||||
|  | ||||
|   db: | ||||
|     image: docker.io/library/postgres:16 | ||||
|     image: docker.io/library/postgres:15 | ||||
|     restart: unless-stopped | ||||
|     volumes: | ||||
|       - pgdata:/var/lib/postgresql/data | ||||
|   | ||||
| @@ -30,6 +30,7 @@ | ||||
| # For more extensive installation and update instructions, refer to the | ||||
| # documentation. | ||||
|  | ||||
| version: "3.4" | ||||
| services: | ||||
|   broker: | ||||
|     image: docker.io/library/redis:7 | ||||
| @@ -59,7 +60,7 @@ services: | ||||
|       PAPERLESS_TIKA_ENDPOINT: http://tika:9998 | ||||
|  | ||||
|   gotenberg: | ||||
|     image: docker.io/gotenberg/gotenberg:8.17 | ||||
|     image: docker.io/gotenberg/gotenberg:7.10 | ||||
|     restart: unless-stopped | ||||
|  | ||||
|     # The gotenberg chromium route is used to convert .eml files. We do not | ||||
| @@ -70,7 +71,7 @@ services: | ||||
|       - "--chromium-allow-list=file:///tmp/.*" | ||||
|  | ||||
|   tika: | ||||
|     image: docker.io/apache/tika:latest | ||||
|     image: ghcr.io/paperless-ngx/tika:latest | ||||
|     restart: unless-stopped | ||||
|  | ||||
| volumes: | ||||
|   | ||||
| @@ -23,6 +23,7 @@ | ||||
| # For more extensive installation and update instructions, refer to the | ||||
| # documentation. | ||||
|  | ||||
| version: "3.4" | ||||
| services: | ||||
|   broker: | ||||
|     image: docker.io/library/redis:7 | ||||
|   | ||||
| @@ -10,8 +10,8 @@ map_uidgid() { | ||||
| 	local -r usermap_new_gid=${USERMAP_GID:-${usermap_original_gid:-$usermap_new_uid}} | ||||
| 	if [[ ${usermap_new_uid} != "${usermap_original_uid}" || ${usermap_new_gid} != "${usermap_original_gid}" ]]; then | ||||
| 		echo "Mapping UID and GID for paperless:paperless to $usermap_new_uid:$usermap_new_gid" | ||||
| 		usermod --non-unique --uid "${usermap_new_uid}" paperless | ||||
| 		groupmod --non-unique --gid "${usermap_new_gid}" paperless | ||||
| 		usermod -o -u "${usermap_new_uid}" paperless | ||||
| 		groupmod -o -g "${usermap_new_gid}" paperless | ||||
| 	fi | ||||
| } | ||||
|  | ||||
| @@ -42,7 +42,7 @@ custom_container_init() { | ||||
| 		fi | ||||
|  | ||||
| 		# Make sure custom init directory has files in it | ||||
| 		if [ -n "$(/bin/ls --almost-all "${custom_script_dir}" 2>/dev/null)" ]; then | ||||
| 		if [ -n "$(/bin/ls -A "${custom_script_dir}" 2>/dev/null)" ]; then | ||||
| 			echo "[custom-init] files found in ${custom_script_dir} executing" | ||||
| 			# Loop over files in the directory | ||||
| 			for SCRIPT in "${custom_script_dir}"/*; do | ||||
| @@ -86,13 +86,13 @@ initialize() { | ||||
| 		"${CONSUME_DIR}"; do | ||||
| 		if [[ ! -d "${dir}" ]]; then | ||||
| 			echo "Creating directory ${dir}" | ||||
| 			mkdir --parents --verbose "${dir}" | ||||
| 			mkdir --parents "${dir}" | ||||
| 		fi | ||||
| 	done | ||||
|  | ||||
| 	local -r tmp_dir="${PAPERLESS_SCRATCH_DIR:=/tmp/paperless}" | ||||
| 	echo "Creating directory scratch directory ${tmp_dir}" | ||||
| 	mkdir --parents --verbose "${tmp_dir}" | ||||
| 	mkdir --parents "${tmp_dir}" | ||||
|  | ||||
| 	set +e | ||||
| 	echo "Adjusting permissions of paperless files. This may take a while." | ||||
| @@ -102,7 +102,7 @@ initialize() { | ||||
| 		"${DATA_DIR}" \ | ||||
| 		"${MEDIA_ROOT_DIR}" \ | ||||
| 		"${CONSUME_DIR}"; do | ||||
| 		find "${dir}" -not \( -user paperless -and -group paperless \) -exec chown --changes paperless:paperless {} + | ||||
| 		find "${dir}" -not \( -user paperless -and -group paperless \) -exec chown paperless:paperless {} + | ||||
| 	done | ||||
| 	set -e | ||||
|  | ||||
| @@ -122,44 +122,33 @@ install_languages() { | ||||
| 	if [ ${#langs[@]} -eq 0 ]; then | ||||
| 		return | ||||
| 	fi | ||||
| 	apt-get update | ||||
|  | ||||
| 	# Build list of packages to install | ||||
| 	to_install=() | ||||
| 	for lang in "${langs[@]}"; do | ||||
| 		pkg="tesseract-ocr-$lang" | ||||
|  | ||||
| 		if dpkg --status "$pkg" &>/dev/null; then | ||||
| 		if dpkg -s "$pkg" &>/dev/null; then | ||||
| 			echo "Package $pkg already installed!" | ||||
| 			continue | ||||
| 		else | ||||
| 			to_install+=("$pkg") | ||||
| 		fi | ||||
| 	done | ||||
|  | ||||
| 	# Use apt only when we install packages | ||||
| 	if [ ${#to_install[@]} -gt 0 ]; then | ||||
| 		apt-get update | ||||
|  | ||||
| 		for pkg in "${to_install[@]}"; do | ||||
|  | ||||
| 		if ! apt-cache show "$pkg" &>/dev/null; then | ||||
| 				echo "Skipped $pkg: Package not found! :(" | ||||
| 			echo "Package $pkg not found! :(" | ||||
| 			continue | ||||
| 		fi | ||||
|  | ||||
| 		echo "Installing package $pkg..." | ||||
| 			if ! apt-get --assume-yes install "$pkg" &>/dev/null; then | ||||
| 		if ! apt-get -y install "$pkg" &>/dev/null; then | ||||
| 			echo "Could not install $pkg" | ||||
| 			exit 1 | ||||
| 		fi | ||||
| 	done | ||||
| 	fi | ||||
| } | ||||
|  | ||||
| echo "Paperless-ngx docker container starting..." | ||||
|  | ||||
| gosu_cmd=(gosu paperless) | ||||
| if [ "$(id --user)" == "$(id --user paperless)" ]; then | ||||
| if [ "$(id -u)" == "$(id -u paperless)" ]; then | ||||
| 	gosu_cmd=() | ||||
| fi | ||||
|  | ||||
|   | ||||
							
								
								
									
										118
									
								
								docker/docker-prepare.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										118
									
								
								docker/docker-prepare.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,118 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| set -e | ||||
|  | ||||
| wait_for_postgres() { | ||||
| 	local attempt_num=1 | ||||
| 	local -r max_attempts=5 | ||||
|  | ||||
| 	echo "Waiting for PostgreSQL to start..." | ||||
|  | ||||
| 	local -r host="${PAPERLESS_DBHOST:-localhost}" | ||||
| 	local -r port="${PAPERLESS_DBPORT:-5432}" | ||||
|  | ||||
| 	# Disable warning, host and port can't have spaces | ||||
| 	# shellcheck disable=SC2086 | ||||
| 	while [ ! "$(pg_isready -h ${host} -p ${port})" ]; do | ||||
|  | ||||
| 		if [ $attempt_num -eq $max_attempts ]; then | ||||
| 			echo "Unable to connect to database." | ||||
| 			exit 1 | ||||
| 		else | ||||
| 			echo "Attempt $attempt_num failed! Trying again in 5 seconds..." | ||||
| 		fi | ||||
|  | ||||
| 		attempt_num=$(("$attempt_num" + 1)) | ||||
| 		sleep 5 | ||||
| 	done | ||||
| } | ||||
|  | ||||
| wait_for_mariadb() { | ||||
| 	echo "Waiting for MariaDB to start..." | ||||
|  | ||||
| 	local -r host="${PAPERLESS_DBHOST:=localhost}" | ||||
| 	local -r port="${PAPERLESS_DBPORT:=3306}" | ||||
|  | ||||
| 	local attempt_num=1 | ||||
| 	local -r max_attempts=5 | ||||
|  | ||||
| 	# Disable warning, host and port can't have spaces | ||||
| 	# shellcheck disable=SC2086 | ||||
| 	while ! true > /dev/tcp/$host/$port; do | ||||
|  | ||||
| 		if [ $attempt_num -eq $max_attempts ]; then | ||||
| 			echo "Unable to connect to database." | ||||
| 			exit 1 | ||||
| 		else | ||||
| 			echo "Attempt $attempt_num failed! Trying again in 5 seconds..." | ||||
|  | ||||
| 		fi | ||||
|  | ||||
| 		attempt_num=$(("$attempt_num" + 1)) | ||||
| 		sleep 5 | ||||
| 	done | ||||
| } | ||||
|  | ||||
| wait_for_redis() { | ||||
| 	# We use a Python script to send the Redis ping | ||||
| 	# instead of installing redis-tools just for 1 thing | ||||
| 	if ! python3 /sbin/wait-for-redis.py; then | ||||
| 		exit 1 | ||||
| 	fi | ||||
| } | ||||
|  | ||||
| migrations() { | ||||
| 	( | ||||
| 		# flock is in place to prevent multiple containers from doing migrations | ||||
| 		# simultaneously. This also ensures that the db is ready when the command | ||||
| 		# of the current container starts. | ||||
| 		flock 200 | ||||
| 		echo "Apply database migrations..." | ||||
| 		python3 manage.py migrate --skip-checks --no-input | ||||
| 	) 200>"${DATA_DIR}/migration_lock" | ||||
| } | ||||
|  | ||||
| django_checks() { | ||||
| 	# Explicitly run the Django system checks | ||||
| 	echo "Running Django checks" | ||||
| 	python3 manage.py check | ||||
| } | ||||
|  | ||||
| search_index() { | ||||
|  | ||||
| 	local -r index_version=9 | ||||
| 	local -r index_version_file=${DATA_DIR}/.index_version | ||||
|  | ||||
| 	if [[ (! -f "${index_version_file}") || $(<"${index_version_file}") != "$index_version" ]]; then | ||||
| 		echo "Search index out of date. Updating..." | ||||
| 		python3 manage.py document_index reindex --no-progress-bar | ||||
| 		echo ${index_version} | tee "${index_version_file}" >/dev/null | ||||
| 	fi | ||||
| } | ||||
|  | ||||
| superuser() { | ||||
| 	if [[ -n "${PAPERLESS_ADMIN_USER}" ]]; then | ||||
| 		python3 manage.py manage_superuser | ||||
| 	fi | ||||
| } | ||||
|  | ||||
| do_work() { | ||||
| 	if [[ "${PAPERLESS_DBENGINE}" == "mariadb" ]]; then | ||||
| 		wait_for_mariadb | ||||
| 	elif [[ -n "${PAPERLESS_DBHOST}" ]]; then | ||||
| 		wait_for_postgres | ||||
| 	fi | ||||
|  | ||||
| 	wait_for_redis | ||||
|  | ||||
| 	migrations | ||||
|  | ||||
| 	django_checks | ||||
|  | ||||
| 	search_index | ||||
|  | ||||
| 	superuser | ||||
|  | ||||
| } | ||||
|  | ||||
| do_work | ||||
							
								
								
									
										42
									
								
								docker/env-from-file.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								docker/env-from-file.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| # Scans the environment variables for those with the suffix _FILE | ||||
| # When located, checks the file exists, and exports the contents | ||||
| # of the file as the same name, minus the suffix | ||||
| # This allows the use of Docker secrets or mounted files | ||||
| # to fill in any of the settings configurable via environment | ||||
| # variables | ||||
|  | ||||
| set -eu | ||||
|  | ||||
| for line in $(printenv) | ||||
| do | ||||
| 	# Extract the name of the environment variable | ||||
| 	env_name=${line%%=*} | ||||
| 	# Check if it starts with "PAPERLESS_" and ends in "_FILE" | ||||
| 	if [[ ${env_name} == PAPERLESS_*_FILE ]]; then | ||||
| 		# This should have been named different.. | ||||
| 		if [[ ${env_name} == "PAPERLESS_OCR_SKIP_ARCHIVE_FILE" ]]; then | ||||
| 			continue | ||||
| 		fi | ||||
| 		# Extract the value of the environment | ||||
| 		env_value=${line#*=} | ||||
|  | ||||
| 		# Check the file exists | ||||
| 		if [[ -f ${env_value} ]]; then | ||||
|  | ||||
| 			# Trim off the _FILE suffix | ||||
| 			non_file_env_name=${env_name%"_FILE"} | ||||
| 			echo "Setting ${non_file_env_name} from file" | ||||
|  | ||||
| 			# Reads the value from th file | ||||
| 			val="$(< "${!env_name}")" | ||||
|  | ||||
| 			# Sets the normal name to the read file contents | ||||
| 			export "${non_file_env_name}"="${val}" | ||||
|  | ||||
| 		else | ||||
| 			echo "File ${env_value} referenced by ${env_name} doesn't exist" | ||||
| 		fi | ||||
| 	fi | ||||
| done | ||||
							
								
								
									
										12
									
								
								docker/flower-conditional.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								docker/flower-conditional.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| echo "Checking if we should start flower..." | ||||
|  | ||||
| if [[ -n  "${PAPERLESS_ENABLE_FLOWER}" ]]; then | ||||
| 	# Small delay to allow celery to be up first | ||||
| 	echo "Starting flower in 5s" | ||||
| 	sleep 5 | ||||
| 	celery --app paperless flower --conf=/usr/src/paperless/src/paperless/flowerconfig.py | ||||
| else | ||||
| 	echo "Not starting flower" | ||||
| fi | ||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 30 KiB | 
| @@ -1,7 +1,5 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| # Run this script to generate the management commands again (for example if a new command is create or the template is updated) | ||||
|  | ||||
| set -eu | ||||
|  | ||||
| for command in decrypt_documents \ | ||||
| @@ -16,11 +14,9 @@ for command in decrypt_documents \ | ||||
| 	document_thumbnails \ | ||||
| 	document_sanity_checker \ | ||||
| 	document_fuzzy_match \ | ||||
| 	manage_superuser \ | ||||
| 	convert_mariadb_uuid \ | ||||
| 	prune_audit_logs; | ||||
| 	manage_superuser; | ||||
| do | ||||
| 	echo "installing $command..." | ||||
| 	sed "s/management_command/$command/g" management_script.sh >"$PWD/rootfs/usr/local/bin/$command" | ||||
| 	chmod +x "$PWD/rootfs/usr/local/bin/$command" | ||||
| 	sed "s/management_command/$command/g" management_script.sh > /usr/local/bin/$command | ||||
| 	chmod +x /usr/local/bin/$command | ||||
| done | ||||
|   | ||||
| @@ -1,13 +1,17 @@ | ||||
| #!/command/with-contenv /usr/bin/bash | ||||
| # shellcheck shell=bash | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| set -e | ||||
|  | ||||
| cd "${PAPERLESS_SRC_DIR}" | ||||
| cd /usr/src/paperless/src/ | ||||
| # This ensures environment is setup | ||||
| # shellcheck disable=SC1091 | ||||
| source /sbin/env-from-file.sh | ||||
|  | ||||
| if [[ $(id -u) == 0 ]]; then | ||||
| 	s6-setuidgid paperless python3 manage.py management_command "$@" | ||||
| elif [[ $(id -un) == "paperless" ]]; then | ||||
| if [[ $(id -u) == 0 ]] ; | ||||
| then | ||||
| 	gosu paperless python3 manage.py management_command "$@" | ||||
| elif [[ $(id -un) == "paperless" ]] ; | ||||
| then | ||||
| 	python3 manage.py management_command "$@" | ||||
| else | ||||
| 	echo "Unknown user." | ||||
|   | ||||
							
								
								
									
										16
									
								
								docker/paperless_cmd.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										16
									
								
								docker/paperless_cmd.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| SUPERVISORD_WORKING_DIR="${PAPERLESS_SUPERVISORD_WORKING_DIR:-$PWD}" | ||||
| rootless_args=() | ||||
| if [ "$(id -u)" == "$(id -u paperless)" ]; then | ||||
| 	rootless_args=( | ||||
| 		--user | ||||
| 		paperless | ||||
| 		--logfile | ||||
| 		"${SUPERVISORD_WORKING_DIR}/supervisord.log" | ||||
| 		--pidfile | ||||
| 		"${SUPERVISORD_WORKING_DIR}/supervisord.pid" | ||||
| 	) | ||||
| fi | ||||
|  | ||||
| exec /usr/local/bin/supervisord -c /etc/supervisord.conf "${rootless_args[@]}" | ||||
| @@ -1,8 +0,0 @@ | ||||
| #!/command/with-contenv /usr/bin/bash | ||||
| # shellcheck shell=bash | ||||
| declare -r log_prefix="[init-complete]" | ||||
| declare -r end_time=$(date +%s) | ||||
| declare -r start_time=${PAPERLESS_START_TIME_S} | ||||
|  | ||||
| echo "${log_prefix} paperless-ngx docker container init completed in $(($end_time-$start_time)) seconds" | ||||
| echo "${log_prefix} Starting services" | ||||
| @@ -1 +0,0 @@ | ||||
| oneshot | ||||
| @@ -1 +0,0 @@ | ||||
| /etc/s6-overlay/s6-rc.d/init-complete/run | ||||
| @@ -1,44 +0,0 @@ | ||||
| #!/command/with-contenv /usr/bin/bash | ||||
| # shellcheck shell=bash | ||||
|  | ||||
| declare -r log_prefix="[custom-init]" | ||||
|  | ||||
| # Mostly borrowed from the LinuxServer.io base image | ||||
| # https://github.com/linuxserver/docker-baseimage-ubuntu/tree/bionic/root/etc/cont-init.d | ||||
| declare -r custom_script_dir="/custom-cont-init.d" | ||||
|  | ||||
| # Tamper checking. | ||||
| # Don't run files which are owned by anyone except root | ||||
| # Don't run files which are writeable by others | ||||
| if [ -d "${custom_script_dir}" ]; then | ||||
| 	if [ -n "$(/usr/bin/find "${custom_script_dir}" -maxdepth 1 ! -user root)" ]; then | ||||
| 		echo "${log_prefix} **** Potential tampering with custom scripts detected ****" | ||||
| 		echo "${log_prefix} **** The folder '${custom_script_dir}' must be owned by root ****" | ||||
| 		exit 0 | ||||
| 	fi | ||||
| 	if [ -n "$(/usr/bin/find "${custom_script_dir}" -maxdepth 1 -perm -o+w)" ]; then | ||||
| 		echo "${log_prefix} **** The folder '${custom_script_dir}' or some of contents have write permissions for others, which is a security risk. ****" | ||||
| 		echo "${log_prefix} **** Please review the permissions and their contents to make sure they are owned by root, and can only be modified by root. ****" | ||||
| 		exit 0 | ||||
| 	fi | ||||
|  | ||||
| 	# Make sure custom init directory has files in it | ||||
| 	if [ -n "$(/bin/ls --almost-all "${custom_script_dir}" 2>/dev/null)" ]; then | ||||
| 		echo "${log_prefix} files found in ${custom_script_dir} executing" | ||||
| 		# Loop over files in the directory | ||||
| 		for SCRIPT in "${custom_script_dir}"/*; do | ||||
| 			NAME="$(basename "${SCRIPT}")" | ||||
| 			if [ -f "${SCRIPT}" ]; then | ||||
| 				echo "${log_prefix} ${NAME}: executing..." | ||||
| 				/command/with-contenv /bin/bash "${SCRIPT}" | ||||
| 				echo "${log_prefix} ${NAME}: exited $?" | ||||
| 			elif [ ! -f "${SCRIPT}" ]; then | ||||
| 				echo "${log_prefix} ${NAME}: is not a file" | ||||
| 			fi | ||||
| 		done | ||||
| 	else | ||||
| 		echo "${log_prefix} no custom files found exiting..." | ||||
| 	fi | ||||
| else | ||||
| 	echo "${log_prefix} ${custom_script_dir} doesn't exist, nothing to do" | ||||
| fi | ||||
| @@ -1 +0,0 @@ | ||||
| oneshot | ||||
| @@ -1 +0,0 @@ | ||||
| /etc/s6-overlay/s6-rc.d/init-custom-init/run | ||||
| @@ -1,30 +0,0 @@ | ||||
| #!/command/with-contenv /usr/bin/bash | ||||
| # shellcheck shell=bash | ||||
|  | ||||
| declare -r log_prefix="[env-init]" | ||||
|  | ||||
| echo "${log_prefix} Checking for environment from files" | ||||
|  | ||||
| if find /run/s6/container_environment/*"_FILE" -maxdepth 1 > /dev/null 2>&1; then | ||||
| 	for FILENAME in /run/s6/container_environment/*; do | ||||
| 		if [[ "${FILENAME##*/}" == PAPERLESS_*_FILE ]]; then | ||||
| 			# This should have been named different.. | ||||
| 			if [[ ${FILENAME} == "PAPERLESS_OCR_SKIP_ARCHIVE_FILE" || ${FILENAME} == "PAPERLESS_MODEL_FILE" ]]; then | ||||
| 				continue | ||||
| 			fi | ||||
| 			SECRETFILE=$(cat "${FILENAME}") | ||||
| 			# Check the file exists | ||||
| 			if [[ -f ${SECRETFILE} ]]; then | ||||
| 				# Trim off trailing _FILE | ||||
| 				FILESTRIP=${FILENAME//_FILE/} | ||||
| 				# Set environment variable | ||||
| 				cat "${SECRETFILE}" > "${FILESTRIP}" | ||||
| 				echo "${log_prefix} ${FILESTRIP##*/} set from ${FILENAME##*/}" | ||||
| 			else | ||||
| 				echo "${log_prefix} cannot find secret in ${FILENAME##*/}" | ||||
| 			fi | ||||
| 		fi | ||||
| 	done | ||||
| else | ||||
| 		echo "${log_prefix} No *_FILE environment found" | ||||
| fi | ||||
| @@ -1 +0,0 @@ | ||||
| oneshot | ||||
| @@ -1 +0,0 @@ | ||||
| /etc/s6-overlay/s6-rc.d/init-env-file/run | ||||
| @@ -1,33 +0,0 @@ | ||||
| #!/command/with-contenv /usr/bin/bash | ||||
| # shellcheck shell=bash | ||||
|  | ||||
| declare -r log_prefix="[init-folders]" | ||||
|  | ||||
| declare -r export_dir="/usr/src/paperless/export" | ||||
| declare -r data_dir="${PAPERLESS_DATA_DIR:-/usr/src/paperless/data}" | ||||
| declare -r media_root_dir="${PAPERLESS_MEDIA_ROOT:-/usr/src/paperless/media}" | ||||
| declare -r consume_dir="${PAPERLESS_CONSUMPTION_DIR:-/usr/src/paperless/consume}" | ||||
| declare -r tmp_dir="${PAPERLESS_SCRATCH_DIR:=/tmp/paperless}" | ||||
|  | ||||
| echo "${log_prefix} Checking for folder existence" | ||||
|  | ||||
| for dir in \ | ||||
| 	"${export_dir}" \ | ||||
| 	"${data_dir}" "${data_dir}/index" \ | ||||
| 	"${media_root_dir}" "${media_root_dir}/documents" "${media_root_dir}/documents/originals" "${media_root_dir}/documents/thumbnails" \ | ||||
| 	"${consume_dir}" \ | ||||
| 	"${tmp_dir}"; do | ||||
| 	if [[ ! -d "${dir}" ]]; then | ||||
| 		mkdir --parents --verbose "${dir}" | ||||
| 	fi | ||||
| done | ||||
|  | ||||
| echo "${log_prefix} Adjusting file and folder permissions" | ||||
| for dir in \ | ||||
| 	"${export_dir}" \ | ||||
| 	"${data_dir}" \ | ||||
| 	"${media_root_dir}" \ | ||||
| 	"${consume_dir}" \ | ||||
| 	"${tmp_dir}"; do | ||||
| 	find "${dir}" -not \( -user paperless -and -group paperless \) -exec chown --changes paperless:paperless {} + | ||||
| done | ||||
| @@ -1 +0,0 @@ | ||||
| oneshot | ||||
| @@ -1 +0,0 @@ | ||||
| /etc/s6-overlay/s6-rc.d/init-folders/run | ||||
| @@ -1,20 +0,0 @@ | ||||
| #!/command/with-contenv /usr/bin/bash | ||||
| # shellcheck shell=bash | ||||
| declare -r log_prefix="[init-migrations]" | ||||
| declare -r data_dir="${PAPERLESS_DATA_DIR:-/usr/src/paperless/data}" | ||||
|  | ||||
| ( | ||||
| 	# flock is in place to prevent multiple containers from doing migrations | ||||
| 	# simultaneously. This also ensures that the db is ready when the command | ||||
| 	# of the current container starts. | ||||
| 	flock 200 | ||||
| 	echo "${log_prefix} Apply database migrations..." | ||||
| 	cd "${PAPERLESS_SRC_DIR}" | ||||
|  | ||||
| 	if [[ -n "${USER_IS_NON_ROOT}" ]]; then | ||||
| 		exec python3 manage.py migrate --skip-checks --no-input | ||||
| 	else | ||||
| 		exec s6-setuidgid paperless python3 manage.py migrate --skip-checks --no-input | ||||
| 	fi | ||||
|  | ||||
| ) 200>"${data_dir}/migration_lock" | ||||
| @@ -1 +0,0 @@ | ||||
| oneshot | ||||
| @@ -1 +0,0 @@ | ||||
| /etc/s6-overlay/s6-rc.d/init-migrations/run | ||||
| @@ -1,22 +0,0 @@ | ||||
| #!/command/with-contenv /usr/bin/bash | ||||
| # shellcheck shell=bash | ||||
| declare -r log_prefix="[init-user]" | ||||
|  | ||||
| declare -r usermap_original_uid=$(id -u paperless) | ||||
| declare -r usermap_original_gid=$(id -g paperless) | ||||
| declare -r usermap_new_uid=${USERMAP_UID:-$usermap_original_uid} | ||||
| declare -r usermap_new_gid=${USERMAP_GID:-${usermap_original_gid:-$usermap_new_uid}} | ||||
|  | ||||
| if [[ ${usermap_new_uid} != "${usermap_original_uid}" ]]; then | ||||
| 	echo "${log_prefix} Mapping UID for paperless to $usermap_new_uid" | ||||
| 	usermod --non-unique --uid "${usermap_new_uid}" paperless | ||||
| else | ||||
| 	echo "${log_prefix} No UID changes for paperless" | ||||
| fi | ||||
|  | ||||
| if [[ ${usermap_new_gid} != "${usermap_original_gid}" ]]; then | ||||
| 	echo "${log_prefix} Mapping GID for paperless to $usermap_new_gid" | ||||
| 	groupmod --non-unique --gid "${usermap_new_gid}" paperless | ||||
| else | ||||
| 	echo "${log_prefix} No GID changes for paperless" | ||||
| fi | ||||
| @@ -1 +0,0 @@ | ||||
| oneshot | ||||
| @@ -1 +0,0 @@ | ||||
| /etc/s6-overlay/s6-rc.d/init-modify-user/run | ||||
| @@ -1,28 +0,0 @@ | ||||
| #!/command/with-contenv /usr/bin/bash | ||||
| # shellcheck shell=bash | ||||
|  | ||||
| declare -r log_prefix="[init-index]" | ||||
|  | ||||
| declare -r index_version=9 | ||||
| declare -r data_dir="${PAPERLESS_DATA_DIR:-/usr/src/paperless/data}" | ||||
| declare -r index_version_file="${data_dir}/.index_version" | ||||
|  | ||||
| update_index () { | ||||
| 	echo "${log_prefix} Search index out of date. Updating..." | ||||
| 	cd "${PAPERLESS_SRC_DIR}" | ||||
| 	if [[ -n "${USER_IS_NON_ROOT}" ]]; then | ||||
| 		python3 manage.py document_index reindex --no-progress-bar | ||||
| 		echo ${index_version} | tee "${index_version_file}" > /dev/null | ||||
| 	else | ||||
| 		s6-setuidgid paperless python3 manage.py document_index reindex --no-progress-bar | ||||
| 		echo ${index_version} | s6-setuidgid paperless tee "${index_version_file}" > /dev/null | ||||
| 	fi | ||||
| } | ||||
|  | ||||
| if [[ (! -f "${index_version_file}") ]]; then | ||||
| 	echo "${log_prefix} No index version file found" | ||||
| 	update_index | ||||
| elif [[ $(<"${index_version_file}") != "$index_version" ]]; then | ||||
| 	echo "${log_prefix} index version updated" | ||||
| 	update_index | ||||
| fi | ||||
| @@ -1 +0,0 @@ | ||||
| oneshot | ||||
| @@ -1 +0,0 @@ | ||||
| /etc/s6-overlay/s6-rc.d/init-search-index/run | ||||
| @@ -1,19 +0,0 @@ | ||||
| #!/command/with-contenv /usr/bin/bash | ||||
| # shellcheck shell=bash | ||||
|  | ||||
| declare -r log_prefix="[init-start]" | ||||
|  | ||||
| echo "${log_prefix} paperless-ngx docker container starting..." | ||||
|  | ||||
| # Set some directories into environment for other steps to access via environment | ||||
| # Sort of like variables for later | ||||
| printf "/usr/src/paperless/src" > /var/run/s6/container_environment/PAPERLESS_SRC_DIR | ||||
| echo $(date +%s) > /var/run/s6/container_environment/PAPERLESS_START_TIME_S | ||||
|  | ||||
| # Check if we're starting as a non-root user | ||||
| if [ $(id -u) == $(id -u paperless) ]; then | ||||
| 	printf "true" > /var/run/s6/container_environment/USER_IS_NON_ROOT | ||||
| 	echo "${log_prefix}  paperless-ngx docker container running under a user" | ||||
| else | ||||
| 	echo "${log_prefix}  paperless-ngx docker container starting init as root" | ||||
| fi | ||||
| @@ -1 +0,0 @@ | ||||
| oneshot | ||||
| @@ -1 +0,0 @@ | ||||
| /etc/s6-overlay/s6-rc.d/init-start/run | ||||
| @@ -1,20 +0,0 @@ | ||||
| #!/command/with-contenv /usr/bin/bash | ||||
| # shellcheck shell=bash | ||||
|  | ||||
| declare -r log_prefix="[init-superuser]" | ||||
|  | ||||
| if [[ -n "${PAPERLESS_ADMIN_USER}" ]]; then | ||||
| 	echo "${log_prefix} Creating superuser..." | ||||
| 	cd "${PAPERLESS_SRC_DIR}" | ||||
|  | ||||
| 	if [[ -n "${USER_IS_NON_ROOT}" ]]; then | ||||
| 		python3 manage.py manage_superuser | ||||
| 	else | ||||
| 		s6-setuidgid paperless python3 manage.py manage_superuser | ||||
| 	fi | ||||
|  | ||||
| 	echo "${log_prefix} Superuser creation done" | ||||
|  | ||||
| else | ||||
| 	echo "${log_prefix} Not creating superuser" | ||||
| fi | ||||
| @@ -1 +0,0 @@ | ||||
| oneshot | ||||
| @@ -1 +0,0 @@ | ||||
| /etc/s6-overlay/s6-rc.d/init-superuser/run | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user