Compare commits
256
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3050ed3cb2 | ||
|
|
7bc8325df9 | ||
|
|
2aca64bfcd | ||
|
|
d656de8883 | ||
|
|
32f0ebaac3 | ||
|
|
4e9c4ebd02 | ||
|
|
12abb592be | ||
|
|
4f0951402a | ||
|
|
bf2cdae3b1 | ||
|
|
cd43bc1f66 | ||
|
|
1b24136590 | ||
|
|
e8d5b549de | ||
|
|
3866a77d68 | ||
|
|
360fe68f92 | ||
|
|
c9229f9c80 | ||
|
|
e5b92d895d | ||
|
|
a7643c1c29 | ||
|
|
45fd4e8565 | ||
|
|
211a9d720a | ||
|
|
da9c2735b4 | ||
|
|
d31baca442 | ||
|
|
499d6f79aa | ||
|
|
49e049f1c5 | ||
|
|
7411d7c1e2 | ||
|
|
3f5d3d15fd | ||
|
|
68fb85ceca | ||
|
|
3ebe6d5aef | ||
|
|
566b3ed53d | ||
|
|
a688c747d7 | ||
|
|
83b90e1416 | ||
|
|
23c6f849d6 | ||
|
|
ba6843df83 | ||
|
|
0b90e69119 | ||
|
|
dbe820323e | ||
|
|
47d95d5b0a | ||
|
|
971192f6f3 | ||
|
|
fbfc7df593 | ||
|
|
3c7644ce79 | ||
|
|
4e4a8bcca8 | ||
|
|
dc5586b16d | ||
|
|
1d87b48471 | ||
|
|
353a3432df | ||
|
|
efe94bbf18 | ||
|
|
cea6ec09bc | ||
|
|
4a3276f69c | ||
|
|
f164def2ed | ||
|
|
511c76ae7a | ||
|
|
bfa6dda0de | ||
|
|
54af734971 | ||
|
|
5b9763ecb4 | ||
|
|
438bad23e8 | ||
|
|
ae5a205ba3 | ||
|
|
19b683e7b0 | ||
|
|
0c92027414 | ||
|
|
c4e3b2ca2f | ||
|
|
ba67b89db7 | ||
|
|
06f308ede3 | ||
|
|
214fb8204b | ||
|
|
2a2d7be9f9 | ||
|
|
23304c3746 | ||
|
|
20829c90b2 | ||
|
|
33cc3ce7e0 | ||
|
|
3487b23e88 | ||
|
|
4718fe13c2 | ||
|
|
8592acf6b8 | ||
|
|
88042d7072 | ||
|
|
bf92e52d5c | ||
|
|
419580b3be | ||
|
|
5ee1f6b82b | ||
|
|
410bb6a84e | ||
|
|
af2b5fef13 | ||
|
|
372ac3a40c | ||
|
|
a1507d6079 | ||
|
|
9242a8901a | ||
|
|
1d4f25f930 | ||
|
|
7323ec8d16 | ||
|
|
39d45367d0 | ||
|
|
a6521952b0 | ||
|
|
7148c10f1b | ||
|
|
4a1a66248d | ||
|
|
67d0773231 | ||
|
|
ff370172b5 | ||
|
|
1f707e86cc | ||
|
|
a3dae02cfb | ||
|
|
3eae8a2210 | ||
|
|
0f18fe1853 | ||
|
|
513c61eb79 | ||
|
|
4031233fd4 | ||
|
|
76ff6100a3 | ||
|
|
05c36f91cf | ||
|
|
6625f8962a | ||
|
|
63402b70d2 | ||
|
|
2ae4a7806d | ||
|
|
fcc4ecd007 | ||
|
|
45497250cd | ||
|
|
7dd957140e | ||
|
|
4cd772a39e | ||
|
|
b3906e7bc1 | ||
|
|
e5009b4cd2 | ||
|
|
10bf9fd1f8 | ||
|
|
bd8e68692e | ||
|
|
b8386a1531 | ||
|
|
61534fb29d | ||
|
|
9ad81be38c | ||
|
|
cf7048e336 | ||
|
|
a6105b3ad3 | ||
|
|
a262a82cad | ||
|
|
635c96accf | ||
|
|
5c174a69c2 | ||
|
|
de08d17835 | ||
|
|
ca1e838c52 | ||
|
|
3b73146ecd | ||
|
|
8e3822f8e6 | ||
|
|
3b912a0de1 | ||
|
|
c72791bd21 | ||
|
|
80ba5b561f | ||
|
|
f9f4d4c937 | ||
|
|
0419c52d35 | ||
|
|
93a79be1e2 | ||
|
|
f8afbae2cd | ||
|
|
4a52d346f9 | ||
|
|
7d59d11725 | ||
|
|
5886348188 | ||
|
|
a8135528b1 | ||
|
|
df6b991161 | ||
|
|
3f33f66387 | ||
|
|
870808f3c2 | ||
|
|
b12fcca20d | ||
|
|
61b47e358f | ||
|
|
40a2fb7936 | ||
|
|
9afc8ba43d | ||
|
|
b122a05c71 | ||
|
|
f568a9fdfa | ||
|
|
a350bb3086 | ||
|
|
8ae4b7560b | ||
|
|
96f4924911 | ||
|
|
f3703fc6e3 | ||
|
|
0d5fd229bf | ||
|
|
1519e66550 | ||
|
|
fcae461430 | ||
|
|
039d797dfc | ||
|
|
4f61868b28 | ||
|
|
9efbc55fd6 | ||
|
|
2e4e88114e | ||
|
|
8ee2e8b23d | ||
|
|
37287c3e7e | ||
|
|
814d90745b | ||
|
|
48e8076e34 | ||
|
|
edb9d934b2 | ||
|
|
ed44f0cb04 | ||
|
|
1c2f3cf9af | ||
|
|
13afd25690 | ||
|
|
f9b6374685 | ||
|
|
56c9b578e3 | ||
|
|
e792a00feb | ||
|
|
c35c4eade9 | ||
|
|
5bf725546b | ||
|
|
6b6862705e | ||
|
|
b89b51b121 | ||
|
|
1b31388232 | ||
|
|
8256e73f04 | ||
|
|
fc4e59ec00 | ||
|
|
428e00ba23 | ||
|
|
2ccbb08c3f | ||
|
|
eefc026a17 | ||
|
|
d89022a280 | ||
|
|
93bd24c9d2 | ||
|
|
197aec2945 | ||
|
|
e16d58cff5 | ||
|
|
92667009be | ||
|
|
c93657f40e | ||
|
|
16658f5939 | ||
|
|
ec0af59596 | ||
|
|
9e1f9d6d9d | ||
|
|
e652b927ce | ||
|
|
5a97f3f94b | ||
|
|
9494c243a4 | ||
|
|
c0a1be4325 | ||
|
|
70fda8e2f8 | ||
|
|
5765893f69 | ||
|
|
dc26c9b7cc | ||
|
|
17b9d7eb42 | ||
|
|
0a897cae32 | ||
|
|
37f56e824a | ||
|
|
a8e7ec0e96 | ||
|
|
b86d853cf1 | ||
|
|
da0c94c9a1 | ||
|
|
0547fd2760 | ||
|
|
e0a6df8435 | ||
|
|
c2d4ca7566 | ||
|
|
56ce278bbd | ||
|
|
e112541f5b | ||
|
|
17c7b0840b | ||
|
|
68658bd407 | ||
|
|
9184845a9d | ||
|
|
8ddb2fb305 | ||
|
|
96f53986b7 | ||
|
|
8566682209 | ||
|
|
4f9ae17059 | ||
|
|
7f9f805c5f | ||
|
|
5208e81715 | ||
|
|
01a786c117 | ||
|
|
8bf4f31954 | ||
|
|
07ab3e98ed | ||
|
|
ba5899de7b | ||
|
|
a4fef056ed | ||
|
|
c266cd6aae | ||
|
|
43d05b2e6d | ||
|
|
6f0c14cc07 | ||
|
|
2eac8fa91c | ||
|
|
31f5e178b3 | ||
|
|
c3d7088168 | ||
|
|
a9e11b1cb7 | ||
|
|
ee51a0be13 | ||
|
|
1091387f48 | ||
|
|
4db75537cb | ||
|
|
cb4e738a0f | ||
|
|
0cc32e7ed7 | ||
|
|
94f90e1e81 | ||
|
|
ce8f315747 | ||
|
|
b761a549c0 | ||
|
|
dd7c5da256 | ||
|
|
02dd7ec615 | ||
|
|
b7b448b870 | ||
|
|
b7326afe5a | ||
|
|
a3c4e4c6b6 | ||
|
|
645297d68c | ||
|
|
6d8782f771 | ||
|
|
2728183eee | ||
|
|
3d0891c73b | ||
|
|
8226a8793e | ||
|
|
d01477b337 | ||
|
|
6bb07c72ab | ||
|
|
a009462b80 | ||
|
|
9111b130e4 | ||
|
|
1dbd7b9bb4 | ||
|
|
2f95dfc0e7 | ||
|
|
acc317ddfd | ||
|
|
1fbd3935ea | ||
|
|
ca2bf962e9 | ||
|
|
1d27a3a14b | ||
|
|
8e1a9dde05 | ||
|
|
8eabf8c77a | ||
|
|
ec4ec41552 | ||
|
|
8960b0300f | ||
|
|
d6a2672cab | ||
|
|
4b281ca89d | ||
|
|
808b507b0f | ||
|
|
18c028cafd | ||
|
|
026c213ea4 | ||
|
|
9514e79bfb | ||
|
|
b6756595d9 | ||
|
|
8ddb3e80b7 | ||
|
|
52bc1a62e1 | ||
|
|
cd72ed2cec | ||
|
|
e3ba968fef |
No files matched your search
+37
@@ -0,0 +1,37 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Verify that all text files end in a trailing newline.
|
||||||
|
|
||||||
|
# Exit on first failing command.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Exit on unset variable.
|
||||||
|
set -u
|
||||||
|
|
||||||
|
success=0
|
||||||
|
|
||||||
|
function is_plaintext_file() {
|
||||||
|
local file="$1"
|
||||||
|
if [[ $file == *.svg ]]; then
|
||||||
|
echo ""
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
file --brief "${file}" | grep text
|
||||||
|
}
|
||||||
|
|
||||||
|
# Split strings on newlines.
|
||||||
|
IFS='
|
||||||
|
'
|
||||||
|
for file in $(git ls-files)
|
||||||
|
do
|
||||||
|
if [[ -z $(is_plaintext_file "${file}") ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [[ -z "$(tail -c 1 "${file}")" ]]; then
|
||||||
|
printf "File must end in a trailing newline: %s\n" "${file}" >&2
|
||||||
|
success=255
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit "${success}"
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Check for trailing whitespace at end of lines.
|
||||||
|
|
||||||
|
# Exit on first failing command.
|
||||||
|
set -e
|
||||||
|
# Exit on unset variable.
|
||||||
|
set -u
|
||||||
|
|
||||||
|
FOUND_TRAILING_WHITESPACE=0
|
||||||
|
|
||||||
|
while read -r line; do
|
||||||
|
if grep \
|
||||||
|
"\s$" \
|
||||||
|
--line-number \
|
||||||
|
--with-filename \
|
||||||
|
--binary-files=without-match \
|
||||||
|
--exclude="*.svg" \
|
||||||
|
--exclude="*.eps" \
|
||||||
|
"${line}"; then
|
||||||
|
echo "ERROR: Found trailing whitespace" >&2;
|
||||||
|
FOUND_TRAILING_WHITESPACE=1
|
||||||
|
fi
|
||||||
|
done < <(git ls-files)
|
||||||
|
|
||||||
|
exit "${FOUND_TRAILING_WHITESPACE}"
|
||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
name: Set up Python
|
name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.9
|
||||||
-
|
-
|
||||||
name: Get pip cache dir
|
name: Get pip cache dir
|
||||||
id: pip-cache
|
id: pip-cache
|
||||||
@@ -59,7 +59,7 @@ jobs:
|
|||||||
name: Set up Python
|
name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.9
|
||||||
-
|
-
|
||||||
name: Get pip cache dir
|
name: Get pip cache dir
|
||||||
id: pip-cache
|
id: pip-cache
|
||||||
@@ -81,12 +81,26 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd src/
|
cd src/
|
||||||
pycodestyle
|
pycodestyle
|
||||||
|
whitespace:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
-
|
||||||
|
name: Ensure there are no trailing spaces
|
||||||
|
run: |
|
||||||
|
.github/workflow-scripts/check-trailing-whitespace
|
||||||
|
-
|
||||||
|
name: Ensure all text files end with a trailing newline
|
||||||
|
run: |
|
||||||
|
.github/workflow-scripts/check-trailing-whitespace
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ['3.6', '3.7', '3.8', '3.9']
|
python-version: ['3.7', '3.8', '3.9']
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
@@ -122,7 +136,7 @@ jobs:
|
|||||||
pytest
|
pytest
|
||||||
-
|
-
|
||||||
name: Publish coverage results
|
name: Publish coverage results
|
||||||
if: matrix.python-version == '3.8'
|
if: matrix.python-version == '3.9'
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
# https://github.com/coveralls-clients/coveralls-python/issues/251
|
# https://github.com/coveralls-clients/coveralls-python/issues/251
|
||||||
@@ -158,7 +172,7 @@ jobs:
|
|||||||
path: src/documents/static/frontend/
|
path: src/documents/static/frontend/
|
||||||
|
|
||||||
build-release:
|
build-release:
|
||||||
needs: [frontend, documentation, tests, codestyle]
|
needs: [frontend, documentation, tests, whitespace, codestyle]
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
@@ -168,7 +182,7 @@ jobs:
|
|||||||
name: Set up Python
|
name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.9
|
||||||
-
|
-
|
||||||
name: Install dependencies
|
name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -268,7 +282,7 @@ jobs:
|
|||||||
build-docker-image:
|
build-docker-image:
|
||||||
if: github.event_name == 'push' && (startsWith(github.ref, 'refs/heads/feature-') || github.ref == 'refs/heads/dev' || startsWith(github.ref, 'refs/tags/ng-'))
|
if: github.event_name == 'push' && (startsWith(github.ref, 'refs/heads/feature-') || github.ref == 'refs/heads/dev' || startsWith(github.ref, 'refs/tags/ng-'))
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [frontend, tests, codestyle]
|
needs: [frontend, tests, whitespace, codestyle]
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Prepare
|
name: Prepare
|
||||||
|
|||||||
+15
-15
@@ -8,19 +8,18 @@ RUN git clone https://github.com/agl/jbig2enc .
|
|||||||
RUN ./autogen.sh
|
RUN ./autogen.sh
|
||||||
RUN ./configure && make
|
RUN ./configure && make
|
||||||
|
|
||||||
FROM python:3.7-slim
|
FROM python:3.9-slim-bullseye
|
||||||
|
|
||||||
# Binary dependencies
|
# Binary dependencies
|
||||||
RUN echo "deb http://deb.debian.org/debian bullseye main" > /etc/apt/sources.list.d/bullseye.list \
|
RUN apt-get update \
|
||||||
&& apt-get update \
|
&& apt-get -y --no-install-recommends install \
|
||||||
&& apt-get -y --no-install-recommends install \
|
|
||||||
# Basic dependencies
|
# Basic dependencies
|
||||||
curl \
|
curl \
|
||||||
gnupg \
|
gnupg \
|
||||||
imagemagick \
|
imagemagick \
|
||||||
gettext \
|
gettext \
|
||||||
sudo \
|
|
||||||
tzdata \
|
tzdata \
|
||||||
|
gosu \
|
||||||
# fonts for text file thumbnail generation
|
# fonts for text file thumbnail generation
|
||||||
fonts-liberation \
|
fonts-liberation \
|
||||||
# for Numpy
|
# for Numpy
|
||||||
@@ -28,16 +27,18 @@ RUN echo "deb http://deb.debian.org/debian bullseye main" > /etc/apt/sources.lis
|
|||||||
libxslt1-dev \
|
libxslt1-dev \
|
||||||
# thumbnail size reduction
|
# thumbnail size reduction
|
||||||
optipng \
|
optipng \
|
||||||
# Mime type detection
|
libxml2 \
|
||||||
|
pngquant \
|
||||||
|
unpaper \
|
||||||
|
zlib1g \
|
||||||
|
ghostscript \
|
||||||
|
icc-profiles-free \
|
||||||
|
# Mime type detection
|
||||||
file \
|
file \
|
||||||
libmagic-dev \
|
libmagic-dev \
|
||||||
media-types \
|
media-types \
|
||||||
# OCRmyPDF dependencies
|
# OCRmyPDF dependencies
|
||||||
ghostscript \
|
|
||||||
icc-profiles-free \
|
|
||||||
liblept5 \
|
liblept5 \
|
||||||
libxml2 \
|
|
||||||
pngquant \
|
|
||||||
qpdf \
|
qpdf \
|
||||||
tesseract-ocr \
|
tesseract-ocr \
|
||||||
tesseract-ocr-eng \
|
tesseract-ocr-eng \
|
||||||
@@ -45,8 +46,6 @@ RUN echo "deb http://deb.debian.org/debian bullseye main" > /etc/apt/sources.lis
|
|||||||
tesseract-ocr-fra \
|
tesseract-ocr-fra \
|
||||||
tesseract-ocr-ita \
|
tesseract-ocr-ita \
|
||||||
tesseract-ocr-spa \
|
tesseract-ocr-spa \
|
||||||
unpaper \
|
|
||||||
zlib1g \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# copy jbig2enc
|
# copy jbig2enc
|
||||||
@@ -78,6 +77,7 @@ RUN cd docker \
|
|||||||
&& mkdir /var/log/supervisord /var/run/supervisord \
|
&& mkdir /var/log/supervisord /var/run/supervisord \
|
||||||
&& cp supervisord.conf /etc/supervisord.conf \
|
&& cp supervisord.conf /etc/supervisord.conf \
|
||||||
&& cp docker-entrypoint.sh /sbin/docker-entrypoint.sh \
|
&& cp docker-entrypoint.sh /sbin/docker-entrypoint.sh \
|
||||||
|
&& cp docker-prepare.sh /sbin/docker-prepare.sh \
|
||||||
&& chmod 755 /sbin/docker-entrypoint.sh \
|
&& chmod 755 /sbin/docker-entrypoint.sh \
|
||||||
&& chmod +x install_management_commands.sh \
|
&& chmod +x install_management_commands.sh \
|
||||||
&& ./install_management_commands.sh \
|
&& ./install_management_commands.sh \
|
||||||
@@ -93,8 +93,8 @@ COPY src/ ./
|
|||||||
RUN addgroup --gid 1000 paperless \
|
RUN addgroup --gid 1000 paperless \
|
||||||
&& useradd --uid 1000 --gid paperless --home-dir /usr/src/paperless paperless \
|
&& useradd --uid 1000 --gid paperless --home-dir /usr/src/paperless paperless \
|
||||||
&& chown -R paperless:paperless ../ \
|
&& chown -R paperless:paperless ../ \
|
||||||
&& sudo -HEu paperless python3 manage.py collectstatic --clear --no-input \
|
&& gosu paperless python3 manage.py collectstatic --clear --no-input \
|
||||||
&& sudo -HEu paperless python3 manage.py compilemessages
|
&& gosu paperless python3 manage.py compilemessages
|
||||||
|
|
||||||
VOLUME ["/usr/src/paperless/data", "/usr/src/paperless/media", "/usr/src/paperless/consume", "/usr/src/paperless/export"]
|
VOLUME ["/usr/src/paperless/data", "/usr/src/paperless/media", "/usr/src/paperless/consume", "/usr/src/paperless/export"]
|
||||||
ENTRYPOINT ["/sbin/docker-entrypoint.sh"]
|
ENTRYPOINT ["/sbin/docker-entrypoint.sh"]
|
||||||
|
|||||||
@@ -10,19 +10,18 @@ name = "piwheels"
|
|||||||
|
|
||||||
[packages]
|
[packages]
|
||||||
dateparser = "~=1.0.0"
|
dateparser = "~=1.0.0"
|
||||||
django = "~=3.1.3"
|
django = "~=3.2"
|
||||||
django-cors-headers = "*"
|
django-cors-headers = "*"
|
||||||
django-extensions = "*"
|
django-extensions = "*"
|
||||||
django-filter = "~=2.4.0"
|
django-filter = "~=2.4.0"
|
||||||
django-q = "==1.3.4"
|
django-q = "~=1.3.4"
|
||||||
djangorestframework = "~=3.12.2"
|
djangorestframework = "~=3.12.2"
|
||||||
filelock = "*"
|
filelock = "*"
|
||||||
fuzzywuzzy = {extras = ["speedup"], version = "*"}
|
fuzzywuzzy = {extras = ["speedup"], version = "*"}
|
||||||
gunicorn = "*"
|
gunicorn = "*"
|
||||||
imap-tools = "*"
|
imap-tools = "*"
|
||||||
langdetect = "*"
|
langdetect = "*"
|
||||||
# numpy 1.20.0 drops python 3.6 support
|
numpy = "~=1.20.0"
|
||||||
numpy = "~=1.19.5"
|
|
||||||
pathvalidate = "*"
|
pathvalidate = "*"
|
||||||
pillow = "~=8.1"
|
pillow = "~=8.1"
|
||||||
pikepdf = "~=2.5"
|
pikepdf = "~=2.5"
|
||||||
@@ -34,13 +33,11 @@ psycopg2-binary = "*"
|
|||||||
redis = "*"
|
redis = "*"
|
||||||
# Pinned because aarch64 wheels and updates cause warnings when loading the classifier model.
|
# Pinned because aarch64 wheels and updates cause warnings when loading the classifier model.
|
||||||
scikit-learn="==0.24.0"
|
scikit-learn="==0.24.0"
|
||||||
# Prevent scipy updates because 1.6 is incompatible with python 3.6
|
whitenoise = "~=5.3.0"
|
||||||
scipy="~=1.5.4"
|
watchdog = "~=2.1.0"
|
||||||
whitenoise = "~=5.2.0"
|
|
||||||
watchdog = "~=1.0.0"
|
|
||||||
whoosh="~=2.7.4"
|
whoosh="~=2.7.4"
|
||||||
inotifyrecursive = "~=0.3.4"
|
inotifyrecursive = "~=0.3.4"
|
||||||
ocrmypdf = "~=11.6"
|
ocrmypdf = "~=12.3"
|
||||||
tqdm = "*"
|
tqdm = "*"
|
||||||
tika = "*"
|
tika = "*"
|
||||||
# TODO: This will sadly also install daphne+dependencies,
|
# TODO: This will sadly also install daphne+dependencies,
|
||||||
@@ -50,9 +47,10 @@ channels-redis = "*"
|
|||||||
uvicorn = {extras = ["standard"], version = "*"}
|
uvicorn = {extras = ["standard"], version = "*"}
|
||||||
concurrent-log-handler = "*"
|
concurrent-log-handler = "*"
|
||||||
# uvloop 0.15+ incompatible with python 3.6
|
# uvloop 0.15+ incompatible with python 3.6
|
||||||
uvloop = "~=0.14.0"
|
uvloop = "~=0.15"
|
||||||
cryptography = "~=3.4"
|
cryptography = "~=3.4"
|
||||||
"pdfminer.six" = "*"
|
"pdfminer.six" = "*"
|
||||||
|
"backports.zoneinfo" = "*"
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
coveralls = "*"
|
coveralls = "*"
|
||||||
|
|||||||
Generated
+766
-670
File diff suppressed because it is too large.
Load diff
@@ -6,6 +6,10 @@
|
|||||||
[](https://hub.docker.com/r/jonaswinkler/paperless-ng)
|
[](https://hub.docker.com/r/jonaswinkler/paperless-ng)
|
||||||
[](https://coveralls.io/github/jonaswinkler/paperless-ng?branch=master)
|
[](https://coveralls.io/github/jonaswinkler/paperless-ng?branch=master)
|
||||||
|
|
||||||
|
# Archive notice
|
||||||
|
|
||||||
|
This project is not dead! Rather, this project is now maintained as a community effort at https://github.com/paperless-ngx/paperless-ngx, a direct continuation of this project and drop-in replacement. Please see their project page and the documentation at https://docs.paperless-ngx.com/ for details.
|
||||||
|
|
||||||
# Paperless-ng
|
# Paperless-ng
|
||||||
|
|
||||||
[Paperless (click me)](https://github.com/the-paperless-project/paperless) is an application by Daniel Quinn and contributors that indexes your scanned documents and allows you to easily search for documents and store metadata alongside your documents.
|
[Paperless (click me)](https://github.com/the-paperless-project/paperless) is an application by Daniel Quinn and contributors that indexes your scanned documents and allows you to easily search for documents and store metadata alongside your documents.
|
||||||
@@ -62,7 +66,7 @@ If you want to see paperless-ng in action, [more screenshots are available in th
|
|||||||
|
|
||||||
# Getting started
|
# Getting started
|
||||||
|
|
||||||
The recommended way to deploy paperless is docker-compose. The files in the /docker/hub directory are configured to pull the image from Docker Hub.
|
The recommended way to deploy paperless is docker-compose. The files in the /docker/compose directory are configured to pull the image from Docker Hub.
|
||||||
|
|
||||||
Read the [documentation](https://paperless-ng.readthedocs.io/en/latest/setup.html#installation) on how to get started.
|
Read the [documentation](https://paperless-ng.readthedocs.io/en/latest/setup.html#installation) on how to get started.
|
||||||
|
|
||||||
@@ -100,6 +104,7 @@ Paperless has been around a while now, and people are starting to build stuff on
|
|||||||
|
|
||||||
* [Paperless App](https://github.com/bauerj/paperless_app): An Android/iOS app for Paperless. Updated to work with paperless-ng.
|
* [Paperless App](https://github.com/bauerj/paperless_app): An Android/iOS app for Paperless. Updated to work with paperless-ng.
|
||||||
* [Paperless Share](https://github.com/qcasey/paperless_share). Share any files from your Android application with paperless. Very simple, but works with all of the mobile scanning apps out there that allow you to share scanned documents.
|
* [Paperless Share](https://github.com/qcasey/paperless_share). Share any files from your Android application with paperless. Very simple, but works with all of the mobile scanning apps out there that allow you to share scanned documents.
|
||||||
|
* [Scan to Paperless](https://github.com/sbrunner/scan-to-paperless): Scan and prepare (crop, deskew, OCR, ...) your documents for Paperless.
|
||||||
|
|
||||||
These projects also exist, but their status and compatibility with paperless-ng is unknown.
|
These projects also exist, but their status and compatibility with paperless-ng is unknown.
|
||||||
|
|
||||||
|
|||||||
+10
-8
@@ -12,27 +12,29 @@ Note that this role requires root access, so either run it in a playbook with a
|
|||||||
|
|
||||||
- hosts: all
|
- hosts: all
|
||||||
roles:
|
roles:
|
||||||
- role: ansible
|
- role: paperless-ng
|
||||||
become: yes
|
become: yes
|
||||||
|
|
||||||
Role Variables
|
Role Variables
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
Most configuration variables from paperless-ng itself are available and accept their respective arguments.
|
Most configuration variables from paperless-ng itself are available and accept their respective arguments.
|
||||||
Every `PAPERLESS_*` configuration varaible is lowercased and instead prefixed with `paperlessng_*` in `defaults/main.yml`.
|
Every `PAPERLESS_*` configuration variable is lowercased and instead prefixed with `paperlessng_*` in `defaults/main.yml`.
|
||||||
|
|
||||||
For a full listing including explainations and allowed values, see the current [documentation](https://paperless-ng.readthedocs.io/en/ng-0.9.14/configuration.html).
|
For a full listing including explanations and allowed values, see the current [documentation](https://paperless-ng.readthedocs.io/en/latest/configuration.html).
|
||||||
|
|
||||||
Additional variables available in this role are listed below, along with default values:
|
Additional variables available in this role are listed below, along with default values:
|
||||||
|
|
||||||
paperlessng_version: 0.9.14
|
paperlessng_version: latest
|
||||||
|
|
||||||
The [release](https://github.com/jonaswinkler/paperless-ng/releases) archive version of paperless-ng to install.
|
The [release](https://github.com/jonaswinkler/paperless-ng/releases) archive version of paperless-ng to install.
|
||||||
|
`latest` stands for the latest release of paperless-ng.
|
||||||
|
To install a specific version of paperless-ng, use the tag name of the release, e. g. `ng-1.4.4`, or specify a branch or commit id.
|
||||||
|
|
||||||
paperlessng_redis_host: localhost
|
paperlessng_redis_host: localhost
|
||||||
paperlessng_redis_port: 6379
|
paperlessng_redis_port: 6379
|
||||||
|
|
||||||
Seperate configuration values that combine into `PAPERLESS_REDIS`.
|
Separate configuration values that combine into `PAPERLESS_REDIS`.
|
||||||
|
|
||||||
paperlessng_db_type: sqlite
|
paperlessng_db_type: sqlite
|
||||||
|
|
||||||
@@ -96,11 +98,11 @@ Example Playbook
|
|||||||
- hosts: all
|
- hosts: all
|
||||||
become: yes
|
become: yes
|
||||||
vars_files:
|
vars_files:
|
||||||
- vars/main.yml
|
- vars/paperless-ng.yml
|
||||||
roles:
|
roles:
|
||||||
- ansible
|
- paperless-ng
|
||||||
|
|
||||||
`vars/main.yml`:
|
`vars/paperless-ng.yml`:
|
||||||
|
|
||||||
paperlessng_media_root: /mnt/media/smbshare
|
paperlessng_media_root: /mnt/media/smbshare
|
||||||
|
|
||||||
|
|||||||
@@ -329,7 +329,7 @@
|
|||||||
- regexp: PAPERLESS_TIKA_ENDPOINT
|
- regexp: PAPERLESS_TIKA_ENDPOINT
|
||||||
line: "PAPERLESS_TIKA_ENDPOINT={{ paperlessng_tika_endpoint }}"
|
line: "PAPERLESS_TIKA_ENDPOINT={{ paperlessng_tika_endpoint }}"
|
||||||
- regexp: PAPERLESS_TIKA_GOTENBERG_ENDPOINT
|
- regexp: PAPERLESS_TIKA_GOTENBERG_ENDPOINT
|
||||||
line: "PAPERLESS_TIKA_GOTENBERG_ENDPOINT={{ paperlessng_tika_endpoint }}"
|
line: "PAPERLESS_TIKA_GOTENBERG_ENDPOINT={{ paperlessng_tika_gotenberg_endpoint }}"
|
||||||
# Software tweaks
|
# Software tweaks
|
||||||
- regexp: PAPERLESS_TIME_ZONE
|
- regexp: PAPERLESS_TIME_ZONE
|
||||||
line: "PAPERLESS_TIME_ZONE={{ paperlessng_time_zone }}"
|
line: "PAPERLESS_TIME_ZONE={{ paperlessng_time_zone }}"
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
COMPOSE_PROJECT_NAME=paperless
|
COMPOSE_PROJECT_NAME=paperless
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
# docker-compose file for running paperless from the Docker Hub.
|
||||||
|
# This file contains everything paperless needs to run.
|
||||||
|
# Paperless supports amd64, arm and arm64 hardware.
|
||||||
|
#
|
||||||
|
# All compose files of paperless configure paperless in the following way:
|
||||||
|
#
|
||||||
|
# - Paperless is (re)started on system boot, if it was running before shutdown.
|
||||||
|
# - Docker volumes for storing data are managed by Docker.
|
||||||
|
# - Folders for importing and exporting files are created in the same directory
|
||||||
|
# as this file and mounted to the correct folders inside the container.
|
||||||
|
# - Paperless listens on port 8010.
|
||||||
|
#
|
||||||
|
# In addition to that, this docker-compose file adds the following optional
|
||||||
|
# configurations:
|
||||||
|
#
|
||||||
|
# - Instead of SQLite (default), PostgreSQL is used as the database server.
|
||||||
|
#
|
||||||
|
# To install and update paperless with this file, do the following:
|
||||||
|
#
|
||||||
|
# - Open portainer Stacks list and click 'Add stack'
|
||||||
|
# - Paste the contents of this file and assign a name, e.g. 'Paperless'
|
||||||
|
# - Click 'Deploy the stack' and wait for it to be deployed
|
||||||
|
# - Open the list of containers, select paperless_webserver_1
|
||||||
|
# - Click 'Console' and then 'Connect' to open the command line inside the container
|
||||||
|
# - Run 'python3 manage.py createsuperuser' to create a user
|
||||||
|
# - Exit the console
|
||||||
|
#
|
||||||
|
# For more extensive installation and update instructions, refer to the
|
||||||
|
# documentation.
|
||||||
|
|
||||||
|
version: "3.4"
|
||||||
|
services:
|
||||||
|
broker:
|
||||||
|
image: redis:6.0
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:13
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- pgdata:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: paperless
|
||||||
|
POSTGRES_USER: paperless
|
||||||
|
POSTGRES_PASSWORD: paperless
|
||||||
|
|
||||||
|
webserver:
|
||||||
|
image: jonaswinkler/paperless-ng:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
- broker
|
||||||
|
ports:
|
||||||
|
- 8010:8000
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:8000"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 5
|
||||||
|
volumes:
|
||||||
|
- data:/usr/src/paperless/data
|
||||||
|
- media:/usr/src/paperless/media
|
||||||
|
- ./export:/usr/src/paperless/export
|
||||||
|
- ./consume:/usr/src/paperless/consume
|
||||||
|
environment:
|
||||||
|
PAPERLESS_REDIS: redis://broker:6379
|
||||||
|
PAPERLESS_DBHOST: db
|
||||||
|
# The UID and GID of the user used to run paperless in the container. Set this
|
||||||
|
# to your UID and GID on the host so that you have write access to the
|
||||||
|
# consumption directory.
|
||||||
|
USERMAP_UID: 1000
|
||||||
|
USERMAP_GID: 100
|
||||||
|
# Additional languages to install for text recognition, separated by a
|
||||||
|
# whitespace. Note that this is
|
||||||
|
# different from PAPERLESS_OCR_LANGUAGE (default=eng), which defines the
|
||||||
|
# language used for OCR.
|
||||||
|
# The container installs English, German, Italian, Spanish and French by
|
||||||
|
# default.
|
||||||
|
# See https://packages.debian.org/search?keywords=tesseract-ocr-&searchon=names&suite=buster
|
||||||
|
# for available languages.
|
||||||
|
#PAPERLESS_OCR_LANGUAGES: tur ces
|
||||||
|
# Adjust this key if you plan to make paperless available publicly. It should
|
||||||
|
# be a very long sequence of random characters. You don't need to remember it.
|
||||||
|
#PAPERLESS_SECRET_KEY: change-me
|
||||||
|
# Use this variable to set a timezone for the Paperless Docker containers. If not specified, defaults to UTC.
|
||||||
|
#PAPERLESS_TIME_ZONE: America/Los_Angeles
|
||||||
|
# The default language to use for OCR. Set this to the language most of your
|
||||||
|
# documents are written in.
|
||||||
|
#PAPERLESS_OCR_LANGUAGE: eng
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
data:
|
||||||
|
media:
|
||||||
|
pgdata:
|
||||||
Regular → Executable
+38
-91
@@ -4,89 +4,37 @@ set -e
|
|||||||
|
|
||||||
# Source: https://github.com/sameersbn/docker-gitlab/
|
# Source: https://github.com/sameersbn/docker-gitlab/
|
||||||
map_uidgid() {
|
map_uidgid() {
|
||||||
USERMAP_ORIG_UID=$(id -u paperless)
|
USERMAP_ORIG_UID=$(id -u paperless)
|
||||||
USERMAP_ORIG_GID=$(id -g paperless)
|
USERMAP_ORIG_GID=$(id -g paperless)
|
||||||
USERMAP_NEW_UID=${USERMAP_UID:-$USERMAP_ORIG_UID}
|
USERMAP_NEW_UID=${USERMAP_UID:-$USERMAP_ORIG_UID}
|
||||||
USERMAP_NEW_GID=${USERMAP_GID:-${USERMAP_ORIG_GID:-$USERMAP_NEW_UID}}
|
USERMAP_NEW_GID=${USERMAP_GID:-${USERMAP_ORIG_GID:-$USERMAP_NEW_UID}}
|
||||||
if [[ ${USERMAP_NEW_UID} != "${USERMAP_ORIG_UID}" || ${USERMAP_NEW_GID} != "${USERMAP_ORIG_GID}" ]]; then
|
if [[ ${USERMAP_NEW_UID} != "${USERMAP_ORIG_UID}" || ${USERMAP_NEW_GID} != "${USERMAP_ORIG_GID}" ]]; then
|
||||||
echo "Mapping UID and GID for paperless:paperless to $USERMAP_NEW_UID:$USERMAP_NEW_GID"
|
echo "Mapping UID and GID for paperless:paperless to $USERMAP_NEW_UID:$USERMAP_NEW_GID"
|
||||||
usermod -u "${USERMAP_NEW_UID}" paperless
|
usermod -u "${USERMAP_NEW_UID}" paperless
|
||||||
groupmod -o -g "${USERMAP_NEW_GID}" paperless
|
groupmod -o -g "${USERMAP_NEW_GID}" paperless
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
wait_for_postgres() {
|
|
||||||
attempt_num=1
|
|
||||||
max_attempts=5
|
|
||||||
|
|
||||||
echo "Waiting for PostgreSQL to start..."
|
|
||||||
|
|
||||||
host="${PAPERLESS_DBHOST}"
|
|
||||||
port="${PAPERLESS_DBPORT}"
|
|
||||||
|
|
||||||
if [[ -z $port ]] ;
|
|
||||||
then
|
|
||||||
port="5432"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
while !</dev/tcp/$host/$port ;
|
|
||||||
do
|
|
||||||
|
|
||||||
if [ $attempt_num -eq $max_attempts ]
|
|
||||||
then
|
|
||||||
echo "Unable to connect to database."
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "Attempt $attempt_num failed! Trying again in 5 seconds..."
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
attempt_num=$(expr "$attempt_num" + 1)
|
|
||||||
sleep 5
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
migrations() {
|
|
||||||
|
|
||||||
if [[ -n "${PAPERLESS_DBHOST}" ]]
|
|
||||||
then
|
|
||||||
wait_for_postgres
|
|
||||||
fi
|
|
||||||
|
|
||||||
(
|
|
||||||
# flock is in place to prevent multiple containers from doing migrations
|
|
||||||
# simultaneously. This also ensures that the db is ready when the command
|
|
||||||
# of the current container starts.
|
|
||||||
flock 200
|
|
||||||
echo "Apply database migrations..."
|
|
||||||
sudo -HEu paperless python3 manage.py migrate
|
|
||||||
) 200>/usr/src/paperless/data/migration_lock
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize() {
|
initialize() {
|
||||||
map_uidgid
|
map_uidgid
|
||||||
|
|
||||||
for dir in export data data/index media media/documents media/documents/originals media/documents/thumbnails; do
|
for dir in export data data/index media media/documents media/documents/originals media/documents/thumbnails; do
|
||||||
if [[ ! -d "../$dir" ]]
|
if [[ ! -d "../$dir" ]]; then
|
||||||
then
|
echo "Creating directory ../$dir"
|
||||||
echo "creating directory ../$dir"
|
|
||||||
mkdir ../$dir
|
mkdir ../$dir
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "creating directory /tmp/paperless"
|
echo "Creating directory /tmp/paperless"
|
||||||
mkdir -p /tmp/paperless
|
mkdir -p /tmp/paperless
|
||||||
|
|
||||||
chown -R paperless:paperless ../
|
set +e
|
||||||
|
echo "Adjusting permissions of paperless files. This may take a while."
|
||||||
chown -R paperless:paperless /tmp/paperless
|
chown -R paperless:paperless /tmp/paperless
|
||||||
|
find .. -not \( -user paperless -and -group paperless \) -exec chown paperless:paperless {} +
|
||||||
|
set -e
|
||||||
|
|
||||||
migrations
|
gosu paperless /sbin/docker-prepare.sh
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
install_languages() {
|
install_languages() {
|
||||||
@@ -102,44 +50,43 @@ install_languages() {
|
|||||||
apt-get update
|
apt-get update
|
||||||
|
|
||||||
for lang in "${langs[@]}"; do
|
for lang in "${langs[@]}"; do
|
||||||
pkg="tesseract-ocr-$lang"
|
pkg="tesseract-ocr-$lang"
|
||||||
# English is installed by default
|
# English is installed by default
|
||||||
#if [[ "$lang" == "eng" ]]; then
|
#if [[ "$lang" == "eng" ]]; then
|
||||||
# continue
|
# continue
|
||||||
#fi
|
#fi
|
||||||
|
|
||||||
if dpkg -s $pkg &> /dev/null; then
|
if dpkg -s $pkg &>/dev/null; then
|
||||||
echo "package $pkg already installed!"
|
echo "Package $pkg already installed!"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! apt-cache show $pkg &> /dev/null; then
|
if ! apt-cache show $pkg &>/dev/null; then
|
||||||
echo "package $pkg not found! :("
|
echo "Package $pkg not found! :("
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Installing package $pkg..."
|
echo "Installing package $pkg..."
|
||||||
if ! apt-get -y install "$pkg" &> /dev/null; then
|
if ! apt-get -y install "$pkg" &>/dev/null; then
|
||||||
echo "Could not install $pkg"
|
echo "Could not install $pkg"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "Paperless-ng docker container starting..."
|
echo "Paperless-ng docker container starting..."
|
||||||
|
|
||||||
# Install additional languages if specified
|
# Install additional languages if specified
|
||||||
if [[ ! -z "$PAPERLESS_OCR_LANGUAGES" ]]; then
|
if [[ ! -z "$PAPERLESS_OCR_LANGUAGES" ]]; then
|
||||||
install_languages "$PAPERLESS_OCR_LANGUAGES"
|
install_languages "$PAPERLESS_OCR_LANGUAGES"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
initialize
|
initialize
|
||||||
|
|
||||||
if [[ "$1" != "/"* ]]; then
|
if [[ "$1" != "/"* ]]; then
|
||||||
echo Executing management command "$@"
|
echo Executing management command "$@"
|
||||||
exec sudo -HEu paperless python3 manage.py "$@"
|
exec gosu paperless python3 manage.py "$@"
|
||||||
else
|
else
|
||||||
echo Executing "$@"
|
echo Executing "$@"
|
||||||
exec "$@"
|
exec "$@"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
Executable
+72
@@ -0,0 +1,72 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
wait_for_postgres() {
|
||||||
|
attempt_num=1
|
||||||
|
max_attempts=5
|
||||||
|
|
||||||
|
echo "Waiting for PostgreSQL to start..."
|
||||||
|
|
||||||
|
host="${PAPERLESS_DBHOST}"
|
||||||
|
port="${PAPERLESS_DBPORT}"
|
||||||
|
|
||||||
|
if [[ -z $port ]]; then
|
||||||
|
port="5432"
|
||||||
|
fi
|
||||||
|
|
||||||
|
while ! </dev/tcp/$host/$port; do
|
||||||
|
|
||||||
|
if [ $attempt_num -eq $max_attempts ]; then
|
||||||
|
echo "Unable to connect to database."
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Attempt $attempt_num failed! Trying again in 5 seconds..."
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
attempt_num=$(expr "$attempt_num" + 1)
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
migrations() {
|
||||||
|
(
|
||||||
|
# flock is in place to prevent multiple containers from doing migrations
|
||||||
|
# simultaneously. This also ensures that the db is ready when the command
|
||||||
|
# of the current container starts.
|
||||||
|
flock 200
|
||||||
|
echo "Apply database migrations..."
|
||||||
|
python3 manage.py migrate
|
||||||
|
) 200>/usr/src/paperless/data/migration_lock
|
||||||
|
}
|
||||||
|
|
||||||
|
search_index() {
|
||||||
|
index_version=1
|
||||||
|
index_version_file=/usr/src/paperless/data/.index_version
|
||||||
|
|
||||||
|
if [[ (! -f "$index_version_file") || $(<$index_version_file) != "$index_version" ]]; then
|
||||||
|
echo "Search index out of date. Updating..."
|
||||||
|
python3 manage.py document_index reindex
|
||||||
|
echo $index_version | tee $index_version_file >/dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
superuser() {
|
||||||
|
if [[ -n "${PAPERLESS_ADMIN_USER}" ]]; then
|
||||||
|
python3 manage.py manage_superuser
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
do_work() {
|
||||||
|
if [[ -n "${PAPERLESS_DBHOST}" ]]; then
|
||||||
|
wait_for_postgres
|
||||||
|
fi
|
||||||
|
|
||||||
|
migrations
|
||||||
|
|
||||||
|
search_index
|
||||||
|
|
||||||
|
superuser
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
do_work
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
for command in document_archiver document_exporter document_importer mail_fetcher document_create_classifier document_index document_renamer document_retagger document_thumbnails document_sanity_checker;
|
for command in document_archiver document_exporter document_importer mail_fetcher document_create_classifier document_index document_renamer document_retagger document_thumbnails document_sanity_checker manage_superuser;
|
||||||
do
|
do
|
||||||
echo "installing $command..."
|
echo "installing $command..."
|
||||||
sed "s/management_command/$command/g" management_script.sh > /usr/local/bin/$command
|
sed "s/management_command/$command/g" management_script.sh > /usr/local/bin/$command
|
||||||
|
|||||||
Regular → Executable
+1
-1
@@ -6,7 +6,7 @@ cd /usr/src/paperless/src/
|
|||||||
|
|
||||||
if [[ $(id -u) == 0 ]] ;
|
if [[ $(id -u) == 0 ]] ;
|
||||||
then
|
then
|
||||||
sudo -HEu paperless python3 manage.py management_command "$@"
|
gosu paperless python3 manage.py management_command "$@"
|
||||||
elif [[ $(id -un) == "paperless" ]] ;
|
elif [[ $(id -un) == "paperless" ]] ;
|
||||||
then
|
then
|
||||||
python3 manage.py management_command "$@"
|
python3 manage.py management_command "$@"
|
||||||
|
|||||||
+9
-12
@@ -149,22 +149,15 @@ Ansible Route
|
|||||||
|
|
||||||
Most of the update process is automated when using the ansible role.
|
Most of the update process is automated when using the ansible role.
|
||||||
|
|
||||||
1. Backup your defined role variables file outside the paperless source-tree:
|
1. Update the role to the target release tag to make sure the ansible scripts are compatible:
|
||||||
|
|
||||||
.. code:: shell-session
|
.. code:: shell-session
|
||||||
|
|
||||||
$ cp ansible/vars.yml ~/vars.yml.old
|
$ ansible-galaxy install git+https://github.com/jonaswinkler/paperless-ng.git,master --force
|
||||||
|
|
||||||
2. Pull the release tag you want to update to:
|
2. Update the role variable definitions ``vars/paperless-ng.yml`` (where appropriate).
|
||||||
|
|
||||||
.. code:: shell-session
|
3. Run the ansible playbook you created created during :ref:`installation <setup-ansible>` again:
|
||||||
|
|
||||||
$ git fetch --all
|
|
||||||
$ git checkout ng-0.9.14
|
|
||||||
|
|
||||||
3. Update the role variable definitions ``ansible/vars.yml`` (where appropriate).
|
|
||||||
|
|
||||||
4. Run the ansible playbook you created created during :ref:`installation <setup-ansible>` again:
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
@@ -193,7 +186,9 @@ This table lists the compatible versions for each database migration number.
|
|||||||
+------------------+-----------------+
|
+------------------+-----------------+
|
||||||
| 1012 | 1.1.0 - 1.2.1 |
|
| 1012 | 1.1.0 - 1.2.1 |
|
||||||
+------------------+-----------------+
|
+------------------+-----------------+
|
||||||
| 1014 | 1.3.0 - current |
|
| 1014 | 1.3.0 - 1.3.1 |
|
||||||
|
+------------------+-----------------+
|
||||||
|
| 1016 | 1.3.2 - current |
|
||||||
+------------------+-----------------+
|
+------------------+-----------------+
|
||||||
|
|
||||||
Execute the following management command to migrate your database:
|
Execute the following management command to migrate your database:
|
||||||
@@ -245,6 +240,8 @@ Document exporter
|
|||||||
The document exporter exports all your data from paperless into a folder for
|
The document exporter exports all your data from paperless into a folder for
|
||||||
backup or migration to another DMS.
|
backup or migration to another DMS.
|
||||||
|
|
||||||
|
If you use the document exporter within a cronjob to backup your data you might use the ``-T`` flag behind exec to suppress "The input device is not a TTY" errors. For example: ``docker-compose exec -T webserver document_exporter ../export``
|
||||||
|
|
||||||
.. code::
|
.. code::
|
||||||
|
|
||||||
document_exporter target [-c] [-f] [-d]
|
document_exporter target [-c] [-f] [-d]
|
||||||
|
|||||||
+38
-74
@@ -147,93 +147,57 @@ The REST api provides three different forms of authentication.
|
|||||||
Searching for documents
|
Searching for documents
|
||||||
#######################
|
#######################
|
||||||
|
|
||||||
Paperless-ng offers API endpoints for full text search. These are as follows:
|
Full text searching is available on the ``/api/documents/`` endpoint. Two specific
|
||||||
|
query parameters cause the API to return full text search results:
|
||||||
|
|
||||||
``/api/search/``
|
* ``/api/documents/?query=your%20search%20query``: Search for a document using a full text query.
|
||||||
================
|
For details on the syntax, see :ref:`basic-usage_searching`.
|
||||||
|
|
||||||
Get search results based on a query.
|
* ``/api/documents/?more_like=1234``: Search for documents similar to the document with id 1234.
|
||||||
|
|
||||||
Query parameters:
|
Pagination works exactly the same as it does for normal requests on this endpoint.
|
||||||
|
|
||||||
* ``query``: The query string. See
|
Certain limitations apply to full text queries:
|
||||||
`here <https://whoosh.readthedocs.io/en/latest/querylang.html>`_
|
|
||||||
for details on the syntax.
|
|
||||||
* ``page``: Specify the page you want to retrieve. Each page
|
|
||||||
contains 10 search results and the first page is ``page=1``, which
|
|
||||||
is the default if this is omitted.
|
|
||||||
|
|
||||||
Result list object returned by the endpoint:
|
* Results are always sorted by search score. The results matching the query best will show up first.
|
||||||
|
|
||||||
.. code:: json
|
* Only a small subset of filtering parameters are supported.
|
||||||
|
|
||||||
|
Furthermore, each returned document has an additional ``__search_hit__`` attribute with various information
|
||||||
|
about the search results:
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
{
|
{
|
||||||
"count": 1,
|
"count": 31,
|
||||||
"page": 1,
|
"next": "http://localhost:8000/api/documents/?page=2&query=test",
|
||||||
"page_count": 1,
|
"previous": null,
|
||||||
"corrected_query": "",
|
|
||||||
"results": [
|
"results": [
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": 123,
|
||||||
|
"title": "title",
|
||||||
|
"content": "content",
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
"__search_hit__": {
|
||||||
|
"score": 0.343,
|
||||||
|
"highlights": "text <span class=\"match\">Test</span> text",
|
||||||
|
"rank": 23
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
* ``count``: The approximate total number of results.
|
* ``score`` is an indication how well this document matches the query relative to the other search results.
|
||||||
* ``page``: The page returned to you. This might be different from
|
* ``highlights`` is an excerpt from the document content and highlights the search terms with ``<span>`` tags as shown above.
|
||||||
the page you requested, if you requested a page that is behind
|
* ``rank`` is the index of the search results. The first result will have rank 0.
|
||||||
the last page. In that case, the last page is returned.
|
|
||||||
* ``page_count``: The total number of pages.
|
|
||||||
* ``corrected_query``: Corrected version of the query string. Can be null.
|
|
||||||
If not null, can be used verbatim to start a new query.
|
|
||||||
* ``results``: A list of result objects on the current page.
|
|
||||||
|
|
||||||
Result object:
|
|
||||||
|
|
||||||
.. code:: json
|
|
||||||
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"highlights": [
|
|
||||||
|
|
||||||
],
|
|
||||||
"score": 6.34234,
|
|
||||||
"rank": 23,
|
|
||||||
"document": {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
* ``id``: the primary key of the found document
|
|
||||||
* ``highlights``: an object containing parsable highlights for the result.
|
|
||||||
See below.
|
|
||||||
* ``score``: The score assigned to the document. A higher score indicates a
|
|
||||||
better match with the query. Search results are sorted descending by score.
|
|
||||||
* ``rank``: the position of the document within the entire search results list.
|
|
||||||
* ``document``: The full json of the document, as returned by
|
|
||||||
``/api/documents/<id>/``.
|
|
||||||
|
|
||||||
Highlights object:
|
|
||||||
|
|
||||||
Highlights are provided as a list of fragments. A fragment is a longer section of
|
|
||||||
text from the original document.
|
|
||||||
Each fragment contains a list of strings, and some of them are marked as a highlight.
|
|
||||||
|
|
||||||
.. code:: json
|
|
||||||
|
|
||||||
[
|
|
||||||
[
|
|
||||||
{"text": "This is a sample text with a ", "highlight": false},
|
|
||||||
{"text": "highlighted", "highlight": true},
|
|
||||||
{"text": " word.", "highlight": false}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{"text": "Another", "highlight": true},
|
|
||||||
{"text": " fragment with a highlight.", "highlight": false}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
A client may use this example to produce the following output:
|
|
||||||
|
|
||||||
... This is a sample text with a **highlighted** word. ... **Another** fragment with a highlight. ...
|
|
||||||
|
|
||||||
``/api/search/autocomplete/``
|
``/api/search/autocomplete/``
|
||||||
=============================
|
=============================
|
||||||
|
|||||||
+110
-11
@@ -5,6 +5,110 @@
|
|||||||
Changelog
|
Changelog
|
||||||
*********
|
*********
|
||||||
|
|
||||||
|
paperless-ng 1.5.0
|
||||||
|
##################
|
||||||
|
|
||||||
|
Support for Python 3.6 was dropped.
|
||||||
|
|
||||||
|
* Updated python dependencies.
|
||||||
|
* Base image of the docker image changed from Debian Buster to Debian Bullseye due to its recent release.
|
||||||
|
* The docker image now uses python 3.9.
|
||||||
|
* Added the Luxembourgish locale. Thanks for translating!
|
||||||
|
* `Daniel Albers`_ added support for making the files and folders ignored by the paperless consume folder scanner configurable. See ``PAPERLESS_CONSUMER_IGNORE_PATTERNS``.
|
||||||
|
|
||||||
|
paperless-ng 1.4.5
|
||||||
|
##################
|
||||||
|
|
||||||
|
This is a maintenance release.
|
||||||
|
|
||||||
|
* Updated Python and Angular dependencies.
|
||||||
|
* Changed the algorithm that changes permissions during startup. This is still fast,
|
||||||
|
and will hopefully cause less issues.
|
||||||
|
* Fixed an issue that would sometimes cause paperless to write an incomplete
|
||||||
|
classification model file to disk.
|
||||||
|
* Fixed an issue with the OCRmyPDF parser that would always try to extract text
|
||||||
|
with PDFminer even from non-PDF files.
|
||||||
|
|
||||||
|
paperless-ng 1.4.4
|
||||||
|
##################
|
||||||
|
|
||||||
|
* Drastically decreased the startup time of the docker container. The startup script adjusts file permissions of all data only if changes are required.
|
||||||
|
* Paperless mail: Added ability to specify the character set for each server.
|
||||||
|
* Document consumption: Ignore Mac OS specific files such as ``.DS_STORE`` and ``._XXXXX.pdf``.
|
||||||
|
* Fixed an issue with the automatic matching algorithm that prevents paperless from consuming new files.
|
||||||
|
* Updated translations.
|
||||||
|
|
||||||
|
paperless-ng 1.4.3
|
||||||
|
##################
|
||||||
|
|
||||||
|
* Additions and changes
|
||||||
|
|
||||||
|
* Added Swedish locale.
|
||||||
|
* `Stéphane Brunner`_ added an option to disable the progress bars of all management commands.
|
||||||
|
* `Jo Vandeginste`_ added support for RTF documents to the Apache TIKA parser.
|
||||||
|
* `Michael Shamoon`_ added dark mode for the login and logout pages.
|
||||||
|
* `Alexander Menk`_ added additional stylesheets for printing. You can now print any page of paperless and the print result will hide the page header, sidebar, and action buttons.
|
||||||
|
* Added support for sorting when using full text search.
|
||||||
|
|
||||||
|
* Fixes
|
||||||
|
|
||||||
|
* `puuu`_ fixed ``PAPERLESS_FORCE_SCRIPT_NAME``. You can now host paperless on sub paths such as ``https://localhost:8000/paperless/``.
|
||||||
|
* Fixed an issue with the document consumer crashing on certain documents due to issues with pdfminer.six. This library is used for PDF text extraction.
|
||||||
|
|
||||||
|
paperless-ng 1.4.2
|
||||||
|
##################
|
||||||
|
|
||||||
|
* Fixed an issue with ``sudo`` that caused paperless to not start on many Raspberry Pi devices. Thank you `WhiteHatTux`_!
|
||||||
|
|
||||||
|
paperless-ng 1.4.1
|
||||||
|
##################
|
||||||
|
|
||||||
|
* Added Polish locale.
|
||||||
|
|
||||||
|
* Changed some parts of the Dockerfile to hopefully restore functionality on certain ARM devices.
|
||||||
|
|
||||||
|
* Updated python dependencies.
|
||||||
|
|
||||||
|
* `Michael Shamoon`_ added a sticky filter / bulk edit bar.
|
||||||
|
|
||||||
|
* `sbrl`_ changed the docker-entrypoint.sh script to increase compatibility with NFS shares.
|
||||||
|
|
||||||
|
* `Chris Nagy`_ added support for creating a super user by passing ``PAPERLESS_ADMIN_USER`` and
|
||||||
|
``PAPERLESS_ADMIN_PASSWORD`` as environment variables to the docker container.
|
||||||
|
|
||||||
|
paperless-ng 1.4.0
|
||||||
|
##################
|
||||||
|
|
||||||
|
* Docker images now use tesseract 4.1.1, which should fix a series of issues with OCR.
|
||||||
|
|
||||||
|
* The full text search now displays results using the default document list. This enables
|
||||||
|
selection, filtering and bulk edit on search results.
|
||||||
|
|
||||||
|
* Changes
|
||||||
|
|
||||||
|
* Firefox only: Highlight search query in PDF previews.
|
||||||
|
|
||||||
|
* New URL pattern for accessing documents by ASN directly (http://<paperless>/asn/123)
|
||||||
|
|
||||||
|
* Added logging when executing pre- and post-consume scripts.
|
||||||
|
|
||||||
|
* Better error logging during document consumption.
|
||||||
|
|
||||||
|
* Updated python dependencies.
|
||||||
|
|
||||||
|
* Automatically inserts typed text when opening "Create new" dialogs on the document details page.
|
||||||
|
|
||||||
|
* Fixes
|
||||||
|
|
||||||
|
* Fixed an issue with null characters in the document content.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The changed to the full text searching require you to reindex your documents.
|
||||||
|
*The docker image does this automatically, you don't need to do anything.*
|
||||||
|
To do this, execute the ``document_index reindex`` management command
|
||||||
|
(see :ref:`administration-index`).
|
||||||
|
|
||||||
paperless-ng 1.3.2
|
paperless-ng 1.3.2
|
||||||
##################
|
##################
|
||||||
|
|
||||||
@@ -108,17 +212,6 @@ paperless-ng 1.2.0
|
|||||||
|
|
||||||
* Paperless no longer depends on ``libpoppler-cpp-dev``.
|
* Paperless no longer depends on ``libpoppler-cpp-dev``.
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Some packages that paperless depends on are slowly dropping Python 3.6
|
|
||||||
support one after another, including the web server. Supporting Python
|
|
||||||
3.6 means that I cannot update these packages anymore.
|
|
||||||
|
|
||||||
At some point, paperless will drop Python 3.6 support. If using a bare
|
|
||||||
metal installation and you're still on Python 3.6, upgrade to 3.7 or newer.
|
|
||||||
|
|
||||||
If using docker, this does not affect you.
|
|
||||||
|
|
||||||
paperless-ng 1.1.4
|
paperless-ng 1.1.4
|
||||||
##################
|
##################
|
||||||
|
|
||||||
@@ -1312,6 +1405,11 @@ bulk of the work on this big change.
|
|||||||
|
|
||||||
* Initial release
|
* Initial release
|
||||||
|
|
||||||
|
.. _Alexander Menk: https://github.com/amenk
|
||||||
|
.. _puuu: https://github.com/puuu
|
||||||
|
.. _WhiteHatTux: https://github.com/WhiteHatTux
|
||||||
|
.. _Chris Nagy: https://github.com/what-name
|
||||||
|
.. _sbrl: https://github.com/sbrl
|
||||||
.. _slorenz: https://github.com/sisao
|
.. _slorenz: https://github.com/sisao
|
||||||
.. _Jo Vandeginste: https://github.com/jovandeginste
|
.. _Jo Vandeginste: https://github.com/jovandeginste
|
||||||
.. _zjean: https://github.com/zjean
|
.. _zjean: https://github.com/zjean
|
||||||
@@ -1384,6 +1482,7 @@ bulk of the work on this big change.
|
|||||||
.. _JOKer: https://github.com/MasterofJOKers
|
.. _JOKer: https://github.com/MasterofJOKers
|
||||||
.. _Brian Cribbs: https://github.com/cribbstechnolog
|
.. _Brian Cribbs: https://github.com/cribbstechnolog
|
||||||
.. _Brendan M. Sleight: https://github.com/bmsleight
|
.. _Brendan M. Sleight: https://github.com/bmsleight
|
||||||
|
.. _Daniel Albers: https://github.com/AlD
|
||||||
|
|
||||||
.. _#20: https://github.com/the-paperless-project/paperless/issues/20
|
.. _#20: https://github.com/the-paperless-project/paperless/issues/20
|
||||||
.. _#44: https://github.com/the-paperless-project/paperless/issues/44
|
.. _#44: https://github.com/the-paperless-project/paperless/issues/44
|
||||||
|
|||||||
+53
-10
@@ -154,10 +154,6 @@ PAPERLESS_FORCE_SCRIPT_NAME=<path>
|
|||||||
To host paperless under a subpath url like example.com/paperless you set
|
To host paperless under a subpath url like example.com/paperless you set
|
||||||
this value to /paperless. No trailing slash!
|
this value to /paperless. No trailing slash!
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
I don't know if this works in paperless-ng. Probably not.
|
|
||||||
|
|
||||||
Defaults to none, which hosts paperless at "/".
|
Defaults to none, which hosts paperless at "/".
|
||||||
|
|
||||||
PAPERLESS_STATIC_URL=<path>
|
PAPERLESS_STATIC_URL=<path>
|
||||||
@@ -177,6 +173,30 @@ PAPERLESS_AUTO_LOGIN_USERNAME=<username>
|
|||||||
|
|
||||||
Defaults to none, which disables this feature.
|
Defaults to none, which disables this feature.
|
||||||
|
|
||||||
|
PAPERLESS_ADMIN_USER=<username>
|
||||||
|
If this environment variable is specified, Paperless automatically creates
|
||||||
|
a superuser with the provided username at start. This is useful in cases
|
||||||
|
where you can not run the `createsuperuser` command seperately, such as Kubernetes
|
||||||
|
or AWS ECS.
|
||||||
|
|
||||||
|
Requires `PAPERLESS_ADMIN_PASSWORD` to be set.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
This will not change an existing [super]user's password, nor will
|
||||||
|
it recreate a user that already exists. You can leave this throughout
|
||||||
|
the lifecycle of the containers.
|
||||||
|
|
||||||
|
PAPERLESS_ADMIN_MAIL=<email>
|
||||||
|
(Optional) Specify superuser email address. Only used when
|
||||||
|
`PAPERLESS_ADMIN_USER` is set.
|
||||||
|
|
||||||
|
Defaults to ``root@localhost``.
|
||||||
|
|
||||||
|
PAPERLESS_ADMIN_PASSWORD=<password>
|
||||||
|
Only used when `PAPERLESS_ADMIN_USER` is set.
|
||||||
|
This will be the password of the automatically created superuser.
|
||||||
|
|
||||||
|
|
||||||
PAPERLESS_COOKIE_PREFIX=<str>
|
PAPERLESS_COOKIE_PREFIX=<str>
|
||||||
Specify a prefix that is added to the cookies used by paperless to identify
|
Specify a prefix that is added to the cookies used by paperless to identify
|
||||||
@@ -202,17 +222,24 @@ PAPERLESS_ENABLE_HTTP_REMOTE_USER=<bool>
|
|||||||
Also see the warning `in the official documentation <https://docs.djangoproject.com/en/3.1/howto/auth-remote-user/#configuration>`.
|
Also see the warning `in the official documentation <https://docs.djangoproject.com/en/3.1/howto/auth-remote-user/#configuration>`.
|
||||||
|
|
||||||
Defaults to `false` which disables this feature.
|
Defaults to `false` which disables this feature.
|
||||||
|
|
||||||
PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME=<str>
|
PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME=<str>
|
||||||
If `PAPERLESS_ENABLE_HTTP_REMOTE_USER` is enabled, this property allows to
|
If `PAPERLESS_ENABLE_HTTP_REMOTE_USER` is enabled, this property allows to
|
||||||
customize the name of the HTTP header from which the authenticated username
|
customize the name of the HTTP header from which the authenticated username
|
||||||
is extracted. Values are in terms of
|
is extracted. Values are in terms of
|
||||||
[HttpRequest.META](https://docs.djangoproject.com/en/3.1/ref/request-response/#django.http.HttpRequest.META).
|
[HttpRequest.META](https://docs.djangoproject.com/en/3.1/ref/request-response/#django.http.HttpRequest.META).
|
||||||
Thus, the configured value must start with `HTTP_` followed by the
|
Thus, the configured value must start with `HTTP_` followed by the
|
||||||
normalized actual header name.
|
normalized actual header name.
|
||||||
|
|
||||||
Defaults to `HTTP_REMOTE_USER`.
|
Defaults to `HTTP_REMOTE_USER`.
|
||||||
|
|
||||||
|
PAPERLESS_LOGOUT_REDIRECT_URL=<str>
|
||||||
|
URL to redirect the user to after a logout. This can be used together with
|
||||||
|
`PAPERLESS_ENABLE_HTTP_REMOTE_USER` to redirect the user back to the SSO
|
||||||
|
application's logout page.
|
||||||
|
|
||||||
|
Defaults to None, which disables this feature.
|
||||||
|
|
||||||
.. _configuration-ocr:
|
.. _configuration-ocr:
|
||||||
|
|
||||||
OCR settings
|
OCR settings
|
||||||
@@ -238,6 +265,8 @@ PAPERLESS_OCR_LANGUAGE=<lang>
|
|||||||
|
|
||||||
Defaults to "eng".
|
Defaults to "eng".
|
||||||
|
|
||||||
|
Note: If your language contains a '-' such as chi-sim, you must use chi_sim
|
||||||
|
|
||||||
PAPERLESS_OCR_MODE=<mode>
|
PAPERLESS_OCR_MODE=<mode>
|
||||||
Tell paperless when and how to perform ocr on your documents. Four modes
|
Tell paperless when and how to perform ocr on your documents. Four modes
|
||||||
are available:
|
are available:
|
||||||
@@ -602,6 +631,20 @@ PAPERLESS_IGNORE_DATES=<string>
|
|||||||
|
|
||||||
Defaults to an empty string to not ignore any dates.
|
Defaults to an empty string to not ignore any dates.
|
||||||
|
|
||||||
|
PAPERLESS_DATE_ORDER=<format>
|
||||||
|
Paperless will try to determine the document creation date from its contents.
|
||||||
|
Specify the date format Paperless should expect to see within your documents.
|
||||||
|
|
||||||
|
This option defaults to DMY which translates to day first, month second, and year
|
||||||
|
last order. Characters D, M, or Y can be shuffled to meet the required order.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
This can be adjusted by configuring a custom json array with patterns to exclude.
|
||||||
|
|
||||||
|
Defautls to ``[".DS_STORE/*", "._*", ".stfolder/*"]``.
|
||||||
|
|
||||||
Binaries
|
Binaries
|
||||||
########
|
########
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Contributing to Paperless
|
|||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
This section is not updated to paperless-ng yet.
|
This section is not updated to paperless-ng yet.
|
||||||
|
|
||||||
Maybe you've been using Paperless for a while and want to add a feature or two,
|
Maybe you've been using Paperless 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
|
or maybe you've come across a bug that you have some ideas how to solve. The
|
||||||
beauty of Free software is that you can see what's wrong and help to get it
|
beauty of Free software is that you can see what's wrong and help to get it
|
||||||
|
|||||||
+9
-9
@@ -23,10 +23,10 @@ Apart from that, the folder structure is as follows:
|
|||||||
* ``scripts/`` - Various scripts that help with different parts of development.
|
* ``scripts/`` - Various scripts that help with different parts of development.
|
||||||
* ``docker/`` - Files required to build the docker image.
|
* ``docker/`` - Files required to build the docker image.
|
||||||
|
|
||||||
Initial setup and first start
|
Initial setup and first start
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
After you forked and cloned the code from github you need to perform a first-time 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:
|
To do the setup you need to perform the steps from the following chapters in a certain order:
|
||||||
|
|
||||||
1. Install prerequisites + pipenv as mentioned in :ref:`Bare metal route <setup-bare_metal>`
|
1. Install prerequisites + pipenv as mentioned in :ref:`Bare metal route <setup-bare_metal>`
|
||||||
@@ -35,19 +35,19 @@ To do the setup you need to perform the steps from the following chapters in a c
|
|||||||
|
|
||||||
.. code:: shell-session
|
.. code:: shell-session
|
||||||
|
|
||||||
$ npm install -g @angular/cli
|
$ npm install -g @angular/cli
|
||||||
|
|
||||||
4. Create ``consume`` and ``media`` folders in the cloned root folder.
|
4. Create ``consume`` and ``media`` folders in the cloned root folder.
|
||||||
|
|
||||||
.. code:: shell-session
|
.. code:: shell-session
|
||||||
|
|
||||||
mkdir -p consume media
|
mkdir -p consume media
|
||||||
|
|
||||||
5. You can now either ...
|
5. You can now either ...
|
||||||
|
|
||||||
* install redis or
|
* install redis or
|
||||||
* 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 postgresql server) or
|
* 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 postgresql server) or
|
||||||
* spin up a bare redis container
|
* spin up a bare redis container
|
||||||
|
|
||||||
.. code:: shell-session
|
.. code:: shell-session
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ To do the setup you need to perform the steps from the following chapters in a c
|
|||||||
python3 manage.py runserver & python3 manage.py document_consumer & python3 manage.py qcluster
|
python3 manage.py runserver & python3 manage.py document_consumer & python3 manage.py qcluster
|
||||||
|
|
||||||
10. Login with the superuser credentials provided in step 8 at ``http://localhost:8000`` to create a session that enables you to use the backend.
|
10. 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.
|
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.
|
||||||
|
|
||||||
Back end development
|
Back end development
|
||||||
@@ -207,7 +207,7 @@ Adding new languages requires adding the translated files in the "src-ui/src/loc
|
|||||||
// Add your new language here
|
// Add your new language here
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
``dateInputFormat`` is a special string that defines the behavior of the date input fields and absolutely needs to contain "dd", "mm" and "yyyy".
|
``dateInputFormat`` is a special string that defines the behavior of the date input fields and absolutely needs to contain "dd", "mm" and "yyyy".
|
||||||
|
|
||||||
3. Import and register the Angular data for this locale in "src-ui/src/app/app.module.ts":
|
3. Import and register the Angular data for this locale in "src-ui/src/app/app.module.ts":
|
||||||
@@ -320,7 +320,7 @@ methods ``parse`` and ``get_thumbnail``. You can provide your own implementation
|
|||||||
|
|
||||||
# The content of the document.
|
# The content of the document.
|
||||||
self.text = "content"
|
self.text = "content"
|
||||||
|
|
||||||
# Optional: path to a PDF document that you created from the original.
|
# Optional: path to a PDF document that you created from the original.
|
||||||
self.archive_path = os.path.join(self.tempdir, "archived.pdf")
|
self.archive_path = os.path.join(self.tempdir, "archived.pdf")
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -68,10 +68,10 @@ reuse the text. The web interface is a lot snappier, since it runs
|
|||||||
in your browser and paperless has to do much less work to serve the data.
|
in your browser and paperless has to do much less work to serve the data.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
You can adjust some of the settings so that paperless uses less processing
|
You can adjust some of the settings so that paperless uses less processing
|
||||||
power. See :ref:`setup-less_powerful_devices` for details.
|
power. See :ref:`setup-less_powerful_devices` for details.
|
||||||
|
|
||||||
|
|
||||||
**Q:** *How do I install paperless-ng on Raspberry Pi?*
|
**Q:** *How do I install paperless-ng on Raspberry Pi?*
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -49,7 +49,7 @@ resources in the documentation:
|
|||||||
paperless-ng.
|
paperless-ng.
|
||||||
* Paperless is now integrated with a
|
* Paperless is now integrated with a
|
||||||
:ref:`task processing queue <setup-task_processor>` that tells you
|
:ref:`task processing queue <setup-task_processor>` that tells you
|
||||||
at a glance when and why something is not working.
|
at a glance when and why something is not working.
|
||||||
* The :ref:`changelog <paperless_changelog>` contains a detailed list of all changes
|
* The :ref:`changelog <paperless_changelog>` contains a detailed list of all changes
|
||||||
in paperless-ng.
|
in paperless-ng.
|
||||||
|
|
||||||
|
|||||||
+35
-25
@@ -13,42 +13,48 @@ that works right for you based on recommendations from other Paperless users.
|
|||||||
Physical scanners
|
Physical scanners
|
||||||
=================
|
=================
|
||||||
|
|
||||||
+---------+----------------+-----+-----+-----+------+----------------+
|
+---------+----------------+-----+-----+-----+------+----------+----------------+
|
||||||
| Brand | Model | Supports | Recommended By |
|
| Brand | Model | Supports | Recommended By |
|
||||||
+---------+----------------+-----+-----+-----+------+----------------+
|
+---------+----------------+-----+-----+-----+------+----------+----------------+
|
||||||
| | | FTP | NFS | SMB | SMTP | |
|
| | | FTP | NFS | SMB | SMTP | API [1]_ | |
|
||||||
+=========+================+=====+=====+=====+======+================+
|
+=========+================+=====+=====+=====+======+==========+================+
|
||||||
| Brother | `ADS-1700W`_ | yes | no | yes | yes |`holzhannes`_ |
|
| Brother | `ADS-1700W`_ | yes | no | yes | yes | |`holzhannes`_ |
|
||||||
+---------+----------------+-----+-----+-----+------+----------------+
|
+---------+----------------+-----+-----+-----+------+----------+----------------+
|
||||||
| Brother | `ADS-1600W`_ | yes | no | yes | yes |`holzhannes`_ |
|
| Brother | `ADS-1600W`_ | yes | no | yes | yes | |`holzhannes`_ |
|
||||||
+---------+----------------+-----+-----+-----+------+----------------+
|
+---------+----------------+-----+-----+-----+------+----------+----------------+
|
||||||
| Brother | `ADS-1500W`_ | yes | no | yes | yes |`danielquinn`_ |
|
| Brother | `ADS-1500W`_ | yes | no | yes | yes | |`danielquinn`_ |
|
||||||
+---------+----------------+-----+-----+-----+------+----------------+
|
+---------+----------------+-----+-----+-----+------+----------+----------------+
|
||||||
| Brother | `MFC-J6930DW`_ | yes | | | |`ayounggun`_ |
|
| Brother | `ADS-1100W`_ | yes | no | no | no | |`ytzelf`_ |
|
||||||
+---------+----------------+-----+-----+-----+------+----------------+
|
+---------+----------------+-----+-----+-----+------+----------+----------------+
|
||||||
| Brother | `MFC-L5850DW`_ | yes | | | yes |`holzhannes`_ |
|
| Brother | `MFC-J6930DW`_ | yes | | | | |`ayounggun`_ |
|
||||||
+---------+----------------+-----+-----+-----+------+----------------+
|
+---------+----------------+-----+-----+-----+------+----------+----------------+
|
||||||
| Brother | `MFC-J5910DW`_ | yes | | | |`bmsleight`_ |
|
| Brother | `MFC-L5850DW`_ | yes | | | yes | |`holzhannes`_ |
|
||||||
+---------+----------------+-----+-----+-----+------+----------------+
|
+---------+----------------+-----+-----+-----+------+----------+----------------+
|
||||||
| Brother | `MFC-9142CDN`_ | yes | | yes | |`REOLDEV`_ |
|
| Brother | `MFC-J5910DW`_ | yes | | | | |`bmsleight`_ |
|
||||||
+---------+----------------+-----+-----+-----+------+----------------+
|
+---------+----------------+-----+-----+-----+------+----------+----------------+
|
||||||
| Fujitsu | `ix500`_ | yes | | yes | |`eonist`_ |
|
| Brother | `MFC-9142CDN`_ | yes | | yes | | |`REOLDEV`_ |
|
||||||
+---------+----------------+-----+-----+-----+------+----------------+
|
+---------+----------------+-----+-----+-----+------+----------+----------------+
|
||||||
| Epson | `WF-7710DWF`_ | yes | | yes | |`Skylinar`_ |
|
| Fujitsu | `ix500`_ | yes | | yes | | |`eonist`_ |
|
||||||
+---------+----------------+-----+-----+-----+------+----------------+
|
+---------+----------------+-----+-----+-----+------+----------+----------------+
|
||||||
| Fujitsu | `S1300i`_ | yes | | yes | |`jonaswinkler`_ |
|
| Epson | `WF-7710DWF`_ | yes | | yes | | |`Skylinar`_ |
|
||||||
+---------+----------------+-----+-----+-----+------+----------------+
|
+---------+----------------+-----+-----+-----+------+----------+----------------+
|
||||||
|
| Fujitsu | `S1300i`_ | yes | | yes | | |`jonaswinkler`_ |
|
||||||
|
+---------+----------------+-----+-----+-----+------+----------+----------------+
|
||||||
|
| Doxie | `Q2`_ | no | no | no | no | yes |`Unkn0wnCat`_ |
|
||||||
|
+---------+----------------+-----+-----+-----+------+----------+----------------+
|
||||||
|
|
||||||
.. _MFC-L5850DW: https://www.brother-usa.com/products/mfcl5850dw
|
.. _MFC-L5850DW: https://www.brother-usa.com/products/mfcl5850dw
|
||||||
.. _ADS-1700W: https://www.brother-usa.com/products/ads1700w
|
.. _ADS-1700W: https://www.brother-usa.com/products/ads1700w
|
||||||
.. _ADS-1600W: https://www.brother-usa.com/products/ads1600w
|
.. _ADS-1600W: https://www.brother-usa.com/products/ads1600w
|
||||||
.. _ADS-1500W: https://www.brother.ca/en/p/ads1500w
|
.. _ADS-1500W: https://www.brother.ca/en/p/ads1500w
|
||||||
|
.. _ADS-1100W: https://support.brother.com/g/b/downloadtop.aspx?c=fr&lang=fr&prod=ads1100w_eu_as_cn
|
||||||
.. _MFC-J6930DW: https://www.brother.ca/en/p/MFCJ6930DW
|
.. _MFC-J6930DW: https://www.brother.ca/en/p/MFCJ6930DW
|
||||||
.. _MFC-J5910DW: https://www.brother.co.uk/printers/inkjet-printers/mfcj5910dw
|
.. _MFC-J5910DW: https://www.brother.co.uk/printers/inkjet-printers/mfcj5910dw
|
||||||
.. _MFC-9142CDN: https://www.brother.co.uk/printers/laser-printers/mfc9140cdn
|
.. _MFC-9142CDN: https://www.brother.co.uk/printers/laser-printers/mfc9140cdn
|
||||||
.. _ix500: http://www.fujitsu.com/us/products/computing/peripheral/scanners/scansnap/ix500/
|
.. _ix500: http://www.fujitsu.com/us/products/computing/peripheral/scanners/scansnap/ix500/
|
||||||
.. _WF-7710DWF: https://www.epson.de/en/products/printers/inkjet-printers/for-home/workforce-wf-7710dwf
|
.. _WF-7710DWF: https://www.epson.de/en/products/printers/inkjet-printers/for-home/workforce-wf-7710dwf
|
||||||
.. _S1300i: https://www.fujitsu.com/global/products/computing/peripheral/scanners/soho/s1300i/
|
.. _S1300i: https://www.fujitsu.com/global/products/computing/peripheral/scanners/soho/s1300i/
|
||||||
|
.. _Q2: https://www.getdoxie.com/product/doxie-q/
|
||||||
|
|
||||||
|
|
||||||
.. _danielquinn: https://github.com/danielquinn
|
.. _danielquinn: https://github.com/danielquinn
|
||||||
@@ -59,6 +65,10 @@ Physical scanners
|
|||||||
.. _Skylinar: https://github.com/Skylinar
|
.. _Skylinar: https://github.com/Skylinar
|
||||||
.. _jonaswinkler: https://github.com/jonaswinkler
|
.. _jonaswinkler: https://github.com/jonaswinkler
|
||||||
.. _holzhannes: https://github.com/holzhannes
|
.. _holzhannes: https://github.com/holzhannes
|
||||||
|
.. _ytzelf: https://github.com/ytzelf
|
||||||
|
.. _Unkn0wnCat: https://github.com/Unkn0wnCat
|
||||||
|
|
||||||
|
.. [1] Scanners with API Integration allow to push scanned documents directly to :ref:`Paperless API <api-file_uploads>`, sometimes referred to as Webhook or Document POST.
|
||||||
|
|
||||||
Mobile phone software
|
Mobile phone software
|
||||||
=====================
|
=====================
|
||||||
|
|||||||
+37
-23
@@ -116,9 +116,7 @@ performs all the steps described in :ref:`setup-docker_hub` automatically.
|
|||||||
|
|
||||||
.. code:: shell-session
|
.. code:: shell-session
|
||||||
|
|
||||||
$ wget https://raw.githubusercontent.com/jonaswinkler/paperless-ng/master/install-paperless-ng.sh
|
$ curl -L https://raw.githubusercontent.com/jonaswinkler/paperless-ng/master/install-paperless-ng.sh | bash
|
||||||
$ chmod +x install-paperless-ng.sh
|
|
||||||
$ ./install-paperless-ng.sh
|
|
||||||
|
|
||||||
.. _setup-docker_hub:
|
.. _setup-docker_hub:
|
||||||
|
|
||||||
@@ -173,6 +171,24 @@ Install Paperless from Docker Hub
|
|||||||
|
|
||||||
Don't change the part after the colon or paperless wont find your documents.
|
Don't change the part after the colon or paperless wont find your documents.
|
||||||
|
|
||||||
|
You may also need to change the default port that the webserver will use
|
||||||
|
from the default (8000):
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
ports:
|
||||||
|
- 8000:8000
|
||||||
|
|
||||||
|
Replace the part BEFORE the colon with a port of your choice:
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
ports:
|
||||||
|
- 8010:8000
|
||||||
|
|
||||||
|
Don't change the part after the colon or edit other lines that refer to
|
||||||
|
port 8000. Modifying the part before the colon will map requests on another
|
||||||
|
port to the webserver running on the default port.
|
||||||
|
|
||||||
5. Modify ``docker-compose.env``, following the comments in the file. The
|
5. Modify ``docker-compose.env``, following the comments in the file. The
|
||||||
most important change is to set ``USERMAP_UID`` and ``USERMAP_GID``
|
most important change is to set ``USERMAP_UID`` and ``USERMAP_GID``
|
||||||
@@ -286,7 +302,7 @@ writing. Windows is not and will never be supported.
|
|||||||
|
|
||||||
Use this list for your preferred package management:
|
Use this list for your preferred package management:
|
||||||
|
|
||||||
.. code::
|
.. code::
|
||||||
|
|
||||||
python3 python3-pip python3-dev imagemagick fonts-liberation optipng gnupg libpq-dev libmagic-dev mime-support
|
python3 python3-pip python3-dev imagemagick fonts-liberation optipng gnupg libpq-dev libmagic-dev mime-support
|
||||||
|
|
||||||
@@ -305,7 +321,7 @@ writing. Windows is not and will never be supported.
|
|||||||
|
|
||||||
Use this list for your preferred package management:
|
Use this list for your preferred package management:
|
||||||
|
|
||||||
.. code::
|
.. code::
|
||||||
|
|
||||||
unpaper ghostscript icc-profiles-free qpdf liblept5 libxml2 pngquant zlib1g tesseract-ocr
|
unpaper ghostscript icc-profiles-free qpdf liblept5 libxml2 pngquant zlib1g tesseract-ocr
|
||||||
|
|
||||||
@@ -360,7 +376,11 @@ writing. Windows is not and will never be supported.
|
|||||||
Adjust as necessary if you configured different folders.
|
Adjust as necessary if you configured different folders.
|
||||||
|
|
||||||
8. Install python requirements from the ``requirements.txt`` file.
|
8. Install python requirements from the ``requirements.txt`` file.
|
||||||
It is up to you if you wish to use a virtual environment or not.
|
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.
|
||||||
|
|
||||||
|
.. code:: shell-session
|
||||||
|
|
||||||
|
sudo -Hu paperless pip3 install --upgrade pip
|
||||||
|
|
||||||
.. code:: shell-session
|
.. code:: shell-session
|
||||||
|
|
||||||
@@ -460,6 +480,7 @@ Install Paperless using ansible
|
|||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
This role currently only supports Debian 10 Buster and Ubuntu 20.04 Focal or later as target hosts.
|
This role currently only supports Debian 10 Buster and Ubuntu 20.04 Focal or later as target hosts.
|
||||||
|
Additionally, only i386 or amd64 based hosts are supported right now, i.e. installation on arm hosts will fail.
|
||||||
|
|
||||||
1. Install ansible 2.7+ on the management node.
|
1. Install ansible 2.7+ on the management node.
|
||||||
This may be the target host paperless-ng is being installed on or any remote host which can access the target host.
|
This may be the target host paperless-ng is being installed on or any remote host which can access the target host.
|
||||||
@@ -485,29 +506,22 @@ Install Paperless using ansible
|
|||||||
|
|
||||||
ansible -m ping YourAnsibleTargetHostGoesHere
|
ansible -m ping YourAnsibleTargetHostGoesHere
|
||||||
|
|
||||||
2. Clone the repository of paperless-ng:
|
2. Install the latest tag of the ansible role using ansible-galaxy
|
||||||
|
|
||||||
.. code:: sh
|
.. code:: sh
|
||||||
|
|
||||||
git clone https://github.com/jonaswinkler/paperless-ng
|
ansible-galaxy install git+https://github.com/jonaswinkler/paperless-ng.git,ng-1.4.2
|
||||||
|
|
||||||
Checkout the latest release tag:
|
3. Create an ansible ``playbook.yml`` in a directory of your choice:
|
||||||
|
|
||||||
.. code:: sh
|
|
||||||
|
|
||||||
cd paperless-ng
|
|
||||||
git checkout ng-1.0.0
|
|
||||||
|
|
||||||
3. Create an ansible ``playbook.yml`` in the paperless-ng root directory:
|
|
||||||
|
|
||||||
.. code:: yaml
|
.. code:: yaml
|
||||||
|
|
||||||
- hosts: YourAnsibleTargetHostGoesHere
|
- hosts: YourAnsibleTargetHostGoesHere
|
||||||
become: yes
|
become: yes
|
||||||
vars_files:
|
vars_files:
|
||||||
- ansible/vars.yml
|
- vars/paperless-ng.yml
|
||||||
roles:
|
roles:
|
||||||
- ansible
|
- paperless-ng
|
||||||
|
|
||||||
Optional: If you also want to use PostgreSQL on the target system, install and add (for example) the `geerlingguy.postgresql <https://github.com/geerlingguy/ansible-role-postgresql>`_ role:
|
Optional: If you also want to use PostgreSQL on the target system, install and add (for example) the `geerlingguy.postgresql <https://github.com/geerlingguy/ansible-role-postgresql>`_ role:
|
||||||
|
|
||||||
@@ -520,10 +534,10 @@ Install Paperless using ansible
|
|||||||
- hosts: YourAnsibleTargetHostGoesHere
|
- hosts: YourAnsibleTargetHostGoesHere
|
||||||
become: yes
|
become: yes
|
||||||
vars_files:
|
vars_files:
|
||||||
- ansible/vars.yml
|
- vars/paperless-ng.yml
|
||||||
roles:
|
roles:
|
||||||
- geerlingguy.postgresql
|
- geerlingguy.postgresql
|
||||||
- ansible
|
- paperless-ng
|
||||||
|
|
||||||
Optional: If you also want to use a reverse proxy on the target system, install and add (for example) the `geerlingguy.nginx <https://github.com/geerlingguy/ansible-role-nginx>`_ role:
|
Optional: If you also want to use a reverse proxy on the target system, install and add (for example) the `geerlingguy.nginx <https://github.com/geerlingguy/ansible-role-nginx>`_ role:
|
||||||
|
|
||||||
@@ -536,13 +550,13 @@ Install Paperless using ansible
|
|||||||
- hosts: YourAnsibleTargetHostGoesHere
|
- hosts: YourAnsibleTargetHostGoesHere
|
||||||
become: yes
|
become: yes
|
||||||
vars_files:
|
vars_files:
|
||||||
- ansible/vars.yml
|
- vars/paperless-ng.yml
|
||||||
roles:
|
roles:
|
||||||
- geerlingguy.postgresql
|
- geerlingguy.postgresql
|
||||||
- ansible
|
- paperless-ng
|
||||||
- geerlingguy.nginx
|
- geerlingguy.nginx
|
||||||
|
|
||||||
4. Create ``ansible/vars.yml`` to configure your ansible deployment:
|
4. Create ``vars/paperless-ng.yml`` to configure your ansible deployment:
|
||||||
|
|
||||||
.. code:: yaml
|
.. code:: yaml
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ UserWarning in sklearn on every single document
|
|||||||
You may encounter warnings like this:
|
You may encounter warnings like this:
|
||||||
|
|
||||||
.. code::
|
.. code::
|
||||||
|
|
||||||
/usr/local/lib/python3.7/site-packages/sklearn/base.py:315:
|
/usr/local/lib/python3.7/site-packages/sklearn/base.py:315:
|
||||||
UserWarning: Trying to unpickle estimator CountVectorizer from version 0.23.2 when using version 0.24.0.
|
UserWarning: Trying to unpickle estimator CountVectorizer from version 0.23.2 when using version 0.24.0.
|
||||||
This might lead to breaking code or invalid results. Use at your own risk.
|
This might lead to breaking code or invalid results. Use at your own risk.
|
||||||
@@ -200,11 +200,24 @@ This might have multiple reasons.
|
|||||||
File "/usr/local/lib/python3.7/site-packages/gunicorn/http/wsgi.py", line 386, in sendfile
|
File "/usr/local/lib/python3.7/site-packages/gunicorn/http/wsgi.py", line 386, in sendfile
|
||||||
sent += os.sendfile(sockno, fileno, offset + sent, count)
|
sent += os.sendfile(sockno, fileno, offset + sent, count)
|
||||||
OSError: [Errno 22] Invalid argument
|
OSError: [Errno 22] Invalid argument
|
||||||
|
|
||||||
To fix this issue, add
|
To fix this issue, add
|
||||||
|
|
||||||
.. code::
|
.. code::
|
||||||
|
|
||||||
SENDFILE=0
|
SENDFILE=0
|
||||||
|
|
||||||
to your `docker-compose.env` file.
|
to your `docker-compose.env` file.
|
||||||
|
|
||||||
|
Error while reading metadata
|
||||||
|
############################
|
||||||
|
|
||||||
|
You might find messages like these in your log files:
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
[WARNING] [paperless.parsing.tesseract] Error while reading metadata
|
||||||
|
|
||||||
|
This indicates that paperless failed to read PDF metadata from one of your documents. This happens when you
|
||||||
|
open the affected documents in paperless for editing. Paperless will continue to work, and will simply not
|
||||||
|
show the invalid metadata.
|
||||||
@@ -71,7 +71,7 @@ your documents:
|
|||||||
|
|
||||||
This process can be configured to fit your needs. If you don't want paperless
|
This process can be configured to fit your needs. If you don't want paperless
|
||||||
to create archived versions for digital documents, you can configure that by
|
to create archived versions for digital documents, you can configure that by
|
||||||
configuring ``PAPERLESS_OCR_MODE=skip_noarchive``. Please read the
|
configuring ``PAPERLESS_OCR_MODE=skip_noarchive``. Please read the
|
||||||
:ref:`relevant section in the documentation <configuration-ocr>`.
|
:ref:`relevant section in the documentation <configuration-ocr>`.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
@@ -255,6 +255,8 @@ Here are a couple examples of tags and types that you could use in your collecti
|
|||||||
* A tag ``missing_metadata`` when you still need to add some metadata to a document, but can't
|
* A tag ``missing_metadata`` when you still need to add some metadata to a document, but can't
|
||||||
or don't want to do this right now.
|
or don't want to do this right now.
|
||||||
|
|
||||||
|
.. _basic-usage_searching:
|
||||||
|
|
||||||
Searching
|
Searching
|
||||||
#########
|
#########
|
||||||
|
|
||||||
@@ -287,7 +289,7 @@ Matching specific tags, correspondents or types:
|
|||||||
Matching dates:
|
Matching dates:
|
||||||
|
|
||||||
.. code::
|
.. code::
|
||||||
|
|
||||||
created:[2005 to 2009]
|
created:[2005 to 2009]
|
||||||
added:yesterday
|
added:yesterday
|
||||||
modified:today
|
modified:today
|
||||||
@@ -304,11 +306,11 @@ Matching inexact words:
|
|||||||
auto complete and query correction.
|
auto complete and query correction.
|
||||||
|
|
||||||
All of these constructs can be combined as you see fit.
|
All of these constructs can be combined as you see fit.
|
||||||
If you want to learn more about the query language used by paperless, paperless uses Whoosh's default query language.
|
If you want to learn more about the query language used by paperless, paperless uses Whoosh's default query language.
|
||||||
Head over to `Whoosh query language <https://whoosh.readthedocs.io/en/latest/querylang.html>`_.
|
Head over to `Whoosh query language <https://whoosh.readthedocs.io/en/latest/querylang.html>`_.
|
||||||
For details on what date parsing utilities are available, see
|
For details on what date parsing utilities are available, see
|
||||||
`Date parsing <https://whoosh.readthedocs.io/en/latest/dates.html#parsing-date-queries>`_.
|
`Date parsing <https://whoosh.readthedocs.io/en/latest/dates.html#parsing-date-queries>`_.
|
||||||
|
|
||||||
|
|
||||||
.. _usage-recommended_workflow:
|
.. _usage-recommended_workflow:
|
||||||
|
|
||||||
@@ -383,7 +385,7 @@ Once you have scanned in a document, proceed in paperless as follows.
|
|||||||
6. Remove inbox tags from the documents.
|
6. Remove inbox tags from the documents.
|
||||||
|
|
||||||
.. hint::
|
.. hint::
|
||||||
|
|
||||||
You can setup manual matching rules for your correspondents and tags and
|
You can setup manual matching rules for your correspondents and tags and
|
||||||
paperless will assign them automatically. After consuming a couple documents,
|
paperless will assign them automatically. After consuming a couple documents,
|
||||||
you can even ask paperless to *learn* when to assign tags and correspondents
|
you can even ask paperless to *learn* when to assign tags and correspondents
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ import os
|
|||||||
|
|
||||||
bind = '0.0.0.0:8000'
|
bind = '0.0.0.0:8000'
|
||||||
workers = int(os.getenv("PAPERLESS_WEBSERVER_WORKERS", 2))
|
workers = int(os.getenv("PAPERLESS_WEBSERVER_WORKERS", 2))
|
||||||
worker_class = 'uvicorn.workers.UvicornWorker'
|
worker_class = 'paperless.workers.ConfigurableWorker'
|
||||||
timeout = 120
|
timeout = 120
|
||||||
|
|
||||||
def pre_fork(server, worker):
|
def pre_fork(server, worker):
|
||||||
|
|||||||
+13
-1
@@ -62,7 +62,7 @@ if [[ -z $(which docker-compose) ]] ; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if user has permissions to run Docker by trying to get the status of Docker (docker status).
|
# Check if user has permissions to run Docker by trying to get the status of Docker (docker status).
|
||||||
# If this fails, the user probably does not have permissions for Docker.
|
# If this fails, the user probably does not have permissions for Docker.
|
||||||
docker stats --no-stream 2>/dev/null 1>&2
|
docker stats --no-stream 2>/dev/null 1>&2
|
||||||
if [ $? -ne 0 ] ; then
|
if [ $? -ne 0 ] ; then
|
||||||
@@ -73,6 +73,8 @@ if [ $? -ne 0 ] ; then
|
|||||||
sleep 3
|
sleep 3
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
default_time_zone=$(timedatectl show -p Timezone --value)
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
@@ -145,6 +147,15 @@ echo ""
|
|||||||
ask "Port" "8000"
|
ask "Port" "8000"
|
||||||
PORT=$ask_result
|
PORT=$ask_result
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Paperless requires you to configure the current time zone correctly."
|
||||||
|
echo "Otherwise, the dates of your documents may appear off by one day,"
|
||||||
|
echo "depending on where you are on earth."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
ask "Current time zone" "$default_time_zone"
|
||||||
|
TIME_ZONE=$ask_result
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Database backend: PostgreSQL and SQLite are available. Use PostgreSQL"
|
echo "Database backend: PostgreSQL and SQLite are available. Use PostgreSQL"
|
||||||
echo "if unsure. If you're running on a low-power device such as Raspberry"
|
echo "if unsure. If you're running on a low-power device such as Raspberry"
|
||||||
@@ -280,6 +291,7 @@ DEFAULT_LANGUAGES="deu eng fra ita spa"
|
|||||||
if [[ ! $USERMAP_GID == "1000" ]] ; then
|
if [[ ! $USERMAP_GID == "1000" ]] ; then
|
||||||
echo "USERMAP_GID=$USERMAP_GID"
|
echo "USERMAP_GID=$USERMAP_GID"
|
||||||
fi
|
fi
|
||||||
|
echo "PAPERLESS_TIME_ZONE=$TIME_ZONE"
|
||||||
echo "PAPERLESS_OCR_LANGUAGE=$OCR_LANGUAGE"
|
echo "PAPERLESS_OCR_LANGUAGE=$OCR_LANGUAGE"
|
||||||
echo "PAPERLESS_SECRET_KEY=$SECRET_KEY"
|
echo "PAPERLESS_SECRET_KEY=$SECRET_KEY"
|
||||||
if [[ ! " ${DEFAULT_LANGUAGES[@]} " =~ " ${OCR_LANGUAGE} " ]] ; then
|
if [[ ! " ${DEFAULT_LANGUAGES[@]} " =~ " ${OCR_LANGUAGE} " ]] ; then
|
||||||
|
|||||||
@@ -57,6 +57,7 @@
|
|||||||
#PAPERLESS_CONSUMER_POLLING=10
|
#PAPERLESS_CONSUMER_POLLING=10
|
||||||
#PAPERLESS_CONSUMER_DELETE_DUPLICATES=false
|
#PAPERLESS_CONSUMER_DELETE_DUPLICATES=false
|
||||||
#PAPERLESS_CONSUMER_RECURSIVE=false
|
#PAPERLESS_CONSUMER_RECURSIVE=false
|
||||||
|
#PAPERLESS_CONSUMER_IGNORE_PATTERNS=[".DS_STORE/*", "._*", ".stfolder/*"]
|
||||||
#PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=false
|
#PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=false
|
||||||
#PAPERLESS_OPTIMIZE_THUMBNAILS=true
|
#PAPERLESS_OPTIMIZE_THUMBNAILS=true
|
||||||
#PAPERLESS_POST_CONSUME_SCRIPT=/path/to/an/arbitrary/script.sh
|
#PAPERLESS_POST_CONSUME_SCRIPT=/path/to/an/arbitrary/script.sh
|
||||||
|
|||||||
+51
-48
@@ -8,93 +8,96 @@
|
|||||||
-i https://pypi.python.org/simple
|
-i https://pypi.python.org/simple
|
||||||
--extra-index-url https://www.piwheels.org/simple
|
--extra-index-url https://www.piwheels.org/simple
|
||||||
aioredis==1.3.1
|
aioredis==1.3.1
|
||||||
arrow==1.0.3; python_version >= '3.6'
|
arrow==1.1.1; python_version >= '3.6'
|
||||||
asgiref==3.3.1; python_version >= '3.5'
|
asgiref==3.4.1; python_version >= '3.6'
|
||||||
async-timeout==3.0.1; python_full_version >= '3.5.3'
|
async-timeout==3.0.1; python_full_version >= '3.5.3'
|
||||||
attrs==20.3.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
attrs==21.2.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
||||||
autobahn==21.3.1; python_version >= '3.7'
|
autobahn==21.3.1; python_version >= '3.7'
|
||||||
automat==20.2.0
|
automat==20.2.0
|
||||||
blessed==1.18.0
|
backports.zoneinfo==0.2.1
|
||||||
certifi==2020.12.5
|
blessed==1.18.1; python_version >= '2.7'
|
||||||
cffi==1.14.5
|
certifi==2021.5.30
|
||||||
channels-redis==3.2.0
|
cffi==1.14.6
|
||||||
channels==3.0.3
|
channels-redis==3.3.0
|
||||||
|
channels==3.0.4
|
||||||
chardet==4.0.0; python_version >= '3.1'
|
chardet==4.0.0; python_version >= '3.1'
|
||||||
click==7.1.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
charset-normalizer==2.0.4; python_version >= '3'
|
||||||
coloredlogs==15.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
click==8.0.1; python_version >= '3.6'
|
||||||
|
coloredlogs==15.0.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
||||||
concurrent-log-handler==0.9.19
|
concurrent-log-handler==0.9.19
|
||||||
constantly==15.1.0
|
constantly==15.1.0
|
||||||
cryptography==3.4.7
|
cryptography==3.4.7
|
||||||
daphne==3.0.1; python_version >= '3.6'
|
daphne==3.0.2; python_version >= '3.6'
|
||||||
dateparser==1.0.0
|
dateparser==1.0.0
|
||||||
django-cors-headers==3.7.0
|
django-cors-headers==3.8.0
|
||||||
django-extensions==3.1.1
|
django-extensions==3.1.3
|
||||||
django-filter==2.4.0
|
django-filter==2.4.0
|
||||||
django-picklefield==3.0.1; python_version >= '3'
|
django-picklefield==3.0.1; python_version >= '3'
|
||||||
django-q==1.3.4
|
django-q==1.3.9
|
||||||
django==3.1.7
|
django==3.2.6
|
||||||
djangorestframework==3.12.4
|
djangorestframework==3.12.4
|
||||||
filelock==3.0.12
|
filelock==3.0.12
|
||||||
fuzzywuzzy[speedup]==0.18.0
|
fuzzywuzzy[speedup]==0.18.0
|
||||||
gunicorn==20.1.0
|
gunicorn==20.1.0
|
||||||
h11==0.12.0; python_version >= '3.6'
|
h11==0.12.0; python_version >= '3.6'
|
||||||
hiredis==2.0.0; python_version >= '3.6'
|
hiredis==2.0.0; python_version >= '3.6'
|
||||||
httptools==0.1.1
|
httptools==0.2.0
|
||||||
humanfriendly==9.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
humanfriendly==9.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
||||||
hyperlink==21.0.0
|
hyperlink==21.0.0
|
||||||
idna==2.10; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
idna==3.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
||||||
imap-tools==0.39.0
|
imap-tools==0.46.0
|
||||||
img2pdf==0.4.0
|
img2pdf==0.4.1
|
||||||
incremental==21.3.0
|
incremental==21.3.0
|
||||||
inotify-simple==1.3.5; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
inotify-simple==1.3.5; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
||||||
inotifyrecursive==0.3.5
|
inotifyrecursive==0.3.5
|
||||||
joblib==1.0.1; python_version >= '3.6'
|
joblib==1.0.1; python_version >= '3.6'
|
||||||
langdetect==1.0.8
|
langdetect==1.0.9
|
||||||
lxml==4.6.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
lxml==4.6.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
||||||
msgpack==1.0.2
|
msgpack==1.0.2
|
||||||
numpy==1.19.5
|
numpy==1.20.3
|
||||||
ocrmypdf==11.7.3
|
ocrmypdf==12.3.2
|
||||||
pathvalidate==2.4.0
|
pathvalidate==2.4.1
|
||||||
pdfminer.six==20201018
|
pdfminer.six==20201018
|
||||||
pikepdf==2.10.0
|
pikepdf==2.16.1
|
||||||
pillow==8.2.0
|
pillow==8.3.1
|
||||||
pluggy==0.13.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
pluggy==0.13.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
||||||
portalocker==2.3.0; python_version >= '3'
|
portalocker==2.3.0; python_version >= '3'
|
||||||
psycopg2-binary==2.8.6
|
psycopg2-binary==2.9.1
|
||||||
pyasn1-modules==0.2.8
|
pyasn1-modules==0.2.8
|
||||||
pyasn1==0.4.8
|
pyasn1==0.4.8
|
||||||
pycparser==2.20; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
pycparser==2.20; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
||||||
pyopenssl==20.0.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
pyopenssl==20.0.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
||||||
python-dateutil==2.8.1
|
python-dateutil==2.8.2
|
||||||
python-dotenv==0.16.0
|
python-dotenv==0.19.0
|
||||||
python-gnupg==0.4.7
|
python-gnupg==0.4.7
|
||||||
python-levenshtein==0.12.2
|
python-levenshtein==0.12.2
|
||||||
python-magic==0.4.22
|
python-magic==0.4.24
|
||||||
pytz==2021.1
|
pytz==2021.1
|
||||||
pyyaml==5.4.1
|
pyyaml==5.4.1
|
||||||
redis==3.5.3
|
redis==3.5.3
|
||||||
regex==2021.3.17
|
regex==2021.8.3
|
||||||
reportlab==3.5.66; python_version >= '2.7' and python_version < '4'
|
reportlab==3.6.1; python_version >= '2.7' and python_version < '4'
|
||||||
requests==2.25.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
requests==2.26.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'
|
||||||
scikit-learn==0.24.0
|
scikit-learn==0.24.0
|
||||||
scipy==1.5.4
|
scipy==1.7.1; python_version < '3.10' and python_version >= '3.7'
|
||||||
service-identity==18.1.0
|
service-identity==21.1.0
|
||||||
six==1.15.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
||||||
sortedcontainers==2.3.0
|
sortedcontainers==2.4.0
|
||||||
sqlparse==0.4.1; python_version >= '3.5'
|
sqlparse==0.4.1; python_version >= '3.5'
|
||||||
threadpoolctl==2.1.0; python_version >= '3.5'
|
threadpoolctl==2.2.0; python_version >= '3.6'
|
||||||
tika==1.24
|
tika==1.24
|
||||||
tqdm==4.59.0
|
tqdm==4.62.1
|
||||||
twisted[tls]==21.2.0; python_full_version >= '3.5.4'
|
twisted[tls]==21.7.0; python_full_version >= '3.6.7'
|
||||||
txaio==21.2.1; python_version >= '3.6'
|
txaio==21.2.1; python_version >= '3.6'
|
||||||
tzlocal==2.1
|
typing-extensions==3.10.0.0
|
||||||
urllib3==1.26.4; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'
|
tzlocal==3.0; python_version >= '3.6'
|
||||||
uvicorn[standard]==0.13.4
|
urllib3==1.26.6; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'
|
||||||
uvloop==0.14.0
|
uvicorn[standard]==0.15.0
|
||||||
watchdog==1.0.2
|
uvloop==0.16.0
|
||||||
|
watchdog==2.1.3
|
||||||
watchgod==0.7
|
watchgod==0.7
|
||||||
wcwidth==0.2.5
|
wcwidth==0.2.5
|
||||||
websockets==8.1
|
websockets==9.1
|
||||||
whitenoise==5.2.0
|
whitenoise==5.3.0
|
||||||
whoosh==2.7.4
|
whoosh==2.7.4
|
||||||
zope.interface==5.3.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
zope.interface==5.4.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Paperless consumer
|
Description=Paperless scheduler
|
||||||
Requires=redis.service
|
Requires=redis.service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
|
|||||||
+4
-2
@@ -25,7 +25,10 @@
|
|||||||
"it-IT": "src/locale/messages.it_IT.xlf",
|
"it-IT": "src/locale/messages.it_IT.xlf",
|
||||||
"ro-RO": "src/locale/messages.ro_RO.xlf",
|
"ro-RO": "src/locale/messages.ro_RO.xlf",
|
||||||
"ru-RU": "src/locale/messages.ru_RU.xlf",
|
"ru-RU": "src/locale/messages.ru_RU.xlf",
|
||||||
"es-ES": "src/locale/messages.es_ES.xlf"
|
"es-ES": "src/locale/messages.es_ES.xlf",
|
||||||
|
"pl-PL": "src/locale/messages.pl_PL.xlf",
|
||||||
|
"sv-SE": "src/locale/messages.sv_SE.xlf",
|
||||||
|
"lb-LU": "src/locale/messages.lb_LU.xlf"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"architect": {
|
"architect": {
|
||||||
@@ -70,7 +73,6 @@
|
|||||||
"optimization": true,
|
"optimization": true,
|
||||||
"outputHashing": "none",
|
"outputHashing": "none",
|
||||||
"sourceMap": false,
|
"sourceMap": false,
|
||||||
"extractCss": true,
|
|
||||||
"namedChunks": false,
|
"namedChunks": false,
|
||||||
"extractLicenses": true,
|
"extractLicenses": true,
|
||||||
"vendorChunk": false,
|
"vendorChunk": false,
|
||||||
|
|||||||
@@ -33,4 +33,4 @@ exports.config = {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
+54
-17
@@ -188,35 +188,35 @@
|
|||||||
<source>Confirm delete</source>
|
<source>Confirm delete</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||||
<context context-type="linenumber">204</context>
|
<context context-type="linenumber">206</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5382975254277698192" datatype="html">
|
<trans-unit id="5382975254277698192" datatype="html">
|
||||||
<source>Do you really want to delete document "<x id="PH" equiv-text="this.document.title"/>"?</source>
|
<source>Do you really want to delete document "<x id="PH" equiv-text="this.document.title"/>"?</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||||
<context context-type="linenumber">205</context>
|
<context context-type="linenumber">207</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6691075929777935948" datatype="html">
|
<trans-unit id="6691075929777935948" datatype="html">
|
||||||
<source>The files for this document will be deleted permanently. This operation cannot be undone.</source>
|
<source>The files for this document will be deleted permanently. This operation cannot be undone.</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||||
<context context-type="linenumber">206</context>
|
<context context-type="linenumber">208</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="719892092227206532" datatype="html">
|
<trans-unit id="719892092227206532" datatype="html">
|
||||||
<source>Delete document</source>
|
<source>Delete document</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||||
<context context-type="linenumber">208</context>
|
<context context-type="linenumber">210</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1844801255494293730" datatype="html">
|
<trans-unit id="1844801255494293730" datatype="html">
|
||||||
<source>Error deleting document: <x id="PH" equiv-text="JSON.stringify(error)"/></source>
|
<source>Error deleting document: <x id="PH" equiv-text="JSON.stringify(error)"/></source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||||
<context context-type="linenumber">215</context>
|
<context context-type="linenumber">217</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="826b25211922a1b46436589233cb6f1a163d89b7" datatype="html">
|
<trans-unit id="826b25211922a1b46436589233cb6f1a163d89b7" datatype="html">
|
||||||
@@ -1057,63 +1057,63 @@
|
|||||||
<source>Title</source>
|
<source>Title</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
|
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
|
||||||
<context context-type="linenumber">85</context>
|
<context context-type="linenumber">88</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3100631071441658964" datatype="html">
|
<trans-unit id="3100631071441658964" datatype="html">
|
||||||
<source>Title & content</source>
|
<source>Title & content</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
|
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
|
||||||
<context context-type="linenumber">86</context>
|
<context context-type="linenumber">89</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7517688192215738656" datatype="html">
|
<trans-unit id="7517688192215738656" datatype="html">
|
||||||
<source>ASN</source>
|
<source>ASN</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
|
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
|
||||||
<context context-type="linenumber">87</context>
|
<context context-type="linenumber">90</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1010505078885609376" datatype="html">
|
<trans-unit id="1010505078885609376" datatype="html">
|
||||||
<source>Advanced search</source>
|
<source>Advanced search</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
|
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
|
||||||
<context context-type="linenumber">88</context>
|
<context context-type="linenumber">91</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2649431021108393503" datatype="html">
|
<trans-unit id="2649431021108393503" datatype="html">
|
||||||
<source>More like</source>
|
<source>More like</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
|
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
|
||||||
<context context-type="linenumber">91</context>
|
<context context-type="linenumber">94</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="02d184c288f567825a1fcbf83bcd3099a10853d5" datatype="html">
|
<trans-unit id="02d184c288f567825a1fcbf83bcd3099a10853d5" datatype="html">
|
||||||
<source>Filter tags</source>
|
<source>Filter tags</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
|
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
|
||||||
<context context-type="linenumber">20</context>
|
<context context-type="linenumber">19</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4b089ca12c472cf0b46167bb5afe4b527b301bbc" datatype="html">
|
<trans-unit id="4b089ca12c472cf0b46167bb5afe4b527b301bbc" datatype="html">
|
||||||
<source>Filter correspondents</source>
|
<source>Filter correspondents</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
|
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
|
||||||
<context context-type="linenumber">28</context>
|
<context context-type="linenumber">27</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="0ad509732aaf702b7ea8c771c7809fa84bc85908" datatype="html">
|
<trans-unit id="0ad509732aaf702b7ea8c771c7809fa84bc85908" datatype="html">
|
||||||
<source>Filter document types</source>
|
<source>Filter document types</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
|
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
|
||||||
<context context-type="linenumber">35</context>
|
<context context-type="linenumber">34</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2d9d55f1b70142ff4597ba32179d16888fd9c6b2" datatype="html">
|
<trans-unit id="2d9d55f1b70142ff4597ba32179d16888fd9c6b2" datatype="html">
|
||||||
<source>Reset filters</source>
|
<source>Reset filters</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
|
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
|
||||||
<context context-type="linenumber">58</context>
|
<context context-type="linenumber">57</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7593728289020204896" datatype="html">
|
<trans-unit id="7593728289020204896" datatype="html">
|
||||||
@@ -1205,7 +1205,7 @@
|
|||||||
<source>Score:</source>
|
<source>Score:</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-card-large/document-card-large.component.html</context>
|
<context context-type="sourcefile">src/app/components/document-list/document-card-large/document-card-large.component.html</context>
|
||||||
<context context-type="linenumber">86</context>
|
<context context-type="linenumber">87</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="727d980bba2b3e0b3d8705607f1208eef046479b" datatype="html">
|
<trans-unit id="727d980bba2b3e0b3d8705607f1208eef046479b" datatype="html">
|
||||||
@@ -1407,11 +1407,19 @@
|
|||||||
<context context-type="linenumber">68</context>
|
<context context-type="linenumber">68</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="0f72a164f5a5d10d1fbdeeb84ac80a63c04b7e1b" datatype="html">
|
||||||
|
<source>Add item</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/common/input/select/select.component.html</context>
|
||||||
|
<context context-type="linenumber">11</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Used for both types and correspondents</note>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="a1e6c11f20d4bf6e8e6b43e3c6d2561b2080645e" datatype="html">
|
<trans-unit id="a1e6c11f20d4bf6e8e6b43e3c6d2561b2080645e" datatype="html">
|
||||||
<source>Suggestions:</source>
|
<source>Suggestions:</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/input/select/select.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/input/select/select.component.html</context>
|
||||||
<context context-type="linenumber">26</context>
|
<context context-type="linenumber">31</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="27d158b47717ff9305d19866960418c603f19d55" datatype="html">
|
<trans-unit id="27d158b47717ff9305d19866960418c603f19d55" datatype="html">
|
||||||
@@ -1421,6 +1429,13 @@
|
|||||||
<context context-type="linenumber">3</context>
|
<context context-type="linenumber">3</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="21fd41eb147f55ca26362f9c398e47733639837a" datatype="html">
|
||||||
|
<source>Add tag</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/common/input/tags/tags.component.html</context>
|
||||||
|
<context context-type="linenumber">11</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4eb84de23219c85432e38fb4fbdeb6c0f103ff8b" datatype="html">
|
<trans-unit id="4eb84de23219c85432e38fb4fbdeb6c0f103ff8b" datatype="html">
|
||||||
<source>Show all</source>
|
<source>Show all</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
@@ -1724,11 +1739,25 @@
|
|||||||
<context context-type="linenumber">100</context>
|
<context context-type="linenumber">100</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="792060551707690640" datatype="html">
|
||||||
|
<source>Polish</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
|
||||||
|
<context context-type="linenumber">101</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="499386805970351976" datatype="html">
|
||||||
|
<source>Swedish</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
|
||||||
|
<context context-type="linenumber">102</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4912706592792948707" datatype="html">
|
<trans-unit id="4912706592792948707" datatype="html">
|
||||||
<source>ISO 8601</source>
|
<source>ISO 8601</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
|
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
|
||||||
<context context-type="linenumber">106</context>
|
<context context-type="linenumber">107</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2119857572761283468" datatype="html">
|
<trans-unit id="2119857572761283468" datatype="html">
|
||||||
@@ -1875,6 +1904,14 @@
|
|||||||
<context context-type="linenumber">23</context>
|
<context context-type="linenumber">23</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="4460262093225954455" datatype="html">
|
||||||
|
<source>Search score</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
|
||||||
|
<context context-type="linenumber">28</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Score is a value returned by the full text search engine and specifies how well a result matches the given query</note>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4561076822163447092" datatype="html">
|
<trans-unit id="4561076822163447092" datatype="html">
|
||||||
<source>Create new item</source>
|
<source>Create new item</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
Generated
+20659
-4490
File diff suppressed because it is too large.
Load diff
+20
-20
@@ -11,41 +11,41 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "~10.1.5",
|
"@angular/animations": "~11.2.14",
|
||||||
"@angular/common": "~10.1.5",
|
"@angular/common": "~11.2.14",
|
||||||
"@angular/compiler": "~10.1.5",
|
"@angular/compiler": "~11.2.14",
|
||||||
"@angular/core": "~10.1.5",
|
"@angular/core": "~11.2.14",
|
||||||
"@angular/forms": "~10.1.5",
|
"@angular/forms": "~11.2.14",
|
||||||
"@angular/localize": "~10.1.5",
|
"@angular/localize": "~11.2.14",
|
||||||
"@angular/platform-browser": "~10.1.5",
|
"@angular/platform-browser": "~11.2.14",
|
||||||
"@angular/platform-browser-dynamic": "~10.1.5",
|
"@angular/platform-browser-dynamic": "~11.2.14",
|
||||||
"@angular/router": "~10.1.5",
|
"@angular/router": "~11.2.14",
|
||||||
"@ng-bootstrap/ng-bootstrap": "^8.0.4",
|
"@ng-bootstrap/ng-bootstrap": "^9.1.2",
|
||||||
"@ng-select/ng-select": "^5.0.9",
|
"@ng-select/ng-select": "^7.0.0",
|
||||||
"bootstrap": "^4.5.0",
|
"bootstrap": "^4.5.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"ng-bootstrap": "^1.6.3",
|
|
||||||
"ng2-pdf-viewer": "^6.3.2",
|
"ng2-pdf-viewer": "^6.3.2",
|
||||||
|
"ngx-bootstrap": "^6.2.0",
|
||||||
"ngx-color": "^6.2.0",
|
"ngx-color": "^6.2.0",
|
||||||
"ngx-cookie-service": "^10.1.1",
|
"ngx-cookie-service": "^10.1.1",
|
||||||
"ngx-file-drop": "^10.0.0",
|
"ngx-file-drop": "^11.1.0",
|
||||||
"ngx-infinite-scroll": "^9.1.0",
|
"ngx-infinite-scroll": "^9.1.0",
|
||||||
"rxjs": "~6.6.0",
|
"rxjs": "~6.6.0",
|
||||||
"tslib": "^2.0.0",
|
"tslib": "^2.0.0",
|
||||||
"uuid": "^8.3.1",
|
"uuid": "^8.3.1",
|
||||||
"zone.js": "~0.10.2"
|
"zone.js": "~0.11.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "^0.1002.0",
|
"@angular-devkit/build-angular": "~0.1102.13",
|
||||||
"@angular/cli": "~10.1.5",
|
"@angular/cli": "~11.2.14",
|
||||||
"@angular/compiler-cli": "~10.1.5",
|
"@angular/compiler-cli": "~11.2.14",
|
||||||
"@types/jasmine": "~3.5.0",
|
"@types/jasmine": "~3.6.0",
|
||||||
"@types/jasminewd2": "~2.0.3",
|
"@types/jasminewd2": "~2.0.3",
|
||||||
"@types/node": "^12.11.1",
|
"@types/node": "^12.11.1",
|
||||||
"codelyzer": "^6.0.0",
|
"codelyzer": "^6.0.0",
|
||||||
"jasmine-core": "~3.6.0",
|
"jasmine-core": "~3.6.0",
|
||||||
"jasmine-spec-reporter": "~5.0.0",
|
"jasmine-spec-reporter": "~5.0.0",
|
||||||
"karma": "~5.0.0",
|
"karma": "~6.3.3",
|
||||||
"karma-chrome-launcher": "~3.1.0",
|
"karma-chrome-launcher": "~3.1.0",
|
||||||
"karma-coverage-istanbul-reporter": "~3.0.2",
|
"karma-coverage-istanbul-reporter": "~3.0.2",
|
||||||
"karma-jasmine": "~4.0.0",
|
"karma-jasmine": "~4.0.0",
|
||||||
@@ -53,6 +53,6 @@
|
|||||||
"protractor": "~7.0.0",
|
"protractor": "~7.0.0",
|
||||||
"ts-node": "~8.3.0",
|
"ts-node": "~8.3.0",
|
||||||
"tslint": "~6.1.0",
|
"tslint": "~6.1.0",
|
||||||
"typescript": "~4.0.2"
|
"typescript": "~4.1.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@ const routes: Routes = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forRoot(routes)],
|
imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })],
|
||||||
exports: [RouterModule]
|
exports: [RouterModule]
|
||||||
})
|
})
|
||||||
export class AppRoutingModule { }
|
export class AppRoutingModule { }
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
<app-toasts></app-toasts>
|
<app-toasts></app-toasts>
|
||||||
|
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
@@ -18,7 +18,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
constructor (private settings: SettingsService, private consumerStatusService: ConsumerStatusService, private toastService: ToastService, private router: Router) {
|
constructor (private settings: SettingsService, private consumerStatusService: ConsumerStatusService, private toastService: ToastService, private router: Router) {
|
||||||
let anyWindow = (window as any)
|
let anyWindow = (window as any)
|
||||||
anyWindow.pdfWorkerSrc = '/assets/js/pdf.worker.min.js';
|
anyWindow.pdfWorkerSrc = 'assets/js/pdf.worker.min.js';
|
||||||
this.settings.updateDarkModeSettings()
|
this.settings.updateDarkModeSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.consumerStatusService.connect()
|
this.consumerStatusService.connect()
|
||||||
|
|
||||||
|
|
||||||
this.successSubscription = this.consumerStatusService.onDocumentConsumptionFinished().subscribe(status => {
|
this.successSubscription = this.consumerStatusService.onDocumentConsumptionFinished().subscribe(status => {
|
||||||
if (this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS)) {
|
if (this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS)) {
|
||||||
this.toastService.show({title: $localize`Document added`, delay: 10000, content: $localize`Document ${status.filename} was added to paperless.`, actionName: $localize`Open document`, action: () => {
|
this.toastService.show({title: $localize`Document added`, delay: 10000, content: $localize`Document ${status.filename} was added to paperless.`, actionName: $localize`Open document`, action: () => {
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ import { LocalizedDateParserFormatter } from './utils/ngb-date-parser-formatter'
|
|||||||
import { ApiVersionInterceptor } from './interceptors/api-version.interceptor';
|
import { ApiVersionInterceptor } from './interceptors/api-version.interceptor';
|
||||||
import { ColorSliderModule } from 'ngx-color/slider';
|
import { ColorSliderModule } from 'ngx-color/slider';
|
||||||
import { ColorComponent } from './components/common/input/color/color.component';
|
import { ColorComponent } from './components/common/input/color/color.component';
|
||||||
|
import { DocumentAsnComponent } from './components/document-asn/document-asn.component';
|
||||||
|
|
||||||
import localeFr from '@angular/common/locales/fr';
|
import localeFr from '@angular/common/locales/fr';
|
||||||
import localeNl from '@angular/common/locales/nl';
|
import localeNl from '@angular/common/locales/nl';
|
||||||
@@ -73,7 +74,9 @@ import localeEnGb from '@angular/common/locales/en-GB';
|
|||||||
import localeRo from '@angular/common/locales/ro';
|
import localeRo from '@angular/common/locales/ro';
|
||||||
import localeRu from '@angular/common/locales/ru';
|
import localeRu from '@angular/common/locales/ru';
|
||||||
import localeEs from '@angular/common/locales/es';
|
import localeEs from '@angular/common/locales/es';
|
||||||
import { DocumentAsnComponent } from './components/document-asn/document-asn.component';
|
import localePl from '@angular/common/locales/pl';
|
||||||
|
import localeSv from '@angular/common/locales/sv';
|
||||||
|
import localeLb from '@angular/common/locales/lb';
|
||||||
|
|
||||||
|
|
||||||
registerLocaleData(localeFr)
|
registerLocaleData(localeFr)
|
||||||
@@ -86,6 +89,9 @@ registerLocaleData(localeEnGb)
|
|||||||
registerLocaleData(localeRo)
|
registerLocaleData(localeRo)
|
||||||
registerLocaleData(localeRu)
|
registerLocaleData(localeRu)
|
||||||
registerLocaleData(localeEs)
|
registerLocaleData(localeEs)
|
||||||
|
registerLocaleData(localePl)
|
||||||
|
registerLocaleData(localeSv)
|
||||||
|
registerLocaleData(localeLb)
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export class ConfirmDialogComponent implements OnInit {
|
|||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
buttonsEnabled = true
|
buttonsEnabled = true
|
||||||
|
|
||||||
confirmButtonEnabled = true
|
confirmButtonEnabled = true
|
||||||
seconds = 0
|
seconds = 0
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+1
-1
@@ -83,7 +83,7 @@ export class FilterableDropdownSelectionModel {
|
|||||||
if (fireEvent) {
|
if (fireEvent) {
|
||||||
this.changed.next(this)
|
this.changed.next(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getNonTemporary(id: number) {
|
private getNonTemporary(id: number) {
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
<path d="M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8z"/>
|
<path d="M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8z"/>
|
||||||
</svg>
|
</svg>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mr-1">
|
<div class="mr-1">
|
||||||
<app-tag *ngIf="isTag; else displayName" [tag]="item" [clickable]="true" linkTitle="Filter by tag"></app-tag>
|
<app-tag *ngIf="isTag; else displayName" [tag]="item" [clickable]="true" linkTitle="Filter by tag"></app-tag>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export class AbstractInputComponent<T> implements OnInit, ControlValueAccessor {
|
|||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
||||||
onChange = (newValue: T) => {};
|
onChange = (newValue: T) => {};
|
||||||
|
|
||||||
onTouched = () => {};
|
onTouched = () => {};
|
||||||
|
|
||||||
writeValue(newValue: any): void {
|
writeValue(newValue: any): void {
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
<input type="checkbox" class="custom-control-input" [id]="inputId" [(ngModel)]="value" (change)="onChange(value)" (blur)="onTouched()" [disabled]="disabled">
|
<input type="checkbox" class="custom-control-input" [id]="inputId" [(ngModel)]="value" (change)="onChange(value)" (blur)="onTouched()" [disabled]="disabled">
|
||||||
<label class="custom-control-label" [for]="inputId">{{title}}</label>
|
<label class="custom-control-label" [for]="inputId">{{title}}</label>
|
||||||
<small *ngIf="hint" class="form-text text-muted">{{hint}}</small>
|
<small *ngIf="hint" class="form-text text-muted">{{hint}}</small>
|
||||||
</div>
|
</div>
|
||||||
@@ -15,7 +15,7 @@ import { AbstractInputComponent } from '../abstract-input';
|
|||||||
})
|
})
|
||||||
export class CheckComponent extends AbstractInputComponent<boolean> {
|
export class CheckComponent extends AbstractInputComponent<boolean> {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,12 @@
|
|||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text" [style.background-color]="value"> </span>
|
<span class="input-group-text" [style.background-color]="value"> </span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ng-template #popContent>
|
<ng-template #popContent>
|
||||||
<div style="min-width: 200px;" class="pb-3">
|
<div style="min-width: 200px;" class="pb-3">
|
||||||
<color-slider [color]="value" (onChangeComplete)="colorChanged($event.color.hex)"></color-slider>
|
<color-slider [color]="value" (onChangeComplete)="colorChanged($event.color.hex)"></color-slider>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<input class="form-control" [class.is-invalid]="error" [id]="inputId" [(ngModel)]="value" (change)="onChange(value)" [autoClose]="'outside'" [ngbPopover]="popContent" placement="bottom" popoverClass="shadow">
|
<input class="form-control" [class.is-invalid]="error" [id]="inputId" [(ngModel)]="value" (change)="onChange(value)" [autoClose]="'outside'" [ngbPopover]="popContent" placement="bottom" popoverClass="shadow">
|
||||||
@@ -30,4 +30,4 @@
|
|||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
{{error}}
|
{{error}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -11,4 +11,4 @@
|
|||||||
</div>
|
</div>
|
||||||
<small *ngIf="hint" class="form-text text-muted">{{hint}}</small>
|
<small *ngIf="hint" class="form-text text-muted">{{hint}}</small>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -1,33 +1,38 @@
|
|||||||
<div class="form-group paperless-input-select">
|
<div class="form-group paperless-input-select">
|
||||||
<label [for]="inputId">{{title}}</label>
|
<label [for]="inputId">{{title}}</label>
|
||||||
<div [class.input-group]="showPlusButton()">
|
<div [class.input-group]="allowCreateNew">
|
||||||
<ng-select name="inputId" [(ngModel)]="value"
|
<ng-select name="inputId" [(ngModel)]="value"
|
||||||
[disabled]="disabled"
|
[disabled]="disabled"
|
||||||
[style.color]="textColor"
|
[style.color]="textColor"
|
||||||
[style.background]="backgroundColor"
|
[style.background]="backgroundColor"
|
||||||
[clearable]="allowNull"
|
[clearable]="allowNull"
|
||||||
[items]="items"
|
[items]="items"
|
||||||
bindLabel="name"
|
[addTag]="allowCreateNew && addItemRef"
|
||||||
bindValue="id"
|
addTagText="Add item"
|
||||||
(change)="onChange(value)"
|
i18n-addTagText="Used for both types and correspondents"
|
||||||
(blur)="onTouched()">
|
bindLabel="name"
|
||||||
</ng-select>
|
bindValue="id"
|
||||||
|
(change)="onChange(value)"
|
||||||
<div *ngIf="showPlusButton()" class="input-group-append">
|
(search)="onSearch($event)"
|
||||||
<button class="btn btn-outline-secondary" type="button" (click)="createNew.emit()">
|
(focus)="clearLastSearchTerm()"
|
||||||
<svg class="buttonicon" fill="currentColor">
|
(clear)="clearLastSearchTerm()"
|
||||||
<use xlink:href="assets/bootstrap-icons.svg#plus" />
|
(blur)="onBlur()">
|
||||||
</svg>
|
</ng-select>
|
||||||
</button>
|
<div *ngIf="allowCreateNew" class="input-group-append">
|
||||||
|
<button class="btn btn-outline-secondary" type="button" (click)="addItem()">
|
||||||
|
<svg class="buttonicon" fill="currentColor">
|
||||||
|
<use xlink:href="assets/bootstrap-icons.svg#plus" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<small *ngIf="hint" class="form-text text-muted">{{hint}}</small>
|
<small *ngIf="hint" class="form-text text-muted">{{hint}}</small>
|
||||||
<small *ngIf="getSuggestions().length > 0">
|
<small *ngIf="getSuggestions().length > 0">
|
||||||
<span i18n>Suggestions:</span>
|
<span i18n>Suggestions:</span>
|
||||||
<ng-container *ngFor="let s of getSuggestions()">
|
<ng-container *ngFor="let s of getSuggestions()">
|
||||||
<a (click)="value = s.id; onChange(value)" [routerLink]="">{{s.name}}</a>
|
<a (click)="value = s.id; onChange(value)" [routerLink]="">{{s.name}}</a>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
@@ -16,6 +16,7 @@ export class SelectComponent extends AbstractInputComponent<number> {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
|
this.addItemRef = this.addItem.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
@@ -34,9 +35,13 @@ export class SelectComponent extends AbstractInputComponent<number> {
|
|||||||
suggestions: number[]
|
suggestions: number[]
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
createNew = new EventEmitter()
|
createNew = new EventEmitter<string>()
|
||||||
|
|
||||||
showPlusButton(): boolean {
|
public addItemRef: (name) => void
|
||||||
|
|
||||||
|
private _lastSearchTerm: string
|
||||||
|
|
||||||
|
get allowCreateNew(): boolean {
|
||||||
return this.createNew.observers.length > 0
|
return this.createNew.observers.length > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,4 +53,29 @@ export class SelectComponent extends AbstractInputComponent<number> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addItem(name: string) {
|
||||||
|
if (name) this.createNew.next(name)
|
||||||
|
else this.createNew.next(this._lastSearchTerm)
|
||||||
|
this.clearLastSearchTerm()
|
||||||
|
}
|
||||||
|
|
||||||
|
clickNew() {
|
||||||
|
this.createNew.next(this._lastSearchTerm)
|
||||||
|
this.clearLastSearchTerm()
|
||||||
|
}
|
||||||
|
|
||||||
|
clearLastSearchTerm() {
|
||||||
|
this._lastSearchTerm = null
|
||||||
|
}
|
||||||
|
|
||||||
|
onSearch($event) {
|
||||||
|
this._lastSearchTerm = $event.term
|
||||||
|
}
|
||||||
|
|
||||||
|
onBlur() {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.clearLastSearchTerm()
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -7,8 +7,14 @@
|
|||||||
[closeOnSelect]="false"
|
[closeOnSelect]="false"
|
||||||
[clearSearchOnAdd]="true"
|
[clearSearchOnAdd]="true"
|
||||||
[hideSelected]="true"
|
[hideSelected]="true"
|
||||||
|
[addTag]="createTagRef"
|
||||||
|
addTagText="Add tag"
|
||||||
|
i18n-addTagText
|
||||||
(change)="onChange(value)"
|
(change)="onChange(value)"
|
||||||
(blur)="onTouched()">
|
(search)="onSearch($event)"
|
||||||
|
(focus)="clearLastSearchTerm()"
|
||||||
|
(clear)="clearLastSearchTerm()"
|
||||||
|
(blur)="onBlur()">
|
||||||
|
|
||||||
<ng-template ng-label-tmp let-item="item">
|
<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" (click)="removeTag(item.id)">
|
||||||
@@ -39,8 +45,8 @@
|
|||||||
<ng-container *ngFor="let tag of getSuggestions()">
|
<ng-container *ngFor="let tag of getSuggestions()">
|
||||||
<a (click)="addTag(tag.id)" [routerLink]="">{{tag.name}}</a>
|
<a (click)="addTag(tag.id)" [routerLink]="">{{tag.name}}</a>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -17,8 +17,9 @@ import { TagService } from 'src/app/services/rest/tag.service';
|
|||||||
})
|
})
|
||||||
export class TagsComponent implements OnInit, ControlValueAccessor {
|
export class TagsComponent implements OnInit, ControlValueAccessor {
|
||||||
|
|
||||||
constructor(private tagService: TagService, private modalService: NgbModal) { }
|
constructor(private tagService: TagService, private modalService: NgbModal) {
|
||||||
|
this.createTagRef = this.createTag.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
onChange = (newValue: number[]) => {};
|
onChange = (newValue: number[]) => {};
|
||||||
|
|
||||||
@@ -56,6 +57,10 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
|
|||||||
|
|
||||||
tags: PaperlessTag[]
|
tags: PaperlessTag[]
|
||||||
|
|
||||||
|
public createTagRef: (name) => void
|
||||||
|
|
||||||
|
private _lastSearchTerm: string
|
||||||
|
|
||||||
getTag(id) {
|
getTag(id) {
|
||||||
if (this.tags) {
|
if (this.tags) {
|
||||||
return this.tags.find(tag => tag.id == id)
|
return this.tags.find(tag => tag.id == id)
|
||||||
@@ -74,9 +79,11 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createTag() {
|
createTag(name: string = null) {
|
||||||
var modal = this.modalService.open(TagEditDialogComponent, {backdrop: 'static'})
|
var modal = this.modalService.open(TagEditDialogComponent, {backdrop: 'static'})
|
||||||
modal.componentInstance.dialogMode = 'create'
|
modal.componentInstance.dialogMode = 'create'
|
||||||
|
if (name) modal.componentInstance.object = { name: name }
|
||||||
|
else if (this._lastSearchTerm) modal.componentInstance.object = { name: this._lastSearchTerm }
|
||||||
modal.componentInstance.success.subscribe(newTag => {
|
modal.componentInstance.success.subscribe(newTag => {
|
||||||
this.tagService.listAll().subscribe(tags => {
|
this.tagService.listAll().subscribe(tags => {
|
||||||
this.tags = tags.results
|
this.tags = tags.results
|
||||||
@@ -99,4 +106,18 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
|
|||||||
this.onChange(this.value)
|
this.onChange(this.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearLastSearchTerm() {
|
||||||
|
this._lastSearchTerm = null
|
||||||
|
}
|
||||||
|
|
||||||
|
onSearch($event) {
|
||||||
|
this._lastSearchTerm = $event.term
|
||||||
|
}
|
||||||
|
|
||||||
|
onBlur() {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.clearLastSearchTerm()
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -5,4 +5,4 @@
|
|||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
{{error}}
|
{{error}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -12,4 +12,4 @@
|
|||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-outline-dark" (click)="cancelClicked()" i18n>Cancel</button>
|
<button type="button" class="btn btn-outline-dark" (click)="cancelClicked()" i18n>Cancel</button>
|
||||||
<button type="button" class="btn btn-primary" (click)="selectClicked.emit(selected)" i18n>Select</button>
|
<button type="button" class="btn btn-primary" (click)="selectClicked.emit(selected)" i18n>Select</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
<span *ngIf="!clickable" class="badge" [style.background]="tag.color" [style.color]="tag.text_color">{{tag.name}}</span>
|
<span *ngIf="!clickable" class="badge" [style.background]="tag.color" [style.color]="tag.text_color">{{tag.name}}</span>
|
||||||
<a [routerLink]="" [title]="linkTitle" *ngIf="clickable" class="badge" [style.background]="tag.color" [style.color]="tag.text_color">{{tag.name}}</a>
|
<a [routerLink]="" [title]="linkTitle" *ngIf="clickable" class="badge" [style.background]="tag.color" [style.color]="tag.text_color">{{tag.name}}</a>
|
||||||
+1
-1
@@ -23,7 +23,7 @@ export class StatisticsWidgetComponent implements OnInit, OnDestroy {
|
|||||||
statistics: Statistics = {}
|
statistics: Statistics = {}
|
||||||
|
|
||||||
subscription: Subscription
|
subscription: Subscription
|
||||||
|
|
||||||
private getStatistics(): Observable<Statistics> {
|
private getStatistics(): Observable<Statistics> {
|
||||||
return this.http.get(`${environment.apiBaseUrl}statistics/`)
|
return this.http.get(`${environment.apiBaseUrl}statistics/`)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -13,4 +13,4 @@
|
|||||||
<p i18n>Consult the documentation on how to use these features. The section on basic usage also has some information on how to use paperless in general.</p>
|
<p i18n>Consult the documentation on how to use these features. The section on basic usage also has some information on how to use paperless in general.</p>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
</app-widget-frame>
|
</app-widget-frame>
|
||||||
+2
-2
@@ -4,9 +4,9 @@
|
|||||||
<h5 class="card-title mb-0">{{title}}</h5>
|
<h5 class="card-title mb-0">{{title}}</h5>
|
||||||
<ng-content select ="[header-buttons]"></ng-content>
|
<ng-content select ="[header-buttons]"></ng-content>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body text-dark">
|
<div class="card-body text-dark">
|
||||||
<ng-content select ="[content]"></ng-content>
|
<ng-content select ="[content]"></ng-content>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -60,9 +60,9 @@
|
|||||||
<app-input-number i18n-title title="Archive serial number" [error]="error?.archive_serial_number" formControlName='archive_serial_number'></app-input-number>
|
<app-input-number i18n-title title="Archive serial number" [error]="error?.archive_serial_number" formControlName='archive_serial_number'></app-input-number>
|
||||||
<app-input-date i18n-title title="Date created" formControlName="created" [error]="error?.created"></app-input-date>
|
<app-input-date i18n-title title="Date created" formControlName="created" [error]="error?.created"></app-input-date>
|
||||||
<app-input-select [items]="correspondents" i18n-title title="Correspondent" formControlName="correspondent" [allowNull]="true"
|
<app-input-select [items]="correspondents" i18n-title title="Correspondent" formControlName="correspondent" [allowNull]="true"
|
||||||
(createNew)="createCorrespondent()" [suggestions]="suggestions?.correspondents"></app-input-select>
|
(createNew)="createCorrespondent($event)" [suggestions]="suggestions?.correspondents"></app-input-select>
|
||||||
<app-input-select [items]="documentTypes" i18n-title title="Document type" formControlName="document_type" [allowNull]="true"
|
<app-input-select [items]="documentTypes" i18n-title title="Document type" formControlName="document_type" [allowNull]="true"
|
||||||
(createNew)="createDocumentType()" [suggestions]="suggestions?.document_types"></app-input-select>
|
(createNew)="createDocumentType($event)" [suggestions]="suggestions?.document_types"></app-input-select>
|
||||||
<app-input-tags formControlName="tags" [suggestions]="suggestions?.tags"></app-input-tags>
|
<app-input-tags formControlName="tags" [suggestions]="suggestions?.tags"></app-input-tags>
|
||||||
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@@ -139,7 +139,7 @@
|
|||||||
<pdf-viewer [src]="previewUrl" [original-size]="false" [show-borders]="true" [show-all]="true" [(page)]="previewCurrentPage" [render-text-mode]="2" (after-load-complete)="pdfPreviewLoaded($event)"></pdf-viewer>
|
<pdf-viewer [src]="previewUrl" [original-size]="false" [show-borders]="true" [show-all]="true" [(page)]="previewCurrentPage" [render-text-mode]="2" (after-load-complete)="pdfPreviewLoaded($event)"></pdf-viewer>
|
||||||
</div>
|
</div>
|
||||||
<ng-template #nativePdfViewer>
|
<ng-template #nativePdfViewer>
|
||||||
<object [data]="previewUrl | safe" type="application/pdf" class="preview-sticky" width="100%"></object>
|
<object [data]="previewUrl | safe" class="preview-sticky" width="100%"></object>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngIf="getContentType() == 'text/plain'">
|
<ng-container *ngIf="getContentType() == 'text/plain'">
|
||||||
|
|||||||
@@ -128,9 +128,10 @@ export class DocumentDetailComponent implements OnInit {
|
|||||||
this.documentForm.patchValue(doc)
|
this.documentForm.patchValue(doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
createDocumentType() {
|
createDocumentType(newName: string) {
|
||||||
var modal = this.modalService.open(DocumentTypeEditDialogComponent, {backdrop: 'static'})
|
var modal = this.modalService.open(DocumentTypeEditDialogComponent, {backdrop: 'static'})
|
||||||
modal.componentInstance.dialogMode = 'create'
|
modal.componentInstance.dialogMode = 'create'
|
||||||
|
if (newName) modal.componentInstance.object = { name: newName }
|
||||||
modal.componentInstance.success.subscribe(newDocumentType => {
|
modal.componentInstance.success.subscribe(newDocumentType => {
|
||||||
this.documentTypeService.listAll().subscribe(documentTypes => {
|
this.documentTypeService.listAll().subscribe(documentTypes => {
|
||||||
this.documentTypes = documentTypes.results
|
this.documentTypes = documentTypes.results
|
||||||
@@ -139,9 +140,10 @@ export class DocumentDetailComponent implements OnInit {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
createCorrespondent() {
|
createCorrespondent(newName: string) {
|
||||||
var modal = this.modalService.open(CorrespondentEditDialogComponent, {backdrop: 'static'})
|
var modal = this.modalService.open(CorrespondentEditDialogComponent, {backdrop: 'static'})
|
||||||
modal.componentInstance.dialogMode = 'create'
|
modal.componentInstance.dialogMode = 'create'
|
||||||
|
if (newName) modal.componentInstance.object = { name: newName }
|
||||||
modal.componentInstance.success.subscribe(newCorrespondent => {
|
modal.componentInstance.success.subscribe(newCorrespondent => {
|
||||||
this.correspondentService.listAll().subscribe(correspondents => {
|
this.correspondentService.listAll().subscribe(correspondents => {
|
||||||
this.correspondents = correspondents.results
|
this.correspondents = correspondents.results
|
||||||
|
|||||||
+1
-1
@@ -20,4 +20,4 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
.metadata-column {
|
.metadata-column {
|
||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
}
|
}
|
||||||
+2
-1
@@ -82,7 +82,8 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<small>{{document.created | customDate:'mediumDate'}}</small>
|
<small>{{document.created | customDate:'mediumDate'}}</small>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="document.__search_hit__" class="list-group-item bg-light text-dark border-0 d-flex search-score">
|
|
||||||
|
<div *ngIf="document.__search_hit__?.score" class="list-group-item bg-light text-dark border-0 d-flex p-0 pl-4 search-score">
|
||||||
<small class="text-muted" i18n>Score:</small>
|
<small class="text-muted" i18n>Score:</small>
|
||||||
<ngb-progressbar [type]="searchScoreClass" [value]="document.__search_hit__.score" class="search-score-bar mx-2 mt-1" [max]="1"></ngb-progressbar>
|
<ngb-progressbar [type]="searchScoreClass" [value]="document.__search_hit__.score" class="search-score-bar mx-2 mt-1" [max]="1"></ngb-progressbar>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+1
-1
@@ -64,4 +64,4 @@
|
|||||||
span ::ng-deep .match {
|
span ::ng-deep .match {
|
||||||
color: black;
|
color: black;
|
||||||
background-color: rgb(255, 211, 66);
|
background-color: rgb(255, 211, 66);
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
|
|
||||||
</app-page-header>
|
</app-page-header>
|
||||||
|
|
||||||
<div class="w-100 mb-2 mb-sm-4">
|
<div class="sticky-top py-2 mt-n2 mt-sm-n3 py-sm-4 bg-body mx-n3 px-3">
|
||||||
<app-filter-editor [hidden]="isBulkEditing" [(filterRules)]="list.filterRules" [unmodifiedFilterRules]="unmodifiedFilterRules" #filterEditor></app-filter-editor>
|
<app-filter-editor [hidden]="isBulkEditing" [(filterRules)]="list.filterRules" [unmodifiedFilterRules]="unmodifiedFilterRules" #filterEditor></app-filter-editor>
|
||||||
<app-bulk-editor [hidden]="!isBulkEditing"></app-bulk-editor>
|
<app-bulk-editor [hidden]="!isBulkEditing"></app-bulk-editor>
|
||||||
</div>
|
</div>
|
||||||
@@ -99,7 +99,7 @@
|
|||||||
<app-document-card-large [selected]="list.isSelected(d)" (toggleSelected)="toggleSelected(d, $event)" *ngFor="let d of list.documents; trackBy: trackByDocumentId" [document]="d" (clickTag)="clickTag($event)" (clickCorrespondent)="clickCorrespondent($event)" (clickDocumentType)="clickDocumentType($event)" (clickMoreLike)="clickMoreLike(d.id)">
|
<app-document-card-large [selected]="list.isSelected(d)" (toggleSelected)="toggleSelected(d, $event)" *ngFor="let d of list.documents; trackBy: trackByDocumentId" [document]="d" (clickTag)="clickTag($event)" (clickCorrespondent)="clickCorrespondent($event)" (clickDocumentType)="clickDocumentType($event)" (clickMoreLike)="clickMoreLike(d.id)">
|
||||||
</app-document-card-large>
|
</app-document-card-large>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="table table-sm border shadow-sm" *ngIf="displayMode == 'details'">
|
<table class="table table-sm border shadow-sm" *ngIf="displayMode == 'details'">
|
||||||
<thead>
|
<thead>
|
||||||
<th></th>
|
<th></th>
|
||||||
@@ -174,10 +174,10 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div class="m-n2 row row-cols-paperless-cards" *ngIf="displayMode == 'smallCards'">
|
<div class="m-n2 row row-cols-paperless-cards" *ngIf="displayMode == 'smallCards'">
|
||||||
<app-document-card-small [selected]="list.isSelected(d)" (toggleSelected)="toggleSelected(d, $event)" [document]="d" *ngFor="let d of list.documents; trackBy: trackByDocumentId" (clickTag)="clickTag($event)" (clickCorrespondent)="clickCorrespondent($event)" (clickDocumentType)="clickDocumentType($event)"></app-document-card-small>
|
<app-document-card-small [selected]="list.isSelected(d)" (toggleSelected)="toggleSelected(d, $event)" [document]="d" *ngFor="let d of list.documents; trackBy: trackByDocumentId" (clickTag)="clickTag($event)" (clickCorrespondent)="clickCorrespondent($event)" (clickDocumentType)="clickDocumentType($event)"></app-document-card-small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@@ -34,3 +34,12 @@ $paperless-card-breakpoints: (
|
|||||||
right: 0 !important;
|
right: 0 !important;
|
||||||
left: auto !important;
|
left: auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sticky-top {
|
||||||
|
z-index: 990; // below main navbar
|
||||||
|
top: calc(7rem - 2px); // height of navbar (mobile)
|
||||||
|
|
||||||
|
@media (min-width: 580px) {
|
||||||
|
top: 3.5rem; // height of navbar
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,14 +2,14 @@ import { Component, OnDestroy, OnInit, QueryList, ViewChild, ViewChildren } from
|
|||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { FilterRule } from 'src/app/data/filter-rule';
|
import { FilterRule, isFullTextFilterRule } from 'src/app/data/filter-rule';
|
||||||
import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type';
|
import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type';
|
||||||
import { PaperlessDocument } from 'src/app/data/paperless-document';
|
import { PaperlessDocument } from 'src/app/data/paperless-document';
|
||||||
import { PaperlessSavedView } from 'src/app/data/paperless-saved-view';
|
import { PaperlessSavedView } from 'src/app/data/paperless-saved-view';
|
||||||
import { SortableDirective, SortEvent } from 'src/app/directives/sortable.directive';
|
import { SortableDirective, SortEvent } from 'src/app/directives/sortable.directive';
|
||||||
import { ConsumerStatusService } from 'src/app/services/consumer-status.service';
|
import { ConsumerStatusService } from 'src/app/services/consumer-status.service';
|
||||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service';
|
import { DocumentListViewService } from 'src/app/services/document-list-view.service';
|
||||||
import { DOCUMENT_SORT_FIELDS } from 'src/app/services/rest/document.service';
|
import { DOCUMENT_SORT_FIELDS, DOCUMENT_SORT_FIELDS_FULLTEXT } from 'src/app/services/rest/document.service';
|
||||||
import { SavedViewService } from 'src/app/services/rest/saved-view.service';
|
import { SavedViewService } from 'src/app/services/rest/saved-view.service';
|
||||||
import { ToastService } from 'src/app/services/toast.service';
|
import { ToastService } from 'src/app/services/toast.service';
|
||||||
import { FilterEditorComponent } from './filter-editor/filter-editor.component';
|
import { FilterEditorComponent } from './filter-editor/filter-editor.component';
|
||||||
@@ -52,7 +52,7 @@ export class DocumentListComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSortFields() {
|
getSortFields() {
|
||||||
return DOCUMENT_SORT_FIELDS
|
return isFullTextFilterRule(this.list.filterRules) ? DOCUMENT_SORT_FIELDS_FULLTEXT : DOCUMENT_SORT_FIELDS
|
||||||
}
|
}
|
||||||
|
|
||||||
onSort(event: SortEvent) {
|
onSort(event: SortEvent) {
|
||||||
|
|||||||
@@ -3,13 +3,12 @@
|
|||||||
<div class="form-inline d-flex align-items-center">
|
<div class="form-inline d-flex align-items-center">
|
||||||
<div class="input-group input-group-sm flex-fill w-auto">
|
<div class="input-group input-group-sm flex-fill w-auto">
|
||||||
<div class="input-group-prepend" ngbDropdown>
|
<div class="input-group-prepend" ngbDropdown>
|
||||||
<button class="btn btn-outline-primary" ngbDropdownToggle>{{textFilterTargetName}}</button>
|
<button class="btn btn-outline-primary" ngbDropdownToggle>{{textFilterTargetName}}</button>
|
||||||
<div class="dropdown-menu shadow" ngbDropdownMenu>
|
<div class="dropdown-menu shadow" ngbDropdownMenu>
|
||||||
<button *ngFor="let t of textFilterTargets" ngbDropdownItem [class.active]="textFilterTarget == t.id" (click)="changeTextFilterTarget(t.id)">{{t.name}}</button>
|
<button *ngFor="let t of textFilterTargets" ngbDropdownItem [class.active]="textFilterTarget == t.id" (click)="changeTextFilterTarget(t.id)">{{t.name}}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input class="form-control form-control-sm" type="text" [(ngModel)]="textFilter" *ngIf="textFilterTarget != 'fulltext-morelike'">
|
<input #textFilterInput class="form-control form-control-sm" type="text" [(ngModel)]="textFilter" [readonly]="textFilterTarget == 'fulltext-morelike'">
|
||||||
<span class="form-control form-control-sm text-truncate" *ngIf="textFilterTarget == 'fulltext-morelike'">{{_moreLikeDoc?.title}}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component, EventEmitter, Input, Output, OnInit, OnDestroy } from '@angular/core';
|
import { Component, EventEmitter, Input, Output, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/core';
|
||||||
import { PaperlessTag } from 'src/app/data/paperless-tag';
|
import { PaperlessTag } from 'src/app/data/paperless-tag';
|
||||||
import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent';
|
import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent';
|
||||||
import { PaperlessDocumentType } from 'src/app/data/paperless-document-type';
|
import { PaperlessDocumentType } from 'src/app/data/paperless-document-type';
|
||||||
@@ -72,6 +72,9 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
|
|||||||
private documentService: DocumentService
|
private documentService: DocumentService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
@ViewChild("textFilterInput")
|
||||||
|
textFilterInput: ElementRef
|
||||||
|
|
||||||
tags: PaperlessTag[] = []
|
tags: PaperlessTag[] = []
|
||||||
correspondents: PaperlessCorrespondent[] = []
|
correspondents: PaperlessCorrespondent[] = []
|
||||||
documentTypes: PaperlessDocumentType[] = []
|
documentTypes: PaperlessDocumentType[] = []
|
||||||
@@ -125,7 +128,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
|
|||||||
@Input()
|
@Input()
|
||||||
set filterRules (value: FilterRule[]) {
|
set filterRules (value: FilterRule[]) {
|
||||||
this._filterRules = value
|
this._filterRules = value
|
||||||
|
|
||||||
this.documentTypeSelectionModel.clear(false)
|
this.documentTypeSelectionModel.clear(false)
|
||||||
this.tagSelectionModel.clear(false)
|
this.tagSelectionModel.clear(false)
|
||||||
this.correspondentSelectionModel.clear(false)
|
this.correspondentSelectionModel.clear(false)
|
||||||
@@ -159,6 +162,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
|
|||||||
this.textFilterTarget = TEXT_FILTER_TARGET_FULLTEXT_MORELIKE
|
this.textFilterTarget = TEXT_FILTER_TARGET_FULLTEXT_MORELIKE
|
||||||
this.documentService.get(this._moreLikeId).subscribe(result => {
|
this.documentService.get(this._moreLikeId).subscribe(result => {
|
||||||
this._moreLikeDoc = result
|
this._moreLikeDoc = result
|
||||||
|
this._textFilter = result.title
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
case FILTER_CREATED_AFTER:
|
case FILTER_CREATED_AFTER:
|
||||||
@@ -286,8 +290,12 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
|
|||||||
distinctUntilChanged()
|
distinctUntilChanged()
|
||||||
).subscribe(text => {
|
).subscribe(text => {
|
||||||
this._textFilter = text
|
this._textFilter = text
|
||||||
|
this.documentService.searchQuery = text
|
||||||
this.updateRules()
|
this.updateRules()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (this._textFilter) this.documentService.searchQuery = this._textFilter
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
@@ -325,7 +333,11 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
changeTextFilterTarget(target) {
|
changeTextFilterTarget(target) {
|
||||||
|
if (this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_MORELIKE && target != TEXT_FILTER_TARGET_FULLTEXT_MORELIKE) {
|
||||||
|
this._textFilter = ""
|
||||||
|
}
|
||||||
this.textFilterTarget = target
|
this.textFilterTarget = target
|
||||||
|
this.textFilterInput.nativeElement.focus()
|
||||||
this.updateRules()
|
this.updateRules()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -32,6 +32,6 @@ export class CorrespondentEditDialogComponent extends EditDialogComponent<Paperl
|
|||||||
match: new FormControl(""),
|
match: new FormControl(""),
|
||||||
is_insensitive: new FormControl(true)
|
is_insensitive: new FormControl(true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@ export class CorrespondentListComponent extends GenericListComponent<PaperlessCo
|
|||||||
constructor(correspondentsService: CorrespondentService, modalService: NgbModal,
|
constructor(correspondentsService: CorrespondentService, modalService: NgbModal,
|
||||||
private list: DocumentListViewService,
|
private list: DocumentListViewService,
|
||||||
toastService: ToastService
|
toastService: ToastService
|
||||||
) {
|
) {
|
||||||
super(correspondentsService,modalService,CorrespondentEditDialogComponent, toastService)
|
super(correspondentsService,modalService,CorrespondentEditDialogComponent, toastService)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ import { ToastService } from 'src/app/services/toast.service';
|
|||||||
})
|
})
|
||||||
export class DocumentTypeEditDialogComponent extends EditDialogComponent<PaperlessDocumentType> {
|
export class DocumentTypeEditDialogComponent extends EditDialogComponent<PaperlessDocumentType> {
|
||||||
|
|
||||||
constructor(service: DocumentTypeService, activeModal: NgbActiveModal, toastService: ToastService) {
|
constructor(service: DocumentTypeService, activeModal: NgbActiveModal, toastService: ToastService) {
|
||||||
super(service, activeModal, toastService)
|
super(service, activeModal, toastService)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -49,4 +49,4 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -52,4 +52,4 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -5,4 +5,4 @@
|
|||||||
<path d="M7 6.5C7 7.328 6.552 8 6 8s-1-.672-1-1.5S5.448 5 6 5s1 .672 1 1.5zm4 0c0 .828-.448 1.5-1 1.5s-1-.672-1-1.5S9.448 5 10 5s1 .672 1 1.5z"/>
|
<path d="M7 6.5C7 7.328 6.552 8 6 8s-1-.672-1-1.5S5.448 5 6 5s1 .672 1 1.5zm4 0c0 .828-.448 1.5-1 1.5s-1-.672-1-1.5S9.448 5 10 5s1 .672 1 1.5z"/>
|
||||||
</svg>
|
</svg>
|
||||||
<h1 i18n>404 Not Found</h1>
|
<h1 i18n>404 Not Found</h1>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,16 +1,22 @@
|
|||||||
|
import { FILTER_FULLTEXT_MORELIKE, FILTER_FULLTEXT_QUERY } from "./filter-rule-type"
|
||||||
|
|
||||||
export function cloneFilterRules(filterRules: FilterRule[]): FilterRule[] {
|
export function cloneFilterRules(filterRules: FilterRule[]): FilterRule[] {
|
||||||
if (filterRules) {
|
if (filterRules) {
|
||||||
let newRules: FilterRule[] = []
|
let newRules: FilterRule[] = []
|
||||||
for (let rule of filterRules) {
|
for (let rule of filterRules) {
|
||||||
newRules.push({rule_type: rule.rule_type, value: rule.value})
|
newRules.push({rule_type: rule.rule_type, value: rule.value})
|
||||||
}
|
}
|
||||||
return newRules
|
return newRules
|
||||||
} else {
|
} else {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isFullTextFilterRule(filterRules: FilterRule[]): boolean {
|
||||||
|
return filterRules.find(r => r.rule_type == FILTER_FULLTEXT_QUERY || r.rule_type == FILTER_FULLTEXT_MORELIKE) != null
|
||||||
|
}
|
||||||
|
|
||||||
export interface FilterRule {
|
export interface FilterRule {
|
||||||
rule_type: number
|
rule_type: number
|
||||||
value: string
|
value: string
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { MatchingModel } from './matching-model';
|
import { MatchingModel } from './matching-model';
|
||||||
|
|
||||||
export interface PaperlessCorrespondent extends MatchingModel {
|
export interface PaperlessCorrespondent extends MatchingModel {
|
||||||
|
|
||||||
last_correspondence?: Date
|
last_correspondence?: Date
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
export interface PaperlessDocumentMetadata {
|
export interface PaperlessDocumentMetadata {
|
||||||
|
|
||||||
original_checksum?: string
|
original_checksum?: string
|
||||||
|
|
||||||
archived_checksum?: string
|
archived_checksum?: string
|
||||||
@@ -10,4 +10,4 @@ export interface PaperlessDocumentMetadata {
|
|||||||
|
|
||||||
has_archive_version?: boolean
|
has_archive_version?: boolean
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -6,4 +6,4 @@ export interface PaperlessDocumentSuggestions {
|
|||||||
|
|
||||||
document_types?: number[]
|
document_types?: number[]
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -15,4 +15,4 @@ export interface PaperlessSavedView extends ObjectWithId {
|
|||||||
|
|
||||||
filter_rules: FilterRule[]
|
filter_rules: FilterRule[]
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3,5 +3,5 @@ export interface Results<T> {
|
|||||||
count: number
|
count: number
|
||||||
|
|
||||||
results: T[]
|
results: T[]
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -8,4 +8,4 @@ export interface WebsocketConsumerStatusMessage {
|
|||||||
message?: string
|
message?: string
|
||||||
document_id: number
|
document_id: number
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ export class ApiVersionInterceptor implements HttpInterceptor {
|
|||||||
'Accept': `application/json; version=${environment.apiVersion}`
|
'Accept': `application/json; version=${environment.apiVersion}`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return next.handle(request);
|
return next.handle(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@ export class CsrfInterceptor implements HttpInterceptor {
|
|||||||
let prefix = ""
|
let prefix = ""
|
||||||
if (this.meta.getTag('name=cookie_prefix')) {
|
if (this.meta.getTag('name=cookie_prefix')) {
|
||||||
prefix = this.meta.getTag('name=cookie_prefix').content
|
prefix = this.meta.getTag('name=cookie_prefix').content
|
||||||
}
|
}
|
||||||
let csrfToken = this.cookieService.get(`${prefix?prefix:''}csrftoken`)
|
let csrfToken = this.cookieService.get(`${prefix?prefix:''}csrftoken`)
|
||||||
if (csrfToken) {
|
if (csrfToken) {
|
||||||
request = request.clone({
|
request = request.clone({
|
||||||
|
|||||||
@@ -11,12 +11,11 @@ const FORMAT_TO_ISO_FORMAT = {
|
|||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'customDate'
|
name: 'customDate'
|
||||||
})
|
})
|
||||||
export class CustomDatePipe extends DatePipe implements PipeTransform {
|
export class CustomDatePipe implements PipeTransform {
|
||||||
|
|
||||||
private defaultLocale: string
|
private defaultLocale: string
|
||||||
|
|
||||||
constructor(@Inject(LOCALE_ID) locale: string, private settings: SettingsService) {
|
constructor(@Inject(LOCALE_ID) locale: string, private datePipe: DatePipe, private settings: SettingsService) {
|
||||||
super(locale)
|
|
||||||
this.defaultLocale = locale
|
this.defaultLocale = locale
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,9 +23,9 @@ export class CustomDatePipe extends DatePipe implements PipeTransform {
|
|||||||
let l = locale || this.settings.get(SETTINGS_KEYS.DATE_LOCALE) || this.defaultLocale
|
let l = locale || this.settings.get(SETTINGS_KEYS.DATE_LOCALE) || this.defaultLocale
|
||||||
let f = format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT)
|
let f = format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT)
|
||||||
if (l == "iso-8601") {
|
if (l == "iso-8601") {
|
||||||
return super.transform(value, FORMAT_TO_ISO_FORMAT[f], timezone)
|
return this.datePipe.transform(value, FORMAT_TO_ISO_FORMAT[f], timezone)
|
||||||
} else {
|
} else {
|
||||||
return super.transform(value, format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT), timezone, l)
|
return this.datePipe.transform(value, format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT), timezone, l)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* https://gist.github.com/JonCatmull/ecdf9441aaa37336d9ae2c7f9cb7289a
|
* https://gist.github.com/JonCatmull/ecdf9441aaa37336d9ae2c7f9cb7289a
|
||||||
*
|
*
|
||||||
* @license
|
* @license
|
||||||
* Copyright (c) 2019 Jonathan Catmull.
|
* Copyright (c) 2019 Jonathan Catmull.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -16,4 +16,4 @@ export class SafePipe implements PipeTransform {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -125,7 +125,7 @@ export class ConsumerStatusService {
|
|||||||
connect() {
|
connect() {
|
||||||
this.disconnect()
|
this.disconnect()
|
||||||
|
|
||||||
this.statusWebSocket = new WebSocket(`${environment.webSocketProtocol}//${environment.webSocketHost}/ws/status/`);
|
this.statusWebSocket = new WebSocket(`${environment.webSocketProtocol}//${environment.webSocketHost}${environment.webSocketBaseUrl}status/`);
|
||||||
this.statusWebSocket.onmessage = (ev) => {
|
this.statusWebSocket.onmessage = (ev) => {
|
||||||
let statusMessage: WebsocketConsumerStatusMessage = JSON.parse(ev['data'])
|
let statusMessage: WebsocketConsumerStatusMessage = JSON.parse(ev['data'])
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,53 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { cloneFilterRules, FilterRule } from '../data/filter-rule';
|
import { cloneFilterRules, FilterRule, isFullTextFilterRule } from '../data/filter-rule';
|
||||||
import { FILTER_FULLTEXT_MORELIKE, FILTER_FULLTEXT_QUERY } from '../data/filter-rule-type';
|
|
||||||
import { PaperlessDocument } from '../data/paperless-document';
|
import { PaperlessDocument } from '../data/paperless-document';
|
||||||
import { PaperlessSavedView } from '../data/paperless-saved-view';
|
import { PaperlessSavedView } from '../data/paperless-saved-view';
|
||||||
import { DOCUMENT_LIST_SERVICE } from '../data/storage-keys';
|
import { DOCUMENT_LIST_SERVICE } from '../data/storage-keys';
|
||||||
import { DocumentService } from './rest/document.service';
|
import { DocumentService } from './rest/document.service';
|
||||||
import { SettingsService, SETTINGS_KEYS } from './settings.service';
|
import { SettingsService, SETTINGS_KEYS } from './settings.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Captures the current state of the list view.
|
||||||
|
*/
|
||||||
interface ListViewState {
|
interface ListViewState {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the document list view. Either "Documents" (localized) or the name of a saved view.
|
||||||
|
*/
|
||||||
title?: string
|
title?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current paginated list of documents displayed.
|
||||||
|
*/
|
||||||
documents?: PaperlessDocument[]
|
documents?: PaperlessDocument[]
|
||||||
|
|
||||||
currentPage: number
|
currentPage: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total amount of documents with the current filter rules. Used to calculate the number of pages.
|
||||||
|
*/
|
||||||
collectionSize: number
|
collectionSize: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently selected sort field.
|
||||||
|
*/
|
||||||
sortField: string
|
sortField: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if the list is sorted in reverse.
|
||||||
|
*/
|
||||||
sortReverse: boolean
|
sortReverse: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter rules for the current list view.
|
||||||
|
*/
|
||||||
filterRules: FilterRule[]
|
filterRules: FilterRule[]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains the IDs of all selected documents.
|
||||||
|
*/
|
||||||
selected?: Set<number>
|
selected?: Set<number>
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -134,10 +159,10 @@ export class DocumentListViewService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set filterRules(filterRules: FilterRule[]) {
|
set filterRules(filterRules: FilterRule[]) {
|
||||||
this.activeListViewState.filterRules = filterRules
|
if (!isFullTextFilterRule(filterRules) && this.activeListViewState.sortField == "score") {
|
||||||
if (filterRules.find(r => (r.rule_type == FILTER_FULLTEXT_QUERY || r.rule_type == FILTER_FULLTEXT_MORELIKE))) {
|
this.activeListViewState.sortField = "created"
|
||||||
this.activeListViewState.currentPage = 1
|
|
||||||
}
|
}
|
||||||
|
this.activeListViewState.filterRules = filterRules
|
||||||
this.reload()
|
this.reload()
|
||||||
this.reduceSelectionToFilter()
|
this.reduceSelectionToFilter()
|
||||||
this.saveDocumentListView()
|
this.saveDocumentListView()
|
||||||
@@ -213,6 +238,10 @@ export class DocumentListViewService {
|
|||||||
this._activeSavedViewId = null
|
this._activeSavedViewId = null
|
||||||
this.activeListViewState.filterRules = filterRules
|
this.activeListViewState.filterRules = filterRules
|
||||||
this.activeListViewState.currentPage = 1
|
this.activeListViewState.currentPage = 1
|
||||||
|
if (isFullTextFilterRule(filterRules)) {
|
||||||
|
this.activeListViewState.sortField = "score"
|
||||||
|
this.activeListViewState.sortReverse = false
|
||||||
|
}
|
||||||
this.reduceSelectionToFilter()
|
this.reduceSelectionToFilter()
|
||||||
this.saveDocumentListView()
|
this.saveDocumentListView()
|
||||||
if (this.router.url == "/documents") {
|
if (this.router.url == "/documents") {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export class OpenDocumentsService {
|
|||||||
|
|
||||||
private MAX_OPEN_DOCUMENTS = 5
|
private MAX_OPEN_DOCUMENTS = 5
|
||||||
|
|
||||||
constructor(private documentService: DocumentService) {
|
constructor(private documentService: DocumentService) {
|
||||||
if (sessionStorage.getItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS)) {
|
if (sessionStorage.getItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS)) {
|
||||||
try {
|
try {
|
||||||
this.openDocuments = JSON.parse(sessionStorage.getItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS))
|
this.openDocuments = JSON.parse(sessionStorage.getItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS))
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ export const DOCUMENT_SORT_FIELDS = [
|
|||||||
{ field: 'modified', name: $localize`Modified` }
|
{ field: 'modified', name: $localize`Modified` }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const DOCUMENT_SORT_FIELDS_FULLTEXT = [
|
||||||
|
...DOCUMENT_SORT_FIELDS,
|
||||||
|
{ field: 'score', name: $localize`:Score is a value returned by the full text search engine and specifies how well a result matches the given query:Search score` }
|
||||||
|
]
|
||||||
|
|
||||||
export interface SelectionDataItem {
|
export interface SelectionDataItem {
|
||||||
id: number
|
id: number
|
||||||
document_count: number
|
document_count: number
|
||||||
@@ -39,6 +44,8 @@ export interface SelectionData {
|
|||||||
})
|
})
|
||||||
export class DocumentService extends AbstractPaperlessService<PaperlessDocument> {
|
export class DocumentService extends AbstractPaperlessService<PaperlessDocument> {
|
||||||
|
|
||||||
|
private _searchQuery: string
|
||||||
|
|
||||||
constructor(http: HttpClient, private correspondentService: CorrespondentService, private documentTypeService: DocumentTypeService, private tagService: TagService) {
|
constructor(http: HttpClient, private correspondentService: CorrespondentService, private documentTypeService: DocumentTypeService, private tagService: TagService) {
|
||||||
super(http, 'documents')
|
super(http, 'documents')
|
||||||
}
|
}
|
||||||
@@ -92,6 +99,7 @@ export class DocumentService extends AbstractPaperlessService<PaperlessDocument>
|
|||||||
|
|
||||||
getPreviewUrl(id: number, original: boolean = false): string {
|
getPreviewUrl(id: number, original: boolean = false): string {
|
||||||
let url = this.getResourceUrl(id, 'preview')
|
let url = this.getResourceUrl(id, 'preview')
|
||||||
|
if (this._searchQuery) url += `#search="${this._searchQuery}"`
|
||||||
if (original) {
|
if (original) {
|
||||||
url += "?original=true"
|
url += "?original=true"
|
||||||
}
|
}
|
||||||
@@ -138,4 +146,8 @@ export class DocumentService extends AbstractPaperlessService<PaperlessDocument>
|
|||||||
return this.http.post(this.getResourceUrl(null, 'bulk_download'), {"documents": ids, "content": content}, { responseType: 'blob' })
|
return this.http.post(this.getResourceUrl(null, 'bulk_download'), {"documents": ids, "content": content}, { responseType: 'blob' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public set searchQuery(query: string) {
|
||||||
|
this._searchQuery = query
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@ export class SavedViewService extends AbstractPaperlessService<PaperlessSavedVie
|
|||||||
tap(() => this.reload())
|
tap(() => this.reload())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
patchMany(objects: PaperlessSavedView[]): Observable<PaperlessSavedView[]> {
|
patchMany(objects: PaperlessSavedView[]): Observable<PaperlessSavedView[]> {
|
||||||
return combineLatest(objects.map(o => super.patch(o))).pipe(
|
return combineLatest(objects.map(o => super.patch(o))).pipe(
|
||||||
tap(() => this.reload())
|
tap(() => this.reload())
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ import { DocumentService } from './document.service';
|
|||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class SearchService {
|
export class SearchService {
|
||||||
|
|
||||||
constructor(private http: HttpClient) { }
|
constructor(private http: HttpClient) { }
|
||||||
|
|
||||||
autocomplete(term: string): Observable<string[]> {
|
autocomplete(term: string): Observable<string[]> {
|
||||||
return this.http.get<string[]>(`${environment.apiBaseUrl}search/autocomplete/`, {params: new HttpParams().set('term', term)})
|
return this.http.get<string[]>(`${environment.apiBaseUrl}search/autocomplete/`, {params: new HttpParams().set('term', term)})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,9 @@ export class SettingsService {
|
|||||||
{code: "ro-ro", name: $localize`Romanian`, englishName: "Romanian", dateInputFormat: "dd.mm.yyyy"},
|
{code: "ro-ro", name: $localize`Romanian`, englishName: "Romanian", dateInputFormat: "dd.mm.yyyy"},
|
||||||
{code: "ru-ru", name: $localize`Russian`, englishName: "Russian", dateInputFormat: "dd.mm.yyyy"},
|
{code: "ru-ru", name: $localize`Russian`, englishName: "Russian", dateInputFormat: "dd.mm.yyyy"},
|
||||||
{code: "es-es", name: $localize`Spanish`, englishName: "Spanish", dateInputFormat: "dd/mm/yyyy"},
|
{code: "es-es", name: $localize`Spanish`, englishName: "Spanish", dateInputFormat: "dd/mm/yyyy"},
|
||||||
|
{code: "pl-pl", name: $localize`Polish`, englishName: "Polish", dateInputFormat: "dd.mm.yyyy"},
|
||||||
|
{code: "sv-se", name: $localize`Swedish`, englishName: "Swedish", dateInputFormat: "yyyy-mm-dd"},
|
||||||
|
{code: "lb-lu", name: $localize`Luxembourgish`, englishName: "Luxembourgish", dateInputFormat: "dd.mm.yyyy"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ function componentToHex(c) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* https://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
|
* https://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
|
||||||
*
|
*
|
||||||
* Converts an HSL color value to RGB. Conversion formula
|
* Converts an HSL color value to RGB. Conversion formula
|
||||||
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
||||||
* Assumes h, s, and l are contained in the set [0, 1] and
|
* Assumes h, s, and l are contained in the set [0, 1] and
|
||||||
@@ -45,4 +45,4 @@ function hslToRgb(h, s, l){
|
|||||||
export function randomColor() {
|
export function randomColor() {
|
||||||
let rgb = hslToRgb(Math.random(), 0.6, Math.random() * 0.4 + 0.4)
|
let rgb = hslToRgb(Math.random(), 0.6, Math.random() * 0.4 + 0.4)
|
||||||
return `#${componentToHex(rgb[0])}${componentToHex(rgb[1])}${componentToHex(rgb[2])}`
|
return `#${componentToHex(rgb[0])}${componentToHex(rgb[1])}${componentToHex(rgb[2])}`
|
||||||
}
|
}
|
||||||
@@ -56,4 +56,4 @@ export class LocalizedDateParserFormatter extends NgbDateParserFormatter {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
|
const base_url = new URL(document.baseURI)
|
||||||
|
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: true,
|
production: true,
|
||||||
apiBaseUrl: "/api/",
|
apiBaseUrl: document.baseURI + "api/",
|
||||||
apiVersion: "2",
|
apiVersion: "2",
|
||||||
appTitle: "Paperless-ng",
|
appTitle: "Paperless-ng",
|
||||||
version: "1.3.2",
|
version: "1.5.0",
|
||||||
webSocketHost: window.location.host,
|
webSocketHost: window.location.host,
|
||||||
webSocketProtocol: (window.location.protocol == "https:" ? "wss:" : "ws:")
|
webSocketProtocol: (window.location.protocol == "https:" ? "wss:" : "ws:"),
|
||||||
|
webSocketBaseUrl: base_url.pathname + "ws/",
|
||||||
};
|
};
|
||||||
Loaded 100 of 183 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user