mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-08-03 18:54:40 -05:00
Compare commits
283 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6c658a676e | ||
![]() |
38de2a7767 | ||
![]() |
ee272da95f | ||
![]() |
8098ac6b15 | ||
![]() |
c08f0054da | ||
![]() |
29f8cda104 | ||
![]() |
0d1a8d6d2f | ||
![]() |
edfd3bbe91 | ||
![]() |
b91ec5a520 | ||
![]() |
0d777343fb | ||
![]() |
3b0fa4f707 | ||
![]() |
8b3d01c49b | ||
![]() |
1d5eb983ea | ||
![]() |
add647afe6 | ||
![]() |
3e777f2a5b | ||
![]() |
7bfb11a711 | ||
![]() |
808cf93a19 | ||
![]() |
37ddc3b8f7 | ||
![]() |
bc91b830ed | ||
![]() |
ced248ad49 | ||
![]() |
d73fbb1643 | ||
![]() |
40db244d4a | ||
![]() |
8181535f40 | ||
![]() |
2d9fa58157 | ||
![]() |
7af0b47ba9 | ||
![]() |
b9f0418038 | ||
![]() |
74b729bf5a | ||
![]() |
66333caebc | ||
![]() |
405c0922f8 | ||
![]() |
bdf9b2453f | ||
![]() |
8ef5f0e93c | ||
![]() |
597bb98cb9 | ||
![]() |
cc971a4569 | ||
![]() |
8955d25a00 | ||
![]() |
bdcba570cb | ||
![]() |
8154c7b53a | ||
![]() |
ac611acaa1 | ||
![]() |
faecd59432 | ||
![]() |
0f536a9b9a | ||
![]() |
a203b006e7 | ||
![]() |
5978650ec6 | ||
![]() |
8fea4c00ad | ||
![]() |
9b3ec22beb | ||
![]() |
54e1c17539 | ||
![]() |
06e2500443 | ||
![]() |
f43c3e0dd6 | ||
![]() |
73b2c366df | ||
![]() |
1547a698cb | ||
![]() |
87b1f5adec | ||
![]() |
8a281452b8 | ||
![]() |
dd38b84116 | ||
![]() |
658d372cd2 | ||
![]() |
61f7e73961 | ||
![]() |
31bcb613ad | ||
![]() |
b85d39b189 | ||
![]() |
dc7bef5d48 | ||
![]() |
dae4550bc3 | ||
![]() |
dace08d4e3 | ||
![]() |
c42a9b8b8f | ||
![]() |
9ee324915f | ||
![]() |
bb211ee779 | ||
![]() |
00c3d8c523 | ||
![]() |
4f0d2cd612 | ||
![]() |
f4304a120b | ||
![]() |
b8c3e564c6 | ||
![]() |
0a47fba9ae | ||
![]() |
9aea8a7d7c | ||
![]() |
7b9c0d65b9 | ||
![]() |
7dd9a4e089 | ||
![]() |
9784ea4a60 | ||
![]() |
4fce5aba63 | ||
![]() |
2ab77fbaf7 | ||
![]() |
94ad290e14 | ||
![]() |
d2b290f789 | ||
![]() |
583f05af2d | ||
![]() |
1b2cb13a21 | ||
![]() |
4dc0c7bbe2 | ||
![]() |
44212d492d | ||
![]() |
3ccb83e49c | ||
![]() |
215691ac1a | ||
![]() |
a884647a7c | ||
![]() |
590d129cd3 | ||
![]() |
8fcb7efbd2 | ||
![]() |
f1204d2749 | ||
![]() |
b07b8d65a6 | ||
![]() |
dadd7472fd | ||
![]() |
2801b60b0e | ||
![]() |
e625ac21c3 | ||
![]() |
7ace9eb325 | ||
![]() |
02465672f9 | ||
![]() |
6ea6c79575 | ||
![]() |
c430b9f8cf | ||
![]() |
92fb390f7b | ||
![]() |
8164840cba | ||
![]() |
8e8b2d7e8a | ||
![]() |
459de80124 | ||
![]() |
b38aacd1ce | ||
![]() |
a4535c11e4 | ||
![]() |
f78e93a364 | ||
![]() |
75d2a3a45f | ||
![]() |
1871ef1a72 | ||
![]() |
5e9a7b94ba | ||
![]() |
51a5746611 | ||
![]() |
16fc7ebecc | ||
![]() |
10a5d50ce9 | ||
![]() |
454264a87f | ||
![]() |
7ecb76dddc | ||
![]() |
64eabbe8d0 | ||
![]() |
197938eaab | ||
![]() |
02a40055f5 | ||
![]() |
72bacc016a | ||
![]() |
aeecc10e45 | ||
![]() |
2b3edbaa46 | ||
![]() |
270f8677a7 | ||
![]() |
447edd1355 | ||
![]() |
024921212a | ||
![]() |
5d08a34365 | ||
![]() |
20763e7c26 | ||
![]() |
b33ba4c902 | ||
![]() |
fae5e834b9 | ||
![]() |
4cb4bd13ad | ||
![]() |
896304ccaa | ||
![]() |
9ae186e6f9 | ||
![]() |
c7690c05f5 | ||
![]() |
7273a8c7a5 | ||
![]() |
4195d5746f | ||
![]() |
8b90b51b1a | ||
![]() |
e74af5c73c | ||
![]() |
99c2442b28 | ||
![]() |
3c2df48a1a | ||
![]() |
a0c1c48dca | ||
![]() |
4e05aba0a5 | ||
![]() |
299a69a2de | ||
![]() |
7bc077ac08 | ||
![]() |
64752f6b57 | ||
![]() |
c2880bcf9a | ||
![]() |
159dcdbda5 | ||
![]() |
1838fa971e | ||
![]() |
d8d111f093 | ||
![]() |
31a03b1d30 | ||
![]() |
5004771d79 | ||
![]() |
92b9fc1ba9 | ||
![]() |
585cc24dd5 | ||
![]() |
f261c70f1e | ||
![]() |
8c9dfa449c | ||
![]() |
d94ca2962e | ||
![]() |
3c7eacf923 | ||
![]() |
643486b14b | ||
![]() |
87045da1e2 | ||
![]() |
a109723ada | ||
![]() |
151573a26e | ||
![]() |
284e0d3f60 | ||
![]() |
7048af276a | ||
![]() |
e6cd3c1970 | ||
![]() |
623ac441d5 | ||
![]() |
003201bc1b | ||
![]() |
1bf6d9165f | ||
![]() |
4b49bd9de8 | ||
![]() |
69f82d503a | ||
![]() |
6c7ff54aad | ||
![]() |
0b53a8981c | ||
![]() |
c4dbd58efd | ||
![]() |
959f80604a | ||
![]() |
dee691b72b | ||
![]() |
a4829ce26a | ||
![]() |
7ed4dedd5e | ||
![]() |
93d272f50b | ||
![]() |
6fe5674ac3 | ||
![]() |
6024a862d6 | ||
![]() |
195f3a5dbf | ||
![]() |
94f0808a2f | ||
![]() |
e3f062b981 | ||
![]() |
22142203ce | ||
![]() |
412d9f5cd2 | ||
![]() |
133532a463 | ||
![]() |
c9683808c9 | ||
![]() |
b25f083687 | ||
![]() |
62ba4b9730 | ||
![]() |
150c7f26a5 | ||
![]() |
4b4111ec03 | ||
![]() |
9e33344808 | ||
![]() |
bba1fc7194 | ||
![]() |
efaa1c4dd7 | ||
![]() |
a88b318d7d | ||
![]() |
2460c3e076 | ||
![]() |
9763b72f81 | ||
![]() |
19ab62c06c | ||
![]() |
eb8f37d846 | ||
![]() |
5c9e2d7070 | ||
![]() |
da9f2b1a8c | ||
![]() |
985f298c46 | ||
![]() |
2bb63b2d02 | ||
![]() |
ac75c61c8c | ||
![]() |
f8f0915a32 | ||
![]() |
7b87511e88 | ||
![]() |
bb05c2218f | ||
![]() |
e96e8472d9 | ||
![]() |
3191c15889 | ||
![]() |
d4af7aa411 | ||
![]() |
7b3719101a | ||
![]() |
4def3bf5c2 | ||
![]() |
3daee46c3d | ||
![]() |
fbebd8d7c0 | ||
![]() |
af5cb35531 | ||
![]() |
61a2dca81f | ||
![]() |
4aa8e9b800 | ||
![]() |
b81fe1695d | ||
![]() |
3625e5080c | ||
![]() |
c21775980f | ||
![]() |
33e597f5bb | ||
![]() |
6fa2ca648a | ||
![]() |
adecf5d927 | ||
![]() |
e69d7d804b | ||
![]() |
a0eecb83cf | ||
![]() |
9955315a10 | ||
![]() |
ee7097b497 | ||
![]() |
387c23d27a | ||
![]() |
359593728e | ||
![]() |
9708832ccd | ||
![]() |
aa2ae8fe4c | ||
![]() |
729845662f | ||
![]() |
6ff28c92a4 | ||
![]() |
d19bf59f47 | ||
![]() |
a340b9c8a1 | ||
![]() |
d7939ca958 | ||
![]() |
00d67d53bf | ||
![]() |
b869ad02a1 | ||
![]() |
91d4941438 | ||
![]() |
5746e8b56d | ||
![]() |
8e83f90952 | ||
![]() |
80910c72cf | ||
![]() |
ca4ece3ccd | ||
![]() |
ac6c0484ed | ||
![]() |
1e4923835b | ||
![]() |
7be9ae9c02 | ||
![]() |
da38efebdf | ||
![]() |
0fd51e35e1 | ||
![]() |
59e0c1fe4e | ||
![]() |
cfe9528884 | ||
![]() |
1b45637e9c | ||
![]() |
76acf2b01d | ||
![]() |
eda2bd2dbd | ||
![]() |
6819decec3 | ||
![]() |
c2220aa1ef | ||
![]() |
0d87e529f3 | ||
![]() |
24ce1830eb | ||
![]() |
dfed4176ed | ||
![]() |
be8615741e | ||
![]() |
fd1f6aa960 | ||
![]() |
067a6107f5 | ||
![]() |
62782be08e | ||
![]() |
428fe4a372 | ||
![]() |
91e3302e54 | ||
![]() |
906d5d0bab | ||
![]() |
06c62abfbd | ||
![]() |
31e4a0a88b | ||
![]() |
cf82cb35c9 | ||
![]() |
53fff1d54a | ||
![]() |
60cf260b71 | ||
![]() |
b9d1499d04 | ||
![]() |
3fe68d7bbe | ||
![]() |
2eeb02638b | ||
![]() |
cb4beb5e71 | ||
![]() |
729f25c435 | ||
![]() |
d8e02c6fa0 | ||
![]() |
26c7fad005 | ||
![]() |
28b26eb4c7 | ||
![]() |
4032315851 | ||
![]() |
3c8d7f2dee | ||
![]() |
c76460bd96 | ||
![]() |
25f0a79d06 | ||
![]() |
20e586fa60 | ||
![]() |
384a118672 | ||
![]() |
7d3110f392 | ||
![]() |
ecd345f3e1 | ||
![]() |
ea637b292d | ||
![]() |
82c0b657c4 | ||
![]() |
0476be0ef0 | ||
![]() |
b12ab5fe04 | ||
![]() |
50c0c65c60 | ||
![]() |
a83058ab11 | ||
![]() |
16d5daa867 | ||
![]() |
06c6f33d97 |
19
.codecov.yml
Normal file
19
.codecov.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
# https://docs.codecov.com/docs/pull-request-comments
|
||||
# codecov will only comment if coverage changes
|
||||
comment:
|
||||
require_changes: true
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
# https://docs.codecov.com/docs/commit-status#threshold
|
||||
threshold: 1%
|
||||
# https://docs.codecov.com/docs/commit-status#only_pulls
|
||||
only_pulls: true
|
||||
patch:
|
||||
default:
|
||||
# For the changed lines only, target 75% covered, but
|
||||
# allow as low as 50%
|
||||
target: 75%
|
||||
threshold: 25%
|
||||
only_pulls: true
|
129
.github/scripts/cleanup-tags.py
vendored
129
.github/scripts/cleanup-tags.py
vendored
@@ -7,6 +7,7 @@ import subprocess
|
||||
from argparse import ArgumentParser
|
||||
from typing import Dict
|
||||
from typing import Final
|
||||
from typing import Iterator
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
|
||||
@@ -18,11 +19,14 @@ from github import GithubContainerRegistryApi
|
||||
logger = logging.getLogger("cleanup-tags")
|
||||
|
||||
|
||||
class DockerManifest2:
|
||||
class ImageProperties:
|
||||
"""
|
||||
Data class wrapping the Docker Image Manifest Version 2.
|
||||
Data class wrapping the properties of an entry in the image index
|
||||
manifests list. It is NOT an actual image with layers, etc
|
||||
|
||||
See https://docs.docker.com/registry/spec/manifest-v2-2/
|
||||
https://docs.docker.com/registry/spec/manifest-v2-2/
|
||||
https://github.com/opencontainers/image-spec/blob/main/manifest.md
|
||||
https://github.com/opencontainers/image-spec/blob/main/descriptor.md
|
||||
"""
|
||||
|
||||
def __init__(self, data: Dict) -> None:
|
||||
@@ -39,6 +43,45 @@ class DockerManifest2:
|
||||
self.platform = f"{platform_data_os}/{platform_arch}{platform_variant}"
|
||||
|
||||
|
||||
class ImageIndex:
|
||||
"""
|
||||
Data class wrapping up logic for an OCI Image Index
|
||||
JSON data. Primary use is to access the manifests listing
|
||||
|
||||
See https://github.com/opencontainers/image-spec/blob/main/image-index.md
|
||||
"""
|
||||
|
||||
def __init__(self, package_url: str, tag: str) -> None:
|
||||
self.qualified_name = f"{package_url}:{tag}"
|
||||
logger.info(f"Getting image index for {self.qualified_name}")
|
||||
try:
|
||||
proc = subprocess.run(
|
||||
[
|
||||
shutil.which("docker"),
|
||||
"buildx",
|
||||
"imagetools",
|
||||
"inspect",
|
||||
"--raw",
|
||||
self.qualified_name,
|
||||
],
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
|
||||
self._data = json.loads(proc.stdout)
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
logger.error(
|
||||
f"Failed to get image index for {self.qualified_name}: {e.stderr}",
|
||||
)
|
||||
raise e
|
||||
|
||||
@property
|
||||
def image_pointers(self) -> Iterator[ImageProperties]:
|
||||
for manifest_data in self._data["manifests"]:
|
||||
yield ImageProperties(manifest_data)
|
||||
|
||||
|
||||
class RegistryTagsCleaner:
|
||||
"""
|
||||
This is the base class for the image registry cleaning. Given a package
|
||||
@@ -85,7 +128,10 @@ class RegistryTagsCleaner:
|
||||
|
||||
def clean(self):
|
||||
"""
|
||||
This method will delete image versions, based on the selected tags to delete
|
||||
This method will delete image versions, based on the selected tags to delete.
|
||||
It behaves more like an unlinking than actual deletion. Removing the tag
|
||||
simply removes a pointer to an image, but the actual image data remains accessible
|
||||
if one has the sha256 digest of it.
|
||||
"""
|
||||
for tag_to_delete in self.tags_to_delete:
|
||||
package_version_info = self.all_pkgs_tags_to_version[tag_to_delete]
|
||||
@@ -149,27 +195,17 @@ class RegistryTagsCleaner:
|
||||
|
||||
# Parse manifests to locate digests pointed to
|
||||
for tag in sorted(self.tags_to_keep):
|
||||
full_name = f"ghcr.io/{self.repo_owner}/{self.package_name}:{tag}"
|
||||
logger.info(f"Checking manifest for {full_name}")
|
||||
try:
|
||||
proc = subprocess.run(
|
||||
[
|
||||
shutil.which("docker"),
|
||||
"manifest",
|
||||
"inspect",
|
||||
full_name,
|
||||
],
|
||||
capture_output=True,
|
||||
image_index = ImageIndex(
|
||||
f"ghcr.io/{self.repo_owner}/{self.package_name}",
|
||||
tag,
|
||||
)
|
||||
|
||||
manifest_list = json.loads(proc.stdout)
|
||||
for manifest_data in manifest_list["manifests"]:
|
||||
manifest = DockerManifest2(manifest_data)
|
||||
for manifest in image_index.image_pointers:
|
||||
|
||||
if manifest.digest in untagged_versions:
|
||||
logger.info(
|
||||
f"Skipping deletion of {manifest.digest},"
|
||||
f" referred to by {full_name}"
|
||||
f" referred to by {image_index.qualified_name}"
|
||||
f" for {manifest.platform}",
|
||||
)
|
||||
del untagged_versions[manifest.digest]
|
||||
@@ -241,6 +277,55 @@ class RegistryTagsCleaner:
|
||||
# By default, keep anything which is tagged
|
||||
self.tags_to_keep = list(set(self.all_pkgs_tags_to_version.keys()))
|
||||
|
||||
def check_remaining_tags_valid(self):
|
||||
"""
|
||||
Checks the non-deleted tags are still valid. The assumption is if the
|
||||
manifest is can be inspected and each image manifest if points to can be
|
||||
inspected, the image will still pull.
|
||||
|
||||
https://github.com/opencontainers/image-spec/blob/main/image-index.md
|
||||
"""
|
||||
logger.info("Beginning confirmation step")
|
||||
a_tag_failed = False
|
||||
for tag in sorted(self.tags_to_keep):
|
||||
|
||||
try:
|
||||
image_index = ImageIndex(
|
||||
f"ghcr.io/{self.repo_owner}/{self.package_name}",
|
||||
tag,
|
||||
)
|
||||
for manifest in image_index.image_pointers:
|
||||
logger.info(f"Checking {manifest.digest} for {manifest.platform}")
|
||||
|
||||
# This follows the pointer from the index to an actual image, layers and all
|
||||
# Note the format is @
|
||||
digest_name = f"ghcr.io/{self.repo_owner}/{self.package_name}@{manifest.digest}"
|
||||
|
||||
try:
|
||||
|
||||
subprocess.run(
|
||||
[
|
||||
shutil.which("docker"),
|
||||
"buildx",
|
||||
"imagetools",
|
||||
"inspect",
|
||||
"--raw",
|
||||
digest_name,
|
||||
],
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
logger.error(f"Failed to inspect digest: {e.stderr}")
|
||||
a_tag_failed = True
|
||||
except subprocess.CalledProcessError as e:
|
||||
a_tag_failed = True
|
||||
logger.error(f"Failed to inspect: {e.stderr}")
|
||||
continue
|
||||
|
||||
if a_tag_failed:
|
||||
raise Exception("At least one image tag failed to inspect")
|
||||
|
||||
|
||||
class MainImageTagsCleaner(RegistryTagsCleaner):
|
||||
def decide_what_tags_to_keep(self):
|
||||
@@ -301,7 +386,7 @@ class MainImageTagsCleaner(RegistryTagsCleaner):
|
||||
|
||||
class LibraryTagsCleaner(RegistryTagsCleaner):
|
||||
"""
|
||||
Exists for the off change that someday, the installer library images
|
||||
Exists for the off chance that someday, the installer library images
|
||||
will need their own logic
|
||||
"""
|
||||
|
||||
@@ -397,6 +482,10 @@ def _main():
|
||||
# Clean images which are untagged
|
||||
cleaner.clean_untagged(args.is_manifest)
|
||||
|
||||
# Verify remaining tags still pull
|
||||
if args.is_manifest:
|
||||
cleaner.check_remaining_tags_valid()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
_main()
|
||||
|
174
.github/workflows/ci.yml
vendored
174
.github/workflows/ci.yml
vendored
@@ -13,6 +13,14 @@ on:
|
||||
branches-ignore:
|
||||
- 'translations**'
|
||||
|
||||
env:
|
||||
# This is the version of pipenv all the steps will use
|
||||
# If changing this, change Dockerfile
|
||||
DEFAULT_PIP_ENV_VERSION: "2022.11.30"
|
||||
# This is the default version of Python to use in most steps
|
||||
# If changing this, change Dockerfile
|
||||
DEFAULT_PYTHON_VERSION: "3.9"
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
name: Linting Checks
|
||||
@@ -21,13 +29,11 @@ jobs:
|
||||
-
|
||||
name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
-
|
||||
name: Install tools
|
||||
name: Install python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.9"
|
||||
|
||||
python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
|
||||
-
|
||||
name: Check files
|
||||
uses: pre-commit/action@v3.0.0
|
||||
@@ -41,29 +47,30 @@ jobs:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Install pipenv
|
||||
run: |
|
||||
pipx install pipenv==2022.11.30
|
||||
-
|
||||
name: Set up Python
|
||||
id: setup-python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.8
|
||||
python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
|
||||
cache: "pipenv"
|
||||
cache-dependency-path: 'Pipfile.lock'
|
||||
-
|
||||
name: Install pipenv
|
||||
run: |
|
||||
pip install --user pipenv==${DEFAULT_PIP_ENV_VERSION}
|
||||
-
|
||||
name: Install dependencies
|
||||
run: |
|
||||
pipenv sync --dev
|
||||
pipenv --python ${{ steps.setup-python.outputs.python-version }} sync --dev
|
||||
-
|
||||
name: List installed Python dependencies
|
||||
run: |
|
||||
pipenv run pip list
|
||||
pipenv --python ${{ steps.setup-python.outputs.python-version }} run pip list
|
||||
-
|
||||
name: Make documentation
|
||||
run: |
|
||||
pipenv run mkdocs build --config-file ./mkdocs.yml
|
||||
pipenv --python ${{ steps.setup-python.outputs.python-version }} run mkdocs build --config-file ./mkdocs.yml
|
||||
-
|
||||
name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -106,72 +113,61 @@ jobs:
|
||||
PAPERLESS_MAIL_TEST_HOST: ${{ secrets.TEST_MAIL_HOST }}
|
||||
PAPERLESS_MAIL_TEST_USER: ${{ secrets.TEST_MAIL_USER }}
|
||||
PAPERLESS_MAIL_TEST_PASSWD: ${{ secrets.TEST_MAIL_PASSWD }}
|
||||
# Skip Tests which require convert
|
||||
PAPERLESS_TEST_SKIP_CONVERT: 1
|
||||
# Enable Gotenberg end to end testing
|
||||
GOTENBERG_LIVE: 1
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Start containers
|
||||
run: |
|
||||
docker compose --file ${GITHUB_WORKSPACE}/docker/compose/docker-compose.ci-test.yml pull --quiet
|
||||
docker compose --file ${GITHUB_WORKSPACE}/docker/compose/docker-compose.ci-test.yml up --detach
|
||||
-
|
||||
name: Install pipenv
|
||||
run: |
|
||||
pipx install pipenv==2022.11.30
|
||||
-
|
||||
name: Set up Python
|
||||
id: setup-python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "${{ matrix.python-version }}"
|
||||
cache: "pipenv"
|
||||
cache-dependency-path: 'Pipfile.lock'
|
||||
-
|
||||
name: Install pipenv
|
||||
run: |
|
||||
pip install --user pipenv==${DEFAULT_PIP_ENV_VERSION}
|
||||
-
|
||||
name: Install system dependencies
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -qq --no-install-recommends unpaper tesseract-ocr imagemagick ghostscript libzbar0 poppler-utils
|
||||
-
|
||||
name: Configure ImageMagick
|
||||
run: |
|
||||
sudo cp docker/imagemagick-policy.xml /etc/ImageMagick-6/policy.xml
|
||||
-
|
||||
name: Install Python dependencies
|
||||
run: |
|
||||
pipenv sync --dev
|
||||
pipenv --python ${{ steps.setup-python.outputs.python-version }} run python --version
|
||||
pipenv --python ${{ steps.setup-python.outputs.python-version }} sync --dev
|
||||
-
|
||||
name: List installed Python dependencies
|
||||
run: |
|
||||
pipenv run pip list
|
||||
pipenv --python ${{ steps.setup-python.outputs.python-version }} run pip list
|
||||
-
|
||||
name: Tests
|
||||
run: |
|
||||
cd src/
|
||||
pipenv run pytest -rfEp
|
||||
pipenv --python ${{ steps.setup-python.outputs.python-version }} run pytest -ra
|
||||
-
|
||||
name: Get changed files
|
||||
id: changed-files-specific
|
||||
uses: tj-actions/changed-files@v34
|
||||
name: Upload coverage to Codecov
|
||||
if: ${{ matrix.python-version == env.DEFAULT_PYTHON_VERSION }}
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: |
|
||||
src/**
|
||||
-
|
||||
name: List all changed files
|
||||
run: |
|
||||
for file in ${{ steps.changed-files-specific.outputs.all_changed_files }}; do
|
||||
echo "${file} was changed"
|
||||
done
|
||||
-
|
||||
name: Publish coverage results
|
||||
if: matrix.python-version == '3.9' && steps.changed-files-specific.outputs.any_changed == 'true'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# https://github.com/coveralls-clients/coveralls-python/issues/251
|
||||
run: |
|
||||
cd src/
|
||||
pipenv run coveralls --service=github
|
||||
# not required for public repos, but intermittently fails otherwise
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
# future expansion
|
||||
flags: backend
|
||||
-
|
||||
name: Stop containers
|
||||
if: always()
|
||||
@@ -203,12 +199,6 @@ jobs:
|
||||
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' || contains(github.ref, 'beta.rc') || startsWith(github.ref, 'refs/tags/v'))
|
||||
runs-on: ubuntu-22.04
|
||||
# If the push triggered the installer library workflow, wait for it to
|
||||
# complete here. This ensures the required versions for the final
|
||||
# image have been built, while not waiting at all if the versions haven't changed
|
||||
concurrency:
|
||||
group: build-installer-library
|
||||
cancel-in-progress: false
|
||||
needs:
|
||||
- documentation
|
||||
- tests-backend
|
||||
@@ -227,7 +217,7 @@ jobs:
|
||||
name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.9"
|
||||
python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
|
||||
-
|
||||
name: Setup qpdf image
|
||||
id: qpdf-setup
|
||||
@@ -344,7 +334,7 @@ jobs:
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
@@ -389,22 +379,22 @@ jobs:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Install pipenv
|
||||
run: |
|
||||
pip3 install --upgrade pip setuptools wheel pipx
|
||||
pipx install pipenv
|
||||
-
|
||||
name: Set up Python
|
||||
id: setup-python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.9
|
||||
python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
|
||||
cache: "pipenv"
|
||||
cache-dependency-path: 'Pipfile.lock'
|
||||
-
|
||||
name: Install pipenv + tools
|
||||
run: |
|
||||
pip install --upgrade --user pipenv==${DEFAULT_PIP_ENV_VERSION} setuptools wheel
|
||||
-
|
||||
name: Install Python dependencies
|
||||
run: |
|
||||
pipenv sync --dev
|
||||
pipenv --python ${{ steps.setup-python.outputs.python-version }} sync --dev
|
||||
-
|
||||
name: Install system dependencies
|
||||
run: |
|
||||
@@ -425,35 +415,62 @@ jobs:
|
||||
-
|
||||
name: Generate requirements file
|
||||
run: |
|
||||
pipenv requirements > requirements.txt
|
||||
pipenv --python ${{ steps.setup-python.outputs.python-version }} requirements > requirements.txt
|
||||
-
|
||||
name: Compile messages
|
||||
run: |
|
||||
cd src/
|
||||
pipenv run python3 manage.py compilemessages
|
||||
pipenv --python ${{ steps.setup-python.outputs.python-version }} run python3 manage.py compilemessages
|
||||
-
|
||||
name: Collect static files
|
||||
run: |
|
||||
cd src/
|
||||
pipenv run python3 manage.py collectstatic --no-input
|
||||
pipenv --python ${{ steps.setup-python.outputs.python-version }} run python3 manage.py collectstatic --no-input
|
||||
-
|
||||
name: Move files
|
||||
run: |
|
||||
mkdir dist
|
||||
mkdir dist/paperless-ngx
|
||||
mkdir dist/paperless-ngx/scripts
|
||||
cp .dockerignore .env Dockerfile Pipfile Pipfile.lock requirements.txt LICENSE README.md dist/paperless-ngx/
|
||||
cp paperless.conf.example dist/paperless-ngx/paperless.conf
|
||||
cp gunicorn.conf.py dist/paperless-ngx/gunicorn.conf.py
|
||||
cp -r docker/ dist/paperless-ngx/docker
|
||||
cp scripts/*.service scripts/*.sh dist/paperless-ngx/scripts/
|
||||
cp -r src/ dist/paperless-ngx/src
|
||||
cp -r docs/_build/html/ dist/paperless-ngx/docs
|
||||
mv static dist/paperless-ngx
|
||||
echo "Making dist folders"
|
||||
for directory in dist \
|
||||
dist/paperless-ngx \
|
||||
dist/paperless-ngx/scripts;
|
||||
do
|
||||
mkdir --verbose --parents ${directory}
|
||||
done
|
||||
|
||||
echo "Copying basic files"
|
||||
for file_name in .dockerignore \
|
||||
.env \
|
||||
Dockerfile \
|
||||
Pipfile \
|
||||
Pipfile.lock \
|
||||
requirements.txt \
|
||||
LICENSE \
|
||||
README.md \
|
||||
paperless.conf.example \
|
||||
gunicorn.conf.py
|
||||
do
|
||||
cp --verbose ${file_name} dist/paperless-ngx/
|
||||
done
|
||||
mv --verbose dist/paperless-ngx/paperless.conf.example paperless.conf
|
||||
|
||||
echo "Copying Docker related files"
|
||||
cp --recursive docker/ dist/paperless-ngx/docker
|
||||
|
||||
echo "Copying startup scripts"
|
||||
cp --verbose scripts/*.service scripts/*.sh scripts/*.socket dist/paperless-ngx/scripts/
|
||||
|
||||
echo "Copying source files"
|
||||
cp --recursive src/ dist/paperless-ngx/src
|
||||
echo "Copying documentation"
|
||||
cp --recursive docs/_build/html/ dist/paperless-ngx/docs
|
||||
|
||||
mv --verbose static dist/paperless-ngx
|
||||
-
|
||||
name: Make release package
|
||||
run: |
|
||||
echo "Creating release archive"
|
||||
cd dist
|
||||
sudo chown -R 1000:1000 paperless-ngx/
|
||||
tar -cJf paperless-ngx.tar.xz paperless-ngx/
|
||||
-
|
||||
name: Upload release artifact
|
||||
@@ -491,7 +508,7 @@ jobs:
|
||||
-
|
||||
name: Create Release and Changelog
|
||||
id: create-release
|
||||
uses: paperless-ngx/release-drafter@master
|
||||
uses: release-drafter/release-drafter@v5
|
||||
with:
|
||||
name: Paperless-ngx ${{ steps.get_version.outputs.version }}
|
||||
tag: ${{ steps.get_version.outputs.version }}
|
||||
@@ -522,18 +539,17 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: main
|
||||
-
|
||||
name: Install pipenv
|
||||
run: |
|
||||
pip3 install --upgrade pip setuptools wheel pipx
|
||||
pipx install pipenv
|
||||
-
|
||||
name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.9
|
||||
python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
|
||||
cache: "pipenv"
|
||||
cache-dependency-path: 'Pipfile.lock'
|
||||
-
|
||||
name: Install pipenv + tools
|
||||
run: |
|
||||
pip install --upgrade --user pipenv==${DEFAULT_PIP_ENV_VERSION} setuptools wheel
|
||||
-
|
||||
name: Append Changelog to docs
|
||||
id: append-Changelog
|
||||
|
14
.github/workflows/cleanup-tags.yml
vendored
14
.github/workflows/cleanup-tags.yml
vendored
@@ -62,9 +62,9 @@ jobs:
|
||||
with:
|
||||
python-version: "3.10"
|
||||
-
|
||||
name: Install httpx
|
||||
name: Install Python libraries
|
||||
run: |
|
||||
python -m pip install httpx
|
||||
python -m pip install httpx docker
|
||||
#
|
||||
# Clean up primary package
|
||||
#
|
||||
@@ -81,13 +81,3 @@ jobs:
|
||||
if: "${{ env.TOKEN != '' }}"
|
||||
run: |
|
||||
python ${GITHUB_WORKSPACE}/.github/scripts/cleanup-tags.py --untagged --delete "${{ matrix.cache-name }}"
|
||||
#
|
||||
# Verify tags which are left still pull
|
||||
#
|
||||
-
|
||||
name: Check all tags still pull
|
||||
run: |
|
||||
ghcr_name=$(echo "ghcr.io/${GITHUB_REPOSITORY_OWNER}/${{ matrix.primary-name }}" | awk '{ print tolower($0) }')
|
||||
echo "Pulling all tags of ${ghcr_name}"
|
||||
docker pull --quiet --all-tags ${ghcr_name}
|
||||
docker image list
|
||||
|
143
.github/workflows/installer-library.yml
vendored
143
.github/workflows/installer-library.yml
vendored
@@ -95,8 +95,8 @@ jobs:
|
||||
name: Setup other versions
|
||||
id: cache-bust-setup
|
||||
run: |
|
||||
pillow_version=$(jq ".default.pillow.version" Pipfile.lock | sed 's/=//g' | sed 's/"//g')
|
||||
lxml_version=$(jq ".default.lxml.version" Pipfile.lock | sed 's/=//g' | sed 's/"//g')
|
||||
pillow_version=$(jq -r '.default.pillow.version | gsub("=";"")' Pipfile.lock)
|
||||
lxml_version=$(jq -r '.default.lxml.version | gsub("=";"")' Pipfile.lock)
|
||||
|
||||
echo "Pillow is ${pillow_version}"
|
||||
echo "lxml is ${lxml_version}"
|
||||
@@ -169,3 +169,142 @@ jobs:
|
||||
PIKEPDF_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.pikepdf-json).version }}
|
||||
PILLOW_VERSION=${{ needs.prepare-docker-build.outputs.pillow-version }}
|
||||
LXML_VERSION=${{ needs.prepare-docker-build.outputs.lxml-version }}
|
||||
|
||||
commit-binary-files:
|
||||
name: Store installers
|
||||
needs:
|
||||
- prepare-docker-build
|
||||
- build-qpdf-debs
|
||||
- build-jbig2enc
|
||||
- build-psycopg2-wheel
|
||||
- build-pikepdf-wheel
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: binary-library
|
||||
-
|
||||
name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.9"
|
||||
-
|
||||
name: Install system dependencies
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -qq --no-install-recommends tree
|
||||
-
|
||||
name: Extract qpdf files
|
||||
run: |
|
||||
version=${{ fromJSON(needs.prepare-docker-build.outputs.qpdf-json).version }}
|
||||
tag=${{ fromJSON(needs.prepare-docker-build.outputs.qpdf-json).image_tag }}
|
||||
|
||||
docker pull --quiet ${tag}
|
||||
docker create --name qpdf-extract ${tag}
|
||||
|
||||
mkdir --parents qpdf/${version}/amd64
|
||||
docker cp qpdf-extract:/usr/src/qpdf/${version}/amd64 qpdf/${version}
|
||||
|
||||
mkdir --parents qpdf/${version}/arm64
|
||||
docker cp qpdf-extract:/usr/src/qpdf/${version}/arm64 qpdf/${version}
|
||||
|
||||
mkdir --parents qpdf/${version}/armv7
|
||||
docker cp qpdf-extract:/usr/src/qpdf/${version}/armv7 qpdf/${version}
|
||||
-
|
||||
name: Extract psycopg2 files
|
||||
run: |
|
||||
version=${{ fromJSON(needs.prepare-docker-build.outputs.psycopg2-json).version }}
|
||||
tag=${{ fromJSON(needs.prepare-docker-build.outputs.psycopg2-json).image_tag }}
|
||||
|
||||
docker pull --quiet --platform linux/amd64 ${tag}
|
||||
docker create --platform linux/amd64 --name psycopg2-extract ${tag}
|
||||
mkdir --parents psycopg2/${version}/amd64
|
||||
docker cp psycopg2-extract:/usr/src/wheels/ psycopg2/${version}/amd64
|
||||
mv psycopg2/${version}/amd64/wheels/* psycopg2/${version}/amd64
|
||||
rm -r psycopg2/${version}/amd64/wheels/
|
||||
docker rm psycopg2-extract
|
||||
|
||||
docker pull --quiet --platform linux/arm64 ${tag}
|
||||
docker create --platform linux/arm64 --name psycopg2-extract ${tag}
|
||||
mkdir --parents psycopg2/${version}/arm64
|
||||
docker cp psycopg2-extract:/usr/src/wheels/ psycopg2/${version}/arm64
|
||||
mv psycopg2/${version}/arm64/wheels/* psycopg2/${version}/arm64
|
||||
rm -r psycopg2/${version}/arm64/wheels/
|
||||
docker rm psycopg2-extract
|
||||
|
||||
docker pull --quiet --platform linux/arm/v7 ${tag}
|
||||
docker create --platform linux/arm/v7 --name psycopg2-extract ${tag}
|
||||
mkdir --parents psycopg2/${version}/armv7
|
||||
docker cp psycopg2-extract:/usr/src/wheels/ psycopg2/${version}/armv7
|
||||
mv psycopg2/${version}/armv7/wheels/* psycopg2/${version}/armv7
|
||||
rm -r psycopg2/${version}/armv7/wheels/
|
||||
docker rm psycopg2-extract
|
||||
-
|
||||
name: Extract pikepdf files
|
||||
run: |
|
||||
version=${{ fromJSON(needs.prepare-docker-build.outputs.pikepdf-json).version }}
|
||||
tag=${{ fromJSON(needs.prepare-docker-build.outputs.pikepdf-json).image_tag }}
|
||||
|
||||
docker pull --quiet --platform linux/amd64 ${tag}
|
||||
docker create --platform linux/amd64 --name pikepdf-extract ${tag}
|
||||
mkdir --parents pikepdf/${version}/amd64
|
||||
docker cp pikepdf-extract:/usr/src/wheels/ pikepdf/${version}/amd64
|
||||
mv pikepdf/${version}/amd64/wheels/* pikepdf/${version}/amd64
|
||||
rm -r pikepdf/${version}/amd64/wheels/
|
||||
docker rm pikepdf-extract
|
||||
|
||||
docker pull --quiet --platform linux/arm64 ${tag}
|
||||
docker create --platform linux/arm64 --name pikepdf-extract ${tag}
|
||||
mkdir --parents pikepdf/${version}/arm64
|
||||
docker cp pikepdf-extract:/usr/src/wheels/ pikepdf/${version}/arm64
|
||||
mv pikepdf/${version}/arm64/wheels/* pikepdf/${version}/arm64
|
||||
rm -r pikepdf/${version}/arm64/wheels/
|
||||
docker rm pikepdf-extract
|
||||
|
||||
docker pull --quiet --platform linux/arm/v7 ${tag}
|
||||
docker create --platform linux/arm/v7 --name pikepdf-extract ${tag}
|
||||
mkdir --parents pikepdf/${version}/armv7
|
||||
docker cp pikepdf-extract:/usr/src/wheels/ pikepdf/${version}/armv7
|
||||
mv pikepdf/${version}/armv7/wheels/* pikepdf/${version}/armv7
|
||||
rm -r pikepdf/${version}/armv7/wheels/
|
||||
docker rm pikepdf-extract
|
||||
-
|
||||
name: Extract jbig2enc files
|
||||
run: |
|
||||
version=${{ fromJSON(needs.prepare-docker-build.outputs.jbig2enc-json).version }}
|
||||
tag=${{ fromJSON(needs.prepare-docker-build.outputs.jbig2enc-json).image_tag }}
|
||||
|
||||
docker pull --quiet --platform linux/amd64 ${tag}
|
||||
docker create --platform linux/amd64 --name jbig2enc-extract ${tag}
|
||||
mkdir --parents jbig2enc/${version}/amd64
|
||||
docker cp jbig2enc-extract:/usr/src/jbig2enc/build jbig2enc/${version}/amd64/
|
||||
mv jbig2enc/${version}/amd64/build/* jbig2enc/${version}/amd64/
|
||||
docker rm jbig2enc-extract
|
||||
|
||||
docker pull --quiet --platform linux/arm64 ${tag}
|
||||
docker create --platform linux/arm64 --name jbig2enc-extract ${tag}
|
||||
mkdir --parents jbig2enc/${version}/arm64
|
||||
docker cp jbig2enc-extract:/usr/src/jbig2enc/build jbig2enc/${version}/arm64
|
||||
mv jbig2enc/${version}/arm64/build/* jbig2enc/${version}/arm64/
|
||||
docker rm jbig2enc-extract
|
||||
|
||||
docker pull --quiet --platform linux/arm/v7 ${tag}
|
||||
docker create --platform linux/arm/v7 --name jbig2enc-extract ${tag}
|
||||
mkdir --parents jbig2enc/${version}/armv7
|
||||
docker cp jbig2enc-extract:/usr/src/jbig2enc/build jbig2enc/${version}/armv7
|
||||
mv jbig2enc/${version}/armv7/build/* jbig2enc/${version}/armv7/
|
||||
docker rm jbig2enc-extract
|
||||
-
|
||||
name: Show file structure
|
||||
run: |
|
||||
tree .
|
||||
-
|
||||
name: Commit files
|
||||
run: |
|
||||
git config --global user.name "github-actions"
|
||||
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git add pikepdf/ qpdf/ psycopg2/ jbig2enc/
|
||||
git commit -m "Updating installer packages" || true
|
||||
git push origin || true
|
||||
|
31
.github/workflows/release-chart.yml
vendored
31
.github/workflows/release-chart.yml
vendored
@@ -1,31 +0,0 @@
|
||||
---
|
||||
name: Release Charts
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
release_chart:
|
||||
name: "Release Chart"
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config user.name "$GITHUB_ACTOR"
|
||||
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
||||
- name: Install Helm
|
||||
uses: azure/setup-helm@v3
|
||||
with:
|
||||
version: v3.10.0
|
||||
|
||||
- name: Run chart-releaser
|
||||
uses: helm/chart-releaser-action@v1.4.1
|
||||
env:
|
||||
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
@@ -45,7 +45,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Build ${{ fromJSON(inputs.build-json).name }}
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ${{ inputs.dockerfile }}
|
||||
|
@@ -11,14 +11,13 @@ repos:
|
||||
- id: check-json
|
||||
exclude: "tsconfig.*json"
|
||||
- id: check-yaml
|
||||
exclude: "charts/paperless-ngx/templates/common.yaml"
|
||||
- id: check-toml
|
||||
- id: check-executables-have-shebangs
|
||||
- id: end-of-file-fixer
|
||||
exclude_types:
|
||||
- svg
|
||||
- pofile
|
||||
exclude: "^(LICENSE|charts/paperless-ngx/README.md)$"
|
||||
exclude: "(^LICENSE$)"
|
||||
- id: mixed-line-ending
|
||||
args:
|
||||
- "--fix=lf"
|
||||
@@ -35,7 +34,7 @@ repos:
|
||||
- javascript
|
||||
- ts
|
||||
- markdown
|
||||
exclude: "(^Pipfile\\.lock$)|(^charts/paperless-ngx/README.md$)"
|
||||
exclude: "(^Pipfile\\.lock$)"
|
||||
# Python hooks
|
||||
- repo: https://github.com/asottile/reorder_python_imports
|
||||
rev: v3.9.0
|
||||
|
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
||||
3.8.16
|
102
Dockerfile
102
Dockerfile
@@ -1,26 +1,12 @@
|
||||
# syntax=docker/dockerfile:1.4
|
||||
# https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/reference.md
|
||||
|
||||
# Pull the installer images from the library
|
||||
# These are all built previously
|
||||
# They provide either a .deb or .whl
|
||||
|
||||
ARG JBIG2ENC_VERSION
|
||||
ARG QPDF_VERSION
|
||||
ARG PIKEPDF_VERSION
|
||||
ARG PSYCOPG2_VERSION
|
||||
|
||||
FROM ghcr.io/paperless-ngx/paperless-ngx/builder/jbig2enc:${JBIG2ENC_VERSION} as jbig2enc-builder
|
||||
FROM ghcr.io/paperless-ngx/paperless-ngx/builder/qpdf:${QPDF_VERSION} as qpdf-builder
|
||||
FROM ghcr.io/paperless-ngx/paperless-ngx/builder/pikepdf:${PIKEPDF_VERSION} as pikepdf-builder
|
||||
FROM ghcr.io/paperless-ngx/paperless-ngx/builder/psycopg2:${PSYCOPG2_VERSION} as psycopg2-builder
|
||||
|
||||
# Stage: compile-frontend
|
||||
# Purpose: Compiles the frontend
|
||||
# Notes:
|
||||
# - Does NPM stuff with Typescript and such
|
||||
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
|
||||
@@ -30,15 +16,13 @@ RUN set -eux \
|
||||
RUN set -eux \
|
||||
&& ./node_modules/.bin/ng build --configuration production
|
||||
|
||||
# Stage: pipenv-base
|
||||
# Purpose: Generates a requirements.txt file for building
|
||||
# Comments:
|
||||
# - pipenv dependencies are not left in the final image
|
||||
# - pipenv can't touch the final image somehow
|
||||
FROM --platform=$BUILDPLATFORM python:3.9-slim-bullseye as pipenv-base
|
||||
|
||||
# This stage generates the requirements.txt file using pipenv
|
||||
# This stage runs once for the native platform, as the outputs are not
|
||||
# dependent on target arch
|
||||
# This way, pipenv dependencies are not left in the final image
|
||||
# nor can pipenv mess up the final image somehow
|
||||
# Inputs: None
|
||||
|
||||
WORKDIR /usr/src/pipenv
|
||||
|
||||
COPY Pipfile* ./
|
||||
@@ -49,6 +33,10 @@ RUN set -eux \
|
||||
&& echo "Generating requirement.txt" \
|
||||
&& pipenv requirements > requirements.txt
|
||||
|
||||
# Stage: main-app
|
||||
# Purpose: The final image
|
||||
# Comments:
|
||||
# - Don't leave anything extra in here
|
||||
FROM python:3.9-slim-bullseye as main-app
|
||||
|
||||
LABEL org.opencontainers.image.authors="paperless-ngx team <hello@paperless-ngx.com>"
|
||||
@@ -58,30 +46,23 @@ LABEL org.opencontainers.image.url="https://github.com/paperless-ngx/paperless-n
|
||||
LABEL org.opencontainers.image.licenses="GPL-3.0-only"
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
# Buildx provided
|
||||
# Buildx provided, must be defined to use though
|
||||
ARG TARGETARCH
|
||||
ARG TARGETVARIANT
|
||||
|
||||
# Workflow provided
|
||||
ARG JBIG2ENC_VERSION
|
||||
ARG QPDF_VERSION
|
||||
ARG PIKEPDF_VERSION
|
||||
ARG PSYCOPG2_VERSION
|
||||
|
||||
#
|
||||
# Begin installation and configuration
|
||||
# Order the steps below from least often changed to most
|
||||
#
|
||||
|
||||
# copy jbig2enc
|
||||
# Basically will never change again
|
||||
COPY --from=jbig2enc-builder /usr/src/jbig2enc/src/.libs/libjbig2enc* /usr/local/lib/
|
||||
COPY --from=jbig2enc-builder /usr/src/jbig2enc/src/jbig2 /usr/local/bin/
|
||||
COPY --from=jbig2enc-builder /usr/src/jbig2enc/src/*.h /usr/local/include/
|
||||
|
||||
# Packages need for running
|
||||
ARG RUNTIME_PACKAGES="\
|
||||
# Python
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3-setuptools \
|
||||
# General utils
|
||||
curl \
|
||||
# Docker specific
|
||||
@@ -145,7 +126,7 @@ RUN set -eux \
|
||||
&& apt-get install --yes --quiet --no-install-recommends ${RUNTIME_PACKAGES} \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& echo "Installing supervisor" \
|
||||
&& python3 -m pip install --default-timeout=1000 --upgrade --no-cache-dir supervisor==4.2.4
|
||||
&& python3 -m pip install --default-timeout=1000 --upgrade --no-cache-dir supervisor==4.2.5
|
||||
|
||||
# Copy gunicorn config
|
||||
# Changes very infrequently
|
||||
@@ -154,7 +135,6 @@ WORKDIR /usr/src/paperless/
|
||||
COPY gunicorn.conf.py .
|
||||
|
||||
# setup docker-specific things
|
||||
# Use mounts to avoid copying installer files into the image
|
||||
# These change sometimes, but rarely
|
||||
WORKDIR /usr/src/paperless/src/docker/
|
||||
|
||||
@@ -165,6 +145,7 @@ COPY [ \
|
||||
"docker/docker-prepare.sh", \
|
||||
"docker/paperless_cmd.sh", \
|
||||
"docker/wait-for-redis.py", \
|
||||
"docker/env-from-file.sh", \
|
||||
"docker/management_script.sh", \
|
||||
"docker/flower-conditional.sh", \
|
||||
"docker/install_management_commands.sh", \
|
||||
@@ -184,6 +165,8 @@ RUN set -eux \
|
||||
&& chmod 755 /sbin/docker-prepare.sh \
|
||||
&& mv wait-for-redis.py /sbin/wait-for-redis.py \
|
||||
&& chmod 755 /sbin/wait-for-redis.py \
|
||||
&& mv env-from-file.sh /sbin/env-from-file.sh \
|
||||
&& chmod 755 /sbin/env-from-file.sh \
|
||||
&& mv paperless_cmd.sh /usr/local/bin/paperless_cmd.sh \
|
||||
&& chmod 755 /usr/local/bin/paperless_cmd.sh \
|
||||
&& mv flower-conditional.sh /usr/local/bin/flower-conditional.sh \
|
||||
@@ -193,21 +176,31 @@ RUN set -eux \
|
||||
&& ./install_management_commands.sh
|
||||
|
||||
# Install the built packages from the installer library images
|
||||
# Use mounts to avoid copying installer files into the image
|
||||
# These change sometimes
|
||||
RUN --mount=type=bind,from=qpdf-builder,target=/qpdf \
|
||||
--mount=type=bind,from=psycopg2-builder,target=/psycopg2 \
|
||||
--mount=type=bind,from=pikepdf-builder,target=/pikepdf \
|
||||
set -eux \
|
||||
RUN set -eux \
|
||||
&& echo "Getting binaries" \
|
||||
&& mkdir paperless-ngx \
|
||||
&& curl --fail --silent --show-error --output paperless-ngx.tar.gz --location https://github.com/paperless-ngx/paperless-ngx/archive/41d6e7e407af09a0882736d50c89b6e015997bff.tar.gz \
|
||||
&& tar -xf paperless-ngx.tar.gz --directory paperless-ngx --strip-components=1 \
|
||||
&& cd paperless-ngx \
|
||||
# Setting a specific revision ensures we know what this installed
|
||||
# and ensures cache breaking on changes
|
||||
&& echo "Installing jbig2enc" \
|
||||
&& cp ./jbig2enc/${JBIG2ENC_VERSION}/${TARGETARCH}${TARGETVARIANT}/jbig2 /usr/local/bin/ \
|
||||
&& cp ./jbig2enc/${JBIG2ENC_VERSION}/${TARGETARCH}${TARGETVARIANT}/libjbig2enc* /usr/local/lib/ \
|
||||
&& echo "Installing qpdf" \
|
||||
&& apt-get install --yes --no-install-recommends /qpdf/usr/src/qpdf/${QPDF_VERSION}/${TARGETARCH}${TARGETVARIANT}/libqpdf29_*.deb \
|
||||
&& apt-get install --yes --no-install-recommends /qpdf/usr/src/qpdf/${QPDF_VERSION}/${TARGETARCH}${TARGETVARIANT}/qpdf_*.deb \
|
||||
&& apt-get install --yes --no-install-recommends ./qpdf/${QPDF_VERSION}/${TARGETARCH}${TARGETVARIANT}/libqpdf29_*.deb \
|
||||
&& apt-get install --yes --no-install-recommends ./qpdf/${QPDF_VERSION}/${TARGETARCH}${TARGETVARIANT}/qpdf_*.deb \
|
||||
&& echo "Installing pikepdf and dependencies" \
|
||||
&& python3 -m pip install --no-cache-dir /pikepdf/usr/src/wheels/*.whl \
|
||||
&& python3 -m pip install --no-cache-dir ./pikepdf/${PIKEPDF_VERSION}/${TARGETARCH}${TARGETVARIANT}/*.whl \
|
||||
&& python3 -m pip list \
|
||||
&& echo "Installing psycopg2" \
|
||||
&& python3 -m pip install --no-cache-dir /psycopg2/usr/src/wheels/psycopg2*.whl \
|
||||
&& python3 -m pip list
|
||||
&& python3 -m pip install --no-cache-dir ./psycopg2/${PSYCOPG2_VERSION}/${TARGETARCH}${TARGETVARIANT}/psycopg2*.whl \
|
||||
&& python3 -m pip list \
|
||||
&& echo "Cleaning up image layer" \
|
||||
&& cd ../ \
|
||||
&& rm -rf paperless-ngx \
|
||||
&& rm paperless-ngx.tar.gz
|
||||
|
||||
WORKDIR /usr/src/paperless/src/
|
||||
|
||||
@@ -231,9 +224,9 @@ RUN set -eux \
|
||||
&& echo "Installing Python requirements" \
|
||||
&& python3 -m pip install --default-timeout=1000 --no-cache-dir --requirement requirements.txt \
|
||||
&& echo "Installing NLTK data" \
|
||||
&& python3 -W ignore::RuntimeWarning -m nltk.downloader -d "/usr/local/share/nltk_data" snowball_data \
|
||||
&& python3 -W ignore::RuntimeWarning -m nltk.downloader -d "/usr/local/share/nltk_data" stopwords \
|
||||
&& python3 -W ignore::RuntimeWarning -m nltk.downloader -d "/usr/local/share/nltk_data" punkt \
|
||||
&& python3 -W ignore::RuntimeWarning -m nltk.downloader -d "/usr/share/nltk_data" snowball_data \
|
||||
&& python3 -W ignore::RuntimeWarning -m nltk.downloader -d "/usr/share/nltk_data" stopwords \
|
||||
&& python3 -W ignore::RuntimeWarning -m nltk.downloader -d "/usr/share/nltk_data" punkt \
|
||||
&& echo "Cleaning up image" \
|
||||
&& apt-get -y purge ${BUILD_PACKAGES} \
|
||||
&& apt-get -y autoremove --purge \
|
||||
@@ -251,11 +244,12 @@ COPY ./src ./
|
||||
COPY --from=compile-frontend /src/src/documents/static/frontend/ ./documents/static/frontend/
|
||||
|
||||
# add users, setup scripts
|
||||
# Mount the compiled frontend to expected location
|
||||
RUN set -eux \
|
||||
&& addgroup --gid 1000 paperless \
|
||||
&& useradd --uid 1000 --gid paperless --home-dir /usr/src/paperless paperless \
|
||||
&& chown -R paperless:paperless ../ \
|
||||
&& gosu paperless python3 manage.py collectstatic --clear --no-input \
|
||||
&& chown -R paperless:paperless /usr/src/paperless \
|
||||
&& gosu paperless python3 manage.py collectstatic --clear --no-input --link \
|
||||
&& gosu paperless python3 manage.py compilemessages
|
||||
|
||||
VOLUME ["/usr/src/paperless/data", \
|
||||
|
13
Pipfile
13
Pipfile
@@ -12,6 +12,7 @@ name = "piwheels"
|
||||
dateparser = "~=1.1"
|
||||
django = "~=4.1"
|
||||
django-cors-headers = "*"
|
||||
django-compression-middleware = "*"
|
||||
django-extensions = "*"
|
||||
django-filter = "~=22.1"
|
||||
djangorestframework = "~=3.14"
|
||||
@@ -44,9 +45,6 @@ channels = "~=3.0"
|
||||
uvicorn = {extras = ["standard"], version = "*"}
|
||||
concurrent-log-handler = "*"
|
||||
"pdfminer.six" = "*"
|
||||
"backports.zoneinfo" = {version = "*", markers = "python_version < '3.9'"}
|
||||
"importlib-resources" = {version = "*", markers = "python_version < '3.9'"}
|
||||
zipp = {version = "*", markers = "python_version < '3.9'"}
|
||||
pyzbar = "*"
|
||||
mysqlclient = "*"
|
||||
celery = {extras = ["redis"], version = "*"}
|
||||
@@ -56,35 +54,28 @@ nltk = "*"
|
||||
pdf2image = "*"
|
||||
flower = "*"
|
||||
bleach = "*"
|
||||
|
||||
#
|
||||
# Packages locked due to issues (try to check if these are fixed in a release every so often)
|
||||
#
|
||||
|
||||
# Pin this until piwheels is building 1.9 (see https://www.piwheels.org/project/scipy/)
|
||||
scipy = "==1.8.1"
|
||||
|
||||
# Newer versions aren't builting yet (see https://www.piwheels.org/project/cryptography/)
|
||||
cryptography = "==38.0.1"
|
||||
|
||||
# Locked version until https://github.com/django/channels_redis/issues/332
|
||||
# is resolved
|
||||
channels-redis = "==3.4.1"
|
||||
|
||||
|
||||
[dev-packages]
|
||||
coveralls = "*"
|
||||
factory-boy = "*"
|
||||
pycodestyle = "*"
|
||||
pytest = "*"
|
||||
pytest-cov = "*"
|
||||
pytest-django = "*"
|
||||
pytest-env = "*"
|
||||
pytest-sugar = "*"
|
||||
pytest-xdist = "*"
|
||||
tox = "*"
|
||||
black = "*"
|
||||
pre-commit = "*"
|
||||
sphinx-autobuild = "*"
|
||||
myst-parser = "*"
|
||||
imagehash = "*"
|
||||
mkdocs-material = "*"
|
||||
|
1157
Pipfile.lock
generated
1157
Pipfile.lock
generated
File diff suppressed because it is too large
Load Diff
11
README.md
11
README.md
@@ -1,7 +1,7 @@
|
||||
[](https://github.com/paperless-ngx/paperless-ngx/actions)
|
||||
[](https://crowdin.com/project/paperless-ngx)
|
||||
[](https://docs.paperless-ngx.com)
|
||||
[](https://coveralls.io/github/paperless-ngx/paperless-ngx?branch=master)
|
||||
[](https://codecov.io/gh/paperless-ngx/paperless-ngx)
|
||||
[](https://matrix.to/#/%23paperlessngx%3Amatrix.org)
|
||||
[](https://demo.paperless-ngx.com)
|
||||
|
||||
@@ -108,15 +108,6 @@ Paperless has been around a while now, and people are starting to build stuff on
|
||||
- [Scan to Paperless](https://github.com/sbrunner/scan-to-paperless): Scan and prepare (crop, deskew, OCR, ...) your documents for Paperless.
|
||||
- [Paperless Mobile](https://github.com/astubenbord/paperless-mobile): A modern, feature rich mobile application for Paperless.
|
||||
|
||||
These projects also exist, but their status and compatibility with paperless-ngx is unknown.
|
||||
|
||||
- [paperless-cli](https://github.com/stgarf/paperless-cli): A golang command line binary to interact with a Paperless instance.
|
||||
|
||||
This project also exists, but needs updates to be compatible with paperless-ngx.
|
||||
|
||||
- [Paperless Desktop](https://github.com/thomasbrueggemann/paperless-desktop): A desktop UI for your Paperless installation. Runs on Mac, Linux, and Windows.
|
||||
Known issues on Mac: (Could not load reminders and documents)
|
||||
|
||||
# Important Note
|
||||
|
||||
Document scanners are typically used to scan sensitive documents. Things like your social insurance number, tax records, invoices, etc. Everything is stored in the clear without encryption. This means that Paperless should never be run on an untrusted host. Instead, I recommend that if you do want to use it, run it locally on a server in your own home.
|
||||
|
@@ -24,12 +24,12 @@ fi
|
||||
branch_name=$(git rev-parse --abbrev-ref HEAD)
|
||||
|
||||
# Parse eithe Pipfile.lock or the .build-config.json
|
||||
jbig2enc_version=$(jq ".jbig2enc.version" .build-config.json | sed 's/"//g')
|
||||
qpdf_version=$(jq ".qpdf.version" .build-config.json | sed 's/"//g')
|
||||
psycopg2_version=$(jq ".default.psycopg2.version" Pipfile.lock | sed 's/=//g' | sed 's/"//g')
|
||||
pikepdf_version=$(jq ".default.pikepdf.version" Pipfile.lock | sed 's/=//g' | sed 's/"//g')
|
||||
pillow_version=$(jq ".default.pillow.version" Pipfile.lock | sed 's/=//g' | sed 's/"//g')
|
||||
lxml_version=$(jq ".default.lxml.version" Pipfile.lock | sed 's/=//g' | sed 's/"//g')
|
||||
jbig2enc_version=$(jq -r '.jbig2enc.version' .build-config.json)
|
||||
qpdf_version=$(jq -r '.qpdf.version' .build-config.json)
|
||||
psycopg2_version=$(jq -r '.default.psycopg2.version | gsub("=";"")' Pipfile.lock)
|
||||
pikepdf_version=$(jq -r '.default.pikepdf.version | gsub("=";"")' Pipfile.lock)
|
||||
pillow_version=$(jq -r '.default.pillow.version | gsub("=";"")' Pipfile.lock)
|
||||
lxml_version=$(jq -r '.default.lxml.version | gsub("=";"")' Pipfile.lock)
|
||||
|
||||
base_filename="$(basename -- "${1}")"
|
||||
build_args_str=""
|
||||
|
@@ -1,26 +0,0 @@
|
||||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
# OWNERS file for Kubernetes
|
||||
OWNERS
|
||||
# helm-docs templates
|
||||
*.gotmpl
|
@@ -1,35 +0,0 @@
|
||||
---
|
||||
apiVersion: v2
|
||||
appVersion: "1.9.2"
|
||||
description: Paperless-ngx - Index and archive all of your scanned paper documents
|
||||
name: paperless
|
||||
version: 10.0.1
|
||||
kubeVersion: ">=1.16.0-0"
|
||||
keywords:
|
||||
- paperless
|
||||
- paperless-ngx
|
||||
- dms
|
||||
- document
|
||||
home: https://github.com/paperless-ngx/paperless-ngx/tree/main/charts/paperless-ngx
|
||||
icon: https://github.com/paperless-ngx/paperless-ngx/raw/main/resources/logo/web/svg/square.svg
|
||||
sources:
|
||||
- https://github.com/paperless-ngx/paperless-ngx
|
||||
maintainers:
|
||||
- name: Paperless-ngx maintainers
|
||||
dependencies:
|
||||
- name: common
|
||||
repository: https://library-charts.k8s-at-home.com
|
||||
version: 4.5.2
|
||||
- name: postgresql
|
||||
version: 11.6.12
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
condition: postgresql.enabled
|
||||
- name: redis
|
||||
version: 16.13.1
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
condition: redis.enabled
|
||||
deprecated: false
|
||||
annotations:
|
||||
artifacthub.io/changes: |
|
||||
- kind: changed
|
||||
description: Moved to Paperless-ngx ownership
|
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2020 k8s@Home
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
@@ -1,50 +0,0 @@
|
||||
# paperless
|
||||
|
||||
 
|
||||
|
||||
Paperless-ngx - Index and archive all of your scanned paper documents
|
||||
|
||||
**Homepage:** <https://github.com/paperless-ngx/paperless-ngx/tree/main/charts/paperless-ngx>
|
||||
|
||||
## Maintainers
|
||||
|
||||
| Name | Email | Url |
|
||||
| ---- | ------ | --- |
|
||||
| Paperless-ngx maintainers | | |
|
||||
|
||||
## Source Code
|
||||
|
||||
* <https://github.com/paperless-ngx/paperless-ngx>
|
||||
|
||||
## Requirements
|
||||
|
||||
Kubernetes: `>=1.16.0-0`
|
||||
|
||||
| Repository | Name | Version |
|
||||
|------------|------|---------|
|
||||
| https://charts.bitnami.com/bitnami | postgresql | 11.6.12 |
|
||||
| https://charts.bitnami.com/bitnami | redis | 16.13.1 |
|
||||
| https://library-charts.k8s-at-home.com | common | 4.5.2 |
|
||||
|
||||
## Values
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|-----|------|---------|-------------|
|
||||
| env | object | See below | See the following files for additional environment variables: https://github.com/paperless-ngx/paperless-ngx/tree/main/docker/compose/ https://github.com/paperless-ngx/paperless-ngx/blob/main/paperless.conf.example |
|
||||
| env.COMPOSE_PROJECT_NAME | string | `"paperless"` | Project name |
|
||||
| env.PAPERLESS_DBHOST | string | `nil` | Database host to use |
|
||||
| env.PAPERLESS_OCR_LANGUAGE | string | `"eng"` | OCR languages to install |
|
||||
| env.PAPERLESS_PORT | int | `8000` | Port to use |
|
||||
| env.PAPERLESS_REDIS | string | `nil` | Redis to use |
|
||||
| image.pullPolicy | string | `"IfNotPresent"` | image pull policy |
|
||||
| image.repository | string | `"ghcr.io/paperless-ngx/paperless-ngx"` | image repository |
|
||||
| image.tag | string | chart.appVersion | image tag |
|
||||
| ingress.main | object | See values.yaml | Enable and configure ingress settings for the chart under this key. |
|
||||
| persistence.consume | object | See values.yaml | Configure volume to monitor for new documents. |
|
||||
| persistence.data | object | See values.yaml | Configure persistence for data. |
|
||||
| persistence.export | object | See values.yaml | Configure export volume. |
|
||||
| persistence.media | object | See values.yaml | Configure persistence for media. |
|
||||
| postgresql | object | See values.yaml | Enable and configure postgresql database subchart under this key. For more options see [postgresql chart documentation](https://github.com/bitnami/charts/tree/master/bitnami/postgresql) |
|
||||
| redis | object | See values.yaml | Enable and configure redis subchart under this key. For more options see [redis chart documentation](https://github.com/bitnami/charts/tree/master/bitnami/redis) |
|
||||
| service | object | See values.yaml | Configures service settings for the chart. |
|
||||
|
@@ -1,8 +0,0 @@
|
||||
{{- define "custom.custom.configuration.header" -}}
|
||||
## Custom configuration
|
||||
{{- end -}}
|
||||
|
||||
{{- define "custom.custom.configuration" -}}
|
||||
{{ template "custom.custom.configuration.header" . }}
|
||||
N/A
|
||||
{{- end -}}
|
@@ -1,26 +0,0 @@
|
||||
env:
|
||||
PAPERLESS_REDIS: redis://paperless-redis-headless:6379
|
||||
|
||||
persistence:
|
||||
data:
|
||||
enabled: true
|
||||
type: emptyDir
|
||||
media:
|
||||
enabled: true
|
||||
type: emptyDir
|
||||
consume:
|
||||
enabled: true
|
||||
type: emptyDir
|
||||
export:
|
||||
enabled: true
|
||||
type: emptyDir
|
||||
|
||||
redis:
|
||||
enabled: true
|
||||
architecture: standalone
|
||||
auth:
|
||||
enabled: false
|
||||
master:
|
||||
persistence:
|
||||
enabled: false
|
||||
fullnameOverride: paperless-redis
|
@@ -1,4 +0,0 @@
|
||||
{{- include "common.notes.defaultNotes" . }}
|
||||
2. Create a super user by running the command:
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "common.names.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
kubectl exec -it --namespace {{ .Release.Namespace }} $POD_NAME -- bash -c "python manage.py createsuperuser"
|
@@ -1,11 +0,0 @@
|
||||
{{/* Make sure all variables are set properly */}}
|
||||
{{- include "common.values.setup" . }}
|
||||
|
||||
{{/* Append the hardcoded settings */}}
|
||||
{{- define "paperless.harcodedValues" -}}
|
||||
env:
|
||||
PAPERLESS_URL: http{{if ne ( len .Values.ingress.main.tls ) 0 }}s{{end}}://{{ (first .Values.ingress.main.hosts).host }}
|
||||
{{- end -}}
|
||||
{{- $_ := merge .Values (include "paperless.harcodedValues" . | fromYaml) -}}
|
||||
|
||||
{{ include "common.all" . }}
|
@@ -1,107 +0,0 @@
|
||||
#
|
||||
# IMPORTANT NOTE
|
||||
#
|
||||
# This chart inherits from our common library chart. You can check the default values/options here:
|
||||
# https://github.com/k8s-at-home/library-charts/tree/main/charts/stable/common/values.yaml
|
||||
#
|
||||
|
||||
image:
|
||||
# -- image repository
|
||||
repository: ghcr.io/paperless-ngx/paperless-ngx
|
||||
# -- image pull policy
|
||||
pullPolicy: IfNotPresent
|
||||
# -- image tag
|
||||
# @default -- chart.appVersion
|
||||
tag:
|
||||
|
||||
# -- See the following files for additional environment variables:
|
||||
# https://github.com/paperless-ngx/paperless-ngx/tree/main/docker/compose/
|
||||
# https://github.com/paperless-ngx/paperless-ngx/blob/main/paperless.conf.example
|
||||
# @default -- See below
|
||||
env:
|
||||
# -- Project name
|
||||
COMPOSE_PROJECT_NAME: paperless
|
||||
# -- Redis to use
|
||||
PAPERLESS_REDIS:
|
||||
# -- OCR languages to install
|
||||
PAPERLESS_OCR_LANGUAGE: eng
|
||||
# USERMAP_UID: 1000
|
||||
# USERMAP_GID: 1000
|
||||
# PAPERLESS_TIME_ZONE: Europe/London
|
||||
# -- Database host to use
|
||||
PAPERLESS_DBHOST:
|
||||
# -- Port to use
|
||||
PAPERLESS_PORT: 8000
|
||||
# -- Username for the root user
|
||||
# PAPERLESS_ADMIN_USER: admin
|
||||
# -- Password for the root user
|
||||
# PAPERLESS_ADMIN_PASSWORD: admin
|
||||
# PAPERLESS_URL: <set to main ingress by default>
|
||||
|
||||
# -- Configures service settings for the chart.
|
||||
# @default -- See values.yaml
|
||||
service:
|
||||
main:
|
||||
ports:
|
||||
http:
|
||||
port: 8000
|
||||
|
||||
ingress:
|
||||
# -- Enable and configure ingress settings for the chart under this key.
|
||||
# @default -- See values.yaml
|
||||
main:
|
||||
enabled: false
|
||||
|
||||
persistence:
|
||||
# -- Configure persistence for data.
|
||||
# @default -- See values.yaml
|
||||
data:
|
||||
enabled: false
|
||||
mountPath: /usr/src/paperless/data
|
||||
accessMode: ReadWriteOnce
|
||||
emptyDir:
|
||||
enabled: false
|
||||
# -- Configure persistence for media.
|
||||
# @default -- See values.yaml
|
||||
media:
|
||||
enabled: false
|
||||
mountPath: /usr/src/paperless/media
|
||||
accessMode: ReadWriteOnce
|
||||
emptyDir:
|
||||
enabled: false
|
||||
# -- Configure volume to monitor for new documents.
|
||||
# @default -- See values.yaml
|
||||
consume:
|
||||
enabled: false
|
||||
mountPath: /usr/src/paperless/consume
|
||||
accessMode: ReadWriteOnce
|
||||
emptyDir:
|
||||
enabled: false
|
||||
# -- Configure export volume.
|
||||
# @default -- See values.yaml
|
||||
export:
|
||||
enabled: false
|
||||
mountPath: /usr/src/paperless/export
|
||||
accessMode: ReadWriteOnce
|
||||
emptyDir:
|
||||
enabled: false
|
||||
|
||||
# -- Enable and configure postgresql database subchart under this key.
|
||||
# For more options see [postgresql chart documentation](https://github.com/bitnami/charts/tree/master/bitnami/postgresql)
|
||||
# @default -- See values.yaml
|
||||
postgresql:
|
||||
enabled: false
|
||||
postgresqlUsername: paperless
|
||||
postgresqlPassword: paperless
|
||||
postgresqlDatabase: paperless
|
||||
persistence:
|
||||
enabled: false
|
||||
# storageClass: ""
|
||||
|
||||
# -- Enable and configure redis subchart under this key.
|
||||
# For more options see [redis chart documentation](https://github.com/bitnami/charts/tree/master/bitnami/redis)
|
||||
# @default -- See values.yaml
|
||||
redis:
|
||||
enabled: false
|
||||
auth:
|
||||
enabled: false
|
@@ -29,7 +29,20 @@ RUN set -eux \
|
||||
&& ./autogen.sh \
|
||||
&& ./configure \
|
||||
&& make \
|
||||
&& echo "Gathering package data" \
|
||||
&& dpkg-query -f '${Package;-40}${Version}\n' -W > ./pkg-list.txt \
|
||||
&& echo "Cleaning up image" \
|
||||
&& apt-get -y purge ${BUILD_PACKAGES} \
|
||||
&& apt-get -y autoremove --purge \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& echo "Moving files around" \
|
||||
&& mkdir build \
|
||||
# Unlink a symlink that causes problems
|
||||
&& unlink ./src/.libs/libjbig2enc.la \
|
||||
# Move what the link pointed to
|
||||
&& mv ./src/libjbig2enc.la ./build/ \
|
||||
# Move the shared library .so files
|
||||
&& mv ./src/.libs/libjbig2enc* ./build/ \
|
||||
# And move the cli binary
|
||||
&& mv ./src/jbig2 ./build/ \
|
||||
&& mv ./pkg-list.txt ./build/
|
||||
|
@@ -7,12 +7,17 @@
|
||||
# Default to pulling from the main repo registry when manually building
|
||||
ARG REPO="paperless-ngx/paperless-ngx"
|
||||
|
||||
ARG QPDF_VERSION
|
||||
FROM ghcr.io/${REPO}/builder/qpdf:${QPDF_VERSION} as qpdf-builder
|
||||
|
||||
# This does nothing, except provide a name for a copy below
|
||||
ARG QPDF_VERSION
|
||||
FROM --platform=$BUILDPLATFORM ghcr.io/${REPO}/builder/qpdf:${QPDF_VERSION} as qpdf-builder
|
||||
|
||||
FROM python:3.9-slim-bullseye as main
|
||||
#
|
||||
# Stage: builder
|
||||
# Purpose:
|
||||
# - Build the pikepdf wheel
|
||||
# - Build any dependent wheels which can't be found
|
||||
#
|
||||
FROM python:3.9-slim-bullseye as builder
|
||||
|
||||
LABEL org.opencontainers.image.description="A intermediate image with pikepdf wheel built"
|
||||
|
||||
@@ -100,3 +105,14 @@ RUN set -eux \
|
||||
&& apt-get -y purge ${BUILD_PACKAGES} \
|
||||
&& apt-get -y autoremove --purge \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
#
|
||||
# Stage: package
|
||||
# Purpose: Holds the compiled .whl files in a tiny image to pull
|
||||
#
|
||||
FROM alpine:3.17 as package
|
||||
|
||||
WORKDIR /usr/src/wheels/
|
||||
|
||||
COPY --from=builder /usr/src/wheels/*.whl ./
|
||||
COPY --from=builder /usr/src/wheels/pkg-list.txt ./
|
||||
|
@@ -2,7 +2,12 @@
|
||||
# Inputs:
|
||||
# - PSYCOPG2_VERSION - Version to build
|
||||
|
||||
FROM python:3.9-slim-bullseye as main
|
||||
#
|
||||
# Stage: builder
|
||||
# Purpose:
|
||||
# - Build the psycopg2 wheel
|
||||
#
|
||||
FROM python:3.9-slim-bullseye as builder
|
||||
|
||||
LABEL org.opencontainers.image.description="A intermediate image with psycopg2 wheel built"
|
||||
|
||||
@@ -48,3 +53,14 @@ RUN set -eux \
|
||||
&& apt-get -y purge ${BUILD_PACKAGES} \
|
||||
&& apt-get -y autoremove --purge \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
#
|
||||
# Stage: package
|
||||
# Purpose: Holds the compiled .whl files in a tiny image to pull
|
||||
#
|
||||
FROM alpine:3.17 as package
|
||||
|
||||
WORKDIR /usr/src/wheels/
|
||||
|
||||
COPY --from=builder /usr/src/wheels/*.whl ./
|
||||
COPY --from=builder /usr/src/wheels/pkg-list.txt ./
|
||||
|
57
docker-builders/README.md
Normal file
57
docker-builders/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Installer Library
|
||||
|
||||
This folder contains the Dockerfiles for building certain installers or libraries, which are then pulled into the main image.
|
||||
|
||||
## [jbig2enc](https://github.com/agl/jbig2enc)
|
||||
|
||||
### Why
|
||||
|
||||
JBIG is an image coding which can achieve better compression of images for PDFs.
|
||||
|
||||
### What
|
||||
|
||||
The Docker image builds a shared library file and utility, which is copied into the correct location in the final image.
|
||||
|
||||
### Updating
|
||||
|
||||
1. Ensure the given qpdf version is present in [Debian bookworm](https://packages.debian.org/bookworm/qpdf)
|
||||
2. Update `.build-config.json` to the given version
|
||||
3. If the Debian specific version has incremented, update `Dockerfile.qpdf`
|
||||
|
||||
See Also:
|
||||
|
||||
- [OCRMyPDF Documentation](https://ocrmypdf.readthedocs.io/en/latest/jbig2.html)
|
||||
|
||||
## [psycopg2](https://www.psycopg.org/)
|
||||
|
||||
### Why
|
||||
|
||||
The pre-built wheels of psycopg2 are built on Debian 9, which provides a quite old version of libpq-dev. This causes issue with authentication methods.
|
||||
|
||||
### What
|
||||
|
||||
The image builds psycopg2 wheels on Debian 10 and places the produced wheels into `/usr/src/wheels/`.
|
||||
|
||||
See Also:
|
||||
|
||||
- [Issue 266](https://github.com/paperless-ngx/paperless-ngx/issues/266)
|
||||
|
||||
## [qpdf](https://qpdf.readthedocs.io/en/stable/index.html)
|
||||
|
||||
### Why
|
||||
|
||||
qpdf and it's library provide tools to read, manipulate and fix up PDFs. Version 11 is also required by `pikepdf` 6+ and Debian 9 does not provide above version 10.
|
||||
|
||||
### What
|
||||
|
||||
The Docker image cross compiles .deb installers for each supported architecture of the main image. The installers are placed in `/usr/src/qpdf/${QPDF_VERSION}/${TARGETARCH}${TARGETVARIANT}/`
|
||||
|
||||
## [pikepdf](https://pikepdf.readthedocs.io/en/latest/)
|
||||
|
||||
### Why
|
||||
|
||||
Required by OCRMyPdf, this is a general purpose library for PDF manipulation in Python via the qpdf libraries.
|
||||
|
||||
### What
|
||||
|
||||
The built wheels are placed into `/usr/src/wheels/`
|
@@ -6,7 +6,7 @@
|
||||
version: "3.7"
|
||||
services:
|
||||
gotenberg:
|
||||
image: docker.io/gotenberg/gotenberg:7.6
|
||||
image: docker.io/gotenberg/gotenberg:7.8
|
||||
hostname: gotenberg
|
||||
container_name: gotenberg
|
||||
network_mode: host
|
||||
|
@@ -59,7 +59,7 @@ services:
|
||||
- gotenberg
|
||||
- tika
|
||||
ports:
|
||||
- 8000:8000
|
||||
- "8000:8000"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8000"]
|
||||
interval: 30s
|
||||
@@ -83,7 +83,7 @@ services:
|
||||
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
|
||||
|
||||
gotenberg:
|
||||
image: docker.io/gotenberg/gotenberg:7.6
|
||||
image: docker.io/gotenberg/gotenberg:7.8
|
||||
restart: unless-stopped
|
||||
# The gotenberg chromium route is used to convert .eml files. We do not
|
||||
# want to allow external content like tracking pixels or even javascript.
|
||||
|
@@ -53,7 +53,7 @@ services:
|
||||
- db
|
||||
- broker
|
||||
ports:
|
||||
- 8000:8000
|
||||
- "8000:8000"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8000"]
|
||||
interval: 30s
|
||||
|
@@ -53,7 +53,7 @@ services:
|
||||
- db
|
||||
- broker
|
||||
ports:
|
||||
- 8010:8000
|
||||
- "8010:8000"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fs", "-S", "--max-time", "2", "http://localhost:8000"]
|
||||
interval: 30s
|
||||
|
@@ -57,7 +57,7 @@ services:
|
||||
- gotenberg
|
||||
- tika
|
||||
ports:
|
||||
- 8000:8000
|
||||
- "8000:8000"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fs", "-S", "--max-time", "2", "http://localhost:8000"]
|
||||
interval: 30s
|
||||
@@ -77,7 +77,7 @@ services:
|
||||
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
|
||||
|
||||
gotenberg:
|
||||
image: docker.io/gotenberg/gotenberg:7.6
|
||||
image: docker.io/gotenberg/gotenberg:7.8
|
||||
restart: unless-stopped
|
||||
|
||||
# The gotenberg chromium route is used to convert .eml files. We do not
|
||||
|
@@ -51,7 +51,7 @@ services:
|
||||
- db
|
||||
- broker
|
||||
ports:
|
||||
- 8000:8000
|
||||
- "8000:8000"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fs", "-S", "--max-time", "2", "http://localhost:8000"]
|
||||
interval: 30s
|
||||
|
@@ -46,7 +46,7 @@ services:
|
||||
- gotenberg
|
||||
- tika
|
||||
ports:
|
||||
- 8000:8000
|
||||
- "8000:8000"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fs", "-S", "--max-time", "2", "http://localhost:8000"]
|
||||
interval: 30s
|
||||
@@ -65,7 +65,7 @@ services:
|
||||
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
|
||||
|
||||
gotenberg:
|
||||
image: docker.io/gotenberg/gotenberg:7.6
|
||||
image: docker.io/gotenberg/gotenberg:7.8
|
||||
restart: unless-stopped
|
||||
|
||||
# The gotenberg chromium route is used to convert .eml files. We do not
|
||||
|
@@ -37,7 +37,7 @@ services:
|
||||
depends_on:
|
||||
- broker
|
||||
ports:
|
||||
- 8000:8000
|
||||
- "8000:8000"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fs", "-S", "--max-time", "2", "http://localhost:8000"]
|
||||
interval: 30s
|
||||
|
@@ -2,37 +2,6 @@
|
||||
|
||||
set -e
|
||||
|
||||
# Adapted from:
|
||||
# https://github.com/docker-library/postgres/blob/master/docker-entrypoint.sh
|
||||
# usage: file_env VAR
|
||||
# ie: file_env 'XYZ_DB_PASSWORD' will allow for "$XYZ_DB_PASSWORD_FILE" to
|
||||
# fill in the value of "$XYZ_DB_PASSWORD" from a file, especially for Docker's
|
||||
# secrets feature
|
||||
file_env() {
|
||||
local -r var="$1"
|
||||
local -r fileVar="${var}_FILE"
|
||||
|
||||
# Basic validation
|
||||
if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
|
||||
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Only export var if the _FILE exists
|
||||
if [ "${!fileVar:-}" ]; then
|
||||
# And the file exists
|
||||
if [[ -f ${!fileVar} ]]; then
|
||||
echo "Setting ${var} from file"
|
||||
val="$(< "${!fileVar}")"
|
||||
export "$var"="$val"
|
||||
else
|
||||
echo "File ${!fileVar} doesn't exist"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
# Source: https://github.com/sameersbn/docker-gitlab/
|
||||
map_uidgid() {
|
||||
local -r usermap_original_uid=$(id -u paperless)
|
||||
@@ -96,19 +65,11 @@ custom_container_init() {
|
||||
initialize() {
|
||||
|
||||
# Setup environment from secrets before anything else
|
||||
for env_var in \
|
||||
PAPERLESS_DBUSER \
|
||||
PAPERLESS_DBPASS \
|
||||
PAPERLESS_SECRET_KEY \
|
||||
PAPERLESS_AUTO_LOGIN_USERNAME \
|
||||
PAPERLESS_ADMIN_USER \
|
||||
PAPERLESS_ADMIN_MAIL \
|
||||
PAPERLESS_ADMIN_PASSWORD \
|
||||
PAPERLESS_REDIS; do
|
||||
# Check for a version of this var with _FILE appended
|
||||
# and convert the contents to the env var value
|
||||
file_env ${env_var}
|
||||
done
|
||||
# Check for a version of this var with _FILE appended
|
||||
# and convert the contents to the env var value
|
||||
# Source it so export is persistent
|
||||
# shellcheck disable=SC1091
|
||||
source /sbin/env-from-file.sh
|
||||
|
||||
# Change the user and group IDs if needed
|
||||
map_uidgid
|
||||
|
@@ -80,7 +80,7 @@ django_checks() {
|
||||
|
||||
search_index() {
|
||||
|
||||
local -r index_version=1
|
||||
local -r index_version=3
|
||||
local -r index_version_file=${DATA_DIR}/.index_version
|
||||
|
||||
if [[ (! -f "${index_version_file}") || $(<"${index_version_file}") != "$index_version" ]]; then
|
||||
|
38
docker/env-from-file.sh
Normal file
38
docker/env-from-file.sh
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Scans the environment variables for those with the suffix _FILE
|
||||
# When located, checks the file exists, and exports the contents
|
||||
# of the file as the same name, minus the suffix
|
||||
# This allows the use of Docker secrets or mounted files
|
||||
# to fill in any of the settings configurable via environment
|
||||
# variables
|
||||
|
||||
set -eu
|
||||
|
||||
for line in $(printenv)
|
||||
do
|
||||
# Extract the name of the environment variable
|
||||
env_name=${line%%=*}
|
||||
# Check if it starts with "PAPERLESS_" and ends in "_FILE"
|
||||
if [[ ${env_name} == PAPERLESS_*_FILE ]]; then
|
||||
# Extract the value of the environment
|
||||
env_value=${line#*=}
|
||||
|
||||
# Check the file exists
|
||||
if [[ -f ${env_value} ]]; then
|
||||
|
||||
# Trim off the _FILE suffix
|
||||
non_file_env_name=${env_name%"_FILE"}
|
||||
echo "Setting ${non_file_env_name} from file"
|
||||
|
||||
# Reads the value from th file
|
||||
val="$(< "${!env_name}")"
|
||||
|
||||
# Sets the normal name to the read file contents
|
||||
export "${non_file_env_name}"="${val}"
|
||||
|
||||
else
|
||||
echo "File ${env_value} referenced by ${env_name} doesn't exist"
|
||||
fi
|
||||
fi
|
||||
done
|
@@ -3,5 +3,10 @@
|
||||
echo "Checking if we should start flower..."
|
||||
|
||||
if [[ -n "${PAPERLESS_ENABLE_FLOWER}" ]]; then
|
||||
celery --app paperless flower
|
||||
# Small delay to allow celery to be up first
|
||||
echo "Starting flower in 5s"
|
||||
sleep 5
|
||||
celery --app paperless flower --conf=/usr/src/paperless/src/paperless/flowerconfig.py
|
||||
else
|
||||
echo "Not starting flower"
|
||||
fi
|
||||
|
@@ -3,6 +3,9 @@
|
||||
set -e
|
||||
|
||||
cd /usr/src/paperless/src/
|
||||
# This ensures environment is setup
|
||||
# shellcheck disable=SC1091
|
||||
source /sbin/env-from-file.sh
|
||||
|
||||
if [[ $(id -u) == 0 ]] ;
|
||||
then
|
||||
|
@@ -152,9 +152,11 @@ following:
|
||||
|
||||
```shell-session
|
||||
$ cd src
|
||||
$ python3 manage.py migrate
|
||||
$ python3 manage.py migrate # (1)
|
||||
```
|
||||
|
||||
1. Including `sudo -Hu <paperless_user>` may be required
|
||||
|
||||
This might not actually do anything. Not every new paperless version
|
||||
comes with new database migrations.
|
||||
|
||||
@@ -210,9 +212,11 @@ Bare metal:
|
||||
|
||||
```shell-session
|
||||
$ cd /path/to/paperless/src
|
||||
$ python3 manage.py <command> <arguments>
|
||||
$ python3 manage.py <command> <arguments> # (1)
|
||||
```
|
||||
|
||||
1. Including `sudo -Hu <paperless_user>` may be required
|
||||
|
||||
All commands have built-in help, which can be accessed by executing them
|
||||
with the argument `--help`.
|
||||
|
||||
@@ -227,12 +231,16 @@ is not a TTY" errors. For example:
|
||||
`docker-compose exec -T webserver document_exporter ../export`
|
||||
|
||||
```
|
||||
document_exporter target [-c] [-f] [-d]
|
||||
document_exporter target [-c] [-d] [-f] [-na] [-nt] [-p] [-sm] [-z]
|
||||
|
||||
optional arguments:
|
||||
-c, --compare-checksums
|
||||
-f, --use-filename-format
|
||||
-d, --delete
|
||||
-f, --use-filename-format
|
||||
-na, --no-archive
|
||||
-nt, --no-thumbnail
|
||||
-p, --use-folder-prefix
|
||||
-sm, --split-manifest
|
||||
-z --zip
|
||||
```
|
||||
|
||||
@@ -249,23 +257,53 @@ will assume that the contents of the export directory are a previous
|
||||
export and will attempt to update the previous export. Paperless will
|
||||
only export changed and added files. Paperless determines whether a file
|
||||
has changed by inspecting the file attributes "date/time modified" and
|
||||
"size". If that does not work out for you, specify
|
||||
"size". If that does not work out for you, specify `-c` or
|
||||
`--compare-checksums` and paperless will attempt to compare file
|
||||
checksums instead. This is slower.
|
||||
|
||||
Paperless will not remove any existing files in the export directory. If
|
||||
you want paperless to also remove files that do not belong to the
|
||||
current export such as files from deleted documents, specify `--delete`.
|
||||
current export such as files from deleted documents, specify `-d` or `--delete`.
|
||||
Be careful when pointing paperless to a directory that already contains
|
||||
other files.
|
||||
|
||||
If `-z` or `--zip` is provided, the export will be a zipfile
|
||||
in the target directory, named according to the current date.
|
||||
|
||||
The filenames generated by this command follow the format
|
||||
`[date created] [correspondent] [title].[extension]`. If you want
|
||||
paperless to use `PAPERLESS_FILENAME_FORMAT` for exported filenames
|
||||
instead, specify `--use-filename-format`.
|
||||
instead, specify `-f` or `--use-filename-format`.
|
||||
|
||||
If `-na` or `--no-archive` is provided, no archive files will be exported,
|
||||
only the original files.
|
||||
|
||||
If `-nt` or `--no-thumbnail` is provided, thumbnail files will not be exported.
|
||||
|
||||
!!! note
|
||||
|
||||
When using the `-na`/`--no-archive` or `-nt`/`--no-thumbnail` options
|
||||
the exporter will not output these files for backup. After importing,
|
||||
the [sanity checker](#sanity-checker) will warn about missing thumbnails and archive files
|
||||
until they are regenerated with `document_thumbnails` or [`document_archiver`](#archiver).
|
||||
It can make sense to omit these files from backup as their content and checksum
|
||||
can change (new archiver algorithm) and may then cause additional used space in
|
||||
a deduplicated backup.
|
||||
|
||||
If `-p` or `--use-folder-prefix` is provided, files will be exported
|
||||
in dedicated folders according to their nature: `archive`, `originals`,
|
||||
`thumbnails` or `json`
|
||||
|
||||
If `-sm` or `--split-manifest` is provided, information about document
|
||||
will be placed in individual json files, instead of a single JSON file. The main
|
||||
manifest.json will still contain application wide information (e.g. tags, correspondent,
|
||||
documenttype, etc)
|
||||
|
||||
If `-z` or `--zip` is provided, the export will be a zipfile
|
||||
in the target directory, named according to the current date.
|
||||
|
||||
!!! warning
|
||||
|
||||
If exporting with the file name format, there may be errors due to
|
||||
your operating system's maximum path lengths. Try adjusting the export
|
||||
target or consider not using the filename format.
|
||||
|
||||
### Document importer {#importer}
|
||||
|
||||
@@ -347,6 +385,14 @@ document_create_classifier
|
||||
|
||||
This command takes no arguments.
|
||||
|
||||
### Document thumbnails {#thumbnails}
|
||||
|
||||
Use this command to re-create document thumbnails. Optionally include the ` --document {id}` option to generate thumbnails for a specific document only.
|
||||
|
||||
```
|
||||
document_thumbnails
|
||||
```
|
||||
|
||||
### Managing the document search index {#index}
|
||||
|
||||
The document search index is responsible for delivering search results
|
||||
|
@@ -121,7 +121,17 @@ Executed after the consumer sees a new document in the consumption
|
||||
folder, but before any processing of the document is performed. This
|
||||
script can access the following relevant environment variables set:
|
||||
|
||||
- `DOCUMENT_SOURCE_PATH`
|
||||
| Environment Variable | Description |
|
||||
| ----------------------- | ------------------------------------------------------------ |
|
||||
| `DOCUMENT_SOURCE_PATH` | Original path of the consumed document |
|
||||
| `DOCUMENT_WORKING_PATH` | Path to a copy of the original that consumption will work on |
|
||||
|
||||
!!! note
|
||||
|
||||
Pre-consume scripts which modify the document should only change
|
||||
the `DOCUMENT_WORKING_PATH` file or a second consume task may
|
||||
be triggered, leading to failures as two tasks work on the
|
||||
same document path
|
||||
|
||||
A simple but common example for this would be creating a simple script
|
||||
like this:
|
||||
@@ -130,7 +140,7 @@ like this:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
pdf2pdfocr.py -i ${DOCUMENT_SOURCE_PATH}
|
||||
pdf2pdfocr.py -i ${DOCUMENT_WORKING_PATH}
|
||||
```
|
||||
|
||||
`/etc/paperless.conf`
|
||||
@@ -157,26 +167,36 @@ Executed after the consumer has successfully processed a document and
|
||||
has moved it into paperless. It receives the following environment
|
||||
variables:
|
||||
|
||||
- `DOCUMENT_ID`
|
||||
- `DOCUMENT_FILE_NAME`
|
||||
- `DOCUMENT_CREATED`
|
||||
- `DOCUMENT_MODIFIED`
|
||||
- `DOCUMENT_ADDED`
|
||||
- `DOCUMENT_SOURCE_PATH`
|
||||
- `DOCUMENT_ARCHIVE_PATH`
|
||||
- `DOCUMENT_THUMBNAIL_PATH`
|
||||
- `DOCUMENT_DOWNLOAD_URL`
|
||||
- `DOCUMENT_THUMBNAIL_URL`
|
||||
- `DOCUMENT_CORRESPONDENT`
|
||||
- `DOCUMENT_TAGS`
|
||||
- `DOCUMENT_ORIGINAL_FILENAME`
|
||||
| Environment Variable | Description |
|
||||
| ---------------------------- | --------------------------------------------- |
|
||||
| `DOCUMENT_ID` | Database primary key of the document |
|
||||
| `DOCUMENT_FILE_NAME` | Formatted filename, not including paths |
|
||||
| `DOCUMENT_CREATED` | Date & time when document created |
|
||||
| `DOCUMENT_MODIFIED` | Date & time when document was last modified |
|
||||
| `DOCUMENT_ADDED` | Date & time when document was added |
|
||||
| `DOCUMENT_SOURCE_PATH` | Path to the original document file |
|
||||
| `DOCUMENT_ARCHIVE_PATH` | Path to the generate archive file (if any) |
|
||||
| `DOCUMENT_THUMBNAIL_PATH` | Path to the generated thumbnail |
|
||||
| `DOCUMENT_DOWNLOAD_URL` | URL for document download |
|
||||
| `DOCUMENT_THUMBNAIL_URL` | URL for the document thumbnail |
|
||||
| `DOCUMENT_CORRESPONDENT` | Assigned correspondent (if any) |
|
||||
| `DOCUMENT_TAGS` | Comma separated list of tags applied (if any) |
|
||||
| `DOCUMENT_ORIGINAL_FILENAME` | Filename of original document |
|
||||
|
||||
The script can be in any language, but for a simple shell script
|
||||
example, you can take a look at
|
||||
[post-consumption-example.sh](https://github.com/paperless-ngx/paperless-ngx/blob/main/scripts/post-consumption-example.sh)
|
||||
in this project.
|
||||
The script can be in any language, A simple shell script example:
|
||||
|
||||
The post consumption script cannot cancel the consumption process.
|
||||
```bash title="post-consumption-example"
|
||||
--8<-- "./scripts/post-consumption-example.sh"
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
The post consumption script cannot cancel the consumption process.
|
||||
|
||||
!!! warning
|
||||
|
||||
The post consumption script should not modify the document files
|
||||
directly
|
||||
|
||||
The script's stdout and stderr will be logged line by line to the
|
||||
webserver log, along with the exit code of the script.
|
||||
@@ -336,6 +356,13 @@ value.
|
||||
However, keep in mind that inside docker, if files get stored outside of
|
||||
the predefined volumes, they will be lost after a restart of paperless.
|
||||
|
||||
!!! warning
|
||||
|
||||
When file naming handling, in particular when using `{tag_list}`,
|
||||
you may run into the limits of your operating system's maximum
|
||||
path lengths. Files will retain the previous path instead and
|
||||
the issue logged.
|
||||
|
||||
## Storage paths
|
||||
|
||||
One of the best things in Paperless is that you can not only access the
|
||||
@@ -392,7 +419,7 @@ structure as in the previous example above.
|
||||
If you adjust the format of an existing storage path, old documents
|
||||
don't get relocated automatically. You need to run the
|
||||
[document renamer](/administration#renamer) to
|
||||
adjust their pathes.
|
||||
adjust their paths.
|
||||
|
||||
## Celery Monitoring {#celery-monitoring}
|
||||
|
||||
@@ -474,3 +501,9 @@ You can also set the default for new tables (this does NOT affect
|
||||
existing tables) with:
|
||||
|
||||
`ALTER DATABASE <db_name> CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`
|
||||
|
||||
!!! warning
|
||||
|
||||
Using mariadb version 10.4+ is recommended. Using the `utf8mb3` character set on
|
||||
an older system may fix issues that can arise while setting up Paperless-ngx but
|
||||
`utf8mb3` can cause issues with consumption (where `utf8mb4` does not).
|
||||
|
@@ -6,7 +6,7 @@ provides a browsable API for most of its endpoints, which you can
|
||||
inspect at `http://<paperless-host>:<port>/api/`. This also documents
|
||||
most of the available filters and ordering fields.
|
||||
|
||||
The API provides 5 main endpoints:
|
||||
The API provides 7 main endpoints:
|
||||
|
||||
- `/api/documents/`: Full CRUD support, except POSTing new documents.
|
||||
See below.
|
||||
|
@@ -1,5 +1,193 @@
|
||||
# Changelog
|
||||
|
||||
## paperless-ngx 1.12.2
|
||||
|
||||
_Note: Version 1.12.x introduced searching of comments which will work for comments added after the upgrade but a reindex of the search index is required in order to be able to search
|
||||
older comments. The Docker image will automatically perform this reindex, bare metal installations will have to perform this manually, see [the docs](https://docs.paperless-ngx.com/administration/#index)._
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Bugfix: Allow pre-consume scripts to modify incoming file [@stumpylog](https://github.com/stumpylog) ([#2547](https://github.com/paperless-ngx/paperless-ngx/pull/2547))
|
||||
- Bugfix: Return to page based barcode scanning [@stumpylog](https://github.com/stumpylog) ([#2544](https://github.com/paperless-ngx/paperless-ngx/pull/2544))
|
||||
- Fix: Try to prevent title debounce overwriting [@shamoon](https://github.com/shamoon) ([#2543](https://github.com/paperless-ngx/paperless-ngx/pull/2543))
|
||||
- Fix comment search highlight + multi-word search [@shamoon](https://github.com/shamoon) ([#2542](https://github.com/paperless-ngx/paperless-ngx/pull/2542))
|
||||
- Bugfix: Request PDF/A format from Gotenberg [@stumpylog](https://github.com/stumpylog) ([#2530](https://github.com/paperless-ngx/paperless-ngx/pull/2530))
|
||||
- Fix: Trigger reindex for pre-existing comments [@shamoon](https://github.com/shamoon) ([#2519](https://github.com/paperless-ngx/paperless-ngx/pull/2519))
|
||||
|
||||
### Documentation
|
||||
|
||||
- Bugfix: Allow pre-consume scripts to modify incoming file [@stumpylog](https://github.com/stumpylog) ([#2547](https://github.com/paperless-ngx/paperless-ngx/pull/2547))
|
||||
- Fix: Trigger reindex for pre-existing comments [@shamoon](https://github.com/shamoon) ([#2519](https://github.com/paperless-ngx/paperless-ngx/pull/2519))
|
||||
- Minor updates to development documentation [@clemensrieder](https://github.com/clemensrieder) ([#2474](https://github.com/paperless-ngx/paperless-ngx/pull/2474))
|
||||
- [Documentation] Add v1.12.1 changelog [@github-actions](https://github.com/github-actions) ([#2515](https://github.com/paperless-ngx/paperless-ngx/pull/2515))
|
||||
|
||||
### Maintenance
|
||||
|
||||
- Chore: Fix tag cleaner to work with attestations [@stumpylog](https://github.com/stumpylog) ([#2532](https://github.com/paperless-ngx/paperless-ngx/pull/2532))
|
||||
- Chore: Make installers statically versioned [@stumpylog](https://github.com/stumpylog) ([#2517](https://github.com/paperless-ngx/paperless-ngx/pull/2517))
|
||||
|
||||
### All App Changes
|
||||
|
||||
- Bugfix: Allow pre-consume scripts to modify incoming file [@stumpylog](https://github.com/stumpylog) ([#2547](https://github.com/paperless-ngx/paperless-ngx/pull/2547))
|
||||
- Bugfix: Return to page based barcode scanning [@stumpylog](https://github.com/stumpylog) ([#2544](https://github.com/paperless-ngx/paperless-ngx/pull/2544))
|
||||
- Fix: Try to prevent title debounce overwriting [@shamoon](https://github.com/shamoon) ([#2543](https://github.com/paperless-ngx/paperless-ngx/pull/2543))
|
||||
- Fix comment search highlight + multi-word search [@shamoon](https://github.com/shamoon) ([#2542](https://github.com/paperless-ngx/paperless-ngx/pull/2542))
|
||||
- Bugfix: Request PDF/A format from Gotenberg [@stumpylog](https://github.com/stumpylog) ([#2530](https://github.com/paperless-ngx/paperless-ngx/pull/2530))
|
||||
|
||||
## paperless-ngx 1.12.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix: comments not showing in search until after manual reindex in v1.12 [@shamoon](https://github.com/shamoon) ([#2513](https://github.com/paperless-ngx/paperless-ngx/pull/2513))
|
||||
- Fix: date range search broken in 1.12 [@shamoon](https://github.com/shamoon) ([#2509](https://github.com/paperless-ngx/paperless-ngx/pull/2509))
|
||||
|
||||
### Documentation
|
||||
|
||||
- [Documentation] Add v1.12.0 changelog [@github-actions](https://github.com/github-actions) ([#2507](https://github.com/paperless-ngx/paperless-ngx/pull/2507))
|
||||
|
||||
### Maintenance
|
||||
|
||||
- Moves back to the main release-drafter now that it does what we wanted [@stumpylog](https://github.com/stumpylog) ([#2503](https://github.com/paperless-ngx/paperless-ngx/pull/2503))
|
||||
|
||||
### All App Changes
|
||||
|
||||
- Fix: comments not showing in search until after manual reindex in v1.12 [@shamoon](https://github.com/shamoon) ([#2513](https://github.com/paperless-ngx/paperless-ngx/pull/2513))
|
||||
- Fix: date range search broken in 1.12 [@shamoon](https://github.com/shamoon) ([#2509](https://github.com/paperless-ngx/paperless-ngx/pull/2509))
|
||||
|
||||
## paperless-ngx 1.12.0
|
||||
|
||||
### Features
|
||||
|
||||
- New document_exporter options [@mhelleboid](https://github.com/mhelleboid) ([#2448](https://github.com/paperless-ngx/paperless-ngx/pull/2448))
|
||||
- Read ASN from barcode on page [@peterkappelt](https://github.com/peterkappelt) ([#2437](https://github.com/paperless-ngx/paperless-ngx/pull/2437))
|
||||
- Add AppleMail color tag support [@clemensrieder](https://github.com/clemensrieder) ([#2407](https://github.com/paperless-ngx/paperless-ngx/pull/2407))
|
||||
- Feature: Retain original filename on upload [@stumpylog](https://github.com/stumpylog) ([#2404](https://github.com/paperless-ngx/paperless-ngx/pull/2404))
|
||||
- Feature: Control scheduled tasks via cron expressions [@stumpylog](https://github.com/stumpylog) ([#2403](https://github.com/paperless-ngx/paperless-ngx/pull/2403))
|
||||
- Simplify json parsing in build scripts [@tribut](https://github.com/tribut) ([#2370](https://github.com/paperless-ngx/paperless-ngx/pull/2370))
|
||||
- Feature: include comments in advanced search [@shamoon](https://github.com/shamoon) ([#2351](https://github.com/paperless-ngx/paperless-ngx/pull/2351))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix: limit asn integer size [@shamoon](https://github.com/shamoon) ([#2498](https://github.com/paperless-ngx/paperless-ngx/pull/2498))
|
||||
- Bugfix: Rescales images for better barcode locating [@stumpylog](https://github.com/stumpylog) ([#2468](https://github.com/paperless-ngx/paperless-ngx/pull/2468))
|
||||
- Fix: fix downgrade migration [@shamoon](https://github.com/shamoon) ([#2494](https://github.com/paperless-ngx/paperless-ngx/pull/2494))
|
||||
- Fix: Allow setting mailrule order from frontend [@shamoon](https://github.com/shamoon) ([#2459](https://github.com/paperless-ngx/paperless-ngx/pull/2459))
|
||||
- Fix: tag color ordering [@shamoon](https://github.com/shamoon) ([#2456](https://github.com/paperless-ngx/paperless-ngx/pull/2456))
|
||||
- Fix: Better Handle arbitrary ISO 8601 strings after celery serializing [@shamoon](https://github.com/shamoon) ([#2441](https://github.com/paperless-ngx/paperless-ngx/pull/2441))
|
||||
- Use correct canonical path for nltk_data [@amo13](https://github.com/amo13) ([#2429](https://github.com/paperless-ngx/paperless-ngx/pull/2429))
|
||||
- Fix: Include optional socket file in release [@stumpylog](https://github.com/stumpylog) ([#2409](https://github.com/paperless-ngx/paperless-ngx/pull/2409))
|
||||
- Fix: display rtl content in correct direction [@shamoon](https://github.com/shamoon) ([#2302](https://github.com/paperless-ngx/paperless-ngx/pull/2302))
|
||||
- Fixed endpoint count in Docs The REST API [@PascalSenn](https://github.com/PascalSenn) ([#2386](https://github.com/paperless-ngx/paperless-ngx/pull/2386))
|
||||
- Fix subpath for websockets [@tribut](https://github.com/tribut) ([#2371](https://github.com/paperless-ngx/paperless-ngx/pull/2371))
|
||||
- Fix: Make missing environment from file files informational only [@stumpylog](https://github.com/stumpylog) ([#2368](https://github.com/paperless-ngx/paperless-ngx/pull/2368))
|
||||
- Bugfix: Backend tests weren't using correct Python version [@stumpylog](https://github.com/stumpylog) ([#2363](https://github.com/paperless-ngx/paperless-ngx/pull/2363))
|
||||
- Fix: preview content remains hidden on mobile [@shamoon](https://github.com/shamoon) ([#2346](https://github.com/paperless-ngx/paperless-ngx/pull/2346))
|
||||
- Bugfix: Removal of alpha channel truncates multipage TIFFs [@stumpylog](https://github.com/stumpylog) ([#2335](https://github.com/paperless-ngx/paperless-ngx/pull/2335))
|
||||
- Documentation: update build instructions to remove deprecated [@shamoon](https://github.com/shamoon) ([#2334](https://github.com/paperless-ngx/paperless-ngx/pull/2334))
|
||||
|
||||
### Documentation
|
||||
|
||||
- Docs: Fix typo - docker-compose.yml file name in setup doc [@muli](https://github.com/muli) ([#2477](https://github.com/paperless-ngx/paperless-ngx/pull/2477))
|
||||
- document existence of document_thumbnails [@frrad](https://github.com/frrad) ([#2470](https://github.com/paperless-ngx/paperless-ngx/pull/2470))
|
||||
- Add optional sudo command to bare metal docs [@shamoon](https://github.com/shamoon) ([#2464](https://github.com/paperless-ngx/paperless-ngx/pull/2464))
|
||||
- Fix link [@edenhaus](https://github.com/edenhaus) ([#2458](https://github.com/paperless-ngx/paperless-ngx/pull/2458))
|
||||
- Documentation: Fix comment re bare metal runserver command [@shamoon](https://github.com/shamoon) ([#2420](https://github.com/paperless-ngx/paperless-ngx/pull/2420))
|
||||
- Fix formatting of config variable in docs [@peterkappelt](https://github.com/peterkappelt) ([#2445](https://github.com/paperless-ngx/paperless-ngx/pull/2445))
|
||||
- Update docs nginx reverse proxy example [@Sprinterfreak](https://github.com/Sprinterfreak) ([#2443](https://github.com/paperless-ngx/paperless-ngx/pull/2443))
|
||||
- [Documentation] Add note re for dev server [@shamoon](https://github.com/shamoon) ([#2387](https://github.com/paperless-ngx/paperless-ngx/pull/2387))
|
||||
- Fixed endpoint count in Docs The REST API [@PascalSenn](https://github.com/PascalSenn) ([#2386](https://github.com/paperless-ngx/paperless-ngx/pull/2386))
|
||||
- [ Docs] Update bare metal setup instructions [@natrius](https://github.com/natrius) ([#2281](https://github.com/paperless-ngx/paperless-ngx/pull/2281))
|
||||
- [Docs] Add Paperless Mobile app to docs [@astubenbord](https://github.com/astubenbord) ([#2378](https://github.com/paperless-ngx/paperless-ngx/pull/2378))
|
||||
- Tiny spelling change [@veverkap](https://github.com/veverkap) ([#2369](https://github.com/paperless-ngx/paperless-ngx/pull/2369))
|
||||
- Documentation: update build instructions to remove deprecated [@shamoon](https://github.com/shamoon) ([#2334](https://github.com/paperless-ngx/paperless-ngx/pull/2334))
|
||||
- [Documentation] Add note that PAPERLESS_URL cant contain a path [@shamoon](https://github.com/shamoon) ([#2319](https://github.com/paperless-ngx/paperless-ngx/pull/2319))
|
||||
- [Documentation] Add v1.11.3 changelog [@github-actions](https://github.com/github-actions) ([#2311](https://github.com/paperless-ngx/paperless-ngx/pull/2311))
|
||||
|
||||
### Maintenance
|
||||
|
||||
- Fix: Include optional socket file in release [@stumpylog](https://github.com/stumpylog) ([#2409](https://github.com/paperless-ngx/paperless-ngx/pull/2409))
|
||||
- Chore: remove helm chart code [@shamoon](https://github.com/shamoon) ([#2388](https://github.com/paperless-ngx/paperless-ngx/pull/2388))
|
||||
- Simplify json parsing in build scripts [@tribut](https://github.com/tribut) ([#2370](https://github.com/paperless-ngx/paperless-ngx/pull/2370))
|
||||
- Bugfix: Backend tests weren't using correct Python version [@stumpylog](https://github.com/stumpylog) ([#2363](https://github.com/paperless-ngx/paperless-ngx/pull/2363))
|
||||
- Bump tj-actions/changed-files from 34 to 35 [@dependabot](https://github.com/dependabot) ([#2303](https://github.com/paperless-ngx/paperless-ngx/pull/2303))
|
||||
|
||||
### Dependencies
|
||||
|
||||
<details>
|
||||
<summary>4 changes</summary>
|
||||
|
||||
- Chore: Backend library updates [@stumpylog](https://github.com/stumpylog) ([#2401](https://github.com/paperless-ngx/paperless-ngx/pull/2401))
|
||||
- Bump tj-actions/changed-files from 34 to 35 [@dependabot](https://github.com/dependabot) ([#2303](https://github.com/paperless-ngx/paperless-ngx/pull/2303))
|
||||
- Bump [@<!---->typescript-eslint/parser from 5.43.0 to 5.47.1 in /src-ui @dependabot](https://github.com/<!---->typescript-eslint/parser from 5.43.0 to 5.47.1 in /src-ui @dependabot) ([#2306](https://github.com/paperless-ngx/paperless-ngx/pull/2306))
|
||||
- Bump [@<!---->typescript-eslint/eslint-plugin from 5.43.0 to 5.47.1 in /src-ui @dependabot](https://github.com/<!---->typescript-eslint/eslint-plugin from 5.43.0 to 5.47.1 in /src-ui @dependabot) ([#2308](https://github.com/paperless-ngx/paperless-ngx/pull/2308))
|
||||
</details>
|
||||
|
||||
### All App Changes
|
||||
|
||||
- New document_exporter options [@mhelleboid](https://github.com/mhelleboid) ([#2448](https://github.com/paperless-ngx/paperless-ngx/pull/2448))
|
||||
- Fix: limit asn integer size [@shamoon](https://github.com/shamoon) ([#2498](https://github.com/paperless-ngx/paperless-ngx/pull/2498))
|
||||
- Fix: fix downgrade migration [@shamoon](https://github.com/shamoon) ([#2494](https://github.com/paperless-ngx/paperless-ngx/pull/2494))
|
||||
- Read ASN from barcode on page [@peterkappelt](https://github.com/peterkappelt) ([#2437](https://github.com/paperless-ngx/paperless-ngx/pull/2437))
|
||||
- Fix: Allow setting mailrule order from frontend [@shamoon](https://github.com/shamoon) ([#2459](https://github.com/paperless-ngx/paperless-ngx/pull/2459))
|
||||
- Chore: Update to Angular 15 \& associated frontend deps [@shamoon](https://github.com/shamoon) ([#2411](https://github.com/paperless-ngx/paperless-ngx/pull/2411))
|
||||
- Fix: tag color ordering [@shamoon](https://github.com/shamoon) ([#2456](https://github.com/paperless-ngx/paperless-ngx/pull/2456))
|
||||
- Fix: Better Handle arbitrary ISO 8601 strings after celery serializing [@shamoon](https://github.com/shamoon) ([#2441](https://github.com/paperless-ngx/paperless-ngx/pull/2441))
|
||||
- Use correct canonical path for nltk_data [@amo13](https://github.com/amo13) ([#2429](https://github.com/paperless-ngx/paperless-ngx/pull/2429))
|
||||
- Add AppleMail color tag support [@clemensrieder](https://github.com/clemensrieder) ([#2407](https://github.com/paperless-ngx/paperless-ngx/pull/2407))
|
||||
- Chore: Convert document exporter to use pathlib [@stumpylog](https://github.com/stumpylog) ([#2416](https://github.com/paperless-ngx/paperless-ngx/pull/2416))
|
||||
- Feature: Retain original filename on upload [@stumpylog](https://github.com/stumpylog) ([#2404](https://github.com/paperless-ngx/paperless-ngx/pull/2404))
|
||||
- Feature: Control scheduled tasks via cron expressions [@stumpylog](https://github.com/stumpylog) ([#2403](https://github.com/paperless-ngx/paperless-ngx/pull/2403))
|
||||
- Fix: display rtl content in correct direction [@shamoon](https://github.com/shamoon) ([#2302](https://github.com/paperless-ngx/paperless-ngx/pull/2302))
|
||||
- Fix subpath for websockets [@tribut](https://github.com/tribut) ([#2371](https://github.com/paperless-ngx/paperless-ngx/pull/2371))
|
||||
- Bugfix: Backend tests weren't using correct Python version [@stumpylog](https://github.com/stumpylog) ([#2363](https://github.com/paperless-ngx/paperless-ngx/pull/2363))
|
||||
- Feature: include comments in advanced search [@shamoon](https://github.com/shamoon) ([#2351](https://github.com/paperless-ngx/paperless-ngx/pull/2351))
|
||||
- Chore: More frontend tests [@shamoon](https://github.com/shamoon) ([#2352](https://github.com/paperless-ngx/paperless-ngx/pull/2352))
|
||||
- Chore: Fixing up some minor annoyances [@stumpylog](https://github.com/stumpylog) ([#2348](https://github.com/paperless-ngx/paperless-ngx/pull/2348))
|
||||
- Bugfix: Removal of alpha channel truncates multipage TIFFs [@stumpylog](https://github.com/stumpylog) ([#2335](https://github.com/paperless-ngx/paperless-ngx/pull/2335))
|
||||
- Documentation: update build instructions to remove deprecated [@shamoon](https://github.com/shamoon) ([#2334](https://github.com/paperless-ngx/paperless-ngx/pull/2334))
|
||||
- Add Arabic language to frontend [@KhaledEmad7](https://github.com/KhaledEmad7) ([#2313](https://github.com/paperless-ngx/paperless-ngx/pull/2313))
|
||||
- Bump [@<!---->typescript-eslint/parser from 5.43.0 to 5.47.1 in /src-ui @dependabot](https://github.com/<!---->typescript-eslint/parser from 5.43.0 to 5.47.1 in /src-ui @dependabot) ([#2306](https://github.com/paperless-ngx/paperless-ngx/pull/2306))
|
||||
- Bump [@<!---->typescript-eslint/eslint-plugin from 5.43.0 to 5.47.1 in /src-ui @dependabot](https://github.com/<!---->typescript-eslint/eslint-plugin from 5.43.0 to 5.47.1 in /src-ui @dependabot) ([#2308](https://github.com/paperless-ngx/paperless-ngx/pull/2308))
|
||||
|
||||
## paperless-ngx 1.11.3
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
_Note: PR #2279 could represent a breaking change to the API which may affect third party applications that were only checking the `post_document` endpoint for e.g. result = 'OK' as opposed to e.g. HTTP status = 200_
|
||||
|
||||
- Bugfix: Return created task ID when posting document to API [@stumpylog](https://github.com/stumpylog) ([#2279](https://github.com/paperless-ngx/paperless-ngx/pull/2279))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Bugfix: Fix no content when processing some RTL files [@stumpylog](https://github.com/stumpylog) ([#2295](https://github.com/paperless-ngx/paperless-ngx/pull/2295))
|
||||
- Bugfix: Handle email dates maybe being naive [@stumpylog](https://github.com/stumpylog) ([#2293](https://github.com/paperless-ngx/paperless-ngx/pull/2293))
|
||||
- Fix: live filterable dropdowns broken in 1.11.x [@shamoon](https://github.com/shamoon) ([#2292](https://github.com/paperless-ngx/paperless-ngx/pull/2292))
|
||||
- Bugfix: Reading environment from files didn't work for management commands [@stumpylog](https://github.com/stumpylog) ([#2261](https://github.com/paperless-ngx/paperless-ngx/pull/2261))
|
||||
- Bugfix: Return created task ID when posting document to API [@stumpylog](https://github.com/stumpylog) ([#2279](https://github.com/paperless-ngx/paperless-ngx/pull/2279))
|
||||
|
||||
### All App Changes
|
||||
|
||||
- Bugfix: Fix no content when processing some RTL files [@stumpylog](https://github.com/stumpylog) ([#2295](https://github.com/paperless-ngx/paperless-ngx/pull/2295))
|
||||
- Bugfix: Handle email dates maybe being naive [@stumpylog](https://github.com/stumpylog) ([#2293](https://github.com/paperless-ngx/paperless-ngx/pull/2293))
|
||||
- Fix: live filterable dropdowns broken in 1.11.x [@shamoon](https://github.com/shamoon) ([#2292](https://github.com/paperless-ngx/paperless-ngx/pull/2292))
|
||||
- Bugfix: Return created task ID when posting document to API [@stumpylog](https://github.com/stumpylog) ([#2279](https://github.com/paperless-ngx/paperless-ngx/pull/2279))
|
||||
|
||||
## paperless-ngx 1.11.2
|
||||
|
||||
Versions 1.11.1 and 1.11.2 contain bug fixes from v1.11.0 that prevented use of the new email consumption feature
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix frontend mailrule missing consumption scope parameter [@shamoon](https://github.com/shamoon) ([#2280](https://github.com/paperless-ngx/paperless-ngx/pull/2280))
|
||||
- Fix: missing frontend email attachment options [@shamoon](https://github.com/shamoon) ([#2272](https://github.com/paperless-ngx/paperless-ngx/pull/2272))
|
||||
- Fix: edit dialog creation in v1.11.0 [@shamoon](https://github.com/shamoon) ([#2273](https://github.com/paperless-ngx/paperless-ngx/pull/2273))
|
||||
|
||||
### All App Changes
|
||||
|
||||
- Fix frontend mailrule missing consumption scope parameter [@shamoon](https://github.com/shamoon) ([#2280](https://github.com/paperless-ngx/paperless-ngx/pull/2280))
|
||||
- Fix: missing frontend email attachment options [@shamoon](https://github.com/shamoon) ([#2272](https://github.com/paperless-ngx/paperless-ngx/pull/2272))
|
||||
- Fix: edit dialog creation in v1.11.0 [@shamoon](https://github.com/shamoon) ([#2273](https://github.com/paperless-ngx/paperless-ngx/pull/2273))
|
||||
|
||||
## paperless-ngx 1.11.0
|
||||
|
||||
### Notable Changes
|
||||
|
@@ -141,7 +141,8 @@ directory.
|
||||
files created using "collectstatic" manager command are stored.
|
||||
|
||||
Unless you're doing something fancy, there is no need to override
|
||||
this.
|
||||
this. If this is changed, you may need to run
|
||||
`collectstatic` again.
|
||||
|
||||
Defaults to "../static/", relative to the "src" directory.
|
||||
|
||||
@@ -179,7 +180,7 @@ Previously, the location defaulted to `PAPERLESS_DATA_DIR/nltk`.
|
||||
Unless you are using this in a bare metal install or other setup,
|
||||
this folder is no longer needed and can be removed manually.
|
||||
|
||||
Defaults to `/usr/local/share/nltk_data`
|
||||
Defaults to `/usr/share/nltk_data`
|
||||
|
||||
## Logging
|
||||
|
||||
@@ -217,6 +218,11 @@ not include a trailing slash. E.g. <https://paperless.domain.com>
|
||||
|
||||
Defaults to empty string, leaving the other settings unaffected.
|
||||
|
||||
!!! note
|
||||
|
||||
This value cannot contain a path (e.g. domain.com/path), even if
|
||||
you are installing paperless-ngx at a subpath.
|
||||
|
||||
`PAPERLESS_CSRF_TRUSTED_ORIGINS=<comma-separated-list>`
|
||||
|
||||
: A list of trusted origins for unsafe requests (e.g. POST). As of
|
||||
@@ -620,7 +626,7 @@ services:
|
||||
# ...
|
||||
|
||||
gotenberg:
|
||||
image: gotenberg/gotenberg:7.6
|
||||
image: gotenberg/gotenberg:7.8
|
||||
restart: unless-stopped
|
||||
# The gotenberg chromium route is used to convert .eml files. We do not
|
||||
# want to allow external content like tracking pixels or even javascript.
|
||||
@@ -711,12 +717,59 @@ for details on how to set it.
|
||||
|
||||
: Enables or disables the advanced natural language processing
|
||||
used during automatic classification. If disabled, paperless will
|
||||
still preform some basic text pre-processing before matching.
|
||||
still perform some basic text pre-processing before matching.
|
||||
|
||||
See also `PAPERLESS_NLTK_DIR`.
|
||||
: See also `PAPERLESS_NLTK_DIR`.
|
||||
|
||||
Defaults to 1.
|
||||
|
||||
`PAPERLESS_EMAIL_TASK_CRON=<cron expression>`
|
||||
|
||||
: Configures the scheduled email fetching frequency. The value
|
||||
should be a valid crontab(5) expression describing when to run.
|
||||
|
||||
: If set to the string "disable", no emails will be fetched automatically.
|
||||
|
||||
Defaults to `*/10 * * * *` or every ten minutes.
|
||||
|
||||
`PAPERLESS_TRAIN_TASK_CRON=<cron expression>`
|
||||
|
||||
: Configures the scheduled automatic classifier training frequency. The value
|
||||
should be a valid crontab(5) expression describing when to run.
|
||||
|
||||
: If set to the string "disable", the classifier will not be trained automatically.
|
||||
|
||||
Defaults to `5 */1 * * *` or every hour at 5 minutes past the hour.
|
||||
|
||||
`PAPERLESS_INDEX_TASK_CRON=<cron expression>`
|
||||
|
||||
: Configures the scheduled search index update frequency. The value
|
||||
should be a valid crontab(5) expression describing when to run.
|
||||
|
||||
: If set to the string "disable", the search index will not be automatically updated.
|
||||
|
||||
Defaults to `0 0 * * *` or daily at midnight.
|
||||
|
||||
`PAPERLESS_SANITY_TASK_CRON=<cron expression>`
|
||||
|
||||
: Configures the scheduled sanity checker frequency.
|
||||
|
||||
: If set to the string "disable", the sanity checker will not run automatically.
|
||||
|
||||
Defaults to `30 0 * * sun` or Sunday at 30 minutes past midnight.
|
||||
|
||||
`PAPERLESS_ENABLE_COMPRESSION=<bool>`
|
||||
|
||||
: Enables compression of the responses from the webserver.
|
||||
|
||||
: Defaults to 1, enabling compression.
|
||||
|
||||
!!! note
|
||||
|
||||
If you are using a proxy such as nginx, it is likely more efficient
|
||||
to enable compression in your proxy configuration rather than
|
||||
the webserver
|
||||
|
||||
## Polling {#polling}
|
||||
|
||||
`PAPERLESS_CONSUMER_POLLING=<num>`
|
||||
@@ -813,7 +866,7 @@ PAPERLESS_CONSUMER_ENABLE_BARCODES has been enabled.
|
||||
|
||||
Defaults to false.
|
||||
|
||||
PAPERLESS_CONSUMER_BARCODE_STRING=PATCHT
|
||||
`PAPERLESS_CONSUMER_BARCODE_STRING=PATCHT`
|
||||
|
||||
: Defines the string to be detected as a separator barcode. If
|
||||
paperless is used with the PATCH-T separator pages, users shouldn't
|
||||
@@ -821,6 +874,31 @@ change this.
|
||||
|
||||
Defaults to "PATCHT"
|
||||
|
||||
`PAPERLESS_CONSUMER_ENABLE_ASN_BARCODE=<bool>`
|
||||
|
||||
: Enables the detection of barcodes in the scanned document and
|
||||
setting the ASN (archive serial number) if a properly formatted
|
||||
barcode is detected.
|
||||
|
||||
The barcode must consist of a (configurable) prefix and the ASN
|
||||
to be set, for instance `ASN00123`.
|
||||
|
||||
This option is compatible with barcode page separation, since
|
||||
pages will be split up before reading the ASN.
|
||||
|
||||
If no ASN barcodes are detected in the uploaded file, no ASN will
|
||||
be set. If a barcode with an already existing ASN is detected, no ASN
|
||||
will be set either and a warning will be logged.
|
||||
|
||||
Defaults to false.
|
||||
|
||||
`PAPERLESS_CONSUMER_ASN_BARCODE_PREFIX=ASN`
|
||||
|
||||
: Defines the prefix that is used to identify a barcode as an ASN
|
||||
barcode.
|
||||
|
||||
Defaults to "ASN"
|
||||
|
||||
`PAPERLESS_CONVERT_MEMORY_LIMIT=<num>`
|
||||
|
||||
: On smaller systems, or even in the case of Very Large Documents, the
|
||||
@@ -921,13 +999,20 @@ within your documents.
|
||||
`PAPERLESS_CONSUMER_IGNORE_PATTERNS=<json>`
|
||||
|
||||
: By default, paperless ignores certain files and folders in the
|
||||
consumption directory, such as system files created by the Mac OS.
|
||||
consumption directory, such as system files created by the Mac OS
|
||||
or hidden folders some tools use to store data.
|
||||
|
||||
This can be adjusted by configuring a custom json array with
|
||||
patterns to exclude.
|
||||
|
||||
For example, `.DS_STORE/*` will ignore any files found in a folder
|
||||
named `.DS_STORE`, including `.DS_STORE/bar.pdf` and `foo/.DS_STORE/bar.pdf`
|
||||
|
||||
A pattern like `._*` will ignore anything starting with `._`, including:
|
||||
`._foo.pdf` and `._bar/foo.pdf`
|
||||
|
||||
Defaults to
|
||||
`[".DS_STORE/*", "._*", ".stfolder/*", ".stversions/*", ".localized/*", "desktop.ini"]`.
|
||||
`[".DS_STORE/*", "._*", ".stfolder/*", ".stversions/*", ".localized/*", "desktop.ini", "@eaDir/*"]`.
|
||||
|
||||
## Binaries
|
||||
|
||||
|
@@ -1,9 +1,9 @@
|
||||
# Development
|
||||
|
||||
This section describes the steps you need to take to start development
|
||||
on paperless-ngx.
|
||||
on Paperless-ngx.
|
||||
|
||||
Check out the source from github. The repository is organized in the
|
||||
Check out the source from GitHub. The repository is organized in the
|
||||
following way:
|
||||
|
||||
- `main` always represents the latest release and will only see
|
||||
@@ -12,7 +12,7 @@ following way:
|
||||
- `feature-X` contain bigger changes that will be in some release, but
|
||||
not necessarily the next one.
|
||||
|
||||
When making functional changes to paperless, _always_ make your changes
|
||||
When making functional changes to Paperless-ngx, _always_ make your changes
|
||||
on the `dev` branch.
|
||||
|
||||
Apart from that, the folder structure is as follows:
|
||||
@@ -24,9 +24,9 @@ Apart from that, the folder structure is as follows:
|
||||
development.
|
||||
- `docker/` - Files required to build the docker image.
|
||||
|
||||
## Contributing to Paperless
|
||||
## Contributing to Paperless-ngx
|
||||
|
||||
Maybe you've been using Paperless for a while and want to add a feature
|
||||
Maybe you've been using Paperless-ngx for a while and want to add a feature
|
||||
or two, or maybe you've come across a bug that you have some ideas how
|
||||
to solve. The beauty of open source software is that you can see what's
|
||||
wrong and help to get it fixed for everyone!
|
||||
@@ -36,13 +36,13 @@ conduct](https://github.com/paperless-ngx/paperless-ngx/blob/main/CODE_OF_CONDUC
|
||||
and other important information in the [contributing
|
||||
guidelines](https://github.com/paperless-ngx/paperless-ngx/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## Code formatting with pre-commit Hooks
|
||||
## Code formatting with pre-commit hooks
|
||||
|
||||
To ensure a consistent style and formatting across the project source,
|
||||
the project utilizes a Git [`pre-commit`](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks)
|
||||
hook to perform some formatting and linting before a commit is allowed.
|
||||
the project utilizes Git [`pre-commit`](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks)
|
||||
hooks to perform some formatting and linting before a commit is allowed.
|
||||
That way, everyone uses the same style and some common issues can be caught
|
||||
early on. See below for installation instructions.
|
||||
early on.
|
||||
|
||||
Once installed, hooks will run when you commit. If the formatting isn't
|
||||
quite right or a linter catches something, the commit will be rejected.
|
||||
@@ -51,129 +51,110 @@ as the Python formatting tool `black`, will format failing
|
||||
files, so all you need to do is `git add` those files again
|
||||
and retry your commit.
|
||||
|
||||
## Initial setup and first start
|
||||
## General setup
|
||||
|
||||
After you forked and cloned the code from github you need to perform a
|
||||
first-time setup. To do the setup you need to perform the steps from the
|
||||
following chapters in a certain order:
|
||||
After you forked and cloned the code from GitHub you need to perform a
|
||||
first-time setup.
|
||||
|
||||
!!! note
|
||||
|
||||
Every command is executed directly from the root folder of the project unless specified otherwise.
|
||||
|
||||
1. Install prerequisites + pipenv as mentioned in
|
||||
[Bare metal route](/setup#bare_metal)
|
||||
[Bare metal route](/setup#bare_metal).
|
||||
|
||||
2. Copy `paperless.conf.example` to `paperless.conf` and enable debug
|
||||
mode.
|
||||
mode within the file via `PAPERLESS_DEBUG=true`.
|
||||
|
||||
3. Install the Angular CLI interface:
|
||||
3. Create `consume` and `media` directories:
|
||||
|
||||
```shell-session
|
||||
$ npm install -g @angular/cli
|
||||
```bash
|
||||
$ mkdir -p consume media
|
||||
```
|
||||
|
||||
4. Install pre-commit hooks
|
||||
4. Install the Python dependencies:
|
||||
|
||||
```shell-session
|
||||
pre-commit install
|
||||
```bash
|
||||
$ pipenv install --dev
|
||||
```
|
||||
|
||||
5. Create `consume` and `media` folders in the cloned root folder.
|
||||
!!! note
|
||||
|
||||
```shell-session
|
||||
mkdir -p consume media
|
||||
Using a virtual environment is highly recommended. You can spawn one via `pipenv shell`.
|
||||
Make sure you're using Python 3.10.x or lower. Otherwise you might
|
||||
get issues with building dependencies. You can use
|
||||
[pyenv](https://github.com/pyenv/pyenv) to install a specific
|
||||
Python version.
|
||||
|
||||
5. Install pre-commit hooks:
|
||||
|
||||
```bash
|
||||
$ pre-commit install
|
||||
```
|
||||
|
||||
6. You can now either ...
|
||||
6. Apply migrations and create a superuser for your development instance:
|
||||
|
||||
```bash
|
||||
# src/
|
||||
|
||||
$ python3 manage.py migrate
|
||||
$ python3 manage.py createsuperuser
|
||||
```
|
||||
|
||||
7. You can now either ...
|
||||
|
||||
- install redis or
|
||||
|
||||
- use the included scripts/start-services.sh to use docker to fire
|
||||
- use the included `scripts/start_services.sh` to use docker to fire
|
||||
up a redis instance (and some other services such as tika,
|
||||
gotenberg and a database server) or
|
||||
|
||||
- spin up a bare redis container
|
||||
|
||||
```shell-session
|
||||
docker run -d -p 6379:6379 --restart unless-stopped redis:latest
|
||||
```
|
||||
$ docker run -d -p 6379:6379 --restart unless-stopped redis:latest
|
||||
```
|
||||
|
||||
7. Install the python dependencies by performing in the src/ directory.
|
||||
|
||||
```shell-session
|
||||
pipenv install --dev
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
Make sure you're using python 3.10.x or lower. Otherwise you might
|
||||
get issues with building dependencies. You can use
|
||||
[pyenv](https://github.com/pyenv/pyenv) to install a specific
|
||||
python version.
|
||||
|
||||
8. Generate the static UI so you can perform a login to get session
|
||||
that is required for frontend development (this needs to be done one
|
||||
time only). From src-ui directory:
|
||||
|
||||
```shell-session
|
||||
npm install .
|
||||
./node_modules/.bin/ng build --configuration production
|
||||
```
|
||||
|
||||
9. Apply migrations and create a superuser for your dev instance:
|
||||
|
||||
```shell-session
|
||||
python3 manage.py migrate
|
||||
python3 manage.py createsuperuser
|
||||
```
|
||||
|
||||
10. Now spin up the dev backend. Depending on which part of paperless
|
||||
you're developing for, you need to have some or all of them
|
||||
running.
|
||||
|
||||
```shell-session
|
||||
python3 manage.py runserver & python3 manage.py document_consumer & celery --app paperless worker
|
||||
```
|
||||
|
||||
11. Login with the superuser credentials provided in step 8 at
|
||||
`http://localhost:8000` to create a session that enables you to use
|
||||
the backend.
|
||||
|
||||
Backend development environment is now ready, to start Frontend
|
||||
development go to `/src-ui` and run `ng serve`. From there you can use
|
||||
`http://localhost:4200` for a preview.
|
||||
8. Continue with either back-end or front-end development – or both :-).
|
||||
|
||||
## Back end development
|
||||
|
||||
The backend is a [Django](https://www.djangoproject.com/) application. PyCharm works well for development,
|
||||
but you can use whatever you want.
|
||||
The back end is a [Django](https://www.djangoproject.com/) application. [PyCharm](https://www.jetbrains.com/de-de/pycharm/) as well as [Visual Studio Code](https://code.visualstudio.com) work well for development, but you can use whatever you want.
|
||||
|
||||
Configure the IDE to use the src/ folder as the base source folder.
|
||||
Configure the IDE to use the `src/`-folder as the base source folder.
|
||||
Configure the following launch configurations in your IDE:
|
||||
|
||||
- `python3 manage.py runserver`
|
||||
- `celery --app paperless worker`
|
||||
- `python3 manage.py document_consumer`
|
||||
- `celery --app paperless worker -l DEBUG` (or any other log level)
|
||||
|
||||
To start them all:
|
||||
|
||||
```shell-session
|
||||
python3 manage.py runserver & python3 manage.py document_consumer & celery --app paperless worker
|
||||
```bash
|
||||
# src/
|
||||
|
||||
$ python3 manage.py runserver & \
|
||||
python3 manage.py document_consumer & \
|
||||
celery --app paperless worker -l DEBUG
|
||||
```
|
||||
|
||||
Testing and code style:
|
||||
You might need the front end to test your back end code. This assumes that you have AngularJS installed on your system. Go to the [Front end development](#front-end-development) section for further details. To build the front end once use this commmand:
|
||||
|
||||
```bash
|
||||
# src-ui/
|
||||
|
||||
$ npm install
|
||||
$ ng build --configuration production
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
- Run `pytest` in the `src/` directory to execute all tests. This also
|
||||
generates a HTML coverage report. When runnings test, paperless.conf
|
||||
is loaded as well. However: the tests rely on the default
|
||||
generates a HTML coverage report. When runnings test, `paperless.conf`
|
||||
is loaded as well. However, the tests rely on the default
|
||||
configuration. This is not ideal. But for now, make sure no settings
|
||||
except for DEBUG are overridden when testing.
|
||||
|
||||
- Coding style is enforced by the Git pre-commit hooks. These will
|
||||
ensure your code is formatted and do some linting when you do a `git commit`.
|
||||
|
||||
- You can also run `black` manually to format your code
|
||||
|
||||
- The `pre-commit` hooks will modify files and interact with each other.
|
||||
It may take a couple of `git add`, `git commit` cycle to satisfy them.
|
||||
|
||||
!!! note
|
||||
|
||||
The line length rule E501 is generally useful for getting multiple
|
||||
@@ -184,98 +165,98 @@ Testing and code style:
|
||||
|
||||
## Front end development
|
||||
|
||||
The front end is built using Angular. In order to get started, you need
|
||||
`npm`. Install the Angular CLI interface with
|
||||
The front end is built using AngularJS. In order to get started, you need Node.js (version 14.15+) and
|
||||
`npm`.
|
||||
|
||||
```shell-session
|
||||
$ npm install -g @angular/cli
|
||||
```
|
||||
!!! note
|
||||
|
||||
and make sure that it's on your path. Next, in the src-ui/ directory,
|
||||
install the required dependencies of the project.
|
||||
The following commands are all performed in the `src-ui`-directory. You will need a running back end (including an active session) to connect to the back end API. To spin it up refer to the commands under the section [above](#back-end-development).
|
||||
|
||||
```shell-session
|
||||
$ npm install
|
||||
```
|
||||
1. Install the Angular CLI. You might need sudo privileges
|
||||
to perform this command:
|
||||
|
||||
You can launch a development server by running
|
||||
```bash
|
||||
$ npm install -g @angular/cli
|
||||
```
|
||||
|
||||
```shell-session
|
||||
$ ng serve
|
||||
```
|
||||
2. Make sure that it's on your path.
|
||||
|
||||
This will automatically update whenever you save. However, in-place
|
||||
compilation might fail on syntax errors, in which case you need to
|
||||
restart it.
|
||||
3. Install all neccessary modules:
|
||||
|
||||
By default, the development server is available on
|
||||
`http://localhost:4200/` and is configured to access the API at
|
||||
`http://localhost:8000/api/`, which is the default of the backend. If
|
||||
you enabled DEBUG on the back end, several security overrides for
|
||||
allowed hosts, CORS and X-Frame-Options are in place so that the front
|
||||
end behaves exactly as in production. This also relies on you being
|
||||
logged into the back end. Without a valid session, The front end will
|
||||
simply not work.
|
||||
```bash
|
||||
$ npm install
|
||||
```
|
||||
|
||||
Testing and code style:
|
||||
4. You can launch a development server by running:
|
||||
|
||||
- The frontend code (.ts, .html, .scss) use `prettier` for code
|
||||
```bash
|
||||
$ ng serve
|
||||
```
|
||||
|
||||
This will automatically update whenever you save. However, in-place
|
||||
compilation might fail on syntax errors, in which case you need to
|
||||
restart it.
|
||||
|
||||
By default, the development server is available on `http://localhost:4200/` and is configured to access the API at
|
||||
`http://localhost:8000/api/`, which is the default of the backend. If you enabled `DEBUG` on the back end, several security overrides for allowed hosts, CORS and X-Frame-Options are in place so that the front end behaves exactly as in production.
|
||||
|
||||
### Testing and code style
|
||||
|
||||
- The front end code (.ts, .html, .scss) use `prettier` for code
|
||||
formatting via the Git `pre-commit` hooks which run automatically on
|
||||
commit. See
|
||||
[above](#code-formatting-with-pre-commit-hooks) for installation. You can also run this via cli with a
|
||||
commit. See [above](#code-formatting-with-pre-commit-hooks) for installation instructions. You can also run this via the CLI with a
|
||||
command such as
|
||||
|
||||
```shell-session
|
||||
```bash
|
||||
$ git ls-files -- '*.ts' | xargs pre-commit run prettier --files
|
||||
```
|
||||
|
||||
- Frontend testing uses jest and cypress. There is currently a need
|
||||
for significantly more frontend tests. Unit tests and e2e tests,
|
||||
- Front end testing uses jest and cypress. There is currently a need
|
||||
for significantly more front end tests. Unit tests and e2e tests,
|
||||
respectively, can be run non-interactively with:
|
||||
|
||||
```shell-session
|
||||
```bash
|
||||
$ ng test
|
||||
$ npm run e2e:ci
|
||||
```
|
||||
|
||||
Cypress also includes a UI which can be run from within the `src-ui`
|
||||
directory with
|
||||
- Cypress also includes a UI which can be run with:
|
||||
|
||||
```shell-session
|
||||
$ ./node_modules/.bin/cypress open
|
||||
```bash
|
||||
$ ./node_modules/.bin/cypress open
|
||||
```
|
||||
|
||||
- In order to build the front end and serve it as part of Django, execute:
|
||||
|
||||
```bash
|
||||
$ ng build --configuration production
|
||||
```
|
||||
|
||||
In order to build the front end and serve it as part of django, execute
|
||||
|
||||
```shell-session
|
||||
$ ng build --prod
|
||||
```
|
||||
|
||||
This will build the front end and put it in a location from which the
|
||||
Django server will serve it as static content. This way, you can verify
|
||||
that authentication is working.
|
||||
This will build the front end and put it in a location from which the
|
||||
Django server will serve it as static content. This way, you can verify
|
||||
that authentication is working.
|
||||
|
||||
## Localization
|
||||
|
||||
Paperless is available in many different languages. Since paperless
|
||||
consists both of a django application and an Angular front end, both
|
||||
Paperless-ngx is available in many different languages. Since Paperless-ngx
|
||||
consists both of a Django application and an AngularJS front end, both
|
||||
these parts have to be translated separately.
|
||||
|
||||
### Front end localization
|
||||
|
||||
- The Angular front end does localization according to the [Angular
|
||||
- The AngularJS front end does localization according to the [Angular
|
||||
documentation](https://angular.io/guide/i18n).
|
||||
- The source language of the project is "en_US".
|
||||
- The source strings end up in the file "src-ui/messages.xlf".
|
||||
- The source strings end up in the file `src-ui/messages.xlf`.
|
||||
- The translated strings need to be placed in the
|
||||
"src-ui/src/locale/" folder.
|
||||
`src-ui/src/locale/` folder.
|
||||
- In order to extract added or changed strings from the source files,
|
||||
call `ng xi18n --ivy`.
|
||||
|
||||
Adding new languages requires adding the translated files in the
|
||||
"src-ui/src/locale/" folder and adjusting a couple files.
|
||||
`src-ui/src/locale/` folder and adjusting a couple files.
|
||||
|
||||
1. Adjust "src-ui/angular.json":
|
||||
1. Adjust `src-ui/angular.json`:
|
||||
|
||||
```json
|
||||
"i18n": {
|
||||
@@ -292,7 +273,7 @@ Adding new languages requires adding the translated files in the
|
||||
```
|
||||
|
||||
2. Add the language to the available options in
|
||||
"src-ui/src/app/services/settings.service.ts":
|
||||
`src-ui/src/app/services/settings.service.ts`:
|
||||
|
||||
```typescript
|
||||
getLanguageOptions(): LanguageOption[] {
|
||||
@@ -313,7 +294,7 @@ Adding new languages requires adding the translated files in the
|
||||
and "yyyy".
|
||||
|
||||
3. Import and register the Angular data for this locale in
|
||||
"src-ui/src/app/app.module.ts":
|
||||
`src-ui/src/app/app.module.ts`:
|
||||
|
||||
```typescript
|
||||
import localeDe from '@angular/common/locales/de'
|
||||
@@ -326,10 +307,10 @@ A majority of the strings that appear in the back end appear only when
|
||||
the admin is used. However, some of these are still shown on the front
|
||||
end (such as error messages).
|
||||
|
||||
- The django application does localization according to the [django
|
||||
- The django application does localization according to the [Django
|
||||
documentation](https://docs.djangoproject.com/en/3.1/topics/i18n/translation/).
|
||||
- The source language of the project is "en_US".
|
||||
- Localization files end up in the folder "src/locale/".
|
||||
- Localization files end up in the folder `src/locale/`.
|
||||
- In order to extract strings from the application, call
|
||||
`python3 manage.py makemessages -l en_US`. This is important after
|
||||
making changes to translatable strings.
|
||||
@@ -340,8 +321,8 @@ end (such as error messages).
|
||||
command.
|
||||
|
||||
Adding new languages requires adding the translated files in the
|
||||
"src/locale/" folder and adjusting the file
|
||||
"src/paperless/settings.py" to include the new language:
|
||||
`src/locale/`-folder and adjusting the file
|
||||
`src/paperless/settings.py` to include the new language:
|
||||
|
||||
```python
|
||||
LANGUAGES = [
|
||||
@@ -360,18 +341,27 @@ LANGUAGES = [
|
||||
The documentation is built using material-mkdocs, see their [documentation](https://squidfunk.github.io/mkdocs-material/reference/).
|
||||
If you want to build the documentation locally, this is how you do it:
|
||||
|
||||
1. Install python dependencies.
|
||||
1. Have an active pipenv shell (`pipenv shell`) and install Python dependencies:
|
||||
|
||||
```shell-session
|
||||
$ cd /path/to/paperless
|
||||
```bash
|
||||
$ pipenv install --dev
|
||||
```
|
||||
|
||||
2. Build the documentation
|
||||
|
||||
```shell-session
|
||||
$ cd /path/to/paperless
|
||||
$ pipenv mkdocs build --config-file mkdocs.yml
|
||||
```bash
|
||||
$ mkdocs build --config-file mkdocs.yml
|
||||
```
|
||||
|
||||
_alternatively..._
|
||||
|
||||
3. Serve the documentation. This will spin up a
|
||||
copy of the documentation at http://127.0.0.1:8000
|
||||
that will automatically refresh everytime you change
|
||||
something.
|
||||
|
||||
```bash
|
||||
$ mkdocs serve
|
||||
```
|
||||
|
||||
## Building the Docker image
|
||||
@@ -384,35 +374,35 @@ helper script `build-docker-image.sh`.
|
||||
|
||||
Building the docker image from source:
|
||||
|
||||
```shell-session
|
||||
```bash
|
||||
./build-docker-image.sh Dockerfile -t <your-tag>
|
||||
```
|
||||
|
||||
## Extending Paperless
|
||||
## Extending Paperless-ngx
|
||||
|
||||
Paperless does not have any fancy plugin systems and will probably never
|
||||
Paperless-ngx does not have any fancy plugin systems and will probably never
|
||||
have. However, some parts of the application have been designed to allow
|
||||
easy integration of additional features without any modification to the
|
||||
base code.
|
||||
|
||||
### Making custom parsers
|
||||
|
||||
Paperless uses parsers to add documents to paperless. A parser is
|
||||
Paperless-ngx uses parsers to add documents. A parser is
|
||||
responsible for:
|
||||
|
||||
- Retrieve the content from the original
|
||||
- Create a thumbnail
|
||||
- Optional: Retrieve a created date from the original
|
||||
- Optional: Create an archived document from the original
|
||||
- Retrieving the content from the original
|
||||
- Creating a thumbnail
|
||||
- _optional:_ Retrieving a created date from the original
|
||||
- _optional:_ Creainge an archived document from the original
|
||||
|
||||
Custom parsers can be added to paperless to support more file types. In
|
||||
Custom parsers can be added to Paperless-ngx to support more file types. In
|
||||
order to do that, you need to write the parser itself and announce its
|
||||
existence to paperless.
|
||||
existence to Paperless-ngx.
|
||||
|
||||
The parser itself must extend `documents.parsers.DocumentParser` and
|
||||
must implement the methods `parse` and `get_thumbnail`. You can provide
|
||||
your own implementation to `get_date` if you don't want to rely on
|
||||
paperless' default date guessing mechanisms.
|
||||
Paperless-ngx' default date guessing mechanisms.
|
||||
|
||||
```python
|
||||
class MyCustomParser(DocumentParser):
|
||||
@@ -444,7 +434,7 @@ to be empty and removed after consumption finished. You can use that
|
||||
directory to store any intermediate files and also use it to store the
|
||||
thumbnail / archived document.
|
||||
|
||||
After that, you need to announce your parser to paperless. You need to
|
||||
After that, you need to announce your parser to Paperless-ngx. You need to
|
||||
connect a handler to the `document_consumer_declaration` signal. Have a
|
||||
look in the file `src/paperless_tesseract/apps.py` on how that's done.
|
||||
The handler is a method that returns information about your parser:
|
||||
@@ -464,11 +454,11 @@ def myparser_consumer_declaration(sender, **kwargs):
|
||||
- `parser` is a reference to a class that extends `DocumentParser`.
|
||||
- `weight` is used whenever two or more parsers are able to parse a
|
||||
file: The parser with the higher weight wins. This can be used to
|
||||
override the parsers provided by paperless.
|
||||
override the parsers provided by Paperless-ngx.
|
||||
- `mime_types` is a dictionary. The keys are the mime types your
|
||||
parser supports and the value is the default file extension that
|
||||
paperless should use when storing files and serving them for
|
||||
Paperless-ngx should use when storing files and serving them for
|
||||
download. We could guess that from the file extensions, but some
|
||||
mime types have many extensions associated with them and the python
|
||||
mime types have many extensions associated with them and the Python
|
||||
methods responsible for guessing the extension do not always return
|
||||
the same value.
|
||||
|
112
docs/setup.md
112
docs/setup.md
@@ -46,7 +46,7 @@ steps described in [Docker setup](#docker_hub) automatically.
|
||||
page](https://github.com/paperless-ngx/paperless-ngx/tree/master/docker/compose)
|
||||
and download one of the `docker-compose.*.yml` files,
|
||||
depending on which database backend you want to use. Rename this
|
||||
file to `docker-compose.*.yml`. If you want to enable
|
||||
file to `docker-compose.yml`. If you want to enable
|
||||
optional support for Office documents, download a file with
|
||||
`-tika` in the file name. Download the
|
||||
`docker-compose.env` file and the `.env` file as well and store them
|
||||
@@ -64,8 +64,7 @@ steps described in [Docker setup](#docker_hub) automatically.
|
||||
|
||||
If you want to use the included `docker-compose.*.yml` file, you
|
||||
need to have at least Docker version **17.09.0** and docker-compose
|
||||
version **1.17.0**. To check do: `docker-compose -v` or
|
||||
`docker -v`
|
||||
version **1.17.0**. To check do: `docker-compose -v` or `docker -v`
|
||||
|
||||
See the [Docker installation guide](https://docs.docker.com/engine/install/) on how to install the current
|
||||
version of Docker for your operating system or Linux distribution of
|
||||
@@ -144,21 +143,13 @@ steps described in [Docker setup](#docker_hub) automatically.
|
||||
!!! note
|
||||
|
||||
You can copy any setting from the file `paperless.conf.example` and
|
||||
paste it here. Have a look at [configuration](/configuration] to see what's available.
|
||||
paste it here. Have a look at [configuration](/configuration) to see what's available.
|
||||
|
||||
!!! note
|
||||
|
||||
You can utilize Docker secrets for some configuration settings by
|
||||
appending `_FILE` to some configuration values. This is
|
||||
supported currently only by:
|
||||
|
||||
- PAPERLESS_DBUSER
|
||||
- PAPERLESS_DBPASS
|
||||
- PAPERLESS_SECRET_KEY
|
||||
- PAPERLESS_AUTO_LOGIN_USERNAME
|
||||
- PAPERLESS_ADMIN_USER
|
||||
- PAPERLESS_ADMIN_MAIL
|
||||
- PAPERLESS_ADMIN_PASSWORD
|
||||
You can utilize Docker secrets for configuration settings by
|
||||
appending `_FILE` to configuration values. For example `PAPERLESS_DBUSER`
|
||||
can be set using `PAPERLESS_DBUSER_FILE=/var/run/secrets/password.txt`.
|
||||
|
||||
!!! warning
|
||||
|
||||
@@ -314,14 +305,34 @@ supported.
|
||||
extension](https://code.djangoproject.com/wiki/JSON1Extension) is
|
||||
enabled. This is usually the case, but not always.
|
||||
|
||||
4. Get the release archive from
|
||||
<https://github.com/paperless-ngx/paperless-ngx/releases>. Extract the
|
||||
archive to a place from where you wish to execute it, such as
|
||||
`/opt/paperless`. If you clone the git repo as it is, you also have to
|
||||
4. Create a system user with a new home folder under which you wish
|
||||
to run paperless.
|
||||
|
||||
```shell-session
|
||||
adduser paperless --system --home /opt/paperless --group
|
||||
```
|
||||
|
||||
5. Get the release archive from
|
||||
<https://github.com/paperless-ngx/paperless-ngx/releases> for example with
|
||||
|
||||
```shell-session
|
||||
curl -O -L https://github.com/paperless-ngx/paperless-ngx/releases/download/v1.10.2/paperless-ngx-v1.10.2.tar.xz
|
||||
```
|
||||
|
||||
Extract the archive with
|
||||
|
||||
```shell-session
|
||||
tar -xf paperless-ngx-v1.10.2.tar.xz
|
||||
```
|
||||
|
||||
and copy the contents to the
|
||||
home folder of the user you created before (`/opt/paperless`).
|
||||
|
||||
Optional: If you cloned the git repo, you will have to
|
||||
compile the frontend yourself, see [here](/development#front-end-development)
|
||||
and use the `build` step, not `serve`.
|
||||
|
||||
5. Configure paperless. See [configuration](/configuration) for details.
|
||||
6. Configure paperless. See [configuration](/configuration) for details.
|
||||
Edit the included `paperless.conf` and adjust the settings to your
|
||||
needs. Required settings for getting
|
||||
paperless running are:
|
||||
@@ -354,29 +365,31 @@ supported.
|
||||
documents are written in.
|
||||
- Set `PAPERLESS_TIME_ZONE` to your local time zone.
|
||||
|
||||
6. Create a system user under which you wish to run paperless.
|
||||
|
||||
```shell-session
|
||||
adduser paperless --system --home /opt/paperless --group
|
||||
```
|
||||
|
||||
7. Ensure that these directories exist and that the paperless user has
|
||||
write permissions to the following directories:
|
||||
7. Create the following directories if they are missing:
|
||||
|
||||
- `/opt/paperless/media`
|
||||
- `/opt/paperless/data`
|
||||
- `/opt/paperless/consume`
|
||||
|
||||
Adjust as necessary if you configured different folders.
|
||||
|
||||
8. Install python requirements from the `requirements.txt` file. It is
|
||||
up to you if you wish to use a virtual environment or not. First you
|
||||
should update your pip, so it gets the actual packages.
|
||||
Ensure that the paperless user has write permissions for every one
|
||||
of these folders with
|
||||
|
||||
```shell-session
|
||||
sudo -Hu paperless pip3 install --upgrade pip
|
||||
ls -l -d /opt/paperless/media
|
||||
```
|
||||
|
||||
If needed, change the owner with
|
||||
|
||||
```shell-session
|
||||
sudo chown paperless:paperless /opt/paperless/media
|
||||
sudo chown paperless:paperless /opt/paperless/data
|
||||
sudo chown paperless:paperless /opt/paperless/consume
|
||||
```
|
||||
|
||||
8. Install python requirements from the `requirements.txt` file. It is
|
||||
up to you if you wish to use a virtual environment or not. First you should update your pip, so it gets the actual packages.
|
||||
|
||||
```shell-session
|
||||
sudo -Hu paperless pip3 install -r requirements.txt
|
||||
```
|
||||
@@ -397,11 +410,15 @@ supported.
|
||||
10. Optional: Test that paperless is working by executing
|
||||
|
||||
```bash
|
||||
# This collects static files from paperless and django.
|
||||
# Manually starts the webserver
|
||||
sudo -Hu paperless python3 manage.py runserver
|
||||
```
|
||||
|
||||
and pointing your browser to <http://localhost:8000/>.
|
||||
and pointing your browser to http://localhost:8000 if
|
||||
accessing from the same devices on which paperless is installed.
|
||||
If accessing from another machine, set up systemd services. You may need
|
||||
to set `PAPERLESS_DEBUG=true` in order for the development server to work
|
||||
normally in your browser.
|
||||
|
||||
!!! warning
|
||||
|
||||
@@ -452,6 +469,14 @@ supported.
|
||||
For instructions on how to use nginx for that,
|
||||
[see the instructions below](/setup#nginx).
|
||||
|
||||
!!! warning
|
||||
|
||||
If celery won't start (check with
|
||||
`sudo systemctl status paperless-task-queue.service` for
|
||||
paperless-task-queue.service and paperless-scheduler.service
|
||||
) you need to change the path in the files. Example:
|
||||
`ExecStart=/opt/paperless/.local/bin/celery --app paperless worker --loglevel INFO`
|
||||
|
||||
12. Optional: Install a samba server and make the consumption folder
|
||||
available as a network share.
|
||||
|
||||
@@ -683,6 +708,12 @@ below use PostgreSQL, but are applicable to MySQL/MariaDB with the
|
||||
MySQL also enforces limits on maximum lengths, but does so differently than
|
||||
PostgreSQL. It may not be possible to migrate to MySQL due to this.
|
||||
|
||||
!!! warning
|
||||
|
||||
Using mariadb version 10.4+ is recommended. Using the `utf8mb3` character set on
|
||||
an older system may fix issues that can arise while setting up Paperless-ngx but
|
||||
`utf8mb3` can cause issues with consumption (where `utf8mb4` does not).
|
||||
|
||||
1. Stop paperless, if it is running.
|
||||
|
||||
2. Tell paperless to use PostgreSQL:
|
||||
@@ -746,7 +777,9 @@ with a few simple steps.
|
||||
|
||||
Paperless-ngx modified the database schema slightly, however, these
|
||||
changes can be reverted while keeping your current data, so that your
|
||||
current data will be compatible with original Paperless.
|
||||
current data will be compatible with original Paperless. Thumbnails
|
||||
were also changed from PNG to WEBP format and will need to be
|
||||
re-generated.
|
||||
|
||||
Execute this:
|
||||
|
||||
@@ -762,9 +795,9 @@ $ cd /path/to/paperless/src
|
||||
$ python3 manage.py migrate documents 0023
|
||||
```
|
||||
|
||||
After that, you need to clear your cookies (Paperless-ngx comes with
|
||||
updated dependencies that do cookie-processing differently) and probably
|
||||
your cache as well.
|
||||
After regenerating thumbnails, you'll need to clear your cookies
|
||||
(Paperless-ngx comes with updated dependencies that do cookie-processing
|
||||
differently) and probably your cache as well.
|
||||
|
||||
# Considerations for less powerful devices {#less-powerful-devices}
|
||||
|
||||
@@ -843,6 +876,7 @@ http {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Host $server_name;
|
||||
add_header P3P 'CP=""'; # may not be required in all setups
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -108,6 +108,8 @@ Furthermore, there is the [Paperless
|
||||
App](https://github.com/bauerj/paperless_app) as well, which not only
|
||||
has document upload, but also document browsing and download features.
|
||||
|
||||
Another option is [Paperless Mobile](https://github.com/astubenbord/paperless-mobile), an Android app that supports document upload, scanning, management of labels and more.
|
||||
|
||||
### IMAP (Email) {#usage-email}
|
||||
|
||||
You can tell paperless-ngx to consume documents from your email
|
||||
@@ -151,6 +153,8 @@ different means. These are as follows:
|
||||
will not consume mails already tagged. Not all mail servers support
|
||||
this feature!
|
||||
|
||||
- **Apple Mail support:** Apple Mail clients allow differently colored tags. For this to work use `apple:<color>` (e.g. _apple:green_) as a custom tag. Available colors are _red_, _orange_, _yellow_, _blue_, _green_, _violet_ and _grey_.
|
||||
|
||||
!!! warning
|
||||
|
||||
The mail consumer will perform these actions on all mails it has
|
||||
@@ -191,7 +195,7 @@ different means. These are as follows:
|
||||
them further.
|
||||
|
||||
Paperless is set up to check your mails every 10 minutes. This can be
|
||||
configured on the 'Scheduled tasks' page in the admin.
|
||||
configured via `PAPERLESS_EMAIL_TASK_CRON` (see [software tweaks](/configuration#software_tweaks))
|
||||
|
||||
### REST API
|
||||
|
||||
@@ -359,6 +363,14 @@ documents in your inbox:
|
||||
sorted by ASN. Don't order this binder in any other way.
|
||||
5. If the document has no ASN, throw it away. Yay!
|
||||
|
||||
!!! tip
|
||||
|
||||
Instead of writing a number on the document by hand, you may also prepare
|
||||
a spool of labels with barcodes with an ascending serial number, that are
|
||||
formatted like `ASN00001`.
|
||||
This also enables Paperless to automatically parse and process the ASN
|
||||
(if enabled in the config), so that you don't need to manually assign it.
|
||||
|
||||
Over time, you will notice that your physical binder will fill up. If it
|
||||
is full, label the binder with the range of ASNs in this binder (i.e.,
|
||||
"Documents 1 to 343"), store the binder in your cellar or elsewhere,
|
||||
|
@@ -321,7 +321,7 @@ fi
|
||||
wget "https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/docker-compose.$DOCKER_COMPOSE_VERSION.yml" -O docker-compose.yml
|
||||
wget "https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/.env" -O .env
|
||||
|
||||
SECRET_KEY=$(tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 64 | head -n 1)
|
||||
SECRET_KEY=$(tr --delete --complement 'a-zA-Z0-9' < /dev/urandom 2>/dev/null | head --bytes 64)
|
||||
|
||||
DEFAULT_LANGUAGES=("deu eng fra ita spa")
|
||||
|
||||
@@ -346,7 +346,7 @@ read -r -a OCR_LANGUAGES_ARRAY <<< "${_split_langs}"
|
||||
fi
|
||||
} > docker-compose.env
|
||||
|
||||
sed -i "s/- 8000:8000/- $PORT:8000/g" docker-compose.yml
|
||||
sed -i "s/- \"8000:8000\"/- \"$PORT:8000\"/g" docker-compose.yml
|
||||
|
||||
sed -i "s#- \./consume:/usr/src/paperless/consume#- $CONSUME_FOLDER:/usr/src/paperless/consume#g" docker-compose.yml
|
||||
|
||||
|
@@ -41,6 +41,7 @@ markdown_extensions:
|
||||
anchor_linenums: true
|
||||
- pymdownx.superfences
|
||||
- pymdownx.inlinehilite
|
||||
- pymdownx.snippets
|
||||
strict: true
|
||||
nav:
|
||||
- index.md
|
||||
@@ -54,7 +55,7 @@ nav:
|
||||
- 'FAQs': faq.md
|
||||
- troubleshooting.md
|
||||
- changelog.md
|
||||
copyright: Copyright © 2016 - 2022 Daniel Quinn, Jonas Winkler, and the Paperless-ngx team
|
||||
copyright: Copyright © 2016 - 2023 Daniel Quinn, Jonas Winkler, and the Paperless-ngx team
|
||||
extra:
|
||||
social:
|
||||
- icon: fontawesome/brands/github
|
||||
|
@@ -2,5 +2,5 @@
|
||||
|
||||
docker run -p 5432:5432 -e POSTGRES_PASSWORD=password -v paperless_pgdata:/var/lib/postgresql/data -d postgres:13
|
||||
docker run -d -p 6379:6379 redis:latest
|
||||
docker run -p 3000:3000 -d gotenberg/gotenberg:7.6 gotenberg --chromium-disable-javascript=true --chromium-allow-list="file:///tmp/.*"
|
||||
docker run -p 3000:3000 -d gotenberg/gotenberg:7.8 gotenberg --chromium-disable-javascript=true --chromium-allow-list="file:///tmp/.*"
|
||||
docker run -p 9998:9998 -d ghcr.io/paperless-ngx/tika:latest
|
||||
|
@@ -1,18 +0,0 @@
|
||||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# For the full list of supported browsers by the Angular framework, please see:
|
||||
# https://angular.io/guide/browser-support
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
last 1 Chrome version
|
||||
last 1 Firefox version
|
||||
last 2 Edge major versions
|
||||
last 2 Safari major versions
|
||||
last 2 iOS major versions
|
||||
Firefox ESR
|
||||
not IE 9-10 # Angular support for IE 9-10 has been deprecated and will be removed as of Angular v11. To opt-in, remove the 'not' prefix on this line.
|
||||
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
|
@@ -12,7 +12,7 @@ Run `ng generate component component-name` to generate a new component. You can
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--configuration production` flag for a production build.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
|
@@ -16,6 +16,7 @@
|
||||
"i18n": {
|
||||
"sourceLocale": "en-US",
|
||||
"locales": {
|
||||
"ar-AR": "src/locale/messages.ar_AR.xlf",
|
||||
"be-BY": "src/locale/messages.be_BY.xlf",
|
||||
"cs-CZ": "src/locale/messages.cs_CZ.xlf",
|
||||
"da-DK": "src/locale/messages.da_DK.xlf",
|
||||
@@ -191,6 +192,15 @@
|
||||
"cli": {
|
||||
"schematicCollections": [
|
||||
"@angular-eslint/schematics"
|
||||
]
|
||||
],
|
||||
"analytics": false
|
||||
},
|
||||
"schematics": {
|
||||
"@angular-eslint/schematics:application": {
|
||||
"setParserOptionsProject": true
|
||||
},
|
||||
"@angular-eslint/schematics:library": {
|
||||
"setParserOptionsProject": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -44,7 +44,7 @@ describe('document-detail', () => {
|
||||
})
|
||||
|
||||
cy.viewport(1024, 1024)
|
||||
cy.visit('/documents/1/')
|
||||
cy.visit('/documents/1/').wait('@ui-settings')
|
||||
})
|
||||
|
||||
it('should activate / deactivate save button when changes are saved', () => {
|
||||
@@ -66,8 +66,21 @@ describe('document-detail', () => {
|
||||
cy.contains('You have unsaved changes').should('not.exist')
|
||||
})
|
||||
|
||||
it('should show a mobile preview', () => {
|
||||
cy.viewport(440, 1000)
|
||||
cy.get('a')
|
||||
.contains('Preview')
|
||||
.scrollIntoView({ offset: { top: 150, left: 0 } })
|
||||
.click()
|
||||
cy.get('pdf-viewer').should('be.visible')
|
||||
})
|
||||
|
||||
it('should show a list of comments', () => {
|
||||
cy.wait(1000).get('a').contains('Comments').click().wait(1000)
|
||||
cy.wait(1000)
|
||||
.get('a')
|
||||
.contains('Comments')
|
||||
.click({ force: true })
|
||||
.wait(1000)
|
||||
cy.get('app-document-comments').find('.card').its('length').should('eq', 3)
|
||||
})
|
||||
|
||||
|
@@ -52,6 +52,10 @@ describe('documents-list', () => {
|
||||
|
||||
req.reply(response)
|
||||
})
|
||||
|
||||
cy.intercept('http://localhost:8000/api/documents/selection_data/', {
|
||||
fixture: 'documents/selection_data.json',
|
||||
}).as('selection-data')
|
||||
})
|
||||
|
||||
cy.viewport(1280, 1024)
|
||||
@@ -76,6 +80,28 @@ describe('documents-list', () => {
|
||||
cy.get('app-document-card-large')
|
||||
})
|
||||
|
||||
it('should show partial tag selection', () => {
|
||||
cy.get('app-document-card-small:nth-child(1)').click()
|
||||
cy.get('app-document-card-small:nth-child(4)').click()
|
||||
cy.get('app-bulk-editor button')
|
||||
.contains('Tags')
|
||||
.click()
|
||||
.wait('@selection-data')
|
||||
cy.get('svg.bi-dash').should('be.visible')
|
||||
cy.get('svg.bi-check').should('be.visible')
|
||||
})
|
||||
|
||||
it('should allow bulk removal', () => {
|
||||
cy.get('app-document-card-small:nth-child(1)').click()
|
||||
cy.get('app-document-card-small:nth-child(4)').click()
|
||||
cy.get('app-bulk-editor').within(() => {
|
||||
cy.get('button').contains('Tags').click().wait('@selection-data')
|
||||
cy.get('button').contains('Another Sample Tag').click()
|
||||
cy.get('button').contains('Apply').click()
|
||||
})
|
||||
cy.contains('operation will remove the tag')
|
||||
})
|
||||
|
||||
it('should filter tags', () => {
|
||||
cy.get('app-filter-editor app-filterable-dropdown[title="Tags"]').within(
|
||||
() => {
|
||||
|
@@ -35,16 +35,58 @@ describe('settings', () => {
|
||||
req.reply(response)
|
||||
}
|
||||
).as('savedViews')
|
||||
})
|
||||
|
||||
cy.intercept('http://localhost:8000/api/mail_accounts/*', {
|
||||
fixture: 'mail_accounts/mail_accounts.json',
|
||||
})
|
||||
cy.intercept('http://localhost:8000/api/mail_rules/*', {
|
||||
fixture: 'mail_rules/mail_rules.json',
|
||||
}).as('mailRules')
|
||||
cy.intercept('http://localhost:8000/api/tasks/', {
|
||||
fixture: 'tasks/tasks.json',
|
||||
})
|
||||
this.newMailAccounts = []
|
||||
|
||||
cy.intercept(
|
||||
'POST',
|
||||
'http://localhost:8000/api/mail_accounts/',
|
||||
(req) => {
|
||||
const newRule = req.body
|
||||
newRule.id = 3
|
||||
this.newMailAccounts.push(newRule) // store this for later
|
||||
req.reply({ result: 'OK' })
|
||||
}
|
||||
).as('saveAccount')
|
||||
|
||||
cy.fixture('mail_accounts/mail_accounts.json').then(
|
||||
(mailAccountsJson) => {
|
||||
cy.intercept(
|
||||
'GET',
|
||||
'http://localhost:8000/api/mail_accounts/*',
|
||||
(req) => {
|
||||
console.log(req, this.newMailAccounts)
|
||||
|
||||
let response = { ...mailAccountsJson }
|
||||
if (this.newMailAccounts.length) {
|
||||
response.results = response.results.concat(this.newMailAccounts)
|
||||
}
|
||||
|
||||
req.reply(response)
|
||||
}
|
||||
).as('getAccounts')
|
||||
}
|
||||
)
|
||||
|
||||
this.newMailRules = []
|
||||
|
||||
cy.intercept('POST', 'http://localhost:8000/api/mail_rules/', (req) => {
|
||||
const newRule = req.body
|
||||
newRule.id = 2
|
||||
this.newMailRules.push(newRule) // store this for later
|
||||
req.reply({ result: 'OK' })
|
||||
}).as('saveRule')
|
||||
|
||||
cy.fixture('mail_rules/mail_rules.json').then((mailRulesJson) => {
|
||||
cy.intercept('GET', 'http://localhost:8000/api/mail_rules/*', (req) => {
|
||||
let response = { ...mailRulesJson }
|
||||
if (this.newMailRules.length) {
|
||||
response.results = response.results.concat(this.newMailRules)
|
||||
}
|
||||
|
||||
req.reply(response)
|
||||
}).as('getRules')
|
||||
})
|
||||
|
||||
cy.fixture('documents/documents.json').then((documentsJson) => {
|
||||
@@ -99,4 +141,42 @@ describe('settings', () => {
|
||||
cy.visit('/dashboard')
|
||||
cy.get('app-saved-view-widget').contains('Inbox').should('not.exist')
|
||||
})
|
||||
|
||||
it('should show a list of mail accounts & rules & support creation', () => {
|
||||
cy.contains('a', 'Mail').click()
|
||||
cy.get('app-settings .tab-content ul li').its('length').should('eq', 5) // 2 headers, 2 accounts, 1 rule
|
||||
cy.contains('button', 'Add Account').click()
|
||||
cy.contains('Create new mail account')
|
||||
cy.get('app-input-text[formcontrolname="name"]').type(
|
||||
'Example Mail Account'
|
||||
)
|
||||
cy.get('app-input-text[formcontrolname="imap_server"]').type(
|
||||
'mail.example.com'
|
||||
)
|
||||
cy.get('app-input-text[formcontrolname="imap_port"]').type('993')
|
||||
cy.get('app-input-text[formcontrolname="username"]').type('username')
|
||||
cy.get('app-input-password[formcontrolname="password"]').type('pass')
|
||||
cy.contains('app-mail-account-edit-dialog button', 'Save')
|
||||
.click()
|
||||
.wait('@saveAccount')
|
||||
.wait('@getAccounts')
|
||||
cy.contains('Saved account')
|
||||
|
||||
cy.wait(1000)
|
||||
cy.contains('button', 'Add Rule').click()
|
||||
cy.contains('Create new mail rule')
|
||||
cy.get('app-input-text[formcontrolname="name"]').type('Example Rule')
|
||||
cy.get('app-input-select[formcontrolname="account"]').type('Example{enter}')
|
||||
cy.get('app-input-number[formcontrolname="maximum_age"]').type('30')
|
||||
cy.get('app-input-text[formcontrolname="filter_subject"]').type(
|
||||
'[paperless]'
|
||||
)
|
||||
cy.contains('app-mail-rule-edit-dialog button', 'Save')
|
||||
.click()
|
||||
.wait('@saveRule')
|
||||
.wait('@getRules')
|
||||
cy.contains('Saved rule').wait(1000)
|
||||
|
||||
cy.get('app-settings .tab-content ul li').its('length').should('eq', 7)
|
||||
})
|
||||
})
|
||||
|
293
src-ui/cypress/fixtures/documents/selection_data.json
Normal file
293
src-ui/cypress/fixtures/documents/selection_data.json
Normal file
@@ -0,0 +1,293 @@
|
||||
{
|
||||
"selected_correspondents": [
|
||||
{
|
||||
"id": 62,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 75,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 55,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 56,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 73,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 58,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 44,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 42,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 74,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 54,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 29,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 71,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 68,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 82,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 34,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 41,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 51,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 46,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 40,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 43,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 80,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 70,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 52,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 67,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 53,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 32,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 63,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 35,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 45,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 38,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 79,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 48,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 72,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 78,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 39,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 57,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 61,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 81,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 77,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 69,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 36,
|
||||
"document_count": 3
|
||||
},
|
||||
{
|
||||
"id": 31,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 30,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 50,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 49,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 60,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 47,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 66,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 37,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 28,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 59,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 33,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 76,
|
||||
"document_count": 0
|
||||
}
|
||||
],
|
||||
"selected_tags": [
|
||||
{
|
||||
"id": 4,
|
||||
"document_count": 2
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"document_count": 1
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"document_count": 1
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"document_count": 0
|
||||
}
|
||||
],
|
||||
"selected_document_types": [
|
||||
{
|
||||
"id": 4,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"document_count": 2
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"document_count": 0
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"document_count": 1
|
||||
}
|
||||
],
|
||||
"selected_storage_paths": []
|
||||
}
|
@@ -23,7 +23,8 @@
|
||||
"assign_correspondent": 2,
|
||||
"assign_document_type": null,
|
||||
"order": 0,
|
||||
"attachment_type": 2
|
||||
"attachment_type": 2,
|
||||
"consumption_scope": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
beforeEach(() => {
|
||||
cy.intercept('http://localhost:8000/api/ui_settings/', {
|
||||
fixture: 'ui_settings/settings.json',
|
||||
})
|
||||
}).as('ui-settings')
|
||||
|
||||
cy.intercept('http://localhost:8000/api/remote_version/', {
|
||||
fixture: 'remote_version/remote_version.json',
|
||||
@@ -29,6 +29,10 @@ beforeEach(() => {
|
||||
fixture: 'storage_paths/storage_paths.json',
|
||||
})
|
||||
|
||||
cy.intercept('http://localhost:8000/api/tasks/', {
|
||||
fixture: 'tasks/tasks.json',
|
||||
})
|
||||
|
||||
cy.intercept('http://localhost:8000/api/documents/1/metadata/', {
|
||||
fixture: 'documents/1/metadata.json',
|
||||
})
|
||||
|
File diff suppressed because it is too large
Load Diff
19479
src-ui/package-lock.json
generated
19479
src-ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -13,46 +13,46 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/common": "~14.2.8",
|
||||
"@angular/compiler": "~14.2.8",
|
||||
"@angular/core": "~14.2.8",
|
||||
"@angular/forms": "~14.2.8",
|
||||
"@angular/localize": "~14.2.8",
|
||||
"@angular/platform-browser": "~14.2.8",
|
||||
"@angular/platform-browser-dynamic": "~14.2.8",
|
||||
"@angular/router": "~14.2.8",
|
||||
"@ng-bootstrap/ng-bootstrap": "^13.0.0",
|
||||
"@ng-select/ng-select": "^9.0.2",
|
||||
"@angular/common": "~15.1.2",
|
||||
"@angular/compiler": "~15.1.2",
|
||||
"@angular/core": "~15.1.2",
|
||||
"@angular/forms": "~15.1.2",
|
||||
"@angular/localize": "~15.1.2",
|
||||
"@angular/platform-browser": "~15.1.2",
|
||||
"@angular/platform-browser-dynamic": "~15.1.2",
|
||||
"@angular/router": "~15.1.2",
|
||||
"@ng-bootstrap/ng-bootstrap": "^14.0.1",
|
||||
"@ng-select/ng-select": "^10.0.1",
|
||||
"@ngneat/dirty-check-forms": "^3.0.3",
|
||||
"@popperjs/core": "^2.11.6",
|
||||
"bootstrap": "^5.2.1",
|
||||
"bootstrap": "^5.2.3",
|
||||
"file-saver": "^2.0.5",
|
||||
"ng2-pdf-viewer": "^9.1.2",
|
||||
"ngx-color": "^8.0.3",
|
||||
"ngx-cookie-service": "^14.0.1",
|
||||
"ngx-cookie-service": "^15.0.0",
|
||||
"ngx-file-drop": "^14.0.2",
|
||||
"ngx-ui-tour-ng-bootstrap": "^11.1.0",
|
||||
"rxjs": "~7.5.7",
|
||||
"ngx-ui-tour-ng-bootstrap": "^12.0.0",
|
||||
"rxjs": "^7.8.0",
|
||||
"tslib": "^2.4.1",
|
||||
"uuid": "^9.0.0",
|
||||
"zone.js": "~0.11.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-builders/jest": "14.1.0",
|
||||
"@angular-devkit/build-angular": "~14.2.7",
|
||||
"@angular-eslint/builder": "14.4.0",
|
||||
"@angular-eslint/eslint-plugin": "14.4.0",
|
||||
"@angular-eslint/eslint-plugin-template": "14.4.0",
|
||||
"@angular-eslint/schematics": "14.4.0",
|
||||
"@angular-eslint/template-parser": "14.4.0",
|
||||
"@angular/cli": "~14.2.7",
|
||||
"@angular/compiler-cli": "~14.2.8",
|
||||
"@angular-builders/jest": "15.0.0",
|
||||
"@angular-devkit/build-angular": "~15.1.4",
|
||||
"@angular-eslint/builder": "15.2.0",
|
||||
"@angular-eslint/eslint-plugin": "15.2.0",
|
||||
"@angular-eslint/eslint-plugin-template": "15.2.0",
|
||||
"@angular-eslint/schematics": "15.2.0",
|
||||
"@angular-eslint/template-parser": "15.2.0",
|
||||
"@angular/cli": "~15.1.4",
|
||||
"@angular/compiler-cli": "~15.1.2",
|
||||
"@types/jest": "28.1.6",
|
||||
"@types/node": "^18.7.23",
|
||||
"@typescript-eslint/eslint-plugin": "5.43.0",
|
||||
"@typescript-eslint/parser": "5.43.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.43.0",
|
||||
"@typescript-eslint/parser": "^5.50.0",
|
||||
"concurrently": "7.4.0",
|
||||
"eslint": "^8.28.0",
|
||||
"eslint": "^8.31.0",
|
||||
"jest": "28.1.3",
|
||||
"jest-environment-jsdom": "^29.2.2",
|
||||
"jest-preset-angular": "^12.2.3",
|
||||
|
@@ -61,7 +61,7 @@ const routes: Routes = [
|
||||
]
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })],
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AppRoutingModule {}
|
||||
|
@@ -80,6 +80,7 @@ import { TourNgBootstrapModule } from 'ngx-ui-tour-ng-bootstrap'
|
||||
import { MailAccountEditDialogComponent } from './components/common/edit-dialog/mail-account-edit-dialog/mail-account-edit-dialog.component'
|
||||
import { MailRuleEditDialogComponent } from './components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component'
|
||||
|
||||
import localeAr from '@angular/common/locales/ar'
|
||||
import localeBe from '@angular/common/locales/be'
|
||||
import localeCs from '@angular/common/locales/cs'
|
||||
import localeDa from '@angular/common/locales/da'
|
||||
@@ -100,6 +101,7 @@ import localeSv from '@angular/common/locales/sv'
|
||||
import localeTr from '@angular/common/locales/tr'
|
||||
import localeZh from '@angular/common/locales/zh'
|
||||
|
||||
registerLocaleData(localeAr)
|
||||
registerLocaleData(localeBe)
|
||||
registerLocaleData(localeCs)
|
||||
registerLocaleData(localeDa)
|
||||
@@ -198,7 +200,7 @@ function initializeApp(settings: SettingsService) {
|
||||
PdfViewerModule,
|
||||
NgSelectModule,
|
||||
ColorSliderModule,
|
||||
TourNgBootstrapModule.forRoot(),
|
||||
TourNgBootstrapModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
|
@@ -11,7 +11,9 @@
|
||||
<app-input-select i18n-title title="Account" [items]="accounts" formControlName="account"></app-input-select>
|
||||
<app-input-text i18n-title title="Folder" formControlName="folder" i18n-hint hint="Subfolders must be separated by a delimiter, often a dot ('.') or slash ('/'), but it varies by mail server." [error]="error?.folder"></app-input-text>
|
||||
<app-input-number i18n-title title="Maximum age (days)" formControlName="maximum_age" [showAdd]="false" [error]="error?.maximum_age"></app-input-number>
|
||||
<app-input-select i18n-title title="Attachment type" [items]="attachmentTypeOptions" formControlName="attachment_type" i18n-hint hint="See docs for .eml processing requirements"></app-input-select>
|
||||
<app-input-select i18n-title title="Attachment type" [items]="attachmentTypeOptions" formControlName="attachment_type"></app-input-select>
|
||||
<app-input-select i18n-title title="Consumption scope" [items]="consumptionScopeOptions" formControlName="consumption_scope" i18n-hint hint="See docs for .eml processing requirements"></app-input-select>
|
||||
<app-input-number i18n-title title="Rule order" formControlName="order" [showAdd]="false" [error]="error?.order"></app-input-number>
|
||||
</div>
|
||||
<div class="col">
|
||||
<p class="small" i18n>Paperless will only process mails that match <em>all</em> of the filters specified below.</p>
|
||||
|
@@ -12,6 +12,7 @@ import {
|
||||
MailMetadataCorrespondentOption,
|
||||
MailMetadataTitleOption,
|
||||
PaperlessMailRule,
|
||||
MailRuleConsumptionScope,
|
||||
} from 'src/app/data/paperless-mail-rule'
|
||||
import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
|
||||
import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
|
||||
@@ -21,15 +22,26 @@ import { MailRuleService } from 'src/app/services/rest/mail-rule.service'
|
||||
const ATTACHMENT_TYPE_OPTIONS = [
|
||||
{
|
||||
id: MailFilterAttachmentType.Attachments,
|
||||
name: $localize`Only process attachments.`,
|
||||
},
|
||||
{
|
||||
id: MailFilterAttachmentType.Email_Only,
|
||||
name: $localize`Process with embedded attachments as .eml`,
|
||||
name: $localize`Only process attachments`,
|
||||
},
|
||||
{
|
||||
id: MailFilterAttachmentType.Everything,
|
||||
name: $localize`Process as .eml and attachments as separate documents`,
|
||||
name: $localize`Process all files, including 'inline' attachments`,
|
||||
},
|
||||
]
|
||||
|
||||
const CONSUMPTION_SCOPE_OPTIONS = [
|
||||
{
|
||||
id: MailRuleConsumptionScope.Attachments,
|
||||
name: $localize`Only process attachments`,
|
||||
},
|
||||
{
|
||||
id: MailRuleConsumptionScope.Email_Only,
|
||||
name: $localize`Process message as .eml`,
|
||||
},
|
||||
{
|
||||
id: MailRuleConsumptionScope.Everything,
|
||||
name: $localize`Process message as .eml and attachments separately`,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -140,6 +152,8 @@ export class MailRuleEditDialogComponent extends EditDialogComponent<PaperlessMa
|
||||
filter_attachment_filename: new FormControl(null),
|
||||
maximum_age: new FormControl(null),
|
||||
attachment_type: new FormControl(MailFilterAttachmentType.Attachments),
|
||||
consumption_scope: new FormControl(MailRuleConsumptionScope.Attachments),
|
||||
order: new FormControl(null),
|
||||
action: new FormControl(MailAction.MarkRead),
|
||||
action_parameter: new FormControl(null),
|
||||
assign_title_from: new FormControl(MailMetadataTitleOption.FromSubject),
|
||||
@@ -181,4 +195,8 @@ export class MailRuleEditDialogComponent extends EditDialogComponent<PaperlessMa
|
||||
get metadataCorrespondentOptions() {
|
||||
return METADATA_CORRESPONDENT_OPTIONS
|
||||
}
|
||||
|
||||
get consumptionScopeOptions() {
|
||||
return CONSUMPTION_SCOPE_OPTIONS
|
||||
}
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@
|
||||
(blur)="onBlur()">
|
||||
|
||||
<ng-template ng-label-tmp let-item="item">
|
||||
<span class="tag-wrap tag-wrap-delete" (click)="removeTag(item.id)">
|
||||
<span class="tag-wrap tag-wrap-delete" (mousedown)="removeTag($event, item.id)">
|
||||
<svg width="1.2em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#x"/>
|
||||
</svg>
|
||||
|
@@ -65,7 +65,7 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
|
||||
|
||||
private _lastSearchTerm: string
|
||||
|
||||
getTag(id) {
|
||||
getTag(id: number) {
|
||||
if (this.tags) {
|
||||
return this.tags.find((tag) => tag.id == id)
|
||||
} else {
|
||||
@@ -73,7 +73,10 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
|
||||
}
|
||||
}
|
||||
|
||||
removeTag(id) {
|
||||
removeTag(event: PointerEvent, id: number) {
|
||||
// prevent opening dropdown
|
||||
event.stopImmediatePropagation()
|
||||
|
||||
let index = this.value.indexOf(id)
|
||||
if (index > -1) {
|
||||
let oldValue = this.value
|
||||
|
@@ -63,7 +63,7 @@
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col mb-4">
|
||||
<div class="col-md-6 col-xl-4 mb-4">
|
||||
|
||||
<form [formGroup]='documentForm' (ngSubmit)="save()">
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
<a ngbNavLink i18n>Content</a>
|
||||
<ng-template ngbNavContent>
|
||||
<div class="mb-3">
|
||||
<textarea class="form-control" id="content" rows="20" formControlName='content'></textarea>
|
||||
<textarea class="form-control" id="content" rows="20" formControlName='content' [class.rtl]="isRTL"></textarea>
|
||||
</div>
|
||||
</ng-template>
|
||||
</li>
|
||||
@@ -149,7 +149,7 @@
|
||||
|
||||
<li [ngbNavItem]="4" class="d-md-none">
|
||||
<a ngbNavLink>Preview</a>
|
||||
<ng-template ngbNavContent *ngIf="pdfPreview.offsetParent === undefined">
|
||||
<ng-template ngbNavContent *ngIf="!pdfPreview.offsetParent">
|
||||
<div class="position-relative">
|
||||
<ng-container *ngIf="getContentType() === 'application/pdf'">
|
||||
<div class="preview-sticky pdf-viewer-container" *ngIf="!useNativePdfViewer ; else nativePdfViewer">
|
||||
@@ -180,9 +180,9 @@
|
||||
|
||||
<div [ngbNavOutlet]="nav" class="mt-2"></div>
|
||||
|
||||
<button type="button" class="btn btn-outline-secondary" (click)="discard()" i18n [disabled]="networkActive || (isDirty$ | async) === false">Discard</button>
|
||||
<button type="button" class="btn btn-outline-primary" (click)="saveEditNext()" *ngIf="hasNext()" i18n [disabled]="networkActive || (isDirty$ | async) === false || error">Save & next</button>
|
||||
<button type="submit" class="btn btn-primary" i18n [disabled]="networkActive || (isDirty$ | async) === false || error">Save</button>
|
||||
<button type="button" class="btn btn-outline-secondary" (click)="discard()" i18n [disabled]="networkActive || (isDirty$ | async) !== true">Discard</button>
|
||||
<button type="button" class="btn btn-outline-primary" (click)="saveEditNext()" *ngIf="hasNext()" i18n [disabled]="networkActive || (isDirty$ | async) !== true || error">Save & next</button>
|
||||
<button type="submit" class="btn btn-primary" i18n [disabled]="networkActive || (isDirty$ | async) !== true || error">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
@@ -22,9 +22,22 @@
|
||||
--page-margin: 1px 0 20px;
|
||||
}
|
||||
|
||||
::ng-deep .ng-select-taggable {
|
||||
max-width: calc(100% - 46px); // fudge factor for ng-select button width
|
||||
}
|
||||
|
||||
.btn-group .dropdown-toggle-split {
|
||||
border-top-right-radius: inherit;
|
||||
border-bottom-right-radius: inherit;
|
||||
}
|
||||
|
||||
.password-prompt {
|
||||
position: absolute;
|
||||
top: 30%;
|
||||
left: 30%;
|
||||
right: 30%;
|
||||
}
|
||||
|
||||
textarea.rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
|
@@ -135,6 +135,13 @@ export class DocumentDetailComponent
|
||||
: this.metadata?.original_mime_type
|
||||
}
|
||||
|
||||
get isRTL() {
|
||||
if (!this.metadata || !this.metadata.lang) return false
|
||||
else {
|
||||
return ['ar', 'he', 'fe'].includes(this.metadata.lang)
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.documentForm.valueChanges
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
@@ -197,6 +204,10 @@ export class DocumentDetailComponent
|
||||
)
|
||||
.subscribe({
|
||||
next: (titleValue) => {
|
||||
// In the rare case when the field changed just after debounced event was fired.
|
||||
// We dont want to overwrite whats actually in the text field, so just return
|
||||
if (titleValue !== this.titleInput.value) return
|
||||
|
||||
this.title = titleValue
|
||||
this.documentForm.patchValue({ title: titleValue })
|
||||
},
|
||||
|
@@ -31,7 +31,7 @@
|
||||
[editing]="true"
|
||||
[multiple]="true"
|
||||
[applyOnClose]="applyOnClose"
|
||||
(open)="openTagsDropdown()"
|
||||
(opened)="openTagsDropdown()"
|
||||
[(selectionModel)]="tagSelectionModel"
|
||||
(apply)="setTags($event)">
|
||||
</app-filterable-dropdown>
|
||||
@@ -40,7 +40,7 @@
|
||||
[items]="correspondents"
|
||||
[editing]="true"
|
||||
[applyOnClose]="applyOnClose"
|
||||
(open)="openCorrespondentDropdown()"
|
||||
(opened)="openCorrespondentDropdown()"
|
||||
[(selectionModel)]="correspondentSelectionModel"
|
||||
(apply)="setCorrespondents($event)">
|
||||
</app-filterable-dropdown>
|
||||
@@ -49,7 +49,7 @@
|
||||
[items]="documentTypes"
|
||||
[editing]="true"
|
||||
[applyOnClose]="applyOnClose"
|
||||
(open)="openDocumentTypeDropdown()"
|
||||
(opened)="openDocumentTypeDropdown()"
|
||||
[(selectionModel)]="documentTypeSelectionModel"
|
||||
(apply)="setDocumentTypes($event)">
|
||||
</app-filterable-dropdown>
|
||||
@@ -58,7 +58,7 @@
|
||||
[items]="storagePaths"
|
||||
[editing]="true"
|
||||
[applyOnClose]="applyOnClose"
|
||||
(open)="openStoragePathDropdown()"
|
||||
(opened)="openStoragePathDropdown()"
|
||||
[(selectionModel)]="storagePathsSelectionModel"
|
||||
(apply)="setStoragePaths($event)">
|
||||
</app-filterable-dropdown>
|
||||
|
@@ -25,7 +25,13 @@
|
||||
</h5>
|
||||
</div>
|
||||
<p class="card-text">
|
||||
<span *ngIf="document.__search_hit__" [innerHtml]="document.__search_hit__.highlights"></span>
|
||||
<span *ngIf="document.__search_hit__ && document.__search_hit__.highlights" [innerHtml]="document.__search_hit__.highlights"></span>
|
||||
<span *ngFor="let highlight of searchCommentHighlights" class="d-block">
|
||||
<svg width="1em" height="1em" fill="currentColor" class="me-2">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#chat-left-text"/>
|
||||
</svg>
|
||||
<span [innerHtml]="highlight"></span>
|
||||
</span>
|
||||
<span *ngIf="!document.__search_hit__" class="result-content">{{contentTrimmed}}</span>
|
||||
</p>
|
||||
|
||||
|
@@ -70,6 +70,22 @@ export class DocumentCardLargeComponent {
|
||||
}
|
||||
}
|
||||
|
||||
get searchCommentHighlights() {
|
||||
let highlights = []
|
||||
if (
|
||||
this.document['__search_hit__'] &&
|
||||
this.document['__search_hit__'].comment_highlights
|
||||
) {
|
||||
// only show comments with a match
|
||||
highlights = (
|
||||
this.document['__search_hit__'].comment_highlights as string
|
||||
)
|
||||
.split(',')
|
||||
.filter((higlight) => higlight.includes('<span'))
|
||||
}
|
||||
return highlights
|
||||
}
|
||||
|
||||
getIsThumbInverted() {
|
||||
return this.settingsService.get(SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED)
|
||||
}
|
||||
|
@@ -30,27 +30,27 @@
|
||||
[(selectionModel)]="tagSelectionModel"
|
||||
(selectionModelChange)="updateRules()"
|
||||
[multiple]="true"
|
||||
(open)="onTagsDropdownOpen()"
|
||||
(opened)="onTagsDropdownOpen()"
|
||||
[allowSelectNone]="true"></app-filterable-dropdown>
|
||||
<app-filterable-dropdown class="flex-fill" title="Correspondent" icon="person-fill" i18n-title
|
||||
filterPlaceholder="Filter correspondents" i18n-filterPlaceholder
|
||||
[items]="correspondents"
|
||||
[(selectionModel)]="correspondentSelectionModel"
|
||||
(selectionModelChange)="updateRules()"
|
||||
(open)="onCorrespondentDropdownOpen()"
|
||||
(opened)="onCorrespondentDropdownOpen()"
|
||||
[allowSelectNone]="true"></app-filterable-dropdown>
|
||||
<app-filterable-dropdown class="flex-fill" title="Document type" icon="file-earmark-fill" i18n-title
|
||||
filterPlaceholder="Filter document types" i18n-filterPlaceholder
|
||||
[items]="documentTypes"
|
||||
[(selectionModel)]="documentTypeSelectionModel"
|
||||
(open)="onDocumentTypeDropdownOpen()"
|
||||
(opened)="onDocumentTypeDropdownOpen()"
|
||||
(selectionModelChange)="updateRules()"
|
||||
[allowSelectNone]="true"></app-filterable-dropdown>
|
||||
<app-filterable-dropdown class="me-2 flex-fill" title="Storage path" icon="folder-fill" i18n-title
|
||||
filterPlaceholder="Filter storage paths" i18n-filterPlaceholder
|
||||
[items]="storagePaths"
|
||||
[(selectionModel)]="storagePathSelectionModel"
|
||||
(open)="onStoragePathDropdownOpen()"
|
||||
(opened)="onStoragePathDropdownOpen()"
|
||||
(selectionModelChange)="updateRules()"
|
||||
[allowSelectNone]="true"></app-filterable-dropdown>
|
||||
</div>
|
||||
|
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ngb-pagination class="col-auto" [pageSize]="25" [collectionSize]="collectionSize" [(page)]="page" (pageChange)="reloadData()" aria-label="Default pagination"></ngb-pagination>
|
||||
<ngb-pagination class="col-auto" [pageSize]="25" [collectionSize]="collectionSize" [(page)]="page" [maxSize]="5" (pageChange)="reloadData()" aria-label="Default pagination"></ngb-pagination>
|
||||
</div>
|
||||
|
||||
<table class="table table-striped align-middle border shadow-sm">
|
||||
@@ -72,5 +72,5 @@
|
||||
|
||||
<div class="d-flex">
|
||||
<div i18n *ngIf="collectionSize > 0">{collectionSize, plural, =1 {One {{typeName}}} other {{{collectionSize || 0}} total {{typeNamePlural}}}}</div>
|
||||
<ngb-pagination *ngIf="collectionSize > 20" class="ms-auto" [pageSize]="25" [collectionSize]="collectionSize" [(page)]="page" (pageChange)="reloadData()" aria-label="Default pagination"></ngb-pagination>
|
||||
<ngb-pagination *ngIf="collectionSize > 20" class="ms-auto" [pageSize]="25" [collectionSize]="collectionSize" [(page)]="page" [maxSize]="5" (pageChange)="reloadData()" aria-label="Default pagination"></ngb-pagination>
|
||||
</div>
|
||||
|
@@ -143,7 +143,7 @@
|
||||
<p i18n>
|
||||
<em>No tracking data is collected by the app in any way.</em>
|
||||
</p>
|
||||
<app-input-check i18n-title title="Enable update checking" formControlName="updateCheckingEnabled" i18n-hint hint="Note that for users of thirdy-party containers e.g. linuxserver.io this notification may be 'ahead' of the current third-party release."></app-input-check>
|
||||
<app-input-check i18n-title title="Enable update checking" formControlName="updateCheckingEnabled" i18n-hint hint="Note that for users of third-party containers e.g. linuxserver.io this notification may be 'ahead' of the current third-party release."></app-input-check>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -189,6 +189,14 @@
|
||||
<a ngbNavLink i18n>Saved views</a>
|
||||
<ng-template ngbNavContent>
|
||||
|
||||
<h4 i18n>Settings</h4>
|
||||
<div class="row mb-3">
|
||||
<div class="offset-md-3 col">
|
||||
<app-input-check i18n-title title="Show warning when closing saved views with unsaved changes" formControlName="savedViewsWarnOnUnsavedChange"></app-input-check>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 i18n>Views</h4>
|
||||
<div formGroupName="savedViews">
|
||||
|
||||
<div *ngFor="let view of savedViews" [formGroupName]="view.id" class="row">
|
||||
|
@@ -84,6 +84,7 @@ export class SettingsComponent
|
||||
notificationsConsumerFailed: new FormControl(null),
|
||||
notificationsConsumerSuppressOnDashboard: new FormControl(null),
|
||||
|
||||
savedViewsWarnOnUnsavedChange: new FormControl(null),
|
||||
savedViews: this.savedViewGroup,
|
||||
|
||||
mailAccounts: this.mailAccountGroup,
|
||||
@@ -194,6 +195,9 @@ export class SettingsComponent
|
||||
notificationsConsumerSuppressOnDashboard: this.settings.get(
|
||||
SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD
|
||||
),
|
||||
savedViewsWarnOnUnsavedChange: this.settings.get(
|
||||
SETTINGS_KEYS.SAVED_VIEWS_WARN_ON_UNSAVED_CHANGE
|
||||
),
|
||||
savedViews: {},
|
||||
mailAccounts: {},
|
||||
mailRules: {},
|
||||
@@ -462,6 +466,10 @@ export class SettingsComponent
|
||||
SETTINGS_KEYS.UPDATE_CHECKING_ENABLED,
|
||||
this.settingsForm.value.updateCheckingEnabled
|
||||
)
|
||||
this.settings.set(
|
||||
SETTINGS_KEYS.SAVED_VIEWS_WARN_ON_UNSAVED_CHANGE,
|
||||
this.settingsForm.value.savedViewsWarnOnUnsavedChange
|
||||
)
|
||||
this.settings.setLanguage(this.settingsForm.value.displayLanguage)
|
||||
this.settings
|
||||
.storeSettings()
|
||||
|
@@ -10,4 +10,6 @@ export interface PaperlessDocumentMetadata {
|
||||
original_filename?: string
|
||||
|
||||
has_archive_version?: boolean
|
||||
|
||||
lang?: string
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ export interface SearchHit {
|
||||
rank?: number
|
||||
|
||||
highlights?: string
|
||||
comment_highlights?: string
|
||||
}
|
||||
|
||||
export interface PaperlessDocument extends ObjectWithId {
|
||||
|
@@ -1,6 +1,11 @@
|
||||
import { ObjectWithId } from './object-with-id'
|
||||
|
||||
export enum MailFilterAttachmentType {
|
||||
Attachments = 1,
|
||||
Everything = 2,
|
||||
}
|
||||
|
||||
export enum MailRuleConsumptionScope {
|
||||
Attachments = 1,
|
||||
Email_Only = 2,
|
||||
Everything = 3,
|
||||
@@ -31,6 +36,8 @@ export interface PaperlessMailRule extends ObjectWithId {
|
||||
|
||||
account: number // PaperlessMailAccount.id
|
||||
|
||||
order: number
|
||||
|
||||
folder: string
|
||||
|
||||
filter_from: string
|
||||
|
@@ -41,6 +41,8 @@ export const SETTINGS_KEYS = {
|
||||
UPDATE_CHECKING_ENABLED: 'general-settings:update-checking:enabled',
|
||||
UPDATE_CHECKING_BACKEND_SETTING:
|
||||
'general-settings:update-checking:backend-setting',
|
||||
SAVED_VIEWS_WARN_ON_UNSAVED_CHANGE:
|
||||
'general-settings:saved-views:warn-on-unsaved-change',
|
||||
}
|
||||
|
||||
export const SETTINGS: PaperlessUiSetting[] = [
|
||||
@@ -139,4 +141,9 @@ export const SETTINGS: PaperlessUiSetting[] = [
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.SAVED_VIEWS_WARN_ON_UNSAVED_CHANGE,
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
},
|
||||
]
|
||||
|
@@ -4,17 +4,25 @@ import { first, Observable, Subject } from 'rxjs'
|
||||
import { DocumentListComponent } from '../components/document-list/document-list.component'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { ConfirmDialogComponent } from '../components/common/confirm-dialog/confirm-dialog.component'
|
||||
import { SettingsService } from '../services/settings.service'
|
||||
import { SETTINGS_KEYS } from '../data/paperless-uisettings'
|
||||
|
||||
@Injectable()
|
||||
export class DirtySavedViewGuard
|
||||
implements CanDeactivate<DocumentListComponent>
|
||||
{
|
||||
constructor(private modalService: NgbModal) {}
|
||||
constructor(
|
||||
private modalService: NgbModal,
|
||||
private settings: SettingsService
|
||||
) {}
|
||||
|
||||
canDeactivate(
|
||||
component: DocumentListComponent
|
||||
): boolean | Observable<boolean> {
|
||||
return component.savedViewIsModified ? this.warn(component) : true
|
||||
return component.savedViewIsModified &&
|
||||
this.settings.get(SETTINGS_KEYS.SAVED_VIEWS_WARN_ON_UNSAVED_CHANGE)
|
||||
? this.warn(component)
|
||||
: true
|
||||
}
|
||||
|
||||
warn(component: DocumentListComponent) {
|
||||
|
@@ -13,6 +13,7 @@ export enum FileStatusPhase {
|
||||
|
||||
export const FILE_STATUS_MESSAGES = {
|
||||
document_already_exists: $localize`Document already exists.`,
|
||||
asn_already_exists: $localize`Document with ASN already exists.`,
|
||||
file_not_found: $localize`File not found.`,
|
||||
pre_consume_script_not_found: $localize`:Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Pre-consume script does not exist.`,
|
||||
pre_consume_script_error: $localize`:Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Error while executing pre-consume script.`,
|
||||
|
@@ -146,6 +146,12 @@ export class SettingsService {
|
||||
englishName: 'English (US)',
|
||||
dateInputFormat: 'mm/dd/yyyy',
|
||||
},
|
||||
{
|
||||
code: 'ar-ar',
|
||||
name: $localize`Arabic`,
|
||||
englishName: 'Arabic',
|
||||
dateInputFormat: 'yyyy-mm-dd',
|
||||
},
|
||||
{
|
||||
code: 'be-by',
|
||||
name: $localize`Belarusian`,
|
||||
|
@@ -5,7 +5,7 @@ export const environment = {
|
||||
apiBaseUrl: document.baseURI + 'api/',
|
||||
apiVersion: '2',
|
||||
appTitle: 'Paperless-ngx',
|
||||
version: '1.11.1',
|
||||
version: '1.13.0',
|
||||
webSocketHost: window.location.host,
|
||||
webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:',
|
||||
webSocketBaseUrl: base_url.pathname + 'ws/',
|
||||
|
@@ -1,5 +1,5 @@
|
||||
// This file can be replaced during build by using the `fileReplacements` array.
|
||||
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
|
||||
// `ng build --configuration production` replaces `environment.ts` with `environment.prod.ts`.
|
||||
// The list of file replacements can be found in `angular.json`.
|
||||
|
||||
export const environment = {
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user