Compare commits

..

2 Commits

Author SHA1 Message Date
Trenton H
1d5a743600 Fixes direct test call 2025-02-21 10:53:22 -08:00
Trenton H
3656c36965 Testing out a switch to rich to remove tqdm 2025-02-21 10:41:42 -08:00
33 changed files with 340 additions and 418 deletions

View File

@@ -123,13 +123,13 @@ RUN set -eux \
WORKDIR /usr/src/paperless/src/docker/
COPY [ \
"docker/rootfs/etc/ImageMagick-6/paperless-policy.xml", \
"docker/imagemagick-policy.xml", \
"./" \
]
RUN set -eux \
&& echo "Configuring ImageMagick" \
&& mv paperless-policy.xml /etc/ImageMagick-6/policy.xml
&& mv imagemagick-policy.xml /etc/ImageMagick-6/policy.xml
# Packages needed only for building a few quick Python
# dependencies

View File

@@ -65,7 +65,7 @@ services:
command: /bin/sh -c "chown -R paperless:paperless /usr/src/paperless/paperless-ngx/src/documents/static/frontend && chown -R paperless:paperless /usr/src/paperless/paperless-ngx/.ruff_cache && while sleep 1000; do :; done"
gotenberg:
image: docker.io/gotenberg/gotenberg:8.17
image: docker.io/gotenberg/gotenberg:7.10
restart: unless-stopped
# The Gotenberg Chromium route is used to convert .eml files. We do not

View File

@@ -5,7 +5,7 @@
services:
gotenberg:
image: docker.io/gotenberg/gotenberg:8.17
image: docker.io/gotenberg/gotenberg:8.7
hostname: gotenberg
container_name: gotenberg
network_mode: host

View File

@@ -77,7 +77,7 @@ services:
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
gotenberg:
image: docker.io/gotenberg/gotenberg:8.17
image: docker.io/gotenberg/gotenberg:8.7
restart: unless-stopped
# The gotenberg chromium route is used to convert .eml files. We do not
# want to allow external content like tracking pixels or even javascript.

View File

@@ -71,7 +71,7 @@ services:
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
gotenberg:
image: docker.io/gotenberg/gotenberg:8.17
image: docker.io/gotenberg/gotenberg:8.7
restart: unless-stopped
# The gotenberg chromium route is used to convert .eml files. We do not

View File

@@ -59,7 +59,7 @@ services:
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
gotenberg:
image: docker.io/gotenberg/gotenberg:8.17
image: docker.io/gotenberg/gotenberg:8.7
restart: unless-stopped
# The gotenberg chromium route is used to convert .eml files. We do not

View File

@@ -1,18 +1,10 @@
#!/command/with-contenv /usr/bin/bash
# shellcheck shell=bash
cd ${PAPERLESS_SRC_DIR}
if [[ -n "${PAPERLESS_CONSUMER_DISABLE}" ]]; then
echo "[svc-consumer] Consumer is disabled, exiting"
# https://skarnet.org/software/s6/s6-svc.html
s6-svc -Od .
if [[ -n "${USER_IS_NON_ROOT}" ]]; then
exec python3 manage.py document_consumer
else
cd ${PAPERLESS_SRC_DIR}
if [[ -n "${USER_IS_NON_ROOT}" ]]; then
exec python3 manage.py document_consumer
else
exec s6-setuidgid paperless python3 manage.py document_consumer
fi
exec s6-setuidgid paperless python3 manage.py document_consumer
fi

View File

@@ -1030,11 +1030,6 @@ be used with caution!
## Document Consumption {#consume_config}
#### [`PAPERLESS_CONSUMER_DISABLE=<bool>`](#PAPERLESS_CONSUMER_DISABLE) {#PAPERLESS_CONSUMER_DISABLE}
: Completely disable the directory-based consumer in docker. If you don't plan to consume documents
via the consumption directory, you can disable the consumer to save resources.
#### [`PAPERLESS_CONSUMER_DELETE_DUPLICATES=<bool>`](#PAPERLESS_CONSUMER_DELETE_DUPLICATES) {#PAPERLESS_CONSUMER_DELETE_DUPLICATES}
: When the consumer detects a duplicate document, it will not touch

View File

