mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Merge remote-tracking branch 'paperless/dev' into feature-consume-eml
This commit is contained in:
		
							
								
								
									
										1
									
								
								.github/release-drafter.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/release-drafter.yml
									
									
									
									
										vendored
									
									
								
							| @@ -30,7 +30,6 @@ replacers: # Changes "Feature: Update checker" to "Update checker" | ||||
|     replace: '' | ||||
| change-template: '- $TITLE @$AUTHOR (#$NUMBER)' | ||||
| change-title-escapes: '\<*_&#@' | ||||
| tag-prefix: "ngx-" | ||||
| template: | | ||||
|   # Changelog | ||||
|  | ||||
|   | ||||
							
								
								
									
										5
									
								
								.github/scripts/get-build-json.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.github/scripts/get-build-json.py
									
									
									
									
										vendored
									
									
								
							| @@ -53,10 +53,7 @@ def _main(): | ||||
|     git_tag = None | ||||
|     extra_config = {} | ||||
|  | ||||
|     if args.package == "frontend": | ||||
|         # Version is just the branch or tag name | ||||
|         version = branch_name | ||||
|     elif args.package in pipfile_data["default"]: | ||||
|     if args.package in pipfile_data["default"]: | ||||
|         # Read the version from Pipfile.lock | ||||
|         pkg_data = pipfile_data["default"][args.package] | ||||
|         pkg_version = pkg_data["version"].split("==")[-1] | ||||
|   | ||||
							
								
								
									
										113
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										113
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -3,8 +3,10 @@ name: ci | ||||
| on: | ||||
|   push: | ||||
|     tags: | ||||
|       - ngx-* | ||||
|       - beta-* | ||||
|       # https://semver.org/#spec-item-2 | ||||
|       - 'v[0-9]+.[0-9]+.[0-9]+' | ||||
|       # https://semver.org/#spec-item-9 | ||||
|       - 'v[0-9]+.[0-9]+.[0-9]+-beta.rc[0-9]+' | ||||
|     branches-ignore: | ||||
|       - 'translations**' | ||||
|   pull_request: | ||||
| @@ -53,7 +55,7 @@ jobs: | ||||
|  | ||||
|   prepare-docker-build: | ||||
|     name: Prepare Docker Pipeline Data | ||||
|     if: github.event_name == 'push' && (startsWith(github.ref, 'refs/heads/feature-') || github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/beta' || startsWith(github.ref, 'refs/tags/ngx-') || startsWith(github.ref, 'refs/tags/beta-')) | ||||
|     if: github.event_name == 'push' && (startsWith(github.ref, 'refs/heads/feature-') || github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/beta' || contains(github.ref, 'beta.rc') || startsWith(github.ref, 'refs/tags/v')) | ||||
|     runs-on: ubuntu-20.04 | ||||
|     needs: | ||||
|       - documentation | ||||
| @@ -104,15 +106,6 @@ jobs: | ||||
|           echo ${build_json} | ||||
|  | ||||
|           echo ::set-output name=jbig2enc-json::${build_json} | ||||
|       - | ||||
|         name: Setup frontend image | ||||
|         id: frontend-setup | ||||
|         run: | | ||||
|           build_json=$(python ${GITHUB_WORKSPACE}/.github/scripts/get-build-json.py frontend) | ||||
|  | ||||
|           echo ${build_json} | ||||
|  | ||||
|           echo ::set-output name=frontend-json::${build_json} | ||||
|  | ||||
|     outputs: | ||||
|  | ||||
| @@ -124,8 +117,6 @@ jobs: | ||||
|  | ||||
|       jbig2enc-json: ${{ steps.jbig2enc-setup.outputs.jbig2enc-json}} | ||||
|  | ||||
|       frontend-json: ${{ steps.frontend-setup.outputs.frontend-json}} | ||||
|  | ||||
|   build-qpdf-debs: | ||||
|     name: qpdf | ||||
|     needs: | ||||
| @@ -175,57 +166,6 @@ jobs: | ||||
|         PIKEPDF_GIT_TAG=${{ fromJSON(needs.prepare-docker-build.outputs.pikepdf-json).git_tag }} | ||||
|         PIKEPDF_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.pikepdf-json).version }} | ||||
|  | ||||
|   build-frontend: | ||||
|     name: Compile frontend | ||||
|     concurrency: | ||||
|       group: ${{ github.workflow }}-build-frontend-${{ github.ref_name }} | ||||
|       cancel-in-progress: false | ||||
|     needs: | ||||
|       - prepare-docker-build | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v3 | ||||
|       - | ||||
|         name: Login to Github Container Registry | ||||
|         uses: docker/login-action@v1 | ||||
|         with: | ||||
|           registry: ghcr.io | ||||
|           username: ${{ github.actor }} | ||||
|           password: ${{ secrets.GITHUB_TOKEN }} | ||||
|       - | ||||
|         name: Set up Docker Buildx | ||||
|         uses: docker/setup-buildx-action@v1 | ||||
|       - | ||||
|         name: Set up QEMU | ||||
|         uses: docker/setup-qemu-action@v1 | ||||
|       - | ||||
|         name: Compile frontend | ||||
|         uses: docker/build-push-action@v2 | ||||
|         with: | ||||
|           context: . | ||||
|           file: ./docker-builders/Dockerfile.frontend | ||||
|           tags: ${{ fromJSON(needs.prepare-docker-build.outputs.frontend-json).image_tag }} | ||||
|           # The compilation is identical between different platforms | ||||
|           # The buildx and QEMU setup is left, just in case that ever changes | ||||
|           # But the platform is set to the runner's native for speedup | ||||
|           platforms: linux/amd64 | ||||
|           push: true | ||||
|           cache-from: type=registry,ref=${{ fromJSON(needs.prepare-docker-build.outputs.frontend-json).cache_tag }} | ||||
|           cache-to: type=registry,mode=max,ref=${{ fromJSON(needs.prepare-docker-build.outputs.frontend-json).cache_tag }} | ||||
|       - | ||||
|         name: Export frontend artifact from docker | ||||
|         run: | | ||||
|           docker create --name frontend-extract ${{ fromJSON(needs.prepare-docker-build.outputs.frontend-json).image_tag }} | ||||
|           docker cp frontend-extract:/src/src/documents/static/frontend src/documents/static/frontend/ | ||||
|       - | ||||
|         name: Upload frontend artifact | ||||
|         uses: actions/upload-artifact@v3 | ||||
|         with: | ||||
|           name: frontend-compiled | ||||
|           path: src/documents/static/frontend/ | ||||
|  | ||||
|   # build and push image to docker hub. | ||||
|   build-docker-image: | ||||
|     runs-on: ubuntu-20.04 | ||||
| @@ -238,7 +178,6 @@ jobs: | ||||
|       - build-jbig2enc | ||||
|       - build-qpdf-debs | ||||
|       - build-pikepdf-wheel | ||||
|       - build-frontend | ||||
|     steps: | ||||
|       - | ||||
|         name: Check pushing to Docker Hub | ||||
| @@ -260,8 +199,12 @@ jobs: | ||||
|             ghcr.io/${{ github.repository }} | ||||
|             name=paperlessngx/paperless-ngx,enable=${{ steps.docker-hub.outputs.enable }} | ||||
|           tags: | | ||||
|             # Tag branches with branch name | ||||
|             type=ref,event=branch | ||||
|             type=ref,event=tag | ||||
|             # Process semver tags | ||||
|             # For a tag x.y.z or vX.Y.Z, output an x.y.z and x.y image tag | ||||
|             type=semver,pattern={{version}} | ||||
|             type=semver,pattern={{major}}.{{minor}} | ||||
|       - | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v3 | ||||
| @@ -297,18 +240,33 @@ jobs: | ||||
|           tags: ${{ steps.docker-meta.outputs.tags }} | ||||
|           labels: ${{ steps.docker-meta.outputs.labels }} | ||||
|           build-args: | | ||||
|             REPO=${{ github.repository }} | ||||
|             JBIG2ENC_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.jbig2enc-json).version }} | ||||
|             QPDF_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.qpdf-json).version }} | ||||
|             PIKEPDF_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.pikepdf-json).version }} | ||||
|             PSYCOPG2_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.psycopg2-json).version }} | ||||
|             FRONTEND_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.frontend-json).version }} | ||||
|           cache-from: type=gha | ||||
|           cache-to: type=gha,mode=max | ||||
|           # Get cache layers from this branch, then dev, then main | ||||
|           # This allows new branches to get at least some cache benefits, generally from dev | ||||
|           cache-from: | | ||||
|             type=registry,ref=ghcr.io/${{ github.repository }}/builder/cache/app:${{ github.ref_name }} | ||||
|             type=registry,ref=ghcr.io/${{ github.repository }}/builder/cache/app:dev | ||||
|             type=registry,ref=ghcr.io/${{ github.repository }}/builder/cache/app:main | ||||
|           cache-to: | | ||||
|             type=registry,mode=max,ref=ghcr.io/${{ github.repository }}/builder/cache/app:${{ github.ref_name }} | ||||
|       - | ||||
|         name: Inspect image | ||||
|         run: | | ||||
|           docker buildx imagetools inspect ${{ fromJSON(steps.docker-meta.outputs.json).tags[0] }} | ||||
|       - | ||||
|         name: Export frontend artifact from docker | ||||
|         run: | | ||||
|           docker create --name frontend-extract ${{ fromJSON(steps.docker-meta.outputs.json).tags[0] }} | ||||
|           docker cp frontend-extract:/usr/src/paperless/src/documents/static/frontend src/documents/static/frontend/ | ||||
|       - | ||||
|         name: Upload frontend artifact | ||||
|         uses: actions/upload-artifact@v3 | ||||
|         with: | ||||
|           name: frontend-compiled | ||||
|           path: src/documents/static/frontend/ | ||||
|  | ||||
|   build-release: | ||||
|     needs: | ||||
| @@ -382,7 +340,7 @@ jobs: | ||||
|     runs-on: ubuntu-20.04 | ||||
|     needs: | ||||
|       - build-release | ||||
|     if: github.ref_type == 'tag' && (startsWith(github.ref_name, 'ngx-') || startsWith(github.ref_name, 'beta-')) | ||||
|     if: github.ref_type == 'tag' && (startsWith(github.ref_name, 'v') || contains(github.ref_name, '-beta.rc')) | ||||
|     steps: | ||||
|       - | ||||
|         name: Download release artifact | ||||
| @@ -394,12 +352,11 @@ jobs: | ||||
|         name: Get version | ||||
|         id: get_version | ||||
|         run: | | ||||
|           if [[ $GITHUB_REF == refs/tags/ngx-* ]]; then | ||||
|             echo ::set-output name=version::${GITHUB_REF#refs/tags/ngx-} | ||||
|             echo ::set-output name=prerelease::false | ||||
|           elif [[ $GITHUB_REF == refs/tags/beta-* ]]; then | ||||
|             echo ::set-output name=version::${GITHUB_REF#refs/tags/beta-} | ||||
|           echo ::set-output name=version::${{ github.ref_name }} | ||||
|           if [[ ${{ contains(github.ref_name, '-beta.rc') }} == 'true' ]]; then | ||||
|             echo ::set-output name=prerelease::true | ||||
|           else | ||||
|             echo ::set-output name=prerelease::false | ||||
|           fi | ||||
|       - | ||||
|         name: Create Release and Changelog | ||||
| @@ -407,7 +364,7 @@ jobs: | ||||
|         uses: release-drafter/release-drafter@v5 | ||||
|         with: | ||||
|           name: Paperless-ngx ${{ steps.get_version.outputs.version }} | ||||
|           tag: ngx-${{ steps.get_version.outputs.version }} | ||||
|           tag: ${{ steps.get_version.outputs.version }} | ||||
|           version: ${{ steps.get_version.outputs.version }} | ||||
|           prerelease: ${{ steps.get_version.outputs.prerelease }} | ||||
|           publish: true # ensures release is not marked as draft | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/reusable-ci-backend.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/reusable-ci-backend.yml
									
									
									
									
										vendored
									
									
								
							| @@ -87,7 +87,7 @@ jobs: | ||||
|       - | ||||
|         name: Get changed files | ||||
|         id: changed-files-specific | ||||
|         uses: tj-actions/changed-files@v18.7 | ||||
|         uses: tj-actions/changed-files@v19 | ||||
|         with: | ||||
|           files: | | ||||
|             src/** | ||||
|   | ||||
							
								
								
									
										40
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -1,19 +1,32 @@ | ||||
| # Default to pulling from the main repo registry when manually building | ||||
| ARG REPO="paperless-ngx/paperless-ngx" | ||||
| # Pull the installer images from the library | ||||
| # These are all built previously | ||||
| # They provide either a .deb or .whl | ||||
|  | ||||
| # These are all built previously in the pipeline | ||||
| # They provide either a .deb, .whl or whatever npm outputs | ||||
| ARG JBIG2ENC_VERSION | ||||
| ARG QPDF_VERSION | ||||
| ARG PIKEPDF_VERSION | ||||
| ARG PSYCOPG2_VERSION | ||||
| ARG FRONTEND_VERSION | ||||
|  | ||||
| FROM ghcr.io/${REPO}/builder/jbig2enc:${JBIG2ENC_VERSION} as jbig2enc-builder | ||||
| FROM ghcr.io/${REPO}/builder/qpdf:${QPDF_VERSION} as qpdf-builder | ||||
| FROM ghcr.io/${REPO}/builder/pikepdf:${PIKEPDF_VERSION} as pikepdf-builder | ||||
| FROM ghcr.io/${REPO}/builder/psycopg2:${PSYCOPG2_VERSION} as psycopg2-builder | ||||
| FROM ghcr.io/${REPO}/builder/frontend:${FRONTEND_VERSION} as compile-frontend | ||||
| FROM ghcr.io/paperless-ngx/paperless-ngx/builder/jbig2enc:${JBIG2ENC_VERSION} as jbig2enc-builder | ||||
| FROM ghcr.io/paperless-ngx/paperless-ngx/builder/qpdf:${QPDF_VERSION} as qpdf-builder | ||||
| FROM ghcr.io/paperless-ngx/paperless-ngx/builder/pikepdf:${PIKEPDF_VERSION} as pikepdf-builder | ||||
| FROM ghcr.io/paperless-ngx/paperless-ngx/builder/psycopg2:${PSYCOPG2_VERSION} as psycopg2-builder | ||||
|  | ||||
| FROM --platform=$BUILDPLATFORM node:16-bullseye-slim AS compile-frontend | ||||
|  | ||||
| # This stage compiles the frontend | ||||
| # This stage runs once for the native platform, as the outputs are not | ||||
| # dependent on target arch | ||||
| # Inputs: None | ||||
|  | ||||
| COPY ./src-ui /src/src-ui | ||||
|  | ||||
| WORKDIR /src/src-ui | ||||
| RUN set -eux \ | ||||
|   && npm update npm -g \ | ||||
|   && npm ci --no-optional | ||||
| RUN set -eux \ | ||||
|   && ./node_modules/.bin/ng build --configuration production | ||||
|  | ||||
| FROM python:3.9-slim-bullseye as main-app | ||||
|  | ||||
| @@ -156,8 +169,11 @@ COPY gunicorn.conf.py . | ||||
|  | ||||
| WORKDIR /usr/src/paperless/src/ | ||||
|  | ||||
| # copy app | ||||
| COPY --from=compile-frontend /src/src/ ./ | ||||
| # copy backend | ||||
| COPY ./src ./ | ||||
|  | ||||
| # copy frontend | ||||
| COPY --from=compile-frontend /src/src/documents/static/frontend/ ./documents/static/frontend/ | ||||
|  | ||||
| # add users, setup scripts | ||||
| RUN set -eux \ | ||||
|   | ||||
							
								
								
									
										3
									
								
								Pipfile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Pipfile
									
									
									
									
									
								
							| @@ -19,7 +19,7 @@ djangorestframework = "~=3.13" | ||||
| filelock = "*" | ||||
| fuzzywuzzy = {extras = ["speedup"], version = "*"} | ||||
| gunicorn = "*" | ||||
| imap-tools = "~=0.53.0" | ||||
| imap-tools = "~=0.54.0" | ||||
| langdetect = "*" | ||||
| pathvalidate = "*" | ||||
| pillow = "~=9.1" | ||||
| @@ -53,7 +53,6 @@ concurrent-log-handler = "*" | ||||
| zipp = {version = "*", markers = "python_version < '3.9'"} | ||||
| pyzbar = "*" | ||||
| pdf2image = "*" | ||||
| click = "==8.0.4" | ||||
| bleach = "*" | ||||
|  | ||||
| [dev-packages] | ||||
|   | ||||
							
								
								
									
										119
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										119
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							| @@ -44,11 +44,11 @@ | ||||
|         }, | ||||
|         "asgiref": { | ||||
|             "hashes": [ | ||||
|                 "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0", | ||||
|                 "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9" | ||||
|                 "sha256:45a429524fba18aba9d512498b19d220c4d628e75b40cf5c627524dbaebc5cc1", | ||||
|                 "sha256:fddeea3c53fa99d0cdb613c3941cc6e52d822491fc2753fba25768fb5bf4e865" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.7'", | ||||
|             "version": "==3.5.0" | ||||
|             "version": "==3.5.1" | ||||
|         }, | ||||
|         "async-timeout": { | ||||
|             "hashes": [ | ||||
| @@ -99,6 +99,7 @@ | ||||
|                 "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac", | ||||
|                 "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "markers": "python_version < '3.9'", | ||||
|             "version": "==0.2.1" | ||||
|         }, | ||||
| @@ -206,11 +207,11 @@ | ||||
|         }, | ||||
|         "click": { | ||||
|             "hashes": [ | ||||
|                 "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e", | ||||
|                 "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72" | ||||
|                 "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", | ||||
|                 "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.7'", | ||||
|             "version": "==8.1.2" | ||||
|             "version": "==8.1.3" | ||||
|         }, | ||||
|         "coloredlogs": { | ||||
|             "hashes": [ | ||||
| @@ -476,7 +477,7 @@ | ||||
|                 "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", | ||||
|                 "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.5'", | ||||
|             "markers": "python_version >= '3'", | ||||
|             "version": "==3.3" | ||||
|         }, | ||||
|         "imap-tools": { | ||||
| @@ -498,6 +499,7 @@ | ||||
|                 "sha256:b6062987dfc51f0fcb809187cffbd60f35df7acb4589091f154214af6d0d49d3", | ||||
|                 "sha256:e447dc01619b1e951286f3929be820029d48c75eb25d265c28b92a16548212b8" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "markers": "python_version < '3.9'", | ||||
|             "version": "==5.7.1" | ||||
|         }, | ||||
| @@ -713,36 +715,36 @@ | ||||
|         }, | ||||
|         "pikepdf": { | ||||
|             "hashes": [ | ||||
|                 "sha256:01be838a44430c4be84b748a33950fed09892472934a8041596c11189f365f7f", | ||||
|                 "sha256:0cc95ef470169dfa5acc9196299bdba236716234a0d8b2746e2a563bc6f1f456", | ||||
|                 "sha256:13e72d0aeeb3fc452569a3f7994acdd007de9aad804ced734d57cec269261b8b", | ||||
|                 "sha256:2873503522ef26a09a6020c29c2efd221fa2ddc31e83bd902be27d317144cf63", | ||||
|                 "sha256:2d5d6d3248b33ca5961d84bc3121a299cd27237fad56868d815e381c9a98d3d1", | ||||
|                 "sha256:2f62e6c7bcf5d631e6ea74cf861f3e816f587c6ccb4ecbf6ac862e088ba2e4ac", | ||||
|                 "sha256:51694d3d2f90510da6a8d7a4d07313ca868b373fffec6de270d9bbff1ce37180", | ||||
|                 "sha256:5c23cbd7ae71f08fb5b5d9660eb0bc61abf345ada01bea6e1b6884c4261e17d6", | ||||
|                 "sha256:6371bf02a436be2b7c63322b83a8e47523f2cd16438b2e93d546c7caf9ae308d", | ||||
|                 "sha256:657293b74af8c7cf03f9905218a7935b26a4f3006803016b40b3db78e04cb35c", | ||||
|                 "sha256:680d47377bb9fd6a36b6a81464ee269b4b29cbf29a84ae4f2ab8f6ea3665bf69", | ||||
|                 "sha256:710535c679ab0d7b8249f72247832773e7a9a121dfbe9cad7f6465bd9bb45fae", | ||||
|                 "sha256:7b4d7c09036d863915cb01007ca183d6fe64e2d57c0472453097bc9e029a58fb", | ||||
|                 "sha256:978b6388ae99a024bdcae5a322c68e90c187cb568d09d43e6586b3479267121d", | ||||
|                 "sha256:9917a03d500aab72715a9236136af7a5c8c7b26c034bf71ebdf028e177f0d25f", | ||||
|                 "sha256:996faa6b119488f96d7271672a22af86e56e5544ec6b8eae6cd7d4432c70ae2d", | ||||
|                 "sha256:9bac9e9d6b28dc0cc5a554051f183fbd070d0f9fe63c4e9aca939b8c44a5bb4d", | ||||
|                 "sha256:aac14061de06843759ea6f5777fd8d7b71af808ed9264f57483a3311a09788ab", | ||||
|                 "sha256:ad5361c3669fc0c8dbaf8fa0a590bddf59fad256bb2c527d5ce5cf991743a240", | ||||
|                 "sha256:bc40b30c37f8f7c5bef873eca1f04e91ce34b6b74507d8d0019238a17d281fdc", | ||||
|                 "sha256:bd9faae19787a5d05b9fcbe84d7cfe4d44e318068e06eca18906b9dba45425b6", | ||||
|                 "sha256:c64e7905ec438b7a6c12626f2859df87f471892fab75b65b1441d9e1b38b4dde", | ||||
|                 "sha256:d4db409b21a8ec0d3a79d2bbd894b997b13223c9ccf341cdc31b64360f1ee4c7", | ||||
|                 "sha256:e0b635d6d9faefb4d0d32722279b8eb4e4d5d7b596c426f3433343de65e0c772", | ||||
|                 "sha256:e62e9e8afe77fe2f06715faf10f38a4810d282d66f1e9e05208bb8d9723e6acf", | ||||
|                 "sha256:f85d309bcfeeb3e2d344346a5050bfc41e332f19d390f79c20e4fc7de4b10a17", | ||||
|                 "sha256:fe3fc2efe498aba6204b85c17c6a5d54ab7303354ecc5c3da624a6b6af0b3406" | ||||
|                 "sha256:101ec256a8d312c17decae52226cf32a3e7dc834583134300c2f4e60b70e6e91", | ||||
|                 "sha256:12b5b3cfc649e2542576a7e55c11e245278f14f727f116904893e54329102867", | ||||
|                 "sha256:1b8f68a75c0a6f6d4d102d0821365ae2aaa9ab635c6eb6c840569a56b1a266f4", | ||||
|                 "sha256:1bef3512be59fe0f481375b7eb415ca51ee7c80555031401f5f17ee3392e4add", | ||||
|                 "sha256:1d3141916dc9efc433fd22beba544f67a53a805800c3ff902baffa398ef4c85e", | ||||
|                 "sha256:3052df8514d26b676c50e65afc49a1d260c43a08c322c75cc2592c10a9a5b26d", | ||||
|                 "sha256:356d5554516a295fc10db3f25cfde4e92326f6d015da55d71b84f5ced2a07a5a", | ||||
|                 "sha256:55330c24b8e04ee09f1bc514c2b6107bb03a5eeb0b74929a61100cd6be22ae29", | ||||
|                 "sha256:553cf11933fdfe07fdd357ab40b9732db102e921b27c1065239308d42b7b858f", | ||||
|                 "sha256:5626312990a894c5db3a269455f7eb98df5f59188dde1797c0e352d60fdf89af", | ||||
|                 "sha256:59c24a65c94693ab4a7e92f4809f847b57461120256c083054e61c99c4952e84", | ||||
|                 "sha256:607deb1181a7cf5369cf70edfc41574d46c0a17c0cac1f6234272bd4cb3487e4", | ||||
|                 "sha256:60bdd49e6251f8c99989e6769d4ad29b209c1eaf88090f49d4b30fba98442e40", | ||||
|                 "sha256:73a7cc3c42609e00393b9d4e1b9ee132f528060254a174bf18ef31a154be0386", | ||||
|                 "sha256:75f1e2917b4d2d6573fe3d1c3b2ec70829b64515b2f723f5c3bebcdd65761e6c", | ||||
|                 "sha256:92ca9191680eccc21697e9e9c218e600ab31e7c24f6125749738c10ae2dc7c07", | ||||
|                 "sha256:9bcaf96e2f571f0fc7e3178cdf1bcca7c13e5c68128e8246031226d47ecf23f1", | ||||
|                 "sha256:a8f3e2229e2683497fe4ccc4af06050c125160a11bb3562b6c4ddaee4d0cc5c5", | ||||
|                 "sha256:c277066938ca0ddb2bfe75874ef8dd3aa259936fe15c4cf7d4282f89ba82ab3a", | ||||
|                 "sha256:c532542a99757d9f41df0cf1fc8f64a044d0eb822822cc069c80be35731df275", | ||||
|                 "sha256:dfa89bd86e01413531c1d7d201fb01f0e62b52ea926a8e8ca6f99f86ed761e95", | ||||
|                 "sha256:e064010b733b0a2ec4ec97982cd2887f9025292f2d228c6d5e6eca9d84851e53", | ||||
|                 "sha256:ea927afe7cb04cc7ade30b961f528ef53e8d9cf467dcc4639cf944fef872a1a1", | ||||
|                 "sha256:f40703b6267aa43d7f72468fa0a3b505ffff74ece2a4c69cfd3c90e023c41381", | ||||
|                 "sha256:f45cc4544bbd4c308a525a6bb8e2e29b3f849803ee557c6e35c684447f0a92e5", | ||||
|                 "sha256:f8ccda5ee992c73f647bcd96c9aa30f5eb9e8a6c5bdd6e3dcb29ebbffbe01a69", | ||||
|                 "sha256:fe386d93345c9b5a9690f7a7bfb789a5ec5467c34402628e10bda8a4f5bac73e" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "version": "==5.1.1" | ||||
|             "version": "==5.1.2" | ||||
|         }, | ||||
|         "pillow": { | ||||
|             "hashes": [ | ||||
| @@ -1448,6 +1450,7 @@ | ||||
|                 "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad", | ||||
|                 "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "markers": "python_version < '3.9'", | ||||
|             "version": "==3.8.0" | ||||
|         }, | ||||
| @@ -1587,13 +1590,14 @@ | ||||
|         }, | ||||
|         "click": { | ||||
|             "hashes": [ | ||||
|                 "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e", | ||||
|                 "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72" | ||||
|                 "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", | ||||
|                 "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.7'", | ||||
|             "version": "==8.1.2" | ||||
|             "version": "==8.1.3" | ||||
|         }, | ||||
|         "coverage": { | ||||
|             "extras": [], | ||||
|             "hashes": [ | ||||
|                 "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9", | ||||
|                 "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d", | ||||
| @@ -1687,11 +1691,11 @@ | ||||
|         }, | ||||
|         "faker": { | ||||
|             "hashes": [ | ||||
|                 "sha256:0d5425894e098410b64aaade38a81074fa30163076251118523adf5bb44f8346", | ||||
|                 "sha256:7ab2f741ef1c006ed7274a6ed75695ca8b610f78861566b599ce83c4953bf687" | ||||
|                 "sha256:0301ace8365d98f3d0bf6e9a40200c8548e845d3812402ae1daf589effe3fb01", | ||||
|                 "sha256:b1903db92175d78051858128ada397c7dc76f376f6967975419da232b3ebd429" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.6'", | ||||
|             "version": "==13.6.0" | ||||
|             "version": "==13.7.0" | ||||
|         }, | ||||
|         "filelock": { | ||||
|             "hashes": [ | ||||
| @@ -1714,7 +1718,7 @@ | ||||
|                 "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", | ||||
|                 "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.5'", | ||||
|             "markers": "python_version >= '3'", | ||||
|             "version": "==3.3" | ||||
|         }, | ||||
|         "imagesize": { | ||||
| @@ -1725,6 +1729,14 @@ | ||||
|             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", | ||||
|             "version": "==1.3.0" | ||||
|         }, | ||||
|         "importlib-metadata": { | ||||
|             "hashes": [ | ||||
|                 "sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6", | ||||
|                 "sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539" | ||||
|             ], | ||||
|             "markers": "python_version < '3.10'", | ||||
|             "version": "==4.11.3" | ||||
|         }, | ||||
|         "iniconfig": { | ||||
|             "hashes": [ | ||||
|                 "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", | ||||
| @@ -1734,11 +1746,11 @@ | ||||
|         }, | ||||
|         "jinja2": { | ||||
|             "hashes": [ | ||||
|                 "sha256:539835f51a74a69f41b848a9645dbdc35b4f20a3b601e2d9a7e22947b15ff119", | ||||
|                 "sha256:640bed4bb501cbd17194b3cace1dc2126f5b619cf068a726b98192a0fde74ae9" | ||||
|                 "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", | ||||
|                 "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.7'", | ||||
|             "version": "==3.1.1" | ||||
|             "version": "==3.1.2" | ||||
|         }, | ||||
|         "markupsafe": { | ||||
|             "hashes": [ | ||||
| @@ -2095,6 +2107,14 @@ | ||||
|             "index": "pypi", | ||||
|             "version": "==3.25.0" | ||||
|         }, | ||||
|         "typing-extensions": { | ||||
|             "hashes": [ | ||||
|                 "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708", | ||||
|                 "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.7'", | ||||
|             "version": "==4.2.0" | ||||
|         }, | ||||
|         "urllib3": { | ||||
|             "hashes": [ | ||||
|                 "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", | ||||
| @@ -2110,6 +2130,15 @@ | ||||
|             ], | ||||
|             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", | ||||
|             "version": "==20.14.1" | ||||
|         }, | ||||
|         "zipp": { | ||||
|             "hashes": [ | ||||
|                 "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad", | ||||
|                 "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "markers": "python_version < '3.9'", | ||||
|             "version": "==3.8.0" | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -2,15 +2,13 @@ | ||||
|  | ||||
| # Helper script for building the Docker image locally. | ||||
| # Parses and provides the nessecary versions of other images to Docker | ||||
| # before passing in the rest of script args.  A future enhancement | ||||
| # would be to combine this with the CI script | ||||
| # before passing in the rest of script args. | ||||
|  | ||||
| # First Argument: The Dockerfile to build | ||||
| # Other Arguments: Additional arguments to docker build | ||||
|  | ||||
| # Example Usage: | ||||
| #	./build-docker-image.sh Dockerfile -t paperless-ngx:my-awesome-feature | ||||
| #	./build-docker-image.sh docker-builders/Dockerfile.qpdf -t paperless-ngx-build-qpdf:x.y.z | ||||
|  | ||||
| set -eux | ||||
|  | ||||
| @@ -28,23 +26,17 @@ psycopg2_version=$(jq ".default.psycopg2.version" Pipfile.lock | sed 's/=//g' | | ||||
| # Read this from the other config file | ||||
| qpdf_version=$(jq ".qpdf.version" .build-config.json | sed 's/"//g') | ||||
| jbig2enc_version=$(jq ".jbig2enc.version" .build-config.json | sed 's/"//g') | ||||
| # Get the branch name | ||||
| frontend_version=$(git rev-parse --abbrev-ref HEAD) | ||||
|  | ||||
| # Get Git tags for building | ||||
| # psycopg2 uses X_Y_Z git tags | ||||
| psycopg2_git_tag=${psycopg2_version//./_} | ||||
| # pikepdf uses vX.Y.Z | ||||
| pikepdf_git_tag="v${pikepdf_version}" | ||||
| # Get the branch name (used for caching) | ||||
| branch_name=$(git rev-parse --abbrev-ref HEAD) | ||||
|  | ||||
| # https://docs.docker.com/develop/develop-images/build_enhancements/ | ||||
| # Required to use cache-from | ||||
| export DOCKER_BUILDKIT=1 | ||||
|  | ||||
| docker build --file "$1" \ | ||||
| 	--cache-from ghcr.io/paperless-ngx/paperless-ngx/builder/cache/app:"${branch_name}" \ | ||||
| 	--cache-from ghcr.io/paperless-ngx/paperless-ngx/builder/cache/app:dev \ | ||||
| 	--build-arg JBIG2ENC_VERSION="${jbig2enc_version}" \ | ||||
| 	--build-arg QPDF_VERSION="${qpdf_version}" \ | ||||
| 	--build-arg PIKEPDF_VERSION="${pikepdf_version}" \ | ||||
| 	--build-arg PIKEPDF_GIT_TAG="${pikepdf_git_tag}" \ | ||||
| 	--build-arg PSYCOPG2_VERSION="${psycopg2_version}" \ | ||||
| 	--build-arg PSYCOPG2_GIT_TAG="${psycopg2_git_tag}" \ | ||||
| 	--build-arg FRONTEND_VERSION="${frontend_version}" "${@:2}" . | ||||
| 	--build-arg PSYCOPG2_VERSION="${psycopg2_version}" "${@:2}" . | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| # docker-compose file for running paperless from the docker container registry. | ||||
| # This file contains everything paperless needs to run. | ||||
| # Paperless supports amd64, arm and arm64 hardware. The apache/tika image | ||||
| # does not support arm or arm64, however. | ||||
| # Paperless supports amd64, arm and arm64 hardware. | ||||
| # | ||||
| # All compose files of paperless configure paperless in the following way: | ||||
| # | ||||
| @@ -78,14 +77,14 @@ services: | ||||
|       PAPERLESS_TIKA_ENDPOINT: http://tika:9998 | ||||
|  | ||||
|   gotenberg: | ||||
|     image: gotenberg/gotenberg:7 | ||||
|     image: gotenberg/gotenberg:7.4 | ||||
|     restart: unless-stopped | ||||
|     command: | ||||
|       - "gotenberg" | ||||
|       - "--chromium-disable-web-security" | ||||
|  | ||||
|   tika: | ||||
|     image: apache/tika | ||||
|     image: ghcr.io/paperless-ngx/tika:latest | ||||
|     restart: unless-stopped | ||||
|  | ||||
| volumes: | ||||
|   | ||||
| @@ -1,85 +0,0 @@ | ||||
| # docker-compose file for running paperless from the docker container registry. | ||||
| # This file contains everything paperless needs to run. | ||||
| # Paperless supports amd64, arm and arm64 hardware. | ||||
| # | ||||
| # All compose files of paperless configure paperless 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. | ||||
| # | ||||
| # iwishiwasaneagle/apache-tika-arm docker image is used to enable arm64 arch | ||||
| # which apache/tika does not currently support. | ||||
| # | ||||
| # In addition to that, this docker-compose file adds the following optional | ||||
| # configurations: | ||||
| # | ||||
| # - Apache Tika and Gotenberg servers are started with paperless and paperless | ||||
| #   is configured to use these services. These provide support for consuming | ||||
| #   Office documents (Word, Excel, Power Point and their LibreOffice counter- | ||||
| #   parts. | ||||
| # | ||||
| # To install and update paperless with this file, do the following: | ||||
| # | ||||
| # - Copy this file as 'docker-compose.yml' and the files 'docker-compose.env' | ||||
| #   and '.env' into a folder. | ||||
| # - Run 'docker-compose pull'. | ||||
| # - Run 'docker-compose run --rm webserver createsuperuser' to create a user. | ||||
| # - Run 'docker-compose up -d'. | ||||
| # | ||||
| # For more extensive installation and update instructions, refer to the | ||||
| # documentation. | ||||
|  | ||||
| version: "3.4" | ||||
| services: | ||||
|   broker: | ||||
|     image: redis:6.0 | ||||
|     restart: unless-stopped | ||||
|     volumes: | ||||
|       - redisdata:/data | ||||
|  | ||||
|   webserver: | ||||
|     image: ghcr.io/paperless-ngx/paperless-ngx:latest | ||||
|     restart: unless-stopped | ||||
|     depends_on: | ||||
|       - broker | ||||
|       - gotenberg | ||||
|       - tika | ||||
|     ports: | ||||
|       - 8000:8000 | ||||
|     healthcheck: | ||||
|       test: ["CMD", "curl", "-f", "http://localhost:8000"] | ||||
|       interval: 30s | ||||
|       timeout: 10s | ||||
|       retries: 5 | ||||
|     volumes: | ||||
|       - data:/usr/src/paperless/data | ||||
|       - media:/usr/src/paperless/media | ||||
|       - ./export:/usr/src/paperless/export | ||||
|       - ./consume:/usr/src/paperless/consume | ||||
|     env_file: docker-compose.env | ||||
|     environment: | ||||
|       PAPERLESS_REDIS: redis://broker:6379 | ||||
|       PAPERLESS_TIKA_ENABLED: 1 | ||||
|       PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000 | ||||
|       PAPERLESS_TIKA_ENDPOINT: http://tika:9998 | ||||
|  | ||||
|   gotenberg: | ||||
|     image: gotenberg/gotenberg:7 | ||||
|     restart: unless-stopped | ||||
|     command: | ||||
|       - "gotenberg" | ||||
|       - "--chromium-disable-web-security" | ||||
|  | ||||
|   tika: | ||||
|     image: iwishiwasaneagle/apache-tika-arm@sha256:a78c25ffe57ecb1a194b2859d42a61af46e9e845191512b8f1a4bf90578ffdfd | ||||
|     restart: unless-stopped | ||||
|  | ||||
| volumes: | ||||
|   data: | ||||
|   media: | ||||
|   redisdata: | ||||
| @@ -1,8 +1,6 @@ | ||||
| # docker-compose file for running paperless from the docker container registry. | ||||
| # This file contains everything paperless needs to run. | ||||
| # Paperless supports amd64, arm and arm64 hardware. The apache/tika image | ||||
| # does not support arm or arm64, however. | ||||
| # | ||||
| # Paperless supports amd64, arm and arm64 hardware. | ||||
| # All compose files of paperless configure paperless in the following way: | ||||
| # | ||||
| # - Paperless is (re)started on system boot, if it was running before shutdown. | ||||
| @@ -67,14 +65,14 @@ services: | ||||
|       PAPERLESS_TIKA_ENDPOINT: http://tika:9998 | ||||
|  | ||||
|   gotenberg: | ||||
|     image: gotenberg/gotenberg:7 | ||||
|     image: gotenberg/gotenberg:7.4 | ||||
|     restart: unless-stopped | ||||
|     command: | ||||
|       - "gotenberg" | ||||
|       - "--chromium-disable-web-security" | ||||
|  | ||||
|   tika: | ||||
|     image: apache/tika | ||||
|     image: ghcr.io/paperless-ngx/tika:latest | ||||
|     restart: unless-stopped | ||||
|  | ||||
| volumes: | ||||
|   | ||||
| @@ -117,6 +117,23 @@ Then you can start paperless-ngx with ``-d`` to have it run in the background. | ||||
|  | ||||
|                 image: ghcr.io/paperless-ngx/paperless-ngx:latest | ||||
|  | ||||
|     .. note:: | ||||
|         In version 1.7.1 and onwards, the Docker image can now pinned to a release series. | ||||
|         This is often combined with automatic updaters such as Watchtower to allow safer | ||||
|         unattended upgrading to new bugfix releases only.  It is still recommended to always | ||||
|         review release notes before upgrading.  To ping your install to a release series, edit | ||||
|         the ``docker-compose.yml`` find the line that says | ||||
|  | ||||
|             .. code:: | ||||
|  | ||||
|                 image: ghcr.io/paperless-ngx/paperless-ngx:latest | ||||
|  | ||||
|         and replace the version with the series you want to track, for example: | ||||
|  | ||||
|             .. code:: | ||||
|  | ||||
|                 image: ghcr.io/paperless-ngx/paperless-ngx:1.7 | ||||
|  | ||||
| Bare Metal Route | ||||
| ================ | ||||
|  | ||||
|   | ||||
| @@ -2,6 +2,8 @@ import sphinx_rtd_theme | ||||
|  | ||||
|  | ||||
| __version__ = None | ||||
| __full_version_str__ = None | ||||
| __major_minor_version_str__ = None | ||||
| exec(open("../src/paperless/version.py").read()) | ||||
|  | ||||
|  | ||||
| @@ -41,9 +43,9 @@ copyright = "2015-2022, Daniel Quinn, Jonas Winkler, and the paperless-ngx team" | ||||
| # | ||||
|  | ||||
| # The short X.Y version. | ||||
| version = ".".join([str(_) for _ in __version__[:2]]) | ||||
| version = __major_minor_version_str__ | ||||
| # The full version, including alpha/beta/rc tags. | ||||
| release = ".".join([str(_) for _ in __version__[:3]]) | ||||
| release = __full_version_str__ | ||||
|  | ||||
| # The language for content autogenerated by Sphinx. Refer to documentation | ||||
| # for a list of supported languages. | ||||
|   | ||||
| @@ -474,7 +474,7 @@ PAPERLESS_TIKA_GOTENBERG_ENDPOINT=<url> | ||||
|     Defaults to "http://localhost:3000". | ||||
|  | ||||
| If you run paperless on docker, you can add those services to the docker-compose | ||||
| file (see the provided ``docker-compose.tika.yml`` file for reference). The changes | ||||
| file (see the provided ``docker-compose.sqlite-tika.yml`` file for reference). The changes | ||||
| requires are as follows: | ||||
|  | ||||
| .. code:: yaml | ||||
| @@ -495,14 +495,14 @@ requires are as follows: | ||||
|         # ... | ||||
|  | ||||
|         gotenberg: | ||||
|             image: gotenberg/gotenberg:7 | ||||
|             image: gotenberg/gotenberg:7.4 | ||||
|             restart: unless-stopped | ||||
|             command: | ||||
|                 - "gotenberg" | ||||
|                 - "--chromium-disable-web-security" | ||||
|  | ||||
|         tika: | ||||
|             image: apache/tika | ||||
|             image: ghcr.io/paperless-ngx/tika:latest | ||||
|             restart: unless-stopped | ||||
|  | ||||
| Add the configuration variables to the environment of the webserver (alternatively | ||||
|   | ||||
| @@ -334,11 +334,17 @@ directory. | ||||
| Building the Docker image | ||||
| ========================= | ||||
|  | ||||
| The docker image is primarily built by the GitHub actions workflow, but it can be | ||||
| faster when developing to build and tag an image locally. | ||||
|  | ||||
| To provide the build arguments automatically, build the image using the helper | ||||
| script ``build-docker-image.sh``. | ||||
|  | ||||
| Building the docker image from source: | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         docker build . -t <your-tag> | ||||
|         ./build-docker-image.sh Dockerfile -t <your-tag> | ||||
|  | ||||
| Extending Paperless | ||||
| =================== | ||||
|   | ||||
| @@ -728,8 +728,6 @@ configuring some options in paperless can help improve performance immensely: | ||||
|     times. Thumbnails will be about 20% larger. | ||||
| *   If using docker, consider setting ``PAPERLESS_WEBSERVER_WORKERS`` to | ||||
|     1. This will save some memory. | ||||
| *   Use the arm compatible docker-compose if you're wanting to use Tika on something like | ||||
| 		a raspberry pi. The official apache/tika image does not support the arm architecture. | ||||
|  | ||||
| For details, refer to :ref:`configuration`. | ||||
|  | ||||
|   | ||||
| @@ -125,7 +125,7 @@ If using docker-compose, this is achieved by the following configuration change | ||||
| .. code:: yaml | ||||
|  | ||||
|     gotenberg: | ||||
|         image: gotenberg/gotenberg:7 | ||||
|         image: gotenberg/gotenberg:7.4 | ||||
|         restart: unless-stopped | ||||
|         command: | ||||
|             - "gotenberg" | ||||
|   | ||||
| @@ -5,12 +5,12 @@ | ||||
| #    pipenv lock --requirements | ||||
| # | ||||
|  | ||||
| -i https://pypi.python.org/simple/ | ||||
| --extra-index-url https://www.piwheels.org/simple/ | ||||
| -i https://pypi.python.org/simple | ||||
| --extra-index-url https://www.piwheels.org/simple | ||||
| aioredis==1.3.1 | ||||
| anyio==3.5.0; python_full_version >= '3.6.2' | ||||
| arrow==1.2.2; python_version >= '3.6' | ||||
| asgiref==3.5.0; python_version >= '3.7' | ||||
| asgiref==3.5.1; python_version >= '3.7' | ||||
| async-timeout==4.0.2; python_version >= '3.6' | ||||
| attrs==21.4.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' | ||||
| autobahn==22.3.2; python_version >= '3.7' | ||||
| @@ -23,7 +23,7 @@ channels-redis==3.4.0 | ||||
| channels==3.0.4 | ||||
| chardet==4.0.0; python_version >= '3.1' | ||||
| charset-normalizer==2.0.12; python_version >= '3' | ||||
| click==8.1.2; python_version >= '3.7' | ||||
| click==8.1.3; python_version >= '3.7' | ||||
| coloredlogs==15.0.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' | ||||
| concurrent-log-handler==0.9.20 | ||||
| constantly==15.1.0 | ||||
| @@ -45,7 +45,7 @@ hiredis==2.0.0; python_version >= '3.6' | ||||
| httptools==0.4.0 | ||||
| humanfriendly==10.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' | ||||
| hyperlink==21.0.0 | ||||
| idna==3.3; python_version >= '3.5' | ||||
| idna==3.3; python_version >= '3' | ||||
| imap-tools==0.54.0 | ||||
| img2pdf==0.4.4 | ||||
| importlib-resources==5.7.1; python_version < '3.9' | ||||
| @@ -62,7 +62,7 @@ packaging==21.3; python_version >= '3.6' | ||||
| pathvalidate==2.5.0 | ||||
| pdf2image==1.16.0 | ||||
| pdfminer.six==20220319 | ||||
| pikepdf==5.1.1 | ||||
| pikepdf==5.1.2 | ||||
| pillow==9.1.0 | ||||
| pluggy==1.0.0; python_version >= '3.6' | ||||
| portalocker==2.4.0; python_version >= '3' | ||||
|   | ||||
| @@ -2,5 +2,5 @@ | ||||
|  | ||||
| docker run -p 5432:5432 -e POSTGRES_PASSWORD=password -v paperless_pgdata:/var/lib/postgresql/data -d postgres:13 | ||||
| docker run -d -p 6379:6379 redis:latest | ||||
| docker run -p 3000:3000 -d gotenberg/gotenberg:7 gotenberg --chromium-disable-web-security | ||||
| docker run -p 9998:9998 -d apache/tika | ||||
| docker run -p 3000:3000 -d gotenberg/gotenberg:7.4 gotenberg --chromium-disable-web-security | ||||
| docker run -p 9998:9998 -d ghcr.io/paperless-ngx/tika:latest | ||||
|   | ||||
							
								
								
									
										9366
									
								
								src-ui/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										9366
									
								
								src-ui/package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -21,7 +21,7 @@ | ||||
|     "@angular/platform-browser": "~13.3.5", | ||||
|     "@angular/platform-browser-dynamic": "~13.3.5", | ||||
|     "@angular/router": "~13.3.5", | ||||
|     "@ng-bootstrap/ng-bootstrap": "^12.1.0", | ||||
|     "@ng-bootstrap/ng-bootstrap": "^12.1.1", | ||||
|     "@ng-select/ng-select": "^8.1.1", | ||||
|     "@ngneat/dirty-check-forms": "^3.0.2", | ||||
|     "@popperjs/core": "^2.11.4", | ||||
| @@ -45,14 +45,16 @@ | ||||
|     "@types/node": "^17.0.30", | ||||
|     "codelyzer": "^6.0.2", | ||||
|     "concurrently": "7.1.0", | ||||
|     "jest": "27.5.1", | ||||
|     "jest": "28.0.3", | ||||
|     "jest-environment-jsdom": "^28.0.2", | ||||
|     "jest-preset-angular": "^12.0.0-next.1", | ||||
|     "ts-node": "~10.7.0", | ||||
|     "tslint": "~6.1.3", | ||||
|     "typescript": "~4.6.3", | ||||
|     "wait-on": "~6.0.1" | ||||
|   }, | ||||
|   "optionalDependencies": { | ||||
|     "cypress": "~9.6.0", | ||||
|     "@cypress/schematic": "^1.6.0" | ||||
|     "@cypress/schematic": "^1.6.0", | ||||
|     "cypress": "~9.6.0" | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import 'jest-preset-angular/setup-jest' | ||||
| import { jest } from '@jest/globals' | ||||
|  | ||||
| /* global mocks for jsdom */ | ||||
| const mock = () => { | ||||
| @@ -26,5 +26,6 @@ Object.defineProperty(document.body.style, 'transform', { | ||||
|   }, | ||||
| }) | ||||
|  | ||||
| /* output shorter and more meaningful Zone error stack traces */ | ||||
| // Error.stackTraceLimit = 2 | ||||
| HTMLCanvasElement.prototype.getContext = < | ||||
|   typeof HTMLCanvasElement.prototype.getContext | ||||
| >jest.fn() | ||||
|   | ||||
| @@ -162,8 +162,8 @@ | ||||
|             <div [ngbNavOutlet]="nav" class="mt-2"></div> | ||||
|  | ||||
|             <button type="button" class="btn btn-outline-secondary" (click)="discard()" i18n [disabled]="networkActive || !(isDirty$ | async)">Discard</button>  | ||||
|             <button type="button" class="btn btn-outline-primary" (click)="saveEditNext()" *ngIf="hasNext()" i18n [disabled]="networkActive || !(isDirty$ | async)">Save & next</button>  | ||||
|             <button type="submit" class="btn btn-primary" i18n [disabled]="networkActive || !(isDirty$ | async)">Save</button>  | ||||
|             <button type="button" class="btn btn-outline-primary" (click)="saveEditNext()" *ngIf="hasNext()" i18n [disabled]="networkActive || !(isDirty$ | async) || error">Save & next</button>  | ||||
|             <button type="submit" class="btn btn-primary" i18n [disabled]="networkActive || !(isDirty$ | async) || error">Save</button>  | ||||
|         </form> | ||||
|     </div> | ||||
|  | ||||
|   | ||||
| @@ -34,6 +34,7 @@ import { | ||||
| } from 'rxjs/operators' | ||||
| import { PaperlessDocumentSuggestions } from 'src/app/data/paperless-document-suggestions' | ||||
| import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type' | ||||
| import { normalizeDateStr } from 'src/app/utils/date' | ||||
|  | ||||
| @Component({ | ||||
|   selector: 'app-document-detail', | ||||
| @@ -145,8 +146,10 @@ export class DocumentDetailComponent | ||||
|     this.documentForm.valueChanges | ||||
|       .pipe(takeUntil(this.unsubscribeNotifier)) | ||||
|       .subscribe((changes) => { | ||||
|         this.error = null | ||||
|         if (this.ogDate) { | ||||
|           let newDate = new Date(changes['created']) | ||||
|           try { | ||||
|             let newDate = new Date(normalizeDateStr(changes['created'])) | ||||
|             newDate.setHours( | ||||
|               this.ogDate.getHours(), | ||||
|               this.ogDate.getMinutes(), | ||||
| @@ -154,9 +157,13 @@ export class DocumentDetailComponent | ||||
|               this.ogDate.getMilliseconds() | ||||
|             ) | ||||
|             this.documentForm.patchValue( | ||||
|             { created: this.formatDate(newDate) }, | ||||
|               { created: newDate.toISOString() }, | ||||
|               { emitEvent: false } | ||||
|             ) | ||||
|           } catch (e) { | ||||
|             // catch this before we try to save and simulate an api error | ||||
|             this.error = { created: e.message } | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         Object.assign(this.document, this.documentForm.value) | ||||
| @@ -199,22 +206,22 @@ export class DocumentDetailComponent | ||||
|             this.updateComponent(doc) | ||||
|           } | ||||
|  | ||||
|           this.ogDate = new Date(doc.created) | ||||
|           this.ogDate = new Date(normalizeDateStr(doc.created.toString())) | ||||
|  | ||||
|           // Initialize dirtyCheck | ||||
|           this.store = new BehaviorSubject({ | ||||
|             title: doc.title, | ||||
|             content: doc.content, | ||||
|             created: this.formatDate(this.ogDate), | ||||
|             created: this.ogDate.toISOString(), | ||||
|             correspondent: doc.correspondent, | ||||
|             document_type: doc.document_type, | ||||
|             archive_serial_number: doc.archive_serial_number, | ||||
|             tags: [...doc.tags], | ||||
|           }) | ||||
|  | ||||
|           // ensure we're always starting with 24-char ISO8601 string | ||||
|           // start with ISO8601 string | ||||
|           this.documentForm.patchValue( | ||||
|             { created: this.formatDate(this.ogDate) }, | ||||
|             { created: this.ogDate.toISOString() }, | ||||
|             { emitEvent: false } | ||||
|           ) | ||||
|  | ||||
| @@ -319,16 +326,17 @@ export class DocumentDetailComponent | ||||
|     this.documentsService | ||||
|       .get(this.documentId) | ||||
|       .pipe(first()) | ||||
|       .subscribe( | ||||
|         (doc) => { | ||||
|       .subscribe({ | ||||
|         next: (doc) => { | ||||
|           Object.assign(this.document, doc) | ||||
|           this.title = doc.title | ||||
|           this.documentForm.patchValue(doc) | ||||
|           this.openDocumentService.setDirty(doc.id, false) | ||||
|         }, | ||||
|         (error) => { | ||||
|         error: () => { | ||||
|           this.router.navigate(['404']) | ||||
|         } | ||||
|       ) | ||||
|         }, | ||||
|       }) | ||||
|   } | ||||
|  | ||||
|   save() { | ||||
| @@ -486,8 +494,4 @@ export class DocumentDetailComponent | ||||
|       this.password = (event.target as HTMLInputElement).value | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   formatDate(date: Date): string { | ||||
|     return date.toISOString().split('.')[0] + 'Z' | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| import { DatePipe } from '@angular/common' | ||||
| import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core' | ||||
| import { SettingsService, SETTINGS_KEYS } from '../services/settings.service' | ||||
| import { normalizeDateStr } from '../utils/date' | ||||
|  | ||||
| const FORMAT_TO_ISO_FORMAT = { | ||||
|   longDate: 'y-MM-dd', | ||||
| @@ -33,6 +34,7 @@ export class CustomDatePipe implements PipeTransform { | ||||
|       this.settings.get(SETTINGS_KEYS.DATE_LOCALE) || | ||||
|       this.defaultLocale | ||||
|     let f = format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT) | ||||
|     if (typeof value == 'string') value = normalizeDateStr(value) | ||||
|     if (l == 'iso-8601') { | ||||
|       return this.datePipe.transform(value, FORMAT_TO_ISO_FORMAT[f], timezone) | ||||
|     } else { | ||||
|   | ||||
							
								
								
									
										5
									
								
								src-ui/src/app/utils/date.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src-ui/src/app/utils/date.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| // see https://github.com/dateutil/dateutil/issues/878 , JS Date does not | ||||
| // seem to accept these strings as valid dates so we must normalize offset | ||||
| export function normalizeDateStr(dateStr: string): string { | ||||
|   return dateStr.replace(/-(\d\d):\d\d:\d\d/gm, `-$1:00`) | ||||
| } | ||||
| @@ -51,11 +51,22 @@ export class LocalizedDateParserFormatter extends NgbDateParserFormatter { | ||||
|     const dateSeparator = inputFormat.replace(/[dmy]/gi, '').charAt(0) | ||||
|  | ||||
|     if (this.separatorRegExp.test(value)) { | ||||
|       // split on separator, pad & re-join without separator | ||||
|       value = value | ||||
|         .split(this.separatorRegExp) | ||||
|         .map((segment) => segment.padStart(2, '0')) | ||||
|         .join('') | ||||
|       let segments = value.split(this.separatorRegExp) | ||||
|  | ||||
|       // always accept strict yyyy*mm*dd format even if thats not the input format since we can be certain its not yyyy*dd*mm | ||||
|       if ( | ||||
|         value.length == 10 && | ||||
|         segments.length == 3 && | ||||
|         segments[0].length == 4 | ||||
|       ) { | ||||
|         return inputFormat | ||||
|           .replace('yyyy', segments[0]) | ||||
|           .replace('mm', segments[1]) | ||||
|           .replace('dd', segments[2]) | ||||
|       } else { | ||||
|         // otherwise pad & re-join without separator | ||||
|         value = segments.map((segment) => segment.padStart(2, '0')).join('') | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if (value.length == 4 && inputFormat.substring(0, 4) != 'yyyy') { | ||||
|   | ||||
| @@ -676,28 +676,33 @@ class RemoteVersionView(GenericAPIView): | ||||
|     def get(self, request, format=None): | ||||
|         remote_version = "0.0.0" | ||||
|         is_greater_than_current = False | ||||
|         current_version = packaging_version.parse(version.__full_version_str__) | ||||
|         # TODO: this can likely be removed when frontend settings are saved to DB | ||||
|         feature_is_set = settings.ENABLE_UPDATE_CHECK != "default" | ||||
|         if feature_is_set and settings.ENABLE_UPDATE_CHECK: | ||||
|             try: | ||||
|                 with urllib.request.urlopen( | ||||
|                     "https://api.github.com/repos/" | ||||
|                     + "paperless-ngx/paperless-ngx/releases/latest", | ||||
|                 ) as response: | ||||
|                 req = urllib.request.Request( | ||||
|                     "https://api.github.com/repos/paperless-ngx/" | ||||
|                     "paperless-ngx/releases/latest", | ||||
|                 ) | ||||
|                 # Ensure a JSON response | ||||
|                 req.add_header("Accept", "application/json") | ||||
|  | ||||
|                 with urllib.request.urlopen(req) as response: | ||||
|                     remote = response.read().decode("utf-8") | ||||
|                 try: | ||||
|                     remote_json = json.loads(remote) | ||||
|                     remote_version = remote_json["tag_name"].replace("ngx-", "") | ||||
|                     remote_version = remote_json["tag_name"].removeprefix("ngx-") | ||||
|                 except ValueError: | ||||
|                     logger.debug("An error occured parsing remote version json") | ||||
|                     logger.debug("An error occurred parsing remote version json") | ||||
|             except urllib.error.URLError: | ||||
|                 logger.debug("An error occured checking for available updates") | ||||
|                 logger.debug("An error occurred checking for available updates") | ||||
|  | ||||
|             current_version = ".".join([str(_) for _ in version.__version__[:3]]) | ||||
|             is_greater_than_current = packaging_version.parse( | ||||
|             is_greater_than_current = ( | ||||
|                 packaging_version.parse( | ||||
|                     remote_version, | ||||
|             ) > packaging_version.parse( | ||||
|                 current_version, | ||||
|                 ) | ||||
|                 > current_version | ||||
|             ) | ||||
|  | ||||
|         return Response( | ||||
|   | ||||
| @@ -11,6 +11,6 @@ class ApiVersionMiddleware: | ||||
|         if request.user.is_authenticated: | ||||
|             versions = settings.REST_FRAMEWORK["ALLOWED_VERSIONS"] | ||||
|             response["X-Api-Version"] = versions[len(versions) - 1] | ||||
|             response["X-Version"] = ".".join([str(_) for _ in version.__version__]) | ||||
|             response["X-Version"] = version.__full_version_str__ | ||||
|  | ||||
|         return response | ||||
|   | ||||
| @@ -1 +1,8 @@ | ||||
| __version__ = (1, 7, 0) | ||||
| from typing import Final | ||||
| from typing import Tuple | ||||
|  | ||||
| __version__: Final[Tuple[int, int, int]] = (1, 7, 0) | ||||
| # Version string like X.Y.Z | ||||
| __full_version_str__: Final[str] = ".".join(map(str, __version__)) | ||||
| # Version string like X.Y | ||||
| __major_minor_version_str__: Final[str] = ".".join(map(str, __version__[:-1])) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 phail
					phail