mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-11-03 03:16:10 -06: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,8 +146,10 @@ 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 {
 | 
				
			||||||
 | 
					            let newDate = new Date(normalizeDateStr(changes['created']))
 | 
				
			||||||
            newDate.setHours(
 | 
					            newDate.setHours(
 | 
				
			||||||
              this.ogDate.getHours(),
 | 
					              this.ogDate.getHours(),
 | 
				
			||||||
              this.ogDate.getMinutes(),
 | 
					              this.ogDate.getMinutes(),
 | 
				
			||||||
@@ -154,9 +157,13 @@ export class DocumentDetailComponent
 | 
				
			|||||||
              this.ogDate.getMilliseconds()
 | 
					              this.ogDate.getMilliseconds()
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            this.documentForm.patchValue(
 | 
					            this.documentForm.patchValue(
 | 
				
			||||||
            { created: this.formatDate(newDate) },
 | 
					              { created: newDate.toISOString() },
 | 
				
			||||||
              { emitEvent: false }
 | 
					              { 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