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: '' |     replace: '' | ||||||
| change-template: '- $TITLE @$AUTHOR (#$NUMBER)' | change-template: '- $TITLE @$AUTHOR (#$NUMBER)' | ||||||
| change-title-escapes: '\<*_&#@' | change-title-escapes: '\<*_&#@' | ||||||
| tag-prefix: "ngx-" |  | ||||||
| template: | | template: | | ||||||
|   # Changelog |   # 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 |     git_tag = None | ||||||
|     extra_config = {} |     extra_config = {} | ||||||
|  |  | ||||||
|     if args.package == "frontend": |     if args.package in pipfile_data["default"]: | ||||||
|         # Version is just the branch or tag name |  | ||||||
|         version = branch_name |  | ||||||
|     elif args.package in pipfile_data["default"]: |  | ||||||
|         # Read the version from Pipfile.lock |         # Read the version from Pipfile.lock | ||||||
|         pkg_data = pipfile_data["default"][args.package] |         pkg_data = pipfile_data["default"][args.package] | ||||||
|         pkg_version = pkg_data["version"].split("==")[-1] |         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: | on: | ||||||
|   push: |   push: | ||||||
|     tags: |     tags: | ||||||
|       - ngx-* |       # https://semver.org/#spec-item-2 | ||||||
|       - beta-* |       - '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: |     branches-ignore: | ||||||
|       - 'translations**' |       - 'translations**' | ||||||
|   pull_request: |   pull_request: | ||||||
| @@ -53,7 +55,7 @@ jobs: | |||||||
|  |  | ||||||
|   prepare-docker-build: |   prepare-docker-build: | ||||||
|     name: Prepare Docker Pipeline Data |     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 |     runs-on: ubuntu-20.04 | ||||||
|     needs: |     needs: | ||||||
|       - documentation |       - documentation | ||||||
| @@ -104,15 +106,6 @@ jobs: | |||||||
|           echo ${build_json} |           echo ${build_json} | ||||||
|  |  | ||||||
|           echo ::set-output name=jbig2enc-json::${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: |     outputs: | ||||||
|  |  | ||||||
| @@ -124,8 +117,6 @@ jobs: | |||||||
|  |  | ||||||
|       jbig2enc-json: ${{ steps.jbig2enc-setup.outputs.jbig2enc-json}} |       jbig2enc-json: ${{ steps.jbig2enc-setup.outputs.jbig2enc-json}} | ||||||
|  |  | ||||||
|       frontend-json: ${{ steps.frontend-setup.outputs.frontend-json}} |  | ||||||
|  |  | ||||||
|   build-qpdf-debs: |   build-qpdf-debs: | ||||||
|     name: qpdf |     name: qpdf | ||||||
|     needs: |     needs: | ||||||
| @@ -175,57 +166,6 @@ jobs: | |||||||
|         PIKEPDF_GIT_TAG=${{ fromJSON(needs.prepare-docker-build.outputs.pikepdf-json).git_tag }} |         PIKEPDF_GIT_TAG=${{ fromJSON(needs.prepare-docker-build.outputs.pikepdf-json).git_tag }} | ||||||
|         PIKEPDF_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.pikepdf-json).version }} |         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 and push image to docker hub. | ||||||
|   build-docker-image: |   build-docker-image: | ||||||
|     runs-on: ubuntu-20.04 |     runs-on: ubuntu-20.04 | ||||||
| @@ -238,7 +178,6 @@ jobs: | |||||||
|       - build-jbig2enc |       - build-jbig2enc | ||||||
|       - build-qpdf-debs |       - build-qpdf-debs | ||||||
|       - build-pikepdf-wheel |       - build-pikepdf-wheel | ||||||
|       - build-frontend |  | ||||||
|     steps: |     steps: | ||||||
|       - |       - | ||||||
|         name: Check pushing to Docker Hub |         name: Check pushing to Docker Hub | ||||||
| @@ -260,8 +199,12 @@ jobs: | |||||||
|             ghcr.io/${{ github.repository }} |             ghcr.io/${{ github.repository }} | ||||||
|             name=paperlessngx/paperless-ngx,enable=${{ steps.docker-hub.outputs.enable }} |             name=paperlessngx/paperless-ngx,enable=${{ steps.docker-hub.outputs.enable }} | ||||||
|           tags: | |           tags: | | ||||||
|  |             # Tag branches with branch name | ||||||
|             type=ref,event=branch |             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 |         name: Checkout | ||||||
|         uses: actions/checkout@v3 |         uses: actions/checkout@v3 | ||||||
| @@ -297,18 +240,33 @@ jobs: | |||||||
|           tags: ${{ steps.docker-meta.outputs.tags }} |           tags: ${{ steps.docker-meta.outputs.tags }} | ||||||
|           labels: ${{ steps.docker-meta.outputs.labels }} |           labels: ${{ steps.docker-meta.outputs.labels }} | ||||||
|           build-args: | |           build-args: | | ||||||
|             REPO=${{ github.repository }} |  | ||||||
|             JBIG2ENC_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.jbig2enc-json).version }} |             JBIG2ENC_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.jbig2enc-json).version }} | ||||||
|             QPDF_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.qpdf-json).version }} |             QPDF_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.qpdf-json).version }} | ||||||
|             PIKEPDF_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.pikepdf-json).version }} |             PIKEPDF_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.pikepdf-json).version }} | ||||||
|             PSYCOPG2_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.psycopg2-json).version }} |             PSYCOPG2_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.psycopg2-json).version }} | ||||||
|             FRONTEND_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.frontend-json).version }} |           # Get cache layers from this branch, then dev, then main | ||||||
|           cache-from: type=gha |           # This allows new branches to get at least some cache benefits, generally from dev | ||||||
|           cache-to: type=gha,mode=max |           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 |         name: Inspect image | ||||||
|         run: | |         run: | | ||||||
|           docker buildx imagetools inspect ${{ fromJSON(steps.docker-meta.outputs.json).tags[0] }} |           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: |   build-release: | ||||||
|     needs: |     needs: | ||||||
| @@ -382,7 +340,7 @@ jobs: | |||||||
|     runs-on: ubuntu-20.04 |     runs-on: ubuntu-20.04 | ||||||
|     needs: |     needs: | ||||||
|       - build-release |       - 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: |     steps: | ||||||
|       - |       - | ||||||
|         name: Download release artifact |         name: Download release artifact | ||||||
| @@ -394,12 +352,11 @@ jobs: | |||||||
|         name: Get version |         name: Get version | ||||||
|         id: get_version |         id: get_version | ||||||
|         run: | |         run: | | ||||||
|           if [[ $GITHUB_REF == refs/tags/ngx-* ]]; then |           echo ::set-output name=version::${{ github.ref_name }} | ||||||
|             echo ::set-output name=version::${GITHUB_REF#refs/tags/ngx-} |           if [[ ${{ contains(github.ref_name, '-beta.rc') }} == 'true' ]]; then | ||||||
|             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=prerelease::true |             echo ::set-output name=prerelease::true | ||||||
|  |           else | ||||||
|  |             echo ::set-output name=prerelease::false | ||||||
|           fi |           fi | ||||||
|       - |       - | ||||||
|         name: Create Release and Changelog |         name: Create Release and Changelog | ||||||
| @@ -407,7 +364,7 @@ jobs: | |||||||
|         uses: release-drafter/release-drafter@v5 |         uses: release-drafter/release-drafter@v5 | ||||||
|         with: |         with: | ||||||
|           name: Paperless-ngx ${{ steps.get_version.outputs.version }} |           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 }} |           version: ${{ steps.get_version.outputs.version }} | ||||||
|           prerelease: ${{ steps.get_version.outputs.prerelease }} |           prerelease: ${{ steps.get_version.outputs.prerelease }} | ||||||
|           publish: true # ensures release is not marked as draft |           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 |         name: Get changed files | ||||||
|         id: changed-files-specific |         id: changed-files-specific | ||||||
|         uses: tj-actions/changed-files@v18.7 |         uses: tj-actions/changed-files@v19 | ||||||
|         with: |         with: | ||||||
|           files: | |           files: | | ||||||
|             src/** |             src/** | ||||||
|   | |||||||
							
								
								
									
										40
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -1,19 +1,32 @@ | |||||||
| # Default to pulling from the main repo registry when manually building | # Pull the installer images from the library | ||||||
| ARG REPO="paperless-ngx/paperless-ngx" | # 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 JBIG2ENC_VERSION | ||||||
| ARG QPDF_VERSION | ARG QPDF_VERSION | ||||||
| ARG PIKEPDF_VERSION | ARG PIKEPDF_VERSION | ||||||
| ARG PSYCOPG2_VERSION | ARG PSYCOPG2_VERSION | ||||||
| ARG FRONTEND_VERSION |  | ||||||
|  |  | ||||||
| FROM ghcr.io/${REPO}/builder/jbig2enc:${JBIG2ENC_VERSION} as jbig2enc-builder | FROM ghcr.io/paperless-ngx/paperless-ngx/builder/jbig2enc:${JBIG2ENC_VERSION} as jbig2enc-builder | ||||||
| FROM ghcr.io/${REPO}/builder/qpdf:${QPDF_VERSION} as qpdf-builder | FROM ghcr.io/paperless-ngx/paperless-ngx/builder/qpdf:${QPDF_VERSION} as qpdf-builder | ||||||
| FROM ghcr.io/${REPO}/builder/pikepdf:${PIKEPDF_VERSION} as pikepdf-builder | FROM ghcr.io/paperless-ngx/paperless-ngx/builder/pikepdf:${PIKEPDF_VERSION} as pikepdf-builder | ||||||
| FROM ghcr.io/${REPO}/builder/psycopg2:${PSYCOPG2_VERSION} as psycopg2-builder | FROM ghcr.io/paperless-ngx/paperless-ngx/builder/psycopg2:${PSYCOPG2_VERSION} as psycopg2-builder | ||||||
| FROM ghcr.io/${REPO}/builder/frontend:${FRONTEND_VERSION} as compile-frontend |  | ||||||
|  | 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 | FROM python:3.9-slim-bullseye as main-app | ||||||
|  |  | ||||||
| @@ -156,8 +169,11 @@ COPY gunicorn.conf.py . | |||||||
|  |  | ||||||
| WORKDIR /usr/src/paperless/src/ | WORKDIR /usr/src/paperless/src/ | ||||||
|  |  | ||||||
| # copy app | # copy backend | ||||||
| COPY --from=compile-frontend /src/src/ ./ | COPY ./src ./ | ||||||
|  |  | ||||||
|  | # copy frontend | ||||||
|  | COPY --from=compile-frontend /src/src/documents/static/frontend/ ./documents/static/frontend/ | ||||||
|  |  | ||||||
| # add users, setup scripts | # add users, setup scripts | ||||||
| RUN set -eux \ | RUN set -eux \ | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								Pipfile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Pipfile
									
									
									
									
									
								
							| @@ -19,7 +19,7 @@ djangorestframework = "~=3.13" | |||||||
| filelock = "*" | filelock = "*" | ||||||
| fuzzywuzzy = {extras = ["speedup"], version = "*"} | fuzzywuzzy = {extras = ["speedup"], version = "*"} | ||||||
| gunicorn = "*" | gunicorn = "*" | ||||||
| imap-tools = "~=0.53.0" | imap-tools = "~=0.54.0" | ||||||
| langdetect = "*" | langdetect = "*" | ||||||
| pathvalidate = "*" | pathvalidate = "*" | ||||||
| pillow = "~=9.1" | pillow = "~=9.1" | ||||||
| @@ -53,7 +53,6 @@ concurrent-log-handler = "*" | |||||||
| zipp = {version = "*", markers = "python_version < '3.9'"} | zipp = {version = "*", markers = "python_version < '3.9'"} | ||||||
| pyzbar = "*" | pyzbar = "*" | ||||||
| pdf2image = "*" | pdf2image = "*" | ||||||
| click = "==8.0.4" |  | ||||||
| bleach = "*" | bleach = "*" | ||||||
|  |  | ||||||
| [dev-packages] | [dev-packages] | ||||||
|   | |||||||
							
								
								
									
										119
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										119
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							| @@ -44,11 +44,11 @@ | |||||||
|         }, |         }, | ||||||
|         "asgiref": { |         "asgiref": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0", |                 "sha256:45a429524fba18aba9d512498b19d220c4d628e75b40cf5c627524dbaebc5cc1", | ||||||
|                 "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9" |                 "sha256:fddeea3c53fa99d0cdb613c3941cc6e52d822491fc2753fba25768fb5bf4e865" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.7'", |             "markers": "python_version >= '3.7'", | ||||||
|             "version": "==3.5.0" |             "version": "==3.5.1" | ||||||
|         }, |         }, | ||||||
|         "async-timeout": { |         "async-timeout": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
| @@ -99,6 +99,7 @@ | |||||||
|                 "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac", |                 "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac", | ||||||
|                 "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2" |                 "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2" | ||||||
|             ], |             ], | ||||||
|  |             "index": "pypi", | ||||||
|             "markers": "python_version < '3.9'", |             "markers": "python_version < '3.9'", | ||||||
|             "version": "==0.2.1" |             "version": "==0.2.1" | ||||||
|         }, |         }, | ||||||
| @@ -206,11 +207,11 @@ | |||||||
|         }, |         }, | ||||||
|         "click": { |         "click": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e", |                 "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", | ||||||
|                 "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72" |                 "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.7'", |             "markers": "python_version >= '3.7'", | ||||||
|             "version": "==8.1.2" |             "version": "==8.1.3" | ||||||
|         }, |         }, | ||||||
|         "coloredlogs": { |         "coloredlogs": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
| @@ -476,7 +477,7 @@ | |||||||
|                 "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", |                 "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", | ||||||
|                 "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" |                 "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.5'", |             "markers": "python_version >= '3'", | ||||||
|             "version": "==3.3" |             "version": "==3.3" | ||||||
|         }, |         }, | ||||||
|         "imap-tools": { |         "imap-tools": { | ||||||
| @@ -498,6 +499,7 @@ | |||||||
|                 "sha256:b6062987dfc51f0fcb809187cffbd60f35df7acb4589091f154214af6d0d49d3", |                 "sha256:b6062987dfc51f0fcb809187cffbd60f35df7acb4589091f154214af6d0d49d3", | ||||||
|                 "sha256:e447dc01619b1e951286f3929be820029d48c75eb25d265c28b92a16548212b8" |                 "sha256:e447dc01619b1e951286f3929be820029d48c75eb25d265c28b92a16548212b8" | ||||||
|             ], |             ], | ||||||
|  |             "index": "pypi", | ||||||
|             "markers": "python_version < '3.9'", |             "markers": "python_version < '3.9'", | ||||||
|             "version": "==5.7.1" |             "version": "==5.7.1" | ||||||
|         }, |         }, | ||||||
| @@ -713,36 +715,36 @@ | |||||||
|         }, |         }, | ||||||
|         "pikepdf": { |         "pikepdf": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:01be838a44430c4be84b748a33950fed09892472934a8041596c11189f365f7f", |                 "sha256:101ec256a8d312c17decae52226cf32a3e7dc834583134300c2f4e60b70e6e91", | ||||||
|                 "sha256:0cc95ef470169dfa5acc9196299bdba236716234a0d8b2746e2a563bc6f1f456", |                 "sha256:12b5b3cfc649e2542576a7e55c11e245278f14f727f116904893e54329102867", | ||||||
|                 "sha256:13e72d0aeeb3fc452569a3f7994acdd007de9aad804ced734d57cec269261b8b", |                 "sha256:1b8f68a75c0a6f6d4d102d0821365ae2aaa9ab635c6eb6c840569a56b1a266f4", | ||||||
|                 "sha256:2873503522ef26a09a6020c29c2efd221fa2ddc31e83bd902be27d317144cf63", |                 "sha256:1bef3512be59fe0f481375b7eb415ca51ee7c80555031401f5f17ee3392e4add", | ||||||
|                 "sha256:2d5d6d3248b33ca5961d84bc3121a299cd27237fad56868d815e381c9a98d3d1", |                 "sha256:1d3141916dc9efc433fd22beba544f67a53a805800c3ff902baffa398ef4c85e", | ||||||
|                 "sha256:2f62e6c7bcf5d631e6ea74cf861f3e816f587c6ccb4ecbf6ac862e088ba2e4ac", |                 "sha256:3052df8514d26b676c50e65afc49a1d260c43a08c322c75cc2592c10a9a5b26d", | ||||||
|                 "sha256:51694d3d2f90510da6a8d7a4d07313ca868b373fffec6de270d9bbff1ce37180", |                 "sha256:356d5554516a295fc10db3f25cfde4e92326f6d015da55d71b84f5ced2a07a5a", | ||||||
|                 "sha256:5c23cbd7ae71f08fb5b5d9660eb0bc61abf345ada01bea6e1b6884c4261e17d6", |                 "sha256:55330c24b8e04ee09f1bc514c2b6107bb03a5eeb0b74929a61100cd6be22ae29", | ||||||
|                 "sha256:6371bf02a436be2b7c63322b83a8e47523f2cd16438b2e93d546c7caf9ae308d", |                 "sha256:553cf11933fdfe07fdd357ab40b9732db102e921b27c1065239308d42b7b858f", | ||||||
|                 "sha256:657293b74af8c7cf03f9905218a7935b26a4f3006803016b40b3db78e04cb35c", |                 "sha256:5626312990a894c5db3a269455f7eb98df5f59188dde1797c0e352d60fdf89af", | ||||||
|                 "sha256:680d47377bb9fd6a36b6a81464ee269b4b29cbf29a84ae4f2ab8f6ea3665bf69", |                 "sha256:59c24a65c94693ab4a7e92f4809f847b57461120256c083054e61c99c4952e84", | ||||||
|                 "sha256:710535c679ab0d7b8249f72247832773e7a9a121dfbe9cad7f6465bd9bb45fae", |                 "sha256:607deb1181a7cf5369cf70edfc41574d46c0a17c0cac1f6234272bd4cb3487e4", | ||||||
|                 "sha256:7b4d7c09036d863915cb01007ca183d6fe64e2d57c0472453097bc9e029a58fb", |                 "sha256:60bdd49e6251f8c99989e6769d4ad29b209c1eaf88090f49d4b30fba98442e40", | ||||||
|                 "sha256:978b6388ae99a024bdcae5a322c68e90c187cb568d09d43e6586b3479267121d", |                 "sha256:73a7cc3c42609e00393b9d4e1b9ee132f528060254a174bf18ef31a154be0386", | ||||||
|                 "sha256:9917a03d500aab72715a9236136af7a5c8c7b26c034bf71ebdf028e177f0d25f", |                 "sha256:75f1e2917b4d2d6573fe3d1c3b2ec70829b64515b2f723f5c3bebcdd65761e6c", | ||||||
|                 "sha256:996faa6b119488f96d7271672a22af86e56e5544ec6b8eae6cd7d4432c70ae2d", |                 "sha256:92ca9191680eccc21697e9e9c218e600ab31e7c24f6125749738c10ae2dc7c07", | ||||||
|                 "sha256:9bac9e9d6b28dc0cc5a554051f183fbd070d0f9fe63c4e9aca939b8c44a5bb4d", |                 "sha256:9bcaf96e2f571f0fc7e3178cdf1bcca7c13e5c68128e8246031226d47ecf23f1", | ||||||
|                 "sha256:aac14061de06843759ea6f5777fd8d7b71af808ed9264f57483a3311a09788ab", |                 "sha256:a8f3e2229e2683497fe4ccc4af06050c125160a11bb3562b6c4ddaee4d0cc5c5", | ||||||
|                 "sha256:ad5361c3669fc0c8dbaf8fa0a590bddf59fad256bb2c527d5ce5cf991743a240", |                 "sha256:c277066938ca0ddb2bfe75874ef8dd3aa259936fe15c4cf7d4282f89ba82ab3a", | ||||||
|                 "sha256:bc40b30c37f8f7c5bef873eca1f04e91ce34b6b74507d8d0019238a17d281fdc", |                 "sha256:c532542a99757d9f41df0cf1fc8f64a044d0eb822822cc069c80be35731df275", | ||||||
|                 "sha256:bd9faae19787a5d05b9fcbe84d7cfe4d44e318068e06eca18906b9dba45425b6", |                 "sha256:dfa89bd86e01413531c1d7d201fb01f0e62b52ea926a8e8ca6f99f86ed761e95", | ||||||
|                 "sha256:c64e7905ec438b7a6c12626f2859df87f471892fab75b65b1441d9e1b38b4dde", |                 "sha256:e064010b733b0a2ec4ec97982cd2887f9025292f2d228c6d5e6eca9d84851e53", | ||||||
|                 "sha256:d4db409b21a8ec0d3a79d2bbd894b997b13223c9ccf341cdc31b64360f1ee4c7", |                 "sha256:ea927afe7cb04cc7ade30b961f528ef53e8d9cf467dcc4639cf944fef872a1a1", | ||||||
|                 "sha256:e0b635d6d9faefb4d0d32722279b8eb4e4d5d7b596c426f3433343de65e0c772", |                 "sha256:f40703b6267aa43d7f72468fa0a3b505ffff74ece2a4c69cfd3c90e023c41381", | ||||||
|                 "sha256:e62e9e8afe77fe2f06715faf10f38a4810d282d66f1e9e05208bb8d9723e6acf", |                 "sha256:f45cc4544bbd4c308a525a6bb8e2e29b3f849803ee557c6e35c684447f0a92e5", | ||||||
|                 "sha256:f85d309bcfeeb3e2d344346a5050bfc41e332f19d390f79c20e4fc7de4b10a17", |                 "sha256:f8ccda5ee992c73f647bcd96c9aa30f5eb9e8a6c5bdd6e3dcb29ebbffbe01a69", | ||||||
|                 "sha256:fe3fc2efe498aba6204b85c17c6a5d54ab7303354ecc5c3da624a6b6af0b3406" |                 "sha256:fe386d93345c9b5a9690f7a7bfb789a5ec5467c34402628e10bda8a4f5bac73e" | ||||||
|             ], |             ], | ||||||
|             "index": "pypi", |             "index": "pypi", | ||||||
|             "version": "==5.1.1" |             "version": "==5.1.2" | ||||||
|         }, |         }, | ||||||
|         "pillow": { |         "pillow": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
| @@ -1448,6 +1450,7 @@ | |||||||
|                 "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad", |                 "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad", | ||||||
|                 "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099" |                 "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099" | ||||||
|             ], |             ], | ||||||
|  |             "index": "pypi", | ||||||
|             "markers": "python_version < '3.9'", |             "markers": "python_version < '3.9'", | ||||||
|             "version": "==3.8.0" |             "version": "==3.8.0" | ||||||
|         }, |         }, | ||||||
| @@ -1587,13 +1590,14 @@ | |||||||
|         }, |         }, | ||||||
|         "click": { |         "click": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e", |                 "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", | ||||||
|                 "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72" |                 "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.7'", |             "markers": "python_version >= '3.7'", | ||||||
|             "version": "==8.1.2" |             "version": "==8.1.3" | ||||||
|         }, |         }, | ||||||
|         "coverage": { |         "coverage": { | ||||||
|  |             "extras": [], | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9", |                 "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9", | ||||||
|                 "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d", |                 "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d", | ||||||
| @@ -1687,11 +1691,11 @@ | |||||||
|         }, |         }, | ||||||
|         "faker": { |         "faker": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:0d5425894e098410b64aaade38a81074fa30163076251118523adf5bb44f8346", |                 "sha256:0301ace8365d98f3d0bf6e9a40200c8548e845d3812402ae1daf589effe3fb01", | ||||||
|                 "sha256:7ab2f741ef1c006ed7274a6ed75695ca8b610f78861566b599ce83c4953bf687" |                 "sha256:b1903db92175d78051858128ada397c7dc76f376f6967975419da232b3ebd429" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6'", |             "markers": "python_version >= '3.6'", | ||||||
|             "version": "==13.6.0" |             "version": "==13.7.0" | ||||||
|         }, |         }, | ||||||
|         "filelock": { |         "filelock": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
| @@ -1714,7 +1718,7 @@ | |||||||
|                 "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", |                 "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", | ||||||
|                 "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" |                 "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.5'", |             "markers": "python_version >= '3'", | ||||||
|             "version": "==3.3" |             "version": "==3.3" | ||||||
|         }, |         }, | ||||||
|         "imagesize": { |         "imagesize": { | ||||||
| @@ -1725,6 +1729,14 @@ | |||||||
|             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", |             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", | ||||||
|             "version": "==1.3.0" |             "version": "==1.3.0" | ||||||
|         }, |         }, | ||||||
|  |         "importlib-metadata": { | ||||||
|  |             "hashes": [ | ||||||
|  |                 "sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6", | ||||||
|  |                 "sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539" | ||||||
|  |             ], | ||||||
|  |             "markers": "python_version < '3.10'", | ||||||
|  |             "version": "==4.11.3" | ||||||
|  |         }, | ||||||
|         "iniconfig": { |         "iniconfig": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", |                 "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", | ||||||
| @@ -1734,11 +1746,11 @@ | |||||||
|         }, |         }, | ||||||
|         "jinja2": { |         "jinja2": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:539835f51a74a69f41b848a9645dbdc35b4f20a3b601e2d9a7e22947b15ff119", |                 "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", | ||||||
|                 "sha256:640bed4bb501cbd17194b3cace1dc2126f5b619cf068a726b98192a0fde74ae9" |                 "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.7'", |             "markers": "python_version >= '3.7'", | ||||||
|             "version": "==3.1.1" |             "version": "==3.1.2" | ||||||
|         }, |         }, | ||||||
|         "markupsafe": { |         "markupsafe": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
| @@ -2095,6 +2107,14 @@ | |||||||
|             "index": "pypi", |             "index": "pypi", | ||||||
|             "version": "==3.25.0" |             "version": "==3.25.0" | ||||||
|         }, |         }, | ||||||
|  |         "typing-extensions": { | ||||||
|  |             "hashes": [ | ||||||
|  |                 "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708", | ||||||
|  |                 "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376" | ||||||
|  |             ], | ||||||
|  |             "markers": "python_version >= '3.7'", | ||||||
|  |             "version": "==4.2.0" | ||||||
|  |         }, | ||||||
|         "urllib3": { |         "urllib3": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", |                 "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'", |             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", | ||||||
|             "version": "==20.14.1" |             "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. | # Helper script for building the Docker image locally. | ||||||
| # Parses and provides the nessecary versions of other images to Docker | # Parses and provides the nessecary versions of other images to Docker | ||||||
| # before passing in the rest of script args.  A future enhancement | # before passing in the rest of script args. | ||||||
| # would be to combine this with the CI script |  | ||||||
|  |  | ||||||
| # First Argument: The Dockerfile to build | # First Argument: The Dockerfile to build | ||||||
| # Other Arguments: Additional arguments to docker build | # Other Arguments: Additional arguments to docker build | ||||||
|  |  | ||||||
| # Example Usage: | # Example Usage: | ||||||
| #	./build-docker-image.sh Dockerfile -t paperless-ngx:my-awesome-feature | #	./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 | set -eux | ||||||
|  |  | ||||||
| @@ -28,23 +26,17 @@ psycopg2_version=$(jq ".default.psycopg2.version" Pipfile.lock | sed 's/=//g' | | |||||||
| # Read this from the other config file | # Read this from the other config file | ||||||
| qpdf_version=$(jq ".qpdf.version" .build-config.json | sed 's/"//g') | qpdf_version=$(jq ".qpdf.version" .build-config.json | sed 's/"//g') | ||||||
| jbig2enc_version=$(jq ".jbig2enc.version" .build-config.json | sed 's/"//g') | jbig2enc_version=$(jq ".jbig2enc.version" .build-config.json | sed 's/"//g') | ||||||
| # Get the branch name | # Get the branch name (used for caching) | ||||||
| frontend_version=$(git rev-parse --abbrev-ref HEAD) | branch_name=$(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}" |  | ||||||
|  |  | ||||||
| # https://docs.docker.com/develop/develop-images/build_enhancements/ | # https://docs.docker.com/develop/develop-images/build_enhancements/ | ||||||
|  | # Required to use cache-from | ||||||
| export DOCKER_BUILDKIT=1 | export DOCKER_BUILDKIT=1 | ||||||
|  |  | ||||||
| docker build --file "$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 JBIG2ENC_VERSION="${jbig2enc_version}" \ | ||||||
| 	--build-arg QPDF_VERSION="${qpdf_version}" \ | 	--build-arg QPDF_VERSION="${qpdf_version}" \ | ||||||
| 	--build-arg PIKEPDF_VERSION="${pikepdf_version}" \ | 	--build-arg PIKEPDF_VERSION="${pikepdf_version}" \ | ||||||
| 	--build-arg PIKEPDF_GIT_TAG="${pikepdf_git_tag}" \ | 	--build-arg PSYCOPG2_VERSION="${psycopg2_version}" "${@:2}" . | ||||||
| 	--build-arg PSYCOPG2_VERSION="${psycopg2_version}" \ |  | ||||||
| 	--build-arg PSYCOPG2_GIT_TAG="${psycopg2_git_tag}" \ |  | ||||||
| 	--build-arg FRONTEND_VERSION="${frontend_version}" "${@:2}" . |  | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| # docker-compose file for running paperless from the docker container registry. | # docker-compose file for running paperless from the docker container registry. | ||||||
| # This file contains everything paperless needs to run. | # This file contains everything paperless needs to run. | ||||||
| # Paperless supports amd64, arm and arm64 hardware. The apache/tika image | # Paperless supports amd64, arm and arm64 hardware. | ||||||
| # does not support arm or arm64, however. |  | ||||||
| # | # | ||||||
| # All compose files of paperless configure paperless in the following way: | # All compose files of paperless configure paperless in the following way: | ||||||
| # | # | ||||||
| @@ -78,14 +77,14 @@ services: | |||||||
|       PAPERLESS_TIKA_ENDPOINT: http://tika:9998 |       PAPERLESS_TIKA_ENDPOINT: http://tika:9998 | ||||||
|  |  | ||||||
|   gotenberg: |   gotenberg: | ||||||
|     image: gotenberg/gotenberg:7 |     image: gotenberg/gotenberg:7.4 | ||||||
|     restart: unless-stopped |     restart: unless-stopped | ||||||
|     command: |     command: | ||||||
|       - "gotenberg" |       - "gotenberg" | ||||||
|       - "--chromium-disable-web-security" |       - "--chromium-disable-web-security" | ||||||
|  |  | ||||||
|   tika: |   tika: | ||||||
|     image: apache/tika |     image: ghcr.io/paperless-ngx/tika:latest | ||||||
|     restart: unless-stopped |     restart: unless-stopped | ||||||
|  |  | ||||||
| volumes: | 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. | # docker-compose file for running paperless from the docker container registry. | ||||||
| # This file contains everything paperless needs to run. | # This file contains everything paperless needs to run. | ||||||
| # Paperless supports amd64, arm and arm64 hardware. The apache/tika image | # Paperless supports amd64, arm and arm64 hardware. | ||||||
| # does not support arm or arm64, however. |  | ||||||
| # |  | ||||||
| # All compose files of paperless configure paperless in the following way: | # All compose files of paperless configure paperless in the following way: | ||||||
| # | # | ||||||
| # - Paperless is (re)started on system boot, if it was running before shutdown. | # - Paperless is (re)started on system boot, if it was running before shutdown. | ||||||
| @@ -67,14 +65,14 @@ services: | |||||||
|       PAPERLESS_TIKA_ENDPOINT: http://tika:9998 |       PAPERLESS_TIKA_ENDPOINT: http://tika:9998 | ||||||
|  |  | ||||||
|   gotenberg: |   gotenberg: | ||||||
|     image: gotenberg/gotenberg:7 |     image: gotenberg/gotenberg:7.4 | ||||||
|     restart: unless-stopped |     restart: unless-stopped | ||||||
|     command: |     command: | ||||||
|       - "gotenberg" |       - "gotenberg" | ||||||
|       - "--chromium-disable-web-security" |       - "--chromium-disable-web-security" | ||||||
|  |  | ||||||
|   tika: |   tika: | ||||||
|     image: apache/tika |     image: ghcr.io/paperless-ngx/tika:latest | ||||||
|     restart: unless-stopped |     restart: unless-stopped | ||||||
|  |  | ||||||
| volumes: | 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 |                 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 | Bare Metal Route | ||||||
| ================ | ================ | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,6 +2,8 @@ import sphinx_rtd_theme | |||||||
|  |  | ||||||
|  |  | ||||||
| __version__ = None | __version__ = None | ||||||
|  | __full_version_str__ = None | ||||||
|  | __major_minor_version_str__ = None | ||||||
| exec(open("../src/paperless/version.py").read()) | 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. | # 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. | # 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 | # The language for content autogenerated by Sphinx. Refer to documentation | ||||||
| # for a list of supported languages. | # for a list of supported languages. | ||||||
|   | |||||||
| @@ -474,7 +474,7 @@ PAPERLESS_TIKA_GOTENBERG_ENDPOINT=<url> | |||||||
|     Defaults to "http://localhost:3000". |     Defaults to "http://localhost:3000". | ||||||
|  |  | ||||||
| If you run paperless on docker, you can add those services to the docker-compose | 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: | requires are as follows: | ||||||
|  |  | ||||||
| .. code:: yaml | .. code:: yaml | ||||||
| @@ -495,14 +495,14 @@ requires are as follows: | |||||||
|         # ... |         # ... | ||||||
|  |  | ||||||
|         gotenberg: |         gotenberg: | ||||||
|             image: gotenberg/gotenberg:7 |             image: gotenberg/gotenberg:7.4 | ||||||
|             restart: unless-stopped |             restart: unless-stopped | ||||||
|             command: |             command: | ||||||
|                 - "gotenberg" |                 - "gotenberg" | ||||||
|                 - "--chromium-disable-web-security" |                 - "--chromium-disable-web-security" | ||||||
|  |  | ||||||
|         tika: |         tika: | ||||||
|             image: apache/tika |             image: ghcr.io/paperless-ngx/tika:latest | ||||||
|             restart: unless-stopped |             restart: unless-stopped | ||||||
|  |  | ||||||
| Add the configuration variables to the environment of the webserver (alternatively | Add the configuration variables to the environment of the webserver (alternatively | ||||||
|   | |||||||
| @@ -334,11 +334,17 @@ directory. | |||||||
| Building the Docker image | 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: | Building the docker image from source: | ||||||
|  |  | ||||||
|     .. code:: shell-session |     .. code:: shell-session | ||||||
|  |  | ||||||
|         docker build . -t <your-tag> |         ./build-docker-image.sh Dockerfile -t <your-tag> | ||||||
|  |  | ||||||
| Extending Paperless | Extending Paperless | ||||||
| =================== | =================== | ||||||
|   | |||||||
| @@ -728,8 +728,6 @@ configuring some options in paperless can help improve performance immensely: | |||||||
|     times. Thumbnails will be about 20% larger. |     times. Thumbnails will be about 20% larger. | ||||||
| *   If using docker, consider setting ``PAPERLESS_WEBSERVER_WORKERS`` to | *   If using docker, consider setting ``PAPERLESS_WEBSERVER_WORKERS`` to | ||||||
|     1. This will save some memory. |     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`. | For details, refer to :ref:`configuration`. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -125,7 +125,7 @@ If using docker-compose, this is achieved by the following configuration change | |||||||
| .. code:: yaml | .. code:: yaml | ||||||
|  |  | ||||||
|     gotenberg: |     gotenberg: | ||||||
|         image: gotenberg/gotenberg:7 |         image: gotenberg/gotenberg:7.4 | ||||||
|         restart: unless-stopped |         restart: unless-stopped | ||||||
|         command: |         command: | ||||||
|             - "gotenberg" |             - "gotenberg" | ||||||
|   | |||||||
| @@ -5,12 +5,12 @@ | |||||||
| #    pipenv lock --requirements | #    pipenv lock --requirements | ||||||
| # | # | ||||||
|  |  | ||||||
| -i https://pypi.python.org/simple/ | -i https://pypi.python.org/simple | ||||||
| --extra-index-url https://www.piwheels.org/simple/ | --extra-index-url https://www.piwheels.org/simple | ||||||
| aioredis==1.3.1 | aioredis==1.3.1 | ||||||
| anyio==3.5.0; python_full_version >= '3.6.2' | anyio==3.5.0; python_full_version >= '3.6.2' | ||||||
| arrow==1.2.2; python_version >= '3.6' | 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' | 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' | 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' | autobahn==22.3.2; python_version >= '3.7' | ||||||
| @@ -23,7 +23,7 @@ channels-redis==3.4.0 | |||||||
| channels==3.0.4 | channels==3.0.4 | ||||||
| chardet==4.0.0; python_version >= '3.1' | chardet==4.0.0; python_version >= '3.1' | ||||||
| charset-normalizer==2.0.12; python_version >= '3' | 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' | 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 | concurrent-log-handler==0.9.20 | ||||||
| constantly==15.1.0 | constantly==15.1.0 | ||||||
| @@ -45,7 +45,7 @@ hiredis==2.0.0; python_version >= '3.6' | |||||||
| httptools==0.4.0 | 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' | 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 | hyperlink==21.0.0 | ||||||
| idna==3.3; python_version >= '3.5' | idna==3.3; python_version >= '3' | ||||||
| imap-tools==0.54.0 | imap-tools==0.54.0 | ||||||
| img2pdf==0.4.4 | img2pdf==0.4.4 | ||||||
| importlib-resources==5.7.1; python_version < '3.9' | importlib-resources==5.7.1; python_version < '3.9' | ||||||
| @@ -62,7 +62,7 @@ packaging==21.3; python_version >= '3.6' | |||||||
| pathvalidate==2.5.0 | pathvalidate==2.5.0 | ||||||
| pdf2image==1.16.0 | pdf2image==1.16.0 | ||||||
| pdfminer.six==20220319 | pdfminer.six==20220319 | ||||||
| pikepdf==5.1.1 | pikepdf==5.1.2 | ||||||
| pillow==9.1.0 | pillow==9.1.0 | ||||||
| pluggy==1.0.0; python_version >= '3.6' | pluggy==1.0.0; python_version >= '3.6' | ||||||
| portalocker==2.4.0; python_version >= '3' | 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 -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 -d -p 6379:6379 redis:latest | ||||||
| docker run -p 3000:3000 -d gotenberg/gotenberg:7 gotenberg --chromium-disable-web-security | docker run -p 3000:3000 -d gotenberg/gotenberg:7.4 gotenberg --chromium-disable-web-security | ||||||
| docker run -p 9998:9998 -d apache/tika | 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": "~13.3.5", | ||||||
|     "@angular/platform-browser-dynamic": "~13.3.5", |     "@angular/platform-browser-dynamic": "~13.3.5", | ||||||
|     "@angular/router": "~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", |     "@ng-select/ng-select": "^8.1.1", | ||||||
|     "@ngneat/dirty-check-forms": "^3.0.2", |     "@ngneat/dirty-check-forms": "^3.0.2", | ||||||
|     "@popperjs/core": "^2.11.4", |     "@popperjs/core": "^2.11.4", | ||||||
| @@ -45,14 +45,16 @@ | |||||||
|     "@types/node": "^17.0.30", |     "@types/node": "^17.0.30", | ||||||
|     "codelyzer": "^6.0.2", |     "codelyzer": "^6.0.2", | ||||||
|     "concurrently": "7.1.0", |     "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", |     "ts-node": "~10.7.0", | ||||||
|     "tslint": "~6.1.3", |     "tslint": "~6.1.3", | ||||||
|     "typescript": "~4.6.3", |     "typescript": "~4.6.3", | ||||||
|     "wait-on": "~6.0.1" |     "wait-on": "~6.0.1" | ||||||
|   }, |   }, | ||||||
|   "optionalDependencies": { |   "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 */ | /* global mocks for jsdom */ | ||||||
| const mock = () => { | const mock = () => { | ||||||
| @@ -26,5 +26,6 @@ Object.defineProperty(document.body.style, 'transform', { | |||||||
|   }, |   }, | ||||||
| }) | }) | ||||||
|  |  | ||||||
| /* output shorter and more meaningful Zone error stack traces */ | HTMLCanvasElement.prototype.getContext = < | ||||||
| // Error.stackTraceLimit = 2 |   typeof HTMLCanvasElement.prototype.getContext | ||||||
|  | >jest.fn() | ||||||
|   | |||||||
| @@ -162,8 +162,8 @@ | |||||||
|             <div [ngbNavOutlet]="nav" class="mt-2"></div> |             <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-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="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)">Save</button>  |             <button type="submit" class="btn btn-primary" i18n [disabled]="networkActive || !(isDirty$ | async) || error">Save</button>  | ||||||
|         </form> |         </form> | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -34,6 +34,7 @@ import { | |||||||
| } from 'rxjs/operators' | } from 'rxjs/operators' | ||||||
| import { PaperlessDocumentSuggestions } from 'src/app/data/paperless-document-suggestions' | import { PaperlessDocumentSuggestions } from 'src/app/data/paperless-document-suggestions' | ||||||
| import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type' | import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type' | ||||||
|  | import { normalizeDateStr } from 'src/app/utils/date' | ||||||
|  |  | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-document-detail', |   selector: 'app-document-detail', | ||||||
| @@ -145,18 +146,24 @@ export class DocumentDetailComponent | |||||||
|     this.documentForm.valueChanges |     this.documentForm.valueChanges | ||||||
|       .pipe(takeUntil(this.unsubscribeNotifier)) |       .pipe(takeUntil(this.unsubscribeNotifier)) | ||||||
|       .subscribe((changes) => { |       .subscribe((changes) => { | ||||||
|  |         this.error = null | ||||||
|         if (this.ogDate) { |         if (this.ogDate) { | ||||||
|           let newDate = new Date(changes['created']) |           try { | ||||||
|           newDate.setHours( |             let newDate = new Date(normalizeDateStr(changes['created'])) | ||||||
|             this.ogDate.getHours(), |             newDate.setHours( | ||||||
|             this.ogDate.getMinutes(), |               this.ogDate.getHours(), | ||||||
|             this.ogDate.getSeconds(), |               this.ogDate.getMinutes(), | ||||||
|             this.ogDate.getMilliseconds() |               this.ogDate.getSeconds(), | ||||||
|           ) |               this.ogDate.getMilliseconds() | ||||||
|           this.documentForm.patchValue( |             ) | ||||||
|             { created: this.formatDate(newDate) }, |             this.documentForm.patchValue( | ||||||
|             { emitEvent: false } |               { 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) |         Object.assign(this.document, this.documentForm.value) | ||||||
| @@ -199,22 +206,22 @@ export class DocumentDetailComponent | |||||||
|             this.updateComponent(doc) |             this.updateComponent(doc) | ||||||
|           } |           } | ||||||
|  |  | ||||||
|           this.ogDate = new Date(doc.created) |           this.ogDate = new Date(normalizeDateStr(doc.created.toString())) | ||||||
|  |  | ||||||
|           // Initialize dirtyCheck |           // Initialize dirtyCheck | ||||||
|           this.store = new BehaviorSubject({ |           this.store = new BehaviorSubject({ | ||||||
|             title: doc.title, |             title: doc.title, | ||||||
|             content: doc.content, |             content: doc.content, | ||||||
|             created: this.formatDate(this.ogDate), |             created: this.ogDate.toISOString(), | ||||||
|             correspondent: doc.correspondent, |             correspondent: doc.correspondent, | ||||||
|             document_type: doc.document_type, |             document_type: doc.document_type, | ||||||
|             archive_serial_number: doc.archive_serial_number, |             archive_serial_number: doc.archive_serial_number, | ||||||
|             tags: [...doc.tags], |             tags: [...doc.tags], | ||||||
|           }) |           }) | ||||||
|  |  | ||||||
|           // ensure we're always starting with 24-char ISO8601 string |           // start with ISO8601 string | ||||||
|           this.documentForm.patchValue( |           this.documentForm.patchValue( | ||||||
|             { created: this.formatDate(this.ogDate) }, |             { created: this.ogDate.toISOString() }, | ||||||
|             { emitEvent: false } |             { emitEvent: false } | ||||||
|           ) |           ) | ||||||
|  |  | ||||||
| @@ -319,16 +326,17 @@ export class DocumentDetailComponent | |||||||
|     this.documentsService |     this.documentsService | ||||||
|       .get(this.documentId) |       .get(this.documentId) | ||||||
|       .pipe(first()) |       .pipe(first()) | ||||||
|       .subscribe( |       .subscribe({ | ||||||
|         (doc) => { |         next: (doc) => { | ||||||
|           Object.assign(this.document, doc) |           Object.assign(this.document, doc) | ||||||
|           this.title = doc.title |           this.title = doc.title | ||||||
|           this.documentForm.patchValue(doc) |           this.documentForm.patchValue(doc) | ||||||
|  |           this.openDocumentService.setDirty(doc.id, false) | ||||||
|         }, |         }, | ||||||
|         (error) => { |         error: () => { | ||||||
|           this.router.navigate(['404']) |           this.router.navigate(['404']) | ||||||
|         } |         }, | ||||||
|       ) |       }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   save() { |   save() { | ||||||
| @@ -486,8 +494,4 @@ export class DocumentDetailComponent | |||||||
|       this.password = (event.target as HTMLInputElement).value |       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 { DatePipe } from '@angular/common' | ||||||
| import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core' | import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core' | ||||||
| import { SettingsService, SETTINGS_KEYS } from '../services/settings.service' | import { SettingsService, SETTINGS_KEYS } from '../services/settings.service' | ||||||
|  | import { normalizeDateStr } from '../utils/date' | ||||||
|  |  | ||||||
| const FORMAT_TO_ISO_FORMAT = { | const FORMAT_TO_ISO_FORMAT = { | ||||||
|   longDate: 'y-MM-dd', |   longDate: 'y-MM-dd', | ||||||
| @@ -33,6 +34,7 @@ export class CustomDatePipe implements PipeTransform { | |||||||
|       this.settings.get(SETTINGS_KEYS.DATE_LOCALE) || |       this.settings.get(SETTINGS_KEYS.DATE_LOCALE) || | ||||||
|       this.defaultLocale |       this.defaultLocale | ||||||
|     let f = format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT) |     let f = format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT) | ||||||
|  |     if (typeof value == 'string') value = normalizeDateStr(value) | ||||||
|     if (l == 'iso-8601') { |     if (l == 'iso-8601') { | ||||||
|       return this.datePipe.transform(value, FORMAT_TO_ISO_FORMAT[f], timezone) |       return this.datePipe.transform(value, FORMAT_TO_ISO_FORMAT[f], timezone) | ||||||
|     } else { |     } 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) |     const dateSeparator = inputFormat.replace(/[dmy]/gi, '').charAt(0) | ||||||
|  |  | ||||||
|     if (this.separatorRegExp.test(value)) { |     if (this.separatorRegExp.test(value)) { | ||||||
|       // split on separator, pad & re-join without separator |       let segments = value.split(this.separatorRegExp) | ||||||
|       value = 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 | ||||||
|         .map((segment) => segment.padStart(2, '0')) |       if ( | ||||||
|         .join('') |         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') { |     if (value.length == 4 && inputFormat.substring(0, 4) != 'yyyy') { | ||||||
|   | |||||||
| @@ -676,28 +676,33 @@ class RemoteVersionView(GenericAPIView): | |||||||
|     def get(self, request, format=None): |     def get(self, request, format=None): | ||||||
|         remote_version = "0.0.0" |         remote_version = "0.0.0" | ||||||
|         is_greater_than_current = False |         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 |         # TODO: this can likely be removed when frontend settings are saved to DB | ||||||
|         feature_is_set = settings.ENABLE_UPDATE_CHECK != "default" |         feature_is_set = settings.ENABLE_UPDATE_CHECK != "default" | ||||||
|         if feature_is_set and settings.ENABLE_UPDATE_CHECK: |         if feature_is_set and settings.ENABLE_UPDATE_CHECK: | ||||||
|             try: |             try: | ||||||
|                 with urllib.request.urlopen( |                 req = urllib.request.Request( | ||||||
|                     "https://api.github.com/repos/" |                     "https://api.github.com/repos/paperless-ngx/" | ||||||
|                     + "paperless-ngx/paperless-ngx/releases/latest", |                     "paperless-ngx/releases/latest", | ||||||
|                 ) as response: |                 ) | ||||||
|  |                 # Ensure a JSON response | ||||||
|  |                 req.add_header("Accept", "application/json") | ||||||
|  |  | ||||||
|  |                 with urllib.request.urlopen(req) as response: | ||||||
|                     remote = response.read().decode("utf-8") |                     remote = response.read().decode("utf-8") | ||||||
|                 try: |                 try: | ||||||
|                     remote_json = json.loads(remote) |                     remote_json = json.loads(remote) | ||||||
|                     remote_version = remote_json["tag_name"].replace("ngx-", "") |                     remote_version = remote_json["tag_name"].removeprefix("ngx-") | ||||||
|                 except ValueError: |                 except ValueError: | ||||||
|                     logger.debug("An error occured parsing remote version json") |                     logger.debug("An error occurred parsing remote version json") | ||||||
|             except urllib.error.URLError: |             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 = ( | ||||||
|             is_greater_than_current = packaging_version.parse( |                 packaging_version.parse( | ||||||
|                 remote_version, |                     remote_version, | ||||||
|             ) > packaging_version.parse( |                 ) | ||||||
|                 current_version, |                 > current_version | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|         return Response( |         return Response( | ||||||
|   | |||||||
| @@ -11,6 +11,6 @@ class ApiVersionMiddleware: | |||||||
|         if request.user.is_authenticated: |         if request.user.is_authenticated: | ||||||
|             versions = settings.REST_FRAMEWORK["ALLOWED_VERSIONS"] |             versions = settings.REST_FRAMEWORK["ALLOWED_VERSIONS"] | ||||||
|             response["X-Api-Version"] = versions[len(versions) - 1] |             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 |         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