@@ -714,8 +714,6 @@ the Pi and configuring some options in paperless can help improve
performance immensely:
- Stick with SQLite to save some resources.
- If you do not need the filesystem-based consumer, consider disabling it
entirely by setting [`PAPERLESS_CONSUMER_DISABLE`](configuration.md#PAPERLESS_CONSUMER_DISABLE) to `true`.
- Consider setting [`PAPERLESS_OCR_PAGES`](configuration.md#PAPERLESS_OCR_PAGES) to 1, so that paperless will
only OCR the first page of your documents. In most cases, this page
contains enough information to be able to find it.

View File

@@ -569,7 +569,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">81</context>
<context context-type="linenumber">76</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component.html</context>
@@ -1453,7 +1453,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">80</context>
<context context-type="linenumber">75</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component.html</context>
@@ -1736,7 +1736,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">87</context>
<context context-type="linenumber">83</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
@@ -3543,7 +3543,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">83</context>
<context context-type="linenumber">79</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
@@ -3890,11 +3890,18 @@
<context context-type="linenumber">113</context>
</context-group>
</trans-unit>
<trans-unit id="220550782947016929" datatype="html">
<source>Order</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">19</context>
</context-group>
</trans-unit>
<trans-unit id="4816216590591222133" datatype="html">
<source>Enabled</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">19</context>
<context context-type="linenumber">22</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
@@ -3909,176 +3916,155 @@
<context context-type="linenumber">41</context>
</context-group>
</trans-unit>
<trans-unit id="220550782947016929" datatype="html">
<source>Order</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">24</context>
</context-group>
</trans-unit>
<trans-unit id="1504364192557145528" datatype="html">
<source>Stop further processing</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">27</context>
</context-group>
</trans-unit>
<trans-unit id="6164556674897067551" datatype="html">
<source>Stop processing further rules if this rule queues any document(s).</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">27</context>
</context-group>
</trans-unit>
<trans-unit id="4348351765075925931" datatype="html">
<source>Paperless will only process mails that match <x id="START_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;em&gt;"/>all<x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;/em&gt;"/> of the criteria specified below.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">32</context>
<context context-type="linenumber">27</context>
</context-group>
</trans-unit>
<trans-unit id="7046259383943324039" datatype="html">
<source>Folder</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">34</context>
<context context-type="linenumber">29</context>
</context-group>
</trans-unit>
<trans-unit id="1391527525114848695" datatype="html">
<source>Subfolders must be separated by a delimiter, often a dot (&apos;.&apos;) or slash (&apos;/&apos;), but it varies by mail server.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">34</context>
<context context-type="linenumber">29</context>
</context-group>
</trans-unit>
<trans-unit id="101686279614365671" datatype="html">
<source>Maximum age (days)</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">35</context>
<context context-type="linenumber">30</context>
</context-group>
</trans-unit>
<trans-unit id="6925928412364847639" datatype="html">
<source>Filter from</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">38</context>
<context context-type="linenumber">33</context>
</context-group>
</trans-unit>
<trans-unit id="8977094263269822022" datatype="html">
<source>Filter to</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">39</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="8497813481090627874" datatype="html">
<source>Filter subject</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">40</context>
<context context-type="linenumber">35</context>
</context-group>
</trans-unit>
<trans-unit id="7314357616097563149" datatype="html">
<source>Filter body</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">41</context>
<context context-type="linenumber">36</context>
</context-group>
</trans-unit>
<trans-unit id="559099472394646919" datatype="html">
<source>Consumption scope</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">47</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="56643687972548912" datatype="html">
<source>See docs for .eml processing requirements</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">47</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="7093509971705471817" datatype="html">
<source>Attachment type</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">48</context>
<context context-type="linenumber">43</context>
</context-group>
</trans-unit>
<trans-unit id="3842519365862452117" datatype="html">
<source>PDF layout</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">49</context>
<context context-type="linenumber">44</context>
</context-group>
</trans-unit>
<trans-unit id="2873939123535615966" datatype="html">
<source>Include only files matching</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">52</context>
<context context-type="linenumber">47</context>
</context-group>
</trans-unit>
<trans-unit id="7233407036155150477" datatype="html">
<source>Optional. Wildcards e.g. *.pdf or *invoice* allowed. Can be comma-separated list. Case insensitive.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">52</context>
<context context-type="linenumber">47</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">53</context>
<context context-type="linenumber">48</context>
</context-group>
</trans-unit>
<trans-unit id="1546332577833742677" datatype="html">
<source>Exclude files matching</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">53</context>
<context context-type="linenumber">48</context>
</context-group>
</trans-unit>
<trans-unit id="9216117865911519658" datatype="html">
<source>Action</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">59</context>
<context context-type="linenumber">54</context>
</context-group>
</trans-unit>
<trans-unit id="7841986067387421166" datatype="html">
<source>Only performed if the mail is processed.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">59</context>
<context context-type="linenumber">54</context>
</context-group>
</trans-unit>
<trans-unit id="1261794314435932203" datatype="html">
<source>Action parameter</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">61</context>
<context context-type="linenumber">56</context>
</context-group>
</trans-unit>
<trans-unit id="6093797930511670257" datatype="html">
<source>Assign title from</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">63</context>
<context context-type="linenumber">58</context>
</context-group>
</trans-unit>
<trans-unit id="5232720756589450549" datatype="html">
<source>Assign owner from rule</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">64</context>
<context context-type="linenumber">59</context>
</context-group>
</trans-unit>
<trans-unit id="6695990587380209737" datatype="html">
<source>Assign document type</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">68</context>
<context context-type="linenumber">63</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
@@ -4089,14 +4075,14 @@
<source>Assign correspondent from</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">69</context>
<context context-type="linenumber">64</context>
</context-group>
</trans-unit>
<trans-unit id="4875491778188965469" datatype="html">
<source>Assign correspondent</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">71</context>
<context context-type="linenumber">66</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
@@ -4107,7 +4093,7 @@
<source>Error</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">73</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
@@ -4398,7 +4384,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">129</context>
<context context-type="linenumber">125</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/profile-edit-dialog/profile-edit-dialog.component.html</context>
@@ -4998,18 +4984,11 @@
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="235571817610183244" datatype="html">
<source>Web UI</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">76</context>
</context-group>
</trans-unit>
<trans-unit id="3553216189604488439" datatype="html">
<source>Modified</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">91</context>
<context context-type="linenumber">87</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/data/document.ts</context>
@@ -5020,70 +4999,70 @@
<source>Custom Field</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">95</context>
<context context-type="linenumber">91</context>
</context-group>
</trans-unit>
<trans-unit id="8696908693776094667" datatype="html">
<source>Consumption Started</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">102</context>
<context context-type="linenumber">98</context>
</context-group>
</trans-unit>
<trans-unit id="7858311467093621703" datatype="html">
<source>Document Added</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">106</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="7955486237346046731" datatype="html">
<source>Document Updated</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">110</context>
<context context-type="linenumber">106</context>
</context-group>
</trans-unit>
<trans-unit id="9172233176401579786" datatype="html">
<source>Scheduled</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">114</context>
<context context-type="linenumber">110</context>
</context-group>
</trans-unit>
<trans-unit id="5502398334173581061" datatype="html">
<source>Assignment</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">121</context>
<context context-type="linenumber">117</context>
</context-group>
</trans-unit>
<trans-unit id="6234812824772766804" datatype="html">
<source>Removal</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">125</context>
<context context-type="linenumber">121</context>
</context-group>
</trans-unit>
<trans-unit id="4206419737792796794" datatype="html">
<source>Webhook</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">133</context>
<context context-type="linenumber">129</context>
</context-group>
</trans-unit>
<trans-unit id="3138206142174978019" datatype="html">
<source>Create new workflow</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">229</context>
<context context-type="linenumber">225</context>
</context-group>
</trans-unit>
<trans-unit id="5996779210524133604" datatype="html">
<source>Edit workflow</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">233</context>
<context context-type="linenumber">229</context>
</context-group>
</trans-unit>
<trans-unit id="7376342558017986274" datatype="html">
@@ -9747,28 +9726,28 @@
<source>Connecting...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/upload-documents.service.ts</context>
<context context-type="linenumber">43</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="1245343823699368872" datatype="html">
<source>Uploading...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/upload-documents.service.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">54</context>
</context-group>
</trans-unit>
<trans-unit id="7446520539098045935" datatype="html">
<source>Upload complete, waiting...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/upload-documents.service.ts</context>
<context context-type="linenumber">58</context>
<context context-type="linenumber">57</context>
</context-group>
</trans-unit>
<trans-unit id="1405142710727603568" datatype="html">
<source>HTTP error: <x id="PH" equiv-text="error.status"/> <x id="PH_1" equiv-text="error.statusText"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/upload-documents.service.ts</context>
<context context-type="linenumber">71</context>
<context context-type="linenumber">70</context>
</context-group>
</trans-unit>
<trans-unit id="2119857572761283468" datatype="html">

View File

@@ -84,7 +84,7 @@ export class SplitConfirmDialogComponent
addSplit() {
if (this.page === this.totalPages) return
this.pages.add(this.page)
this.pages = new Set(Array.from(this.pages).sort((a, b) => a - b))
this.pages = new Set(Array.from(this.pages).sort())
this.confirmButtonEnabled = this.pages.size > 0
}

View File

@@ -9,24 +9,19 @@
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-6">
<div class="col-md-4">
<pngx-input-text [horizontal]="true" i18n-title title="Name" formControlName="name" [error]="error?.name" autocomplete="off"></pngx-input-text>
</div>
<div class="col-md-4">
<div class="col-md-3">
<pngx-input-select [horizontal]="true" i18n-title title="Account" [items]="accounts" formControlName="account"></pngx-input-select>
</div>
<div class="col-md-3">
<pngx-input-number [horizontal]="true" i18n-title title="Order" formControlName="order" [showAdd]="false" [error]="error?.order"></pngx-input-number>
</div>
<div class="col-md-2 pt-2">
<pngx-input-switch [horizontal]="true" i18n-title title="Enabled" formControlName="enabled"></pngx-input-switch>
</div>
</div>
<div class="row">
<div class="col-md-6">
<pngx-input-number [horizontal]="true" i18n-title title="Order" formControlName="order" [showAdd]="false" [error]="error?.order"></pngx-input-number>
</div>
<div class="col-md-6">
<pngx-input-switch [horizontal]="true" i18n-title title="Stop further processing" formControlName="stop_processing" i18n-hint hint="Stop processing further rules if this rule queues any document(s)."></pngx-input-switch>
</div>
</div>
<hr class="mt-0"/>
<div class="row">
<p class="small" i18n>Paperless will only process mails that match <em>all</em> of the criteria specified below.</p>

View File

@@ -221,7 +221,6 @@ export class MailRuleEditDialogComponent extends EditDialogComponent<MailRule> {
),
assign_correspondent: new FormControl(null),
assign_owner_from_rule: new FormControl(true),
stop_processing: new FormControl(false),
})
}

View File

@@ -84,6 +84,4 @@ export interface MailRule extends ObjectWithPermissions {
assign_correspondent?: number // PaperlessCorrespondent.id
assign_owner_from_rule: boolean
stop_processing: boolean
}

View File

@@ -33,7 +33,6 @@ const mail_rules = [
action: MailAction.MarkRead,
assign_title_from: MailMetadataTitleOption.FromSubject,
assign_owner_from_rule: true,
stop_processing: false,
},
{
name: 'Mail Rule 2',
@@ -53,7 +52,6 @@ const mail_rules = [
action: MailAction.Delete,
assign_title_from: MailMetadataTitleOption.FromSubject,
assign_owner_from_rule: true,
stop_processing: false,
},
{
name: 'Mail Rule 3',
@@ -73,7 +71,6 @@ const mail_rules = [
action: MailAction.Flag,
assign_title_from: MailMetadataTitleOption.FromSubject,
assign_owner_from_rule: false,
stop_processing: false,
},
]

View File

@@ -1,10 +1,10 @@
import logging
import multiprocessing
import tqdm
from django import db
from django.conf import settings
from django.core.management.base import BaseCommand
from rich.progress import track
from documents.management.commands.mixins import MultiProcessMixin
from documents.management.commands.mixins import ProgressBarMixin
@@ -81,7 +81,7 @@ class Command(MultiProcessMixin, ProgressBarMixin, BaseCommand):
else: # pragma: no cover
with multiprocessing.Pool(self.process_count) as pool:
list(
tqdm.tqdm(
track(
pool.imap_unordered(
update_document_content_maybe_archive_file,
document_ids,

View File

@@ -7,7 +7,6 @@ import time
from pathlib import Path
from typing import TYPE_CHECKING
import tqdm
from allauth.mfa.models import Authenticator
from allauth.socialaccount.models import SocialAccount
from allauth.socialaccount.models import SocialApp
@@ -25,6 +24,11 @@ from django.utils import timezone
from filelock import FileLock
from guardian.models import GroupObjectPermission
from guardian.models import UserObjectPermission
from rich.progress import BarColumn
from rich.progress import MofNCompleteColumn
from rich.progress import Progress
from rich.progress import TaskProgressColumn
from rich.progress import TextColumn
if TYPE_CHECKING:
from django.db.models import QuerySet
@@ -229,8 +233,17 @@ class Command(CryptMixin, BaseCommand):
try:
# Prevent any ongoing changes in the documents
with FileLock(settings.MEDIA_LOCK):
self.dump()
with (
FileLock(settings.MEDIA_LOCK),
Progress(
TextColumn("[progress.description]{task.description}"),
BarColumn(),
TaskProgressColumn(),
MofNCompleteColumn(),
disable=self.no_progress_bar,
) as progress,
):
self.dump(progress)
# We've written everything to the temporary directory in this case,
# now make an archive in the original target, with all files stored
@@ -249,7 +262,7 @@ class Command(CryptMixin, BaseCommand):
if self.zip_export and temp_dir is not None:
temp_dir.cleanup()
def dump(self):
def dump(self, progress: Progress):
# 1. Take a snapshot of what files exist in the current export folder
for x in self.target.glob("**/*"):
if x.is_file():
@@ -297,11 +310,17 @@ class Command(CryptMixin, BaseCommand):
with transaction.atomic():
manifest_dict = {}
serialize_task = progress.add_task(
"Serializing database",
total=len(manifest_key_to_object_query),
)
# Build an overall manifest
for key, object_query in manifest_key_to_object_query.items():
manifest_dict[key] = json.loads(
serializers.serialize("json", object_query),
)
progress.advance(serialize_task)
self.encrypt_secret_fields(manifest_dict)
@@ -313,12 +332,10 @@ class Command(CryptMixin, BaseCommand):
}
document_manifest = manifest_dict["documents"]
copy_task = progress.add_task("Copying files", total=len(document_manifest))
# 3. Export files from each document
for index, document_dict in tqdm.tqdm(
enumerate(document_manifest),
total=len(document_manifest),
disable=self.no_progress_bar,
):
for index, document_dict in enumerate(document_manifest):
# 3.1. store files unencrypted
document_dict["fields"]["storage_type"] = Document.STORAGE_TYPE_UNENCRYPTED
@@ -365,6 +382,7 @@ class Command(CryptMixin, BaseCommand):
content,
manifest_name,
)
progress.advance(copy_task)
# These were exported already
if self.split_manifest:

View File

@@ -3,9 +3,9 @@ import multiprocessing
from typing import Final
import rapidfuzz
import tqdm
from django.core.management import BaseCommand
from django.core.management import CommandError
from rich.progress import track
from documents.management.commands.mixins import MultiProcessMixin
from documents.management.commands.mixins import ProgressBarMixin
@@ -105,12 +105,12 @@ class Command(MultiProcessMixin, ProgressBarMixin, BaseCommand):
# Don't spin up a pool of 1 process
if self.process_count == 1:
results = []
for work in tqdm.tqdm(work_pkgs, disable=self.no_progress_bar):
for work in track(work_pkgs, disable=self.no_progress_bar):
results.append(_process_and_match(work))
else: # pragma: no cover
with multiprocessing.Pool(processes=self.process_count) as pool:
results = list(
tqdm.tqdm(
track(
pool.imap_unordered(_process_and_match, work_pkgs),
total=len(work_pkgs),
disable=self.no_progress_bar,

View File

@@ -5,7 +5,6 @@ from collections.abc import Generator
from contextlib import contextmanager
from pathlib import Path
import tqdm
from django.conf import settings
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
@@ -20,6 +19,7 @@ from django.db import transaction
from django.db.models.signals import m2m_changed
from django.db.models.signals import post_save
from filelock import FileLock
from rich.progress import Progress
from documents.file_handling import create_source_path_directory
from documents.management.commands.mixins import CryptMixin
@@ -138,7 +138,7 @@ class Command(CryptMixin, BaseCommand):
pre_check_maybe_not_empty()
pre_check_manifest_exists()
def load_manifest_files(self) -> None:
def load_manifest_files(self, progress: Progress) -> None:
"""
Loads manifest data from the various JSON files for parsing and loading the database
"""
@@ -148,10 +148,15 @@ class Command(CryptMixin, BaseCommand):
self.manifest = json.load(infile)
self.manifest_paths.append(main_manifest_path)
split_manifest_task = progress.add_task("Parsing split manifests")
for file in Path(self.source).glob("**/*-manifest.json"):
progress.update(split_manifest_task, visible=True)
with file.open() as infile:
self.manifest += json.load(infile)
self.manifest_paths.append(file)
progress.advance(split_manifest_task)
progress.update(split_manifest_task, total=1, completed=1)
def load_metadata(self) -> None:
"""
@@ -191,7 +196,7 @@ class Command(CryptMixin, BaseCommand):
),
)
def load_data_to_database(self) -> None:
def load_data_to_database(self, progress: Progress) -> None:
"""
As the name implies, loads data from the JSON file(s) into the database
"""
@@ -201,7 +206,7 @@ class Command(CryptMixin, BaseCommand):
ContentType.objects.all().delete()
Permission.objects.all().delete()
for manifest_path in self.manifest_paths:
call_command("loaddata", manifest_path)
call_command("loaddata", "-v", "0", manifest_path)
except (FieldDoesNotExist, DeserializationError, IntegrityError) as e:
self.stdout.write(self.style.ERROR("Database import failed"))
if (
@@ -234,55 +239,56 @@ class Command(CryptMixin, BaseCommand):
self.manifest_paths = []
self.manifest = []
self.pre_check()
with Progress(disable=self.no_progress_bar) as progress:
self.pre_check()
self.load_metadata()
self.load_metadata()
self.load_manifest_files()
self.load_manifest_files(progress)
self.check_manifest_validity()
self.check_manifest_validity(progress)
self.decrypt_secret_fields()
self.decrypt_secret_fields()
# see /src/documents/signals/handlers.py
with (
disable_signal(
post_save,
receiver=update_filename_and_move_files,
sender=Document,
),
disable_signal(
m2m_changed,
receiver=update_filename_and_move_files,
sender=Document.tags.through,
),
disable_signal(
post_save,
receiver=update_filename_and_move_files,
sender=CustomFieldInstance,
),
disable_signal(
post_save,
receiver=check_paths_and_prune_custom_fields,
sender=CustomField,
),
):
if settings.AUDIT_LOG_ENABLED:
auditlog.unregister(Document)
auditlog.unregister(Correspondent)
auditlog.unregister(Tag)
auditlog.unregister(DocumentType)
auditlog.unregister(Note)
auditlog.unregister(CustomField)
auditlog.unregister(CustomFieldInstance)
# see /src/documents/signals/handlers.py
with (
disable_signal(
post_save,
receiver=update_filename_and_move_files,
sender=Document,
),
disable_signal(
m2m_changed,
receiver=update_filename_and_move_files,
sender=Document.tags.through,
),
disable_signal(
post_save,
receiver=update_filename_and_move_files,
sender=CustomFieldInstance,
),
disable_signal(
post_save,
receiver=check_paths_and_prune_custom_fields,
sender=CustomField,
),
):
if settings.AUDIT_LOG_ENABLED:
auditlog.unregister(Document)
auditlog.unregister(Correspondent)
auditlog.unregister(Tag)
auditlog.unregister(DocumentType)
auditlog.unregister(Note)
auditlog.unregister(CustomField)
auditlog.unregister(CustomFieldInstance)
# Fill up the database with whatever is in the manifest
self.load_data_to_database()
# Fill up the database with whatever is in the manifest
self.load_data_to_database(progress)
if not self.data_only:
self._import_files_from_manifest()
else:
self.stdout.write(self.style.NOTICE("Data only import completed"))
if not self.data_only:
self._import_files_from_manifest(progress)
else:
self.stdout.write(self.style.NOTICE("Data only import completed"))
self.stdout.write("Updating search index...")
call_command(
@@ -291,7 +297,7 @@ class Command(CryptMixin, BaseCommand):
no_progress_bar=self.no_progress_bar,
)
def check_manifest_validity(self) -> None:
def check_manifest_validity(self, progress: Progress) -> None:
"""
Attempts to verify the manifest is valid. Namely checking the files
referred to exist and the files can be read from
@@ -335,45 +341,56 @@ class Command(CryptMixin, BaseCommand):
f"Failed to read from archive file {doc_archive_path}",
) from e
self.stdout.write("Checking the manifest")
manifest_valid_task = progress.add_task(
"Checking validity",
total=None,
visible=not self.data_only,
)
# self.stdout.write("Checking the manifest")
for record in self.manifest:
# Only check if the document files exist if this is not data only
# We don't care about documents for a data only import
if not self.data_only and record["model"] == "documents.document":
check_document_validity(record)
progress.advance(manifest_valid_task)
progress.update(manifest_valid_task, total=1, completed=1)
def _import_files_from_manifest(self) -> None:
def _import_files_from_manifest(self, progress: Progress) -> None:
settings.ORIGINALS_DIR.mkdir(parents=True, exist_ok=True)
settings.THUMBNAIL_DIR.mkdir(parents=True, exist_ok=True)
settings.ARCHIVE_DIR.mkdir(parents=True, exist_ok=True)
self.stdout.write("Copy files into paperless...")
# self.stdout.write("Copy files into paperless...")
manifest_documents = list(
filter(lambda r: r["model"] == "documents.document", self.manifest),
)
copy_file_task = progress.add_task(
"Copying files",
total=len(manifest_documents),
)
with FileLock(settings.MEDIA_LOCK):
for record in manifest_documents:
document = Document.objects.get(pk=record["pk"])
for record in tqdm.tqdm(manifest_documents, disable=self.no_progress_bar):
document = Document.objects.get(pk=record["pk"])
doc_file = record[EXPORTER_FILE_NAME]
document_path = self.source / doc_file
doc_file = record[EXPORTER_FILE_NAME]
document_path = self.source / doc_file
if EXPORTER_THUMBNAIL_NAME in record:
thumb_file = record[EXPORTER_THUMBNAIL_NAME]
thumbnail_path = (self.source / thumb_file).resolve()
else:
thumbnail_path = None
if EXPORTER_THUMBNAIL_NAME in record:
thumb_file = record[EXPORTER_THUMBNAIL_NAME]
thumbnail_path = (self.source / thumb_file).resolve()
else:
thumbnail_path = None
if EXPORTER_ARCHIVE_NAME in record:
archive_file = record[EXPORTER_ARCHIVE_NAME]
archive_path = self.source / archive_file
else:
archive_path = None
if EXPORTER_ARCHIVE_NAME in record:
archive_file = record[EXPORTER_ARCHIVE_NAME]
archive_path = self.source / archive_file
else:
archive_path = None
document.storage_type = Document.STORAGE_TYPE_UNENCRYPTED
document.storage_type = Document.STORAGE_TYPE_UNENCRYPTED
with FileLock(settings.MEDIA_LOCK):
if Path(document.source_path).is_file():
raise FileExistsError(document.source_path)
@@ -406,7 +423,8 @@ class Command(CryptMixin, BaseCommand):
# archived files
copy_file_with_basic_stats(archive_path, document.archive_path)
document.save()
document.save()
progress.advance(copy_file_task)
def decrypt_secret_fields(self) -> None:
"""

View File

@@ -1,8 +1,8 @@
import logging
import tqdm
from django.core.management.base import BaseCommand
from django.db.models.signals import post_save
from rich.progress import track
from documents.management.commands.mixins import ProgressBarMixin
from documents.models import Document
@@ -17,9 +17,10 @@ class Command(ProgressBarMixin, BaseCommand):
def handle(self, *args, **options):
self.handle_progress_bar_mixin(**options)
logging.getLogger().handlers[0].level = logging.ERROR
for document in tqdm.tqdm(
Document.objects.all(),
qs = Document.objects.all()
for document in track(
qs,
total=qs.count(),
disable=self.no_progress_bar,
):
post_save.send(Document, instance=document, created=False)

View File

@@ -1,7 +1,7 @@
import logging
import tqdm
from django.core.management.base import BaseCommand
from rich.progress import track
from documents.classifier import load_classifier
from documents.management.commands.mixins import ProgressBarMixin
@@ -84,7 +84,11 @@ class Command(ProgressBarMixin, BaseCommand):
classifier = load_classifier()
for document in tqdm.tqdm(documents, disable=self.no_progress_bar):
for document in track(
documents,
total=documents.count(),
disable=self.no_progress_bar,
):
if options["correspondent"]:
set_correspondent(
sender=None,

View File

@@ -2,9 +2,9 @@ import logging
import multiprocessing
import shutil
import tqdm
from django import db
from django.core.management.base import BaseCommand
from rich.progress import track
from documents.management.commands.mixins import MultiProcessMixin
from documents.management.commands.mixins import ProgressBarMixin
@@ -76,7 +76,7 @@ class Command(MultiProcessMixin, ProgressBarMixin, BaseCommand):
else: # pragma: no cover
with multiprocessing.Pool(processes=self.process_count) as pool:
list(
tqdm.tqdm(
track(
pool.imap_unordered(_process_document, ids),
total=len(ids),
disable=self.no_progress_bar,

View File

@@ -1,7 +1,7 @@
from auditlog.models import LogEntry
from django.core.management.base import BaseCommand
from django.db import transaction
from tqdm import tqdm
from rich.progress import track
from documents.management.commands.mixins import ProgressBarMixin
@@ -19,7 +19,10 @@ class Command(BaseCommand, ProgressBarMixin):
def handle(self, **options):
self.handle_progress_bar_mixin(**options)
with transaction.atomic():
for log_entry in tqdm(LogEntry.objects.all(), disable=self.no_progress_bar):
for log_entry in track(
LogEntry.objects.all(),
disable=self.no_progress_bar,
):
model_class = log_entry.content_type.model_class()
# use global_objects for SoftDeleteModel
objects = (
@@ -32,7 +35,7 @@ class Command(BaseCommand, ProgressBarMixin):
and not objects.filter(pk=log_entry.object_id).exists()
):
log_entry.delete()
tqdm.write(
self.stdout.write(
self.style.NOTICE(
f"Deleted audit log entry for {model_class.__name__} #{log_entry.object_id}",
),

View File

@@ -5,7 +5,7 @@ from pathlib import Path
from typing import Final
from django.conf import settings
from tqdm import tqdm
from rich.progress import track
from documents.models import Document
@@ -68,7 +68,9 @@ def check_sanity(*, progress=False) -> SanityCheckMessages:
if lockfile in present_files:
present_files.remove(lockfile)
for doc in tqdm(Document.global_objects.all(), disable=not progress):
qs = Document.global_objects.all()
for doc in track(qs, total=qs.count(), disable=not progress):
# Check sanity of the thumbnail
thumbnail_path: Final[Path] = Path(doc.thumbnail_path).resolve()
if not thumbnail_path.exists() or not thumbnail_path.is_file():

View File

@@ -6,7 +6,6 @@ from datetime import timedelta
from pathlib import Path
from tempfile import TemporaryDirectory
import tqdm
from celery import Task
from celery import shared_task
from django.conf import settings
@@ -16,6 +15,7 @@ from django.db import transaction
from django.db.models.signals import post_save
from django.utils import timezone
from filelock import FileLock
from rich.progress import track
from whoosh.writing import AsyncWriter
from documents import index
@@ -69,7 +69,12 @@ def index_reindex(*, progress_bar_disable=False):
ix = index.open_index(recreate=True)
with AsyncWriter(ix) as writer:
for document in tqdm.tqdm(documents, disable=progress_bar_disable):
for document in track(
documents,
total=documents.count(),
description="Indexing...",
disable=progress_bar_disable,
):
index.update_document(writer, document)

View File

@@ -7,6 +7,7 @@ from django.contrib.auth.models import User
from django.core.management import call_command
from django.core.management.base import CommandError
from django.test import TestCase
from rich.progress import Progress
from documents.management.commands.document_importer import Command
from documents.models import Document
@@ -126,15 +127,21 @@ class TestCommandImport(
},
]
cmd.data_only = False
with self.assertRaises(CommandError) as cm:
cmd.check_manifest_validity()
with (
self.assertRaises(CommandError) as cm,
Progress(disable=True) as progress,
):
cmd.check_manifest_validity(progress)
self.assertInt("Failed to read from original file", str(cm.exception))
original_path.chmod(0o444)
archive_path.chmod(0o222)
with self.assertRaises(CommandError) as cm:
cmd.check_manifest_validity()
with (
self.assertRaises(CommandError) as cm,
Progress(disable=True) as progress,
):
cmd.check_manifest_validity(progress)
self.assertInt("Failed to read from archive file", str(cm.exception))
def test_import_source_not_existing(self):

View File

@@ -8,7 +8,7 @@ class TestMigrateWorkflow(TestMigrations):
dependencies = (
(
"paperless_mail",
"0030_mailrule_stop_processing",
"0029_mailrule_pdf_layout",
),
)

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-24 09:00-0800\n"
"POT-Creation-Date: 2025-02-11 18:43-0800\n"
"PO-Revision-Date: 2022-02-17 04:17\n"
"Last-Translator: \n"
"Language-Team: English\n"
@@ -89,20 +89,20 @@ msgstr ""
msgid "Automatic"
msgstr ""
#: documents/models.py:67 documents/models.py:433 documents/models.py:1502
#: documents/models.py:67 documents/models.py:433 documents/models.py:1498
#: paperless_mail/models.py:23 paperless_mail/models.py:143
msgid "name"
msgstr ""
#: documents/models.py:69 documents/models.py:1086
#: documents/models.py:69 documents/models.py:1085
msgid "match"
msgstr ""
#: documents/models.py:72 documents/models.py:1089
#: documents/models.py:72 documents/models.py:1088
msgid "matching algorithm"
msgstr ""
#: documents/models.py:77 documents/models.py:1094
#: documents/models.py:77 documents/models.py:1093
msgid "is insensitive"
msgstr ""
@@ -256,7 +256,7 @@ msgid "The position of this document in your physical document archive."
msgstr ""
#: documents/models.py:295 documents/models.py:737 documents/models.py:791
#: documents/models.py:1545
#: documents/models.py:1541
msgid "document"
msgstr ""
@@ -276,7 +276,7 @@ msgstr ""
msgid "warning"
msgstr ""
#: documents/models.py:387 paperless_mail/models.py:371
#: documents/models.py:387 paperless_mail/models.py:363
msgid "error"
msgstr ""
@@ -320,11 +320,11 @@ msgstr ""
msgid "Title"
msgstr ""
#: documents/models.py:420 documents/models.py:1038
#: documents/models.py:420 documents/models.py:1037
msgid "Created"
msgstr ""
#: documents/models.py:421 documents/models.py:1037
#: documents/models.py:421 documents/models.py:1036
msgid "Added"
msgstr ""
@@ -812,381 +812,377 @@ msgstr ""
msgid "Mail Fetch"
msgstr ""
#: documents/models.py:1034
msgid "Web UI"
msgstr ""
#: documents/models.py:1039
#: documents/models.py:1038
msgid "Modified"
msgstr ""
#: documents/models.py:1040
#: documents/models.py:1039
msgid "Custom Field"
msgstr ""
#: documents/models.py:1043
#: documents/models.py:1042
msgid "Workflow Trigger Type"
msgstr ""
#: documents/models.py:1055
#: documents/models.py:1054
msgid "filter path"
msgstr ""
#: documents/models.py:1060
#: documents/models.py:1059
msgid ""
"Only consume documents with a path that matches this if specified. Wildcards "
"specified as * are allowed. Case insensitive."
msgstr ""
#: documents/models.py:1067
#: documents/models.py:1066
msgid "filter filename"
msgstr ""
#: documents/models.py:1072 paperless_mail/models.py:200
#: documents/models.py:1071 paperless_mail/models.py:200
msgid ""
"Only consume documents which entirely match this filename if specified. "
"Wildcards such as *.pdf or *invoice* are allowed. Case insensitive."
msgstr ""
#: documents/models.py:1083
#: documents/models.py:1082
msgid "filter documents from this mail rule"
msgstr ""
#: documents/models.py:1099
#: documents/models.py:1098
msgid "has these tag(s)"
msgstr ""
#: documents/models.py:1107
#: documents/models.py:1106
msgid "has this document type"
msgstr ""
#: documents/models.py:1115
#: documents/models.py:1114
msgid "has this correspondent"
msgstr ""
#: documents/models.py:1119
#: documents/models.py:1118
msgid "schedule offset days"
msgstr ""
#: documents/models.py:1122
#: documents/models.py:1121
msgid "The number of days to offset the schedule trigger by."
msgstr ""
#: documents/models.py:1127
#: documents/models.py:1126
msgid "schedule is recurring"
msgstr ""
#: documents/models.py:1130
#: documents/models.py:1129
msgid "If the schedule should be recurring."
msgstr ""
#: documents/models.py:1135
#: documents/models.py:1134
msgid "schedule recurring delay in days"
msgstr ""
#: documents/models.py:1139
#: documents/models.py:1138
msgid "The number of days between recurring schedule triggers."
msgstr ""
#: documents/models.py:1144
#: documents/models.py:1143
msgid "schedule date field"
msgstr ""
#: documents/models.py:1149
#: documents/models.py:1148
msgid "The field to check for a schedule trigger."
msgstr ""
#: documents/models.py:1158
#: documents/models.py:1157
msgid "schedule date custom field"
msgstr ""
#: documents/models.py:1162
#: documents/models.py:1161
msgid "workflow trigger"
msgstr ""
#: documents/models.py:1163
#: documents/models.py:1162
msgid "workflow triggers"
msgstr ""
#: documents/models.py:1171
#: documents/models.py:1170
msgid "email subject"
msgstr ""
#: documents/models.py:1175
#: documents/models.py:1174
msgid ""
"The subject of the email, can include some placeholders, see documentation."
msgstr ""
#: documents/models.py:1181
#: documents/models.py:1180
msgid "email body"
msgstr ""
#: documents/models.py:1184
#: documents/models.py:1183
msgid ""
"The body (message) of the email, can include some placeholders, see "
"documentation."
msgstr ""
#: documents/models.py:1190
#: documents/models.py:1189
msgid "emails to"
msgstr ""
#: documents/models.py:1193
#: documents/models.py:1192
msgid "The destination email addresses, comma separated."
msgstr ""
#: documents/models.py:1199
#: documents/models.py:1198
msgid "include document in email"
msgstr ""
#: documents/models.py:1210
#: documents/models.py:1207
msgid "webhook url"
msgstr ""
#: documents/models.py:1213
#: documents/models.py:1209
msgid "The destination URL for the notification."
msgstr ""
#: documents/models.py:1218
#: documents/models.py:1214
msgid "use parameters"
msgstr ""
#: documents/models.py:1223
#: documents/models.py:1219
msgid "send as JSON"
msgstr ""
#: documents/models.py:1227
#: documents/models.py:1223
msgid "webhook parameters"
msgstr ""
#: documents/models.py:1230
#: documents/models.py:1226
msgid "The parameters to send with the webhook URL if body not used."
msgstr ""
#: documents/models.py:1234
#: documents/models.py:1230
msgid "webhook body"
msgstr ""
#: documents/models.py:1237
#: documents/models.py:1233
msgid "The body to send with the webhook URL if parameters not used."
msgstr ""
#: documents/models.py:1241
#: documents/models.py:1237
msgid "webhook headers"
msgstr ""
#: documents/models.py:1244
#: documents/models.py:1240
msgid "The headers to send with the webhook URL."
msgstr ""
#: documents/models.py:1249
#: documents/models.py:1245
msgid "include document in webhook"
msgstr ""
#: documents/models.py:1260
#: documents/models.py:1256
msgid "Assignment"
msgstr ""
#: documents/models.py:1264
#: documents/models.py:1260
msgid "Removal"
msgstr ""
#: documents/models.py:1268 documents/templates/account/password_reset.html:15
#: documents/models.py:1264 documents/templates/account/password_reset.html:15
msgid "Email"
msgstr ""
#: documents/models.py:1272
#: documents/models.py:1268
msgid "Webhook"
msgstr ""
#: documents/models.py:1276
#: documents/models.py:1272
msgid "Workflow Action Type"
msgstr ""
#: documents/models.py:1282
#: documents/models.py:1278
msgid "assign title"
msgstr ""
#: documents/models.py:1287
#: documents/models.py:1283
msgid ""
"Assign a document title, can include some placeholders, see documentation."
msgstr ""
#: documents/models.py:1296 paperless_mail/models.py:274
#: documents/models.py:1292 paperless_mail/models.py:274
msgid "assign this tag"
msgstr ""
#: documents/models.py:1305 paperless_mail/models.py:282
#: documents/models.py:1301 paperless_mail/models.py:282
msgid "assign this document type"
msgstr ""
#: documents/models.py:1314 paperless_mail/models.py:296
#: documents/models.py:1310 paperless_mail/models.py:296
msgid "assign this correspondent"
msgstr ""
#: documents/models.py:1323
#: documents/models.py:1319
msgid "assign this storage path"
msgstr ""
#: documents/models.py:1332
#: documents/models.py:1328
msgid "assign this owner"
msgstr ""
#: documents/models.py:1339
#: documents/models.py:1335
msgid "grant view permissions to these users"
msgstr ""
#: documents/models.py:1346
#: documents/models.py:1342
msgid "grant view permissions to these groups"
msgstr ""
#: documents/models.py:1353
#: documents/models.py:1349
msgid "grant change permissions to these users"
msgstr ""
#: documents/models.py:1360
#: documents/models.py:1356
msgid "grant change permissions to these groups"
msgstr ""
#: documents/models.py:1367
#: documents/models.py:1363
msgid "assign these custom fields"
msgstr ""
#: documents/models.py:1374
#: documents/models.py:1370
msgid "remove these tag(s)"
msgstr ""
#: documents/models.py:1379
#: documents/models.py:1375
msgid "remove all tags"
msgstr ""
#: documents/models.py:1386
#: documents/models.py:1382
msgid "remove these document type(s)"
msgstr ""
#: documents/models.py:1391
#: documents/models.py:1387
msgid "remove all document types"
msgstr ""
#: documents/models.py:1398
#: documents/models.py:1394
msgid "remove these correspondent(s)"
msgstr ""
#: documents/models.py:1403
#: documents/models.py:1399
msgid "remove all correspondents"
msgstr ""
#: documents/models.py:1410
#: documents/models.py:1406
msgid "remove these storage path(s)"
msgstr ""
#: documents/models.py:1415
#: documents/models.py:1411
msgid "remove all storage paths"
msgstr ""
#: documents/models.py:1422
#: documents/models.py:1418
msgid "remove these owner(s)"
msgstr ""
#: documents/models.py:1427
#: documents/models.py:1423
msgid "remove all owners"
msgstr ""
#: documents/models.py:1434
#: documents/models.py:1430
msgid "remove view permissions for these users"
msgstr ""
#: documents/models.py:1441
#: documents/models.py:1437
msgid "remove view permissions for these groups"
msgstr ""
#: documents/models.py:1448
#: documents/models.py:1444
msgid "remove change permissions for these users"
msgstr ""
#: documents/models.py:1455
#: documents/models.py:1451
msgid "remove change permissions for these groups"
msgstr ""
#: documents/models.py:1460
#: documents/models.py:1456
msgid "remove all permissions"
msgstr ""
#: documents/models.py:1467
#: documents/models.py:1463
msgid "remove these custom fields"
msgstr ""
#: documents/models.py:1472
#: documents/models.py:1468
msgid "remove all custom fields"
msgstr ""
#: documents/models.py:1481
#: documents/models.py:1477
msgid "email"
msgstr ""
#: documents/models.py:1490
#: documents/models.py:1486
msgid "webhook"
msgstr ""
#: documents/models.py:1494
#: documents/models.py:1490
msgid "workflow action"
msgstr ""
#: documents/models.py:1495
#: documents/models.py:1491
msgid "workflow actions"
msgstr ""
#: documents/models.py:1504 paperless_mail/models.py:145
#: documents/models.py:1500 paperless_mail/models.py:145
msgid "order"
msgstr ""
#: documents/models.py:1510
#: documents/models.py:1506
msgid "triggers"
msgstr ""
#: documents/models.py:1517
#: documents/models.py:1513
msgid "actions"
msgstr ""
#: documents/models.py:1520 paperless_mail/models.py:154
#: documents/models.py:1516 paperless_mail/models.py:154
msgid "enabled"
msgstr ""
#: documents/models.py:1531
#: documents/models.py:1527
msgid "workflow"
msgstr ""
#: documents/models.py:1535
#: documents/models.py:1531
msgid "workflow trigger type"
msgstr ""
#: documents/models.py:1549
#: documents/models.py:1545
msgid "date run"
msgstr ""
#: documents/models.py:1555
#: documents/models.py:1551
msgid "workflow run"
msgstr ""
#: documents/models.py:1556
#: documents/models.py:1552
msgid "workflow runs"
msgstr ""
#: documents/serialisers.py:128
#: documents/serialisers.py:127
#, python-format
msgid "Invalid regular expression: %(error)s"
msgstr ""
#: documents/serialisers.py:554
#: documents/serialisers.py:553
msgid "Invalid color."
msgstr ""
#: documents/serialisers.py:1570
#: documents/serialisers.py:1554
#, python-format
msgid "File type %(type)s not supported"
msgstr ""
#: documents/serialisers.py:1659
#: documents/serialisers.py:1643
msgid "Invalid variable detected."
msgstr ""
@@ -1406,23 +1402,17 @@ msgstr ""
msgid "As a final step, please complete the following form:"
msgstr ""
#: documents/validators.py:24
#: documents/validators.py:17
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#: documents/validators.py:22
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36
msgid ""
"URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '."
"join(allowed_schemes)}"
msgstr ""
#: documents/validators.py:45
#: documents/validators.py:27
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr ""
@@ -1711,7 +1701,7 @@ msgstr ""
msgid "Chinese Traditional"
msgstr ""
#: paperless/urls.py:369
#: paperless/urls.py:364
msgid "Paperless-ngx administration"
msgstr ""
@@ -1943,7 +1933,7 @@ msgstr ""
msgid "account"
msgstr ""
#: paperless_mail/models.py:157 paperless_mail/models.py:326
#: paperless_mail/models.py:157 paperless_mail/models.py:318
msgid "folder"
msgstr ""
@@ -2035,32 +2025,22 @@ msgstr ""
msgid "Assign the rule owner to documents"
msgstr ""
#: paperless_mail/models.py:305
msgid "Stop processing further rules"
msgstr ""
#: paperless_mail/models.py:308
msgid ""
"If True, no further rules will be processed after this one if any document "
"is queued."
msgstr ""
#: paperless_mail/models.py:334
#: paperless_mail/models.py:326
msgid "uid"
msgstr ""
#: paperless_mail/models.py:342
#: paperless_mail/models.py:334
msgid "subject"
msgstr ""
#: paperless_mail/models.py:350
#: paperless_mail/models.py:342
msgid "received"
msgstr ""
#: paperless_mail/models.py:357
#: paperless_mail/models.py:349
msgid "processed"
msgstr ""
#: paperless_mail/models.py:363
#: paperless_mail/models.py:355
msgid "status"
msgstr ""

View File

@@ -571,11 +571,6 @@ class MailAccountHandler(LoggingMixin):
rule,
supports_gmail_labels=supports_gmail_labels,
)
if total_processed_files > 0 and rule.stop_processing:
self.log.debug(
f"Rule {rule}: Stopping processing rules due to stop_processing flag",
)
break
except Exception as e:
self.log.exception(
f"Rule {rule}: Error while processing rule: {e}",

View File

@@ -1,22 +0,0 @@
# Generated by Django 5.1.6 on 2025-02-24 16:07
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("paperless_mail", "0029_mailrule_pdf_layout"),
]
operations = [
migrations.AddField(
model_name="mailrule",
name="stop_processing",
field=models.BooleanField(
default=False,
help_text="If True, no further rules will be processed after this one if any document is consumed.",
verbose_name="Stop processing further rules",
),
),
]

View File

@@ -301,14 +301,6 @@ class MailRule(document_models.ModelWithOwner):
default=True,
)
stop_processing = models.BooleanField(
_("Stop processing further rules"),
default=False,
help_text=_(
"If True, no further rules will be processed after this one if any document is queued.",
),
)
def __str__(self):
return f"{self.account.name}.{self.name}"

View File

@@ -101,7 +101,6 @@ class MailRuleSerializer(OwnedObjectSerializer):
"user_can_change",
"permissions",
"set_permissions",
"stop_processing",
]
def update(self, instance, validated_data):

View File

@@ -1671,39 +1671,6 @@ class TestTasks(TestCase):
result = tasks.process_mail_accounts(account_ids=[account_b.id])
self.assertIn("No new", result)
@mock.patch("paperless_mail.tasks.MailAccountHandler.handle_mail_account")
def test_rule_with_stop_processing(self, m):
"""
GIVEN:
- Mail account with a rule with stop_processing=True
WHEN:
- Mail account is processed
THEN:
- Should only process the first rule
"""
m.side_effect = lambda account: 6
account = MailAccount.objects.create(
name="A",
imap_server="A",
username="A",
password="A",
)
MailRule.objects.create(
name="A",
account=account,
stop_processing=True,
)
MailRule.objects.create(
name="B",
account=account,
)
result = tasks.process_mail_accounts()
self.assertEqual(m.call_count, 1)
self.assertIn("Added 6", result)
class TestMailAccountTestView(APITestCase):
def setUp(self):