Compare commits

...

49 Commits

Author SHA1 Message Date
Trenton H
864e242ed9 Bumps version to 1.14.1 2023-04-27 07:12:44 -07:00
Trenton H
8f18baea8f Merge remote-tracking branch 'origin/dev' 2023-04-27 07:10:04 -07:00
Paperless-ngx Bot [bot]
130489a1a9 New Crowdin updates (#3175)
* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (French)
[ci skip]
2023-04-27 07:08:48 -07:00
shamoon
88a5a2049b Dont perform permissions queries by default 2023-04-27 07:06:49 -07:00
shamoon
15fb3e5328 Remove debug line 2023-04-27 01:24:22 -07:00
shamoon
90b800b030 Merge pull request #3199 from paperless-ngx/fix/issue-3197
Fix: permissions-aware statistics
2023-04-26 10:47:18 -07:00
shamoon
be88ad2676 Merge pull request #3198 from paperless-ngx/fix/issue-3196
Fix: Use document owner for matching if set
2023-04-26 10:46:43 -07:00
shamoon
dfadfc0f13 Respect permissions for statistics 2023-04-26 09:51:26 -07:00
shamoon
5ae48c8012 Use document owner for matching if set 2023-04-26 09:42:03 -07:00
Trenton H
6f163111ce Upgrades black to v23, upgrades ruff 2023-04-26 09:35:27 -07:00
Trenton H
3bcbd05252 Fixes ruff not running isort against the codebase 2023-04-26 09:35:27 -07:00
shamoon
e0d2697618 Merge pull request #3174 from paperless-ngx/fix/issue-3172
Fix: respect permissions on document view actions
2023-04-26 09:10:58 -07:00
shamoon
7340535b9a Remove outdated owner field from post_document docs 2023-04-26 08:50:42 -07:00
shamoon
c385355c2b Merge pull request #3191 from paperless-ngx/fix/increment-api-version
Increment API version for 1.14.1+
2023-04-26 08:36:39 -07:00
shamoon
a119790697 Merge pull request #3189 from paperless-ngx/fix/issue-3178 2023-04-26 08:20:19 -07:00
shamoon
e392098e35 Merge pull request #3190 from paperless-ngx/fix/issue-3167 2023-04-26 08:18:39 -07:00
Trenton H
a2d4d16867 Make the importer a little more robust against some types of errors 2023-04-26 07:08:50 -07:00
shamoon
7f74a85400 Increment API version for 1.14.1+ 2023-04-25 23:44:36 -07:00
shamoon
1fc9eaf360 Merge pull request #3163 from paperless-ngx/fix/issue-3162
Fix: Specify backend for auto-login
2023-04-25 23:40:33 -07:00
shamoon
1898f9b183 Add gnu-sed note for macOS 2023-04-25 23:37:22 -07:00
shamoon
1fb03a755f Respect permissions on document view actions 2023-04-25 22:49:37 -07:00
shamoon
8a505e3b66 Specify backend for auto-login 2023-04-25 22:15:21 -07:00
shamoon
45ecec5623 Fix dropdown Private items with empty set 2023-04-25 22:06:16 -07:00
Trenton H
b34dfcd72f Fixes StoragePath missing the owned or granted filter 2023-04-25 18:48:22 -07:00
Trenton H
319aa39925 Selectivly upgrade redis-py to resolve issues with socket connections 2023-04-25 10:03:41 -07:00
shamoon
08ac40dd48 Merge pull request #3161 from paperless-ngx/fix/issue-3160
Fix: Handle delete mail action with no filters
2023-04-25 08:11:23 -07:00
shamoon
0a0dc25e15 Merge pull request #3171 from FizzyMUC/fix-documentation
Fix typos and wrong version number in doc
2023-04-25 07:48:18 -07:00
shamoon
0557a15fa8 Update src/paperless_mail/mail.py with code suggestions
Co-authored-by: Trenton H <797416+stumpylog@users.noreply.github.com>
2023-04-25 07:22:16 -07:00
pascal
c5fafdda11 Fix typos and wrong version number in doc 2023-04-25 16:22:16 +02:00
shamoon
434d1fe225 Handle delete mail action with no filters 2023-04-24 20:55:01 -07:00
shamoon
405769dc97 Update environment.prod.ts 2023-04-24 13:10:35 -07:00
shamoon
ffa116bf44 Merge branch 'main' into dev 2023-04-24 13:10:18 -07:00
shamoon
6b1d8cabf4 Remove hidden Admin button from screenshots 2023-04-24 13:06:27 -07:00
shamoon
20c21e9e65 Merge pull request #3159 from paperless-ngx/v1.14.0-changelog
[Documentation] Add v1.14.0 changelog
2023-04-24 13:05:19 -07:00
github-actions
088743a155 Changelog v1.14.0 - GHA 2023-04-24 19:59:27 +00:00
Paperless-ngx Bot [bot]
2b244165e2 New Crowdin updates (#3123)
* New translations django.po (Catalan)
[ci skip]

* New translations django.po (Catalan)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations django.po (German)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations django.po (Indonesian)
[ci skip]

* New translations django.po (Catalan)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations django.po (Catalan)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations django.po (Catalan)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations django.po (Catalan)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations django.po (Catalan)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations django.po (Catalan)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]
2023-04-24 12:00:59 -07:00
shamoon
0dcfb97824 Merge pull request #3146 from paperless-ngx/feature-catalan-translation
Feature: Catalan translation
2023-04-22 09:34:33 -07:00
shamoon
50af671e02 Add Catalan translation 2023-04-22 09:34:33 -07:00
shamoon
3241968626 Update frontend strings 2023-04-22 09:23:50 -07:00
shamoon
bf1e49fc4c Merge pull request #3105 from dcava/dev 2023-04-18 21:02:11 -07:00
shamoon
d1984c0dda Update testing for ignore macOS directory services file 2023-04-18 19:10:03 -07:00
David Cavallucci
22bb28db62 Changed consumer ignore files pattern for .DS_STORE, .DS_Store 2023-04-18 19:10:03 -07:00
Paperless-ngx Bot [bot]
edf4f98d41 New Crowdin updates (#3015)
* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations django.po (Spanish)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations django.po (Spanish)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations django.po (German)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations django.po (Czech)
[ci skip]

* New translations django.po (Indonesian)
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations django.po (Indonesian)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations django.po (Polish)
[ci skip]

* New translations django.po (Polish)
[ci skip]

* New translations django.po (Indonesian)
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations django.po (Catalan)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations django.po (Catalan)
[ci skip]

* New translations django.po (Catalan)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations django.po (French)
[ci skip]

* New translations django.po (Indonesian)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]
2023-04-17 19:58:58 -07:00
shamoon
7321ea1603 Update messages.xlf 2023-04-17 19:56:20 -07:00
shamoon
b80c2126a3 Fix multi-select with private items 2023-04-17 19:56:20 -07:00
shamoon
f5d6a9f428 Use stale action & merge with lock action 2023-04-17 13:27:47 -07:00
shamoon
930bac3c8b Change lock old threads to once daily 2023-04-17 12:43:27 -07:00
shamoon
dd8514a84d Update lock.yml 2023-04-16 19:25:29 -07:00
shamoon
7bcfeab85c Merge branch 'main' into dev 2023-04-16 17:14:24 -07:00
221 changed files with 1144 additions and 811 deletions

View File

@@ -200,7 +200,6 @@ class RegistryTagsCleaner:
tag,
)
for manifest in image_index.image_pointers:
if manifest.digest in untagged_versions:
logger.info(
f"Skipping deletion of {manifest.digest},"
@@ -287,7 +286,6 @@ class RegistryTagsCleaner:
logger.info("Beginning confirmation step")
a_tag_failed = False
for tag in sorted(self.tags_to_keep):
try:
image_index = ImageIndex(
f"ghcr.io/{self.repo_owner}/{self.package_name}",
@@ -301,7 +299,6 @@ class RegistryTagsCleaner:
digest_name = f"ghcr.io/{self.repo_owner}/{self.package_name}@{manifest.digest}"
try:
subprocess.run(
[
shutil.which("docker"),

View File

@@ -37,16 +37,16 @@ repos:
exclude: "(^Pipfile\\.lock$)"
# Python hooks
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: 'v0.0.259'
rev: 'v0.0.263'
hooks:
- id: ruff
- repo: https://github.com/psf/black
rev: 22.12.0
rev: 23.3.0
hooks:
- id: black
# Dockerfile hooks
- repo: https://github.com/AleksaC/hadolint-py
rev: v2.10.0
rev: v2.12.0.2
hooks:
- id: hadolint
# Shell script hooks

View File

@@ -1,6 +1,6 @@
# https://beta.ruff.rs/docs/settings/
# https://beta.ruff.rs/docs/rules/
select = ["F", "E", "W", "UP", "COM", "DJ", "EXE", "ISC", "ICN", "G201", "INP", "PIE", "RSE", "SIM", "TID", "PLC", "PLE", "RUF"]
extend-select = ["I", "W", "UP", "COM", "DJ", "EXE", "ISC", "ICN", "G201", "INP", "PIE", "RSE", "SIM", "TID", "PLC", "PLE", "RUF"]
# TODO PTH
ignore = ["DJ001", "SIM105"]
fix = true

112
Pipfile.lock generated
View File

@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "8395f25f876a71a7307a55dd542e69a4cdcb3be3be38c4e89ed06ce3d52a5345"
"sha256": "77248fee6dad10b9e5189e9ba80f7c506c9f49c875bac8b259e90dadecba03f1"
},
"pipfile-spec": 6,
"requires": {},
@@ -1508,11 +1508,11 @@
"hiredis"
],
"hashes": [
"sha256:56732e156fe31801c4f43396bd3ca0c2a7f6f83d7936798531b9848d103381aa",
"sha256:7df17a0a2b72a4c8895b462dd07616c51b1dcb48fdd7ecb7b6f4bf39ecb2e94e"
"sha256:2c19e6767c474f2e85167909061d525ed65bea9301c0770bb151e041b7ac89a2",
"sha256:73ec35da4da267d6847e47f68730fdd5f62e2ca69e3ef5885c6a78a9374c3893"
],
"index": "pypi",
"version": "==4.5.3"
"version": "==4.5.4"
},
"regex": {
"hashes": [
@@ -2256,34 +2256,35 @@
},
"black": {
"hashes": [
"sha256:0052dba51dec07ed029ed61b18183942043e00008ec65d5028814afaab9a22fd",
"sha256:0680d4380db3719ebcfb2613f34e86c8e6d15ffeabcf8ec59355c5e7b85bb555",
"sha256:121ca7f10b4a01fd99951234abdbd97728e1240be89fde18480ffac16503d481",
"sha256:162e37d49e93bd6eb6f1afc3e17a3d23a823042530c37c3c42eeeaf026f38468",
"sha256:2a951cc83ab535d248c89f300eccbd625e80ab880fbcfb5ac8afb5f01a258ac9",
"sha256:2bf649fda611c8550ca9d7592b69f0637218c2369b7744694c5e4902873b2f3a",
"sha256:382998821f58e5c8238d3166c492139573325287820963d2f7de4d518bd76958",
"sha256:49f7b39e30f326a34b5c9a4213213a6b221d7ae9d58ec70df1c4a307cf2a1580",
"sha256:57c18c5165c1dbe291d5306e53fb3988122890e57bd9b3dcb75f967f13411a26",
"sha256:7a0f701d314cfa0896b9001df70a530eb2472babb76086344e688829efd97d32",
"sha256:8178318cb74f98bc571eef19068f6ab5613b3e59d4f47771582f04e175570ed8",
"sha256:8b70eb40a78dfac24842458476135f9b99ab952dd3f2dab738c1881a9b38b753",
"sha256:9880d7d419bb7e709b37e28deb5e68a49227713b623c72b2b931028ea65f619b",
"sha256:9afd3f493666a0cd8f8df9a0200c6359ac53940cbde049dcb1a7eb6ee2dd7074",
"sha256:a29650759a6a0944e7cca036674655c2f0f63806ddecc45ed40b7b8aa314b651",
"sha256:a436e7881d33acaf2536c46a454bb964a50eff59b21b51c6ccf5a40601fbef24",
"sha256:a59db0a2094d2259c554676403fa2fac3473ccf1354c1c63eccf7ae65aac8ab6",
"sha256:a8471939da5e824b891b25751955be52ee7f8a30a916d570a5ba8e0f2eb2ecad",
"sha256:b0bd97bea8903f5a2ba7219257a44e3f1f9d00073d6cc1add68f0beec69692ac",
"sha256:b6a92a41ee34b883b359998f0c8e6eb8e99803aa8bf3123bf2b2e6fec505a221",
"sha256:bb460c8561c8c1bec7824ecbc3ce085eb50005883a6203dcfb0122e95797ee06",
"sha256:bfffba28dc52a58f04492181392ee380e95262af14ee01d4bc7bb1b1c6ca8d27",
"sha256:c1c476bc7b7d021321e7d93dc2cbd78ce103b84d5a4cf97ed535fbc0d6660648",
"sha256:c91dfc2c2a4e50df0026f88d2215e166616e0c80e86004d0003ece0488db2739",
"sha256:e6663f91b6feca5d06f2ccd49a10f254f9298cc1f7f49c46e498a0771b507104"
"sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5",
"sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915",
"sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326",
"sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940",
"sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b",
"sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30",
"sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c",
"sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c",
"sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab",
"sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27",
"sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2",
"sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961",
"sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9",
"sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb",
"sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70",
"sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331",
"sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2",
"sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266",
"sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d",
"sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6",
"sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b",
"sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925",
"sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8",
"sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4",
"sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3"
],
"index": "pypi",
"version": "==23.1.0"
"markers": "python_version >= '3.7'",
"version": "==23.3.0"
},
"certifi": {
"hashes": [
@@ -2718,11 +2719,11 @@
},
"packaging": {
"hashes": [
"sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2",
"sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"
"sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61",
"sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"
],
"markers": "python_version >= '3.7'",
"version": "==23.0"
"version": "==23.1"
},
"pathspec": {
"hashes": [
@@ -2817,11 +2818,11 @@
},
"platformdirs": {
"hashes": [
"sha256:024996549ee88ec1a9aa99ff7f8fc819bb59e2c3477b410d90a16d32d6e707aa",
"sha256:e5986afb596e4bb5bde29a79ac9061aa955b94fca2399b7aaac4090860920dd8"
"sha256:64370d47dc3fca65b4879f89bdead8197e93e05d696d6d1816243ebae8595da5",
"sha256:ea61fd7b85554beecbbd3e9b37fb26689b227ffae38f73353cbcc1cf8bd01878"
],
"markers": "python_version >= '3.7'",
"version": "==3.1.1"
"version": "==3.3.0"
},
"pluggy": {
"hashes": [
@@ -3071,26 +3072,27 @@
},
"ruff": {
"hashes": [
"sha256:22e1e35bf5f12072cd644d22afd9203641ccf258bc14ff91aa1c43dc14f6047d",
"sha256:29e2b77b7d5da6a7dd5cf9b738b511355c5734ece56f78e500d4b5bffd58c1a0",
"sha256:38704f151323aa5858370a2f792e122cc25e5d1aabe7d42ceeab83da18f0b456",
"sha256:40ae87f2638484b7e8a7567b04a7af719f1c484c5bf132038b702bb32e1f6577",
"sha256:428507fb321b386dda70d66cd1a8aa0abf51d7c197983d83bb9e4fa5ee60300b",
"sha256:49e903bcda19f6bb0725a962c058eb5d61f40d84ef52ed53b61939b69402ab4e",
"sha256:5b3c1beacf6037e7f0781d4699d9a2dd4ba2462f475be5b1f45cf84c4ba3c69d",
"sha256:71f0ef1985e9a6696fa97da8459917fa34bdaa2c16bd33bd5edead585b7d44f7",
"sha256:79b02fa17ec1fd8d306ae302cb47fb614b71e1f539997858243769bcbe78c6d9",
"sha256:7cfef26619cba184d59aa7fa17b48af5891d51fc0b755a9bc533478a10d4d066",
"sha256:8b56496063ab3bfdf72339a5fbebb8bd46e5c5fee25ef11a9f03b208fa0562ec",
"sha256:aa9449b898287e621942cc71b9327eceb8f0c357e4065fecefb707ef2d978df8",
"sha256:c5fbaea9167f1852757f02133e5daacdb8c75b3431343205395da5b10499927a",
"sha256:d2fb20e89e85d147c85caa807707a1488bccc1f3854dc3d53533e89b52a0c5ff",
"sha256:daaea322e7e85f4c13d82be9536309e1c4b8b9851bb0cbc7eeb15d490fd46bf9",
"sha256:e4f39e18702de69faaaee3969934b92d7467285627f99a5b6ecd55a7d9f5d086",
"sha256:f3938dc45e2a3f818e9cbd53007265c22246fbfded8837b2c563bf0ebde1a226"
"sha256:04e0b280dd246448564c892bce5607d820ad1f14944f3d535db98692e2a7ac07",
"sha256:1008f211ad8aa1d998517ac5bf3d68fbc68ec516d1da89b6081f25ff2f30b687",
"sha256:15386933dd8e03aafa3186f9e996d6823105492817311338fbcb64d0ecbcd95f",
"sha256:3e9fcee3f81129eabc75da005d839235e32d7d374f2d4c0db0c708dad4703d6e",
"sha256:4010b156f2e9fa6e74b5581098467f6ff68beac48945599b3a9239481e578ab4",
"sha256:4f75fa1632ea065b8f10678e7b6ae9873f84d5046bdf146990112751e98af42a",
"sha256:7890499c2c3dcb1e60de2a8b4c5f5775b2bfcdff7d3e68e38db5cb2d65b12006",
"sha256:82c41f276106017b6f075dd2f2cc68e1a0b434cc75488f816fc98bd41982628d",
"sha256:981e3c4d773f7ff52479c4fd74a65e408f1e13fa5f889b72214d400cd1299ce4",
"sha256:9af932f665e177de62e172901704257fd6e5bfabb95893867ff7382a851459d3",
"sha256:bed1d3fba306e3f7e13ce226927b84200350e25abd1e754e06ee361c6d41de15",
"sha256:c2b79919ebd93674b93dfc2c843e264bf8e52fbe737467e9b58521775c85f4ad",
"sha256:c3b7d4b365207f3e4c40d235127091478e595b31e35b6cd57d940920cdfae68b",
"sha256:ddcee0d91629a4fa4bc9faebf5b94d4615d50d1cd76d1098fa71fbe1c54f4104",
"sha256:ddf4503595b560bfa5fae92fa2e4cb09ec465ee4cf88cc248f10ad2e956deec3",
"sha256:ebc778d95f29c9917e6e7608b2b67815707e6ab8eb5af9341617beda479c3edf",
"sha256:ee6c7a77f142c427fa73e1f5f603fc1a39413a36fe6966ed0fc55e97f6921d9c"
],
"index": "pypi",
"version": "==0.0.259"
"markers": "python_version >= '3.7'",
"version": "==0.0.263"
},
"scipy": {
"hashes": [
@@ -3158,7 +3160,7 @@
"sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb",
"sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"
],
"markers": "python_version >= '3.7'",
"markers": "python_version < '3.10'",
"version": "==4.5.0"
},
"urllib3": {

View File

@@ -12,7 +12,6 @@ from typing import Final
from redis import Redis
if __name__ == "__main__":
MAX_RETRY_COUNT: Final[int] = 5
RETRY_SLEEP_SECONDS: Final[int] = 5

View File

@@ -257,7 +257,6 @@ The endpoint supports the following optional form fields:
- `document_type`: Similar to correspondent.
- `tags`: Similar to correspondent. Specify this multiple times to
have multiple tags added to the document.
- `owner`: An optional user ID to set as the owner.
- `archive_serial_number`: An optional archive serial number to set.
The endpoint will immediately return HTTP 200 if the document consumption

Binary file not shown.

Before

Width:  |  Height:  |  Size: 661 KiB

After

Width:  |  Height:  |  Size: 740 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 KiB

After

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 890 KiB

After

Width:  |  Height:  |  Size: 704 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 KiB

After

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 608 KiB

After

Width:  |  Height:  |  Size: 616 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 698 KiB

After

Width:  |  Height:  |  Size: 708 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 706 KiB

After

Width:  |  Height:  |  Size: 705 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 480 KiB

After

Width:  |  Height:  |  Size: 480 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 680 KiB

After

Width:  |  Height:  |  Size: 689 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 686 KiB

After

Width:  |  Height:  |  Size: 685 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 848 KiB

After

Width:  |  Height:  |  Size: 859 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 703 KiB

After

Width:  |  Height:  |  Size: 706 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 388 KiB

After

Width:  |  Height:  |  Size: 393 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 517 KiB

After

Width:  |  Height:  |  Size: 516 KiB

View File

@@ -1,5 +1,188 @@
# Changelog
## paperless-ngx 1.14.0
### Notable Changes
- Feature: multi-user permissions [@shamoon](https://github.com/shamoon) ([#2147](https://github.com/paperless-ngx/paperless-ngx/pull/2147))
### Features
- Feature: Stronger typing for file consumption [@stumpylog](https://github.com/stumpylog) ([#2744](https://github.com/paperless-ngx/paperless-ngx/pull/2744))
- Feature: double-click docs [@shamoon](https://github.com/shamoon) ([#2966](https://github.com/paperless-ngx/paperless-ngx/pull/2966))
- feature: Add support for zxing as barcode scanning lib [@margau](https://github.com/margau) ([#2907](https://github.com/paperless-ngx/paperless-ngx/pull/2907))
- Feature: Enable images to be released on Quay.io [@stumpylog](https://github.com/stumpylog) ([#2972](https://github.com/paperless-ngx/paperless-ngx/pull/2972))
- Feature: test mail account [@shamoon](https://github.com/shamoon) ([#2949](https://github.com/paperless-ngx/paperless-ngx/pull/2949))
- Feature: Capture celery and kombu logs to a file [@stumpylog](https://github.com/stumpylog) ([#2954](https://github.com/paperless-ngx/paperless-ngx/pull/2954))
- Fix: Resolve Redis connection issues with ACLs [@stumpylog](https://github.com/stumpylog) ([#2939](https://github.com/paperless-ngx/paperless-ngx/pull/2939))
- Feature: Allow mail account to use access tokens [@stumpylog](https://github.com/stumpylog) ([#2930](https://github.com/paperless-ngx/paperless-ngx/pull/2930))
- Fix: Consumer polling could overwhelm database [@stumpylog](https://github.com/stumpylog) ([#2922](https://github.com/paperless-ngx/paperless-ngx/pull/2922))
- Feature: Improved statistics widget [@shamoon](https://github.com/shamoon) ([#2910](https://github.com/paperless-ngx/paperless-ngx/pull/2910))
- Enhancement: rename comments to notes and improve notes UI [@shamoon](https://github.com/shamoon) ([#2904](https://github.com/paperless-ngx/paperless-ngx/pull/2904))
- Allow psql client certificate authentication [@Ongy](https://github.com/Ongy) ([#2899](https://github.com/paperless-ngx/paperless-ngx/pull/2899))
- Enhancement: support filtering multiple correspondents, doctypes \& storage paths [@shamoon](https://github.com/shamoon) ([#2893](https://github.com/paperless-ngx/paperless-ngx/pull/2893))
- Feature: Change celery serializer to pickle [@stumpylog](https://github.com/stumpylog) ([#2861](https://github.com/paperless-ngx/paperless-ngx/pull/2861))
- Feature: Allow naming to include owner and original name [@stumpylog](https://github.com/stumpylog) ([#2873](https://github.com/paperless-ngx/paperless-ngx/pull/2873))
- Feature: Allows filtering email by the TO value(s) as well [@stumpylog](https://github.com/stumpylog) ([#2871](https://github.com/paperless-ngx/paperless-ngx/pull/2871))
- Feature: owner-aware unique model name constraint [@shamoon](https://github.com/shamoon) ([#2827](https://github.com/paperless-ngx/paperless-ngx/pull/2827))
- Feature/2396 better mail actions [@jonaswinkler](https://github.com/jonaswinkler) ([#2718](https://github.com/paperless-ngx/paperless-ngx/pull/2718))
- Feature: Reduce classifier memory usage somewhat during training [@stumpylog](https://github.com/stumpylog) ([#2733](https://github.com/paperless-ngx/paperless-ngx/pull/2733))
- Feature: Add PAPERLESS_OCR_SKIP_ARCHIVE_FILE config setting [@bdr99](https://github.com/bdr99) ([#2743](https://github.com/paperless-ngx/paperless-ngx/pull/2743))
- Feature: dynamic document counts in dropdowns [@shamoon](https://github.com/shamoon) ([#2704](https://github.com/paperless-ngx/paperless-ngx/pull/2704))
- Allow setting the ASN on document upload [@stumpylog](https://github.com/stumpylog) ([#2713](https://github.com/paperless-ngx/paperless-ngx/pull/2713))
- Feature: Log failed login attempts [@shamoon](https://github.com/shamoon) ([#2359](https://github.com/paperless-ngx/paperless-ngx/pull/2359))
- Feature: Rename documents when storage path format changes [@stumpylog](https://github.com/stumpylog) ([#2696](https://github.com/paperless-ngx/paperless-ngx/pull/2696))
- Feature: update error message colors \& show on document failures [@shamoon](https://github.com/shamoon) ([#2689](https://github.com/paperless-ngx/paperless-ngx/pull/2689))
- Feature: multi-user permissions [@shamoon](https://github.com/shamoon) ([#2147](https://github.com/paperless-ngx/paperless-ngx/pull/2147))
### Bug Fixes
- Fix: Allow setting additional Django settings for proxies [@stumpylog](https://github.com/stumpylog) ([#3135](https://github.com/paperless-ngx/paperless-ngx/pull/3135))
- Fix: Use exclude instead of difference for mariadb [@shamoon](https://github.com/shamoon) ([#2983](https://github.com/paperless-ngx/paperless-ngx/pull/2983))
- Fix: permissions display should not show users with inherited permissions \& unable to change owner [@shamoon](https://github.com/shamoon) ([#2818](https://github.com/paperless-ngx/paperless-ngx/pull/2818))
- Fix: Resolve Redis connection issues with ACLs [@stumpylog](https://github.com/stumpylog) ([#2939](https://github.com/paperless-ngx/paperless-ngx/pull/2939))
- Fix: unable to edit correspondents (in ) [@shamoon](https://github.com/shamoon) ([#2938](https://github.com/paperless-ngx/paperless-ngx/pull/2938))
- Fix: Consumer polling could overwhelm database [@stumpylog](https://github.com/stumpylog) ([#2922](https://github.com/paperless-ngx/paperless-ngx/pull/2922))
- Fix: Chrome struggles with commas [@stumpylog](https://github.com/stumpylog) ([#2892](https://github.com/paperless-ngx/paperless-ngx/pull/2892))
- Fix formatting in Setup documentation page [@igrybkov](https://github.com/igrybkov) ([#2880](https://github.com/paperless-ngx/paperless-ngx/pull/2880))
- Fix: logout on change password via frontend [@shamoon](https://github.com/shamoon) ([#2863](https://github.com/paperless-ngx/paperless-ngx/pull/2863))
- Fix: give superuser full doc perms [@shamoon](https://github.com/shamoon) ([#2820](https://github.com/paperless-ngx/paperless-ngx/pull/2820))
- Fix: Append Gmail labels instead of replacing [@stumpylog](https://github.com/stumpylog) ([#2860](https://github.com/paperless-ngx/paperless-ngx/pull/2860))
- Fix: Ensure email date is made aware during action processing [@stumpylog](https://github.com/stumpylog) ([#2837](https://github.com/paperless-ngx/paperless-ngx/pull/2837))
- Fix: disable bulk edit dialog buttons during operation [@shamoon](https://github.com/shamoon) ([#2819](https://github.com/paperless-ngx/paperless-ngx/pull/2819))
- fix database locked error [@jonaswinkler](https://github.com/jonaswinkler) ([#2808](https://github.com/paperless-ngx/paperless-ngx/pull/2808))
- Fix: Disable suggestions for read-only docs [@shamoon](https://github.com/shamoon) ([#2813](https://github.com/paperless-ngx/paperless-ngx/pull/2813))
- Update processed mail migration [@shamoon](https://github.com/shamoon) ([#2804](https://github.com/paperless-ngx/paperless-ngx/pull/2804))
- Fix: Ensure scratch directory exists before using [@stumpylog](https://github.com/stumpylog) ([#2775](https://github.com/paperless-ngx/paperless-ngx/pull/2775))
- Don't submit owner via API on document upload [@jonaswinkler](https://github.com/jonaswinkler) ([#2777](https://github.com/paperless-ngx/paperless-ngx/pull/2777))
- Fix: only offer log files that exist [@shamoon](https://github.com/shamoon) ([#2739](https://github.com/paperless-ngx/paperless-ngx/pull/2739))
- Fix: permissions editing and initial view issues [@shamoon](https://github.com/shamoon) ([#2717](https://github.com/paperless-ngx/paperless-ngx/pull/2717))
- Fix: reset saved view ID on quickFilter [@shamoon](https://github.com/shamoon) ([#2703](https://github.com/paperless-ngx/paperless-ngx/pull/2703))
- Fix: bulk edit reset apply button state [@shamoon](https://github.com/shamoon) ([#2701](https://github.com/paperless-ngx/paperless-ngx/pull/2701))
- Fix: add missing i18n for mobile preview tab title [@nathanaelhoun](https://github.com/nathanaelhoun) ([#2692](https://github.com/paperless-ngx/paperless-ngx/pull/2692))
### Documentation
- Whitespace changes, making sure the example is correcly aligned [@denilsonsa](https://github.com/denilsonsa) ([#3089](https://github.com/paperless-ngx/paperless-ngx/pull/3089))
- Docs: Include additional information about barcodes [@stumpylog](https://github.com/stumpylog) ([#2889](https://github.com/paperless-ngx/paperless-ngx/pull/2889))
- Fix formatting in Setup documentation page [@igrybkov](https://github.com/igrybkov) ([#2880](https://github.com/paperless-ngx/paperless-ngx/pull/2880))
- [Documentation] Update docker-compose steps to support podman [@white-gecko](https://github.com/white-gecko) ([#2855](https://github.com/paperless-ngx/paperless-ngx/pull/2855))
- docs: better language code help [@tooomm](https://github.com/tooomm) ([#2830](https://github.com/paperless-ngx/paperless-ngx/pull/2830))
- Feature: Add an option to disable matching [@bdr99](https://github.com/bdr99) ([#2727](https://github.com/paperless-ngx/paperless-ngx/pull/2727))
- Docs: Remove outdated PAPERLESS_WORKER_RETRY [@shamoon](https://github.com/shamoon) ([#2694](https://github.com/paperless-ngx/paperless-ngx/pull/2694))
- Fix: add missing i18n for mobile preview tab title [@nathanaelhoun](https://github.com/nathanaelhoun) ([#2692](https://github.com/paperless-ngx/paperless-ngx/pull/2692))
### Maintenance
- Chore: Configure ruff as the primary linter for Python [@stumpylog](https://github.com/stumpylog) ([#2988](https://github.com/paperless-ngx/paperless-ngx/pull/2988))
- Feature: Enable images to be released on Quay.io [@stumpylog](https://github.com/stumpylog) ([#2972](https://github.com/paperless-ngx/paperless-ngx/pull/2972))
- Chore: Updates locked pipenv to latest version [@stumpylog](https://github.com/stumpylog) ([#2943](https://github.com/paperless-ngx/paperless-ngx/pull/2943))
- Chore: Properly collapse section in releases [@tooomm](https://github.com/tooomm) ([#2838](https://github.com/paperless-ngx/paperless-ngx/pull/2838))
- Chore: Don't include changelog PR for different releases [@tooomm](https://github.com/tooomm) ([#2832](https://github.com/paperless-ngx/paperless-ngx/pull/2832))
- Chore: Speed up frontend CI testing [@stumpylog](https://github.com/stumpylog) ([#2796](https://github.com/paperless-ngx/paperless-ngx/pull/2796))
- Bump leonsteinhaeuser/project-beta-automations from 2.0.1 to 2.1.0 [@dependabot](https://github.com/dependabot) ([#2789](https://github.com/paperless-ngx/paperless-ngx/pull/2789))
### Dependencies
<details>
<summary>15 changes</summary>
- Bump ng2-pdf-viewer from 9.1.4 to 9.1.5 in /src-ui [@dependabot](https://github.com/dependabot) ([#3109](https://github.com/paperless-ngx/paperless-ngx/pull/3109))
- Grouped bump angular packages from 15.2.6 to 15.2.7 in /src-ui [@dependabot](https://github.com/dependabot) ([#3108](https://github.com/paperless-ngx/paperless-ngx/pull/3108))
- Bump typescript from 4.8.4 to 4.9.5 in /src-ui [@dependabot](https://github.com/dependabot) ([#3071](https://github.com/paperless-ngx/paperless-ngx/pull/3071))
- Bulk Bump npm packages 04.23 [@dependabot](https://github.com/dependabot) ([#3068](https://github.com/paperless-ngx/paperless-ngx/pull/3068))
- Bump wait-on from 6.0.1 to 7.0.1 in /src-ui [@dependabot](https://github.com/dependabot) ([#2990](https://github.com/paperless-ngx/paperless-ngx/pull/2990))
- Bulk bump angular packages to 15.2.5 in /src-ui [@dependabot](https://github.com/dependabot) ([#2991](https://github.com/paperless-ngx/paperless-ngx/pull/2991))
- Bump [@<!---->types/node from 18.11.18 to 18.15.11 in /src-ui @dependabot](https://github.com/<!---->types/node from 18.11.18 to 18.15.11 in /src-ui @dependabot) ([#2993](https://github.com/paperless-ngx/paperless-ngx/pull/2993))
- Bump [@<!---->ng-select/ng-select from 10.0.3 to 10.0.4 in /src-ui @dependabot](https://github.com/<!---->ng-select/ng-select from 10.0.3 to 10.0.4 in /src-ui @dependabot) ([#2992](https://github.com/paperless-ngx/paperless-ngx/pull/2992))
- Bump [@<!---->typescript-eslint/eslint-plugin from 5.50.0 to 5.57.0 in /src-ui @dependabot](https://github.com/<!---->typescript-eslint/eslint-plugin from 5.50.0 to 5.57.0 in /src-ui @dependabot) ([#2989](https://github.com/paperless-ngx/paperless-ngx/pull/2989))
- Chore: Update cryptography to latest version [@stumpylog](https://github.com/stumpylog) ([#2891](https://github.com/paperless-ngx/paperless-ngx/pull/2891))
- Chore: Update to qpdf 11.3.0 in Docker image [@stumpylog](https://github.com/stumpylog) ([#2862](https://github.com/paperless-ngx/paperless-ngx/pull/2862))
- Bump leonsteinhaeuser/project-beta-automations from 2.0.1 to 2.1.0 [@dependabot](https://github.com/dependabot) ([#2789](https://github.com/paperless-ngx/paperless-ngx/pull/2789))
- Bump zone.js from 0.11.8 to 0.12.0 in /src-ui [@dependabot](https://github.com/dependabot) ([#2793](https://github.com/paperless-ngx/paperless-ngx/pull/2793))
- Bump [@<!---->typescript-eslint/parser from 5.50.0 to 5.54.0 in /src-ui @dependabot](https://github.com/<!---->typescript-eslint/parser from 5.50.0 to 5.54.0 in /src-ui @dependabot) ([#2792](https://github.com/paperless-ngx/paperless-ngx/pull/2792))
- Bulk Bump angular packages to 15.2.1 in /src-ui [@dependabot](https://github.com/dependabot) ([#2788](https://github.com/paperless-ngx/paperless-ngx/pull/2788))
</details>
### All App Changes
<details>
<summary>72 changes</summary>
- Feature: Catalan translation [@shamoon](https://github.com/shamoon) ([#3146](https://github.com/paperless-ngx/paperless-ngx/pull/3146))
- Fix: Allow setting additional Django settings for proxies [@stumpylog](https://github.com/stumpylog) ([#3135](https://github.com/paperless-ngx/paperless-ngx/pull/3135))
- Fix: Increase mail account password field length [@stumpylog](https://github.com/stumpylog) ([#3134](https://github.com/paperless-ngx/paperless-ngx/pull/3134))
- Fix: respect permissions for matching suggestions [@shamoon](https://github.com/shamoon) ([#3103](https://github.com/paperless-ngx/paperless-ngx/pull/3103))
- Bump ng2-pdf-viewer from 9.1.4 to 9.1.5 in /src-ui [@dependabot](https://github.com/dependabot) ([#3109](https://github.com/paperless-ngx/paperless-ngx/pull/3109))
- Grouped bump angular packages from 15.2.6 to 15.2.7 in /src-ui [@dependabot](https://github.com/dependabot) ([#3108](https://github.com/paperless-ngx/paperless-ngx/pull/3108))
- Fix: update PaperlessTask on hard failures [@shamoon](https://github.com/shamoon) ([#3062](https://github.com/paperless-ngx/paperless-ngx/pull/3062))
- Bump typescript from 4.8.4 to 4.9.5 in /src-ui [@dependabot](https://github.com/dependabot) ([#3071](https://github.com/paperless-ngx/paperless-ngx/pull/3071))
- Bulk Bump npm packages 04.23 [@dependabot](https://github.com/dependabot) ([#3068](https://github.com/paperless-ngx/paperless-ngx/pull/3068))
- Fix: Hide UI tour steps if user doesnt have permissions [@shamoon](https://github.com/shamoon) ([#3060](https://github.com/paperless-ngx/paperless-ngx/pull/3060))
- Fix: Hide Permissions tab if user cannot view users [@shamoon](https://github.com/shamoon) ([#3061](https://github.com/paperless-ngx/paperless-ngx/pull/3061))
- v1.14.0 delete document fixes [@shamoon](https://github.com/shamoon) ([#3020](https://github.com/paperless-ngx/paperless-ngx/pull/3020))
- Bump wait-on from 6.0.1 to 7.0.1 in /src-ui [@dependabot](https://github.com/dependabot) ([#2990](https://github.com/paperless-ngx/paperless-ngx/pull/2990))
- Fix: inline plaintext docs to enforce styling [@shamoon](https://github.com/shamoon) ([#3013](https://github.com/paperless-ngx/paperless-ngx/pull/3013))
- Chore: Configure ruff as the primary linter for Python [@stumpylog](https://github.com/stumpylog) ([#2988](https://github.com/paperless-ngx/paperless-ngx/pull/2988))
- Bulk bump angular packages to 15.2.5 in /src-ui [@dependabot](https://github.com/dependabot) ([#2991](https://github.com/paperless-ngx/paperless-ngx/pull/2991))
- Bump [@<!---->types/node from 18.11.18 to 18.15.11 in /src-ui @dependabot](https://github.com/<!---->types/node from 18.11.18 to 18.15.11 in /src-ui @dependabot) ([#2993](https://github.com/paperless-ngx/paperless-ngx/pull/2993))
- Bump [@<!---->ng-select/ng-select from 10.0.3 to 10.0.4 in /src-ui @dependabot](https://github.com/<!---->ng-select/ng-select from 10.0.3 to 10.0.4 in /src-ui @dependabot) ([#2992](https://github.com/paperless-ngx/paperless-ngx/pull/2992))
- Bump [@<!---->typescript-eslint/eslint-plugin from 5.50.0 to 5.57.0 in /src-ui @dependabot](https://github.com/<!---->typescript-eslint/eslint-plugin from 5.50.0 to 5.57.0 in /src-ui @dependabot) ([#2989](https://github.com/paperless-ngx/paperless-ngx/pull/2989))
- Feature: Stronger typing for file consumption [@stumpylog](https://github.com/stumpylog) ([#2744](https://github.com/paperless-ngx/paperless-ngx/pull/2744))
- Fix: Use exclude instead of difference for mariadb [@shamoon](https://github.com/shamoon) ([#2983](https://github.com/paperless-ngx/paperless-ngx/pull/2983))
- Fix: permissions display should not show users with inherited permissions \& unable to change owner [@shamoon](https://github.com/shamoon) ([#2818](https://github.com/paperless-ngx/paperless-ngx/pull/2818))
- Feature: double-click docs [@shamoon](https://github.com/shamoon) ([#2966](https://github.com/paperless-ngx/paperless-ngx/pull/2966))
- feature: Add support for zxing as barcode scanning lib [@margau](https://github.com/margau) ([#2907](https://github.com/paperless-ngx/paperless-ngx/pull/2907))
- Feature: test mail account [@shamoon](https://github.com/shamoon) ([#2949](https://github.com/paperless-ngx/paperless-ngx/pull/2949))
- Feature: Capture celery and kombu logs to a file [@stumpylog](https://github.com/stumpylog) ([#2954](https://github.com/paperless-ngx/paperless-ngx/pull/2954))
- Fix: Resolve Redis connection issues with ACLs [@stumpylog](https://github.com/stumpylog) ([#2939](https://github.com/paperless-ngx/paperless-ngx/pull/2939))
- Feature: Allow mail account to use access tokens [@stumpylog](https://github.com/stumpylog) ([#2930](https://github.com/paperless-ngx/paperless-ngx/pull/2930))
- Fix: Consumer polling could overwhelm database [@stumpylog](https://github.com/stumpylog) ([#2922](https://github.com/paperless-ngx/paperless-ngx/pull/2922))
- Feature: Improved statistics widget [@shamoon](https://github.com/shamoon) ([#2910](https://github.com/paperless-ngx/paperless-ngx/pull/2910))
- Enhancement: rename comments to notes and improve notes UI [@shamoon](https://github.com/shamoon) ([#2904](https://github.com/paperless-ngx/paperless-ngx/pull/2904))
- Allow psql client certificate authentication [@Ongy](https://github.com/Ongy) ([#2899](https://github.com/paperless-ngx/paperless-ngx/pull/2899))
- Enhancement: support filtering multiple correspondents, doctypes \& storage paths [@shamoon](https://github.com/shamoon) ([#2893](https://github.com/paperless-ngx/paperless-ngx/pull/2893))
- Fix: frontend handle private tags, doctypes, correspondents [@shamoon](https://github.com/shamoon) ([#2839](https://github.com/paperless-ngx/paperless-ngx/pull/2839))
- Fix: Chrome struggles with commas [@stumpylog](https://github.com/stumpylog) ([#2892](https://github.com/paperless-ngx/paperless-ngx/pull/2892))
- Feature: Change celery serializer to pickle [@stumpylog](https://github.com/stumpylog) ([#2861](https://github.com/paperless-ngx/paperless-ngx/pull/2861))
- Feature: Allow naming to include owner and original name [@stumpylog](https://github.com/stumpylog) ([#2873](https://github.com/paperless-ngx/paperless-ngx/pull/2873))
- Feature: Allows filtering email by the TO value(s) as well [@stumpylog](https://github.com/stumpylog) ([#2871](https://github.com/paperless-ngx/paperless-ngx/pull/2871))
- Fix: logout on change password via frontend [@shamoon](https://github.com/shamoon) ([#2863](https://github.com/paperless-ngx/paperless-ngx/pull/2863))
- Fix: give superuser full doc perms [@shamoon](https://github.com/shamoon) ([#2820](https://github.com/paperless-ngx/paperless-ngx/pull/2820))
- Fix: Append Gmail labels instead of replacing [@stumpylog](https://github.com/stumpylog) ([#2860](https://github.com/paperless-ngx/paperless-ngx/pull/2860))
- Feature: owner-aware unique model name constraint [@shamoon](https://github.com/shamoon) ([#2827](https://github.com/paperless-ngx/paperless-ngx/pull/2827))
- Chore: Create list parsing utility for settings [@stumpylog](https://github.com/stumpylog) ([#2816](https://github.com/paperless-ngx/paperless-ngx/pull/2816))
- Fix: Ensure email date is made aware during action processing [@stumpylog](https://github.com/stumpylog) ([#2837](https://github.com/paperless-ngx/paperless-ngx/pull/2837))
- Chore: Convert more code to pathlib [@stumpylog](https://github.com/stumpylog) ([#2817](https://github.com/paperless-ngx/paperless-ngx/pull/2817))
- Fix: disable bulk edit dialog buttons during operation [@shamoon](https://github.com/shamoon) ([#2819](https://github.com/paperless-ngx/paperless-ngx/pull/2819))
- fix database locked error [@jonaswinkler](https://github.com/jonaswinkler) ([#2808](https://github.com/paperless-ngx/paperless-ngx/pull/2808))
- Fix: Disable suggestions for read-only docs [@shamoon](https://github.com/shamoon) ([#2813](https://github.com/paperless-ngx/paperless-ngx/pull/2813))
- update django.po messages [@jonaswinkler](https://github.com/jonaswinkler) ([#2806](https://github.com/paperless-ngx/paperless-ngx/pull/2806))
- Update processed mail migration [@shamoon](https://github.com/shamoon) ([#2804](https://github.com/paperless-ngx/paperless-ngx/pull/2804))
- Feature/2396 better mail actions [@jonaswinkler](https://github.com/jonaswinkler) ([#2718](https://github.com/paperless-ngx/paperless-ngx/pull/2718))
- Bump zone.js from 0.11.8 to 0.12.0 in /src-ui [@dependabot](https://github.com/dependabot) ([#2793](https://github.com/paperless-ngx/paperless-ngx/pull/2793))
- Bump [@<!---->typescript-eslint/parser from 5.50.0 to 5.54.0 in /src-ui @dependabot](https://github.com/<!---->typescript-eslint/parser from 5.50.0 to 5.54.0 in /src-ui @dependabot) ([#2792](https://github.com/paperless-ngx/paperless-ngx/pull/2792))
- Bulk Bump angular packages to 15.2.1 in /src-ui [@dependabot](https://github.com/dependabot) ([#2788](https://github.com/paperless-ngx/paperless-ngx/pull/2788))
- Fix: Ensure scratch directory exists before using [@stumpylog](https://github.com/stumpylog) ([#2775](https://github.com/paperless-ngx/paperless-ngx/pull/2775))
- Don't submit owner via API on document upload [@jonaswinkler](https://github.com/jonaswinkler) ([#2777](https://github.com/paperless-ngx/paperless-ngx/pull/2777))
- Feature: Reduce classifier memory usage somewhat during training [@stumpylog](https://github.com/stumpylog) ([#2733](https://github.com/paperless-ngx/paperless-ngx/pull/2733))
- Chore: Setup for mypy typing checks [@stumpylog](https://github.com/stumpylog) ([#2742](https://github.com/paperless-ngx/paperless-ngx/pull/2742))
- Feature: Add PAPERLESS_OCR_SKIP_ARCHIVE_FILE config setting [@bdr99](https://github.com/bdr99) ([#2743](https://github.com/paperless-ngx/paperless-ngx/pull/2743))
- Fix: only offer log files that exist [@shamoon](https://github.com/shamoon) ([#2739](https://github.com/paperless-ngx/paperless-ngx/pull/2739))
- Feature: dynamic document counts in dropdowns [@shamoon](https://github.com/shamoon) ([#2704](https://github.com/paperless-ngx/paperless-ngx/pull/2704))
- Fix: permissions editing and initial view issues [@shamoon](https://github.com/shamoon) ([#2717](https://github.com/paperless-ngx/paperless-ngx/pull/2717))
- Fix: reset saved view ID on quickFilter [@shamoon](https://github.com/shamoon) ([#2703](https://github.com/paperless-ngx/paperless-ngx/pull/2703))
- Feature: Add an option to disable matching [@bdr99](https://github.com/bdr99) ([#2727](https://github.com/paperless-ngx/paperless-ngx/pull/2727))
- Chore: Improve clarity of some test asserting [@stumpylog](https://github.com/stumpylog) ([#2714](https://github.com/paperless-ngx/paperless-ngx/pull/2714))
- Allow setting the ASN on document upload [@stumpylog](https://github.com/stumpylog) ([#2713](https://github.com/paperless-ngx/paperless-ngx/pull/2713))
- Fix: bulk edit reset apply button state [@shamoon](https://github.com/shamoon) ([#2701](https://github.com/paperless-ngx/paperless-ngx/pull/2701))
- Feature: Log failed login attempts [@shamoon](https://github.com/shamoon) ([#2359](https://github.com/paperless-ngx/paperless-ngx/pull/2359))
- Feature: Rename documents when storage path format changes [@stumpylog](https://github.com/stumpylog) ([#2696](https://github.com/paperless-ngx/paperless-ngx/pull/2696))
- Feature: update error message colors \& show on document failures [@shamoon](https://github.com/shamoon) ([#2689](https://github.com/paperless-ngx/paperless-ngx/pull/2689))
- Feature: multi-user permissions [@shamoon](https://github.com/shamoon) ([#2147](https://github.com/paperless-ngx/paperless-ngx/pull/2147))
- Fix: add missing i18n for mobile preview tab title [@nathanaelhoun](https://github.com/nathanaelhoun) ([#2692](https://github.com/paperless-ngx/paperless-ngx/pull/2692))
</details>
## paperless-ngx 1.13.0
### Features

View File

@@ -33,6 +33,11 @@ steps described in [Docker setup](#docker_hub) automatically.
$ bash -c "$(curl -L https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)"
```
!!! note
macOS users will need to install e.g. [gnu-sed](https://formulae.brew.sh/formula/gnu-sed) with support
for running as `sed`.
### From GHCR / Docker Hub {#docker_hub}
1. Login with your user and create a folder in your home-directory to have a place for your

View File

@@ -204,7 +204,7 @@ for details.
## Permissions
As of version 1.13.0 Paperless-ngx added core support for user / group permissions. Permissions is
As of version 1.14.0 Paperless-ngx added core support for user / group permissions. Permissions is
based around an object 'owner' and 'view' and 'edit' permissions can be granted to other users
or groups.
@@ -212,13 +212,13 @@ Permissions uses the built-in user model of the backend framework, Django.
!!! note
After migration to version 1.13.0 all existing documents, tags etc. will have no explicit owner
After migration to version 1.14.0 all existing documents, tags etc. will have no explicit owner
set which means they will be visible / editable by all users. Once an object has an owner set,
only the owner can explicitly grant / revoke permissions.
!!! note
When first migrating to permissions it is recommended to user a 'superuser' account (which
When first migrating to permissions it is recommended to use a 'superuser' account (which
would usually have been setup during installation) to ensure you have full permissions.
Note that superusers have access to all objects.
@@ -230,7 +230,7 @@ do not have an owner set.
### Users and Groups
Paperless-ngx versions after 1.13.0 allow creating and editing users and groups via the 'frontend' UI.
Paperless-ngx versions after 1.14.0 allow creating and editing users and groups via the 'frontend' UI.
These can be found under Settings > Users & Groups, assuming the user has access. If a user is designated
as a member of a group those permissions will be inherited and this is reflected in the UI. Explicit
permissions can be granted to limit access to certain parts of the UI (and corresponding API endpoints).

View File

@@ -5,11 +5,15 @@ describe('document-detail', () => {
this.modifiedDocuments = []
cy.fixture('documents/documents.json').then((documentsJson) => {
cy.intercept('GET', 'http://localhost:8000/api/documents/1/', (req) => {
let response = { ...documentsJson }
response = response.results.find((d) => d.id == 1)
req.reply(response)
})
cy.intercept(
'GET',
'http://localhost:8000/api/documents/1/?full_perms=true',
(req) => {
let response = { ...documentsJson }
response = response.results.find((d) => d.id == 1)
req.reply(response)
}
)
})
cy.intercept('PUT', 'http://localhost:8000/api/documents/1/', (req) => {

View File

@@ -21,6 +21,7 @@
"original_file_name": "2022-03-22 no latin title.pdf",
"archived_file_name": "2022-03-22 no latin title.pdf",
"owner": null,
"user_can_change": true,
"permissions": {
"view": {
"users": [],
@@ -68,6 +69,7 @@
"original_file_name": "2022-03-23 lorem ipsum dolor sit amet.pdf",
"archived_file_name": "2022-03-23 llorem ipsum dolor sit amet.pdf",
"owner": null,
"user_can_change": true,
"permissions": {
"view": {
"users": [],
@@ -98,6 +100,7 @@
"original_file_name": "2022-03-24 dolor.pdf",
"archived_file_name": "2022-03-24 dolor.pdf",
"owner": null,
"user_can_change": true,
"permissions": {
"view": {
"users": [],
@@ -128,6 +131,7 @@
"original_file_name": "2022-06-01 sit amet.pdf",
"archived_file_name": "2022-06-01 sit amet.pdf",
"owner": null,
"user_can_change": true,
"permissions": {
"view": {
"users": [],

View File

@@ -43,8 +43,8 @@ export class SelectComponent extends AbstractInputComponent<number> {
}
checkForPrivateItems(value: any) {
if (Array.isArray(value) && value.length > 0) {
value.forEach((id) => this.checkForPrivateItem(id))
if (Array.isArray(value)) {
if (value.length > 0) value.forEach((id) => this.checkForPrivateItem(id))
} else {
this.checkForPrivateItem(value)
}

View File

@@ -122,7 +122,8 @@ export abstract class ManagementListComponent<T extends ObjectWithId>
null,
this.sortField,
this.sortReverse,
this._nameFilter
this._nameFilter,
true
)
.subscribe((c) => {
this.data = c.results

View File

@@ -16,4 +16,6 @@ export interface ObjectWithPermissions extends ObjectWithId {
owner?: number
permissions?: PermissionsObject
user_can_change?: boolean
}

View File

@@ -58,17 +58,24 @@ export class PermissionsService {
action: string,
object: ObjectWithPermissions
): boolean {
let actionObject = null
if (action === PermissionAction.View) actionObject = object.permissions.view
else if (action === PermissionAction.Change)
actionObject = object.permissions.change
if (!actionObject) return false
return (
this.currentUserOwnsObject(object) ||
actionObject.users.includes(this.currentUser.id) ||
actionObject.groups.filter((g) => this.currentUser.groups.includes(g))
.length > 0
)
if (action === PermissionAction.View) {
return (
this.currentUserOwnsObject(object) ||
object.permissions?.view.users.includes(this.currentUser.id) ||
object.permissions?.view.groups.filter((g) =>
this.currentUser.groups.includes(g)
).length > 0
)
} else if (action === PermissionAction.Change) {
return (
this.currentUserOwnsObject(object) ||
object.user_can_change ||
object.permissions?.change.users.includes(this.currentUser.id) ||
object.permissions?.change.groups.filter((g) =>
this.currentUser.groups.includes(g)
).length > 0
)
}
}
public getPermissionCode(

View File

@@ -9,11 +9,15 @@ export abstract class AbstractNameFilterService<
pageSize?: number,
sortField?: string,
sortReverse?: boolean,
nameFilter?: string
nameFilter?: string,
fullPerms?: boolean
) {
let params = {}
if (nameFilter) {
params = { name__icontains: nameFilter }
params['name__icontains'] = nameFilter
}
if (fullPerms) {
params['full_perms'] = true
}
return this.list(page, pageSize, sortField, sortReverse, params)
}

View File

@@ -113,6 +113,14 @@ export class DocumentService extends AbstractPaperlessService<PaperlessDocument>
}).pipe(map((response) => response.results.map((doc) => doc.id)))
}
get(id: number): Observable<PaperlessDocument> {
return this.http.get<PaperlessDocument>(this.getResourceUrl(id), {
params: {
full_perms: true,
},
})
}
getPreviewUrl(id: number, original: boolean = false): string {
let url = this.getResourceUrl(id, 'preview')
if (this._searchQuery) url += `#search="${this._searchQuery}"`

View File

@@ -5,7 +5,7 @@ export const environment = {
apiBaseUrl: document.baseURI + 'api/',
apiVersion: '2',
appTitle: 'Paperless-ngx',
version: '1.14.0',
version: '1.14.1',
webSocketHost: window.location.host,
webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:',
webSocketBaseUrl: base_url.pathname + 'ws/',

View File

@@ -625,7 +625,7 @@
<context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context>
<context context-type="linenumber">134</context>
</context-group>
<target state="translated">Corresponsal és</target>
<target state="translated">Corresponsals</target>
</trans-unit>
<trans-unit id="7886570921510760899" datatype="html">
<source>Tags</source>
@@ -4186,7 +4186,7 @@
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
<context context-type="linenumber">2</context>
</context-group>
<target state="translated">Creat</target>
<target state="translated">Crear</target>
</trans-unit>
<trans-unit id="4010735610815226758" datatype="html">
<source>Filter by:</source>

View File

@@ -797,7 +797,7 @@
<context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context>
<context context-type="linenumber">235</context>
</context-group>
<target state="translated">Aktualisierung verfügbar</target>
<target state="translated">Update verfügbar</target>
</trans-unit>
<trans-unit id="3011185103048412841" datatype="html">
<source>An error occurred while saving settings.</source>
@@ -3076,7 +3076,7 @@
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">595,597</context>
</context-group>
<target state="needs-translation">Error deleting document: <x id="PH" equiv-text="error.error?.detail ?? error.message ?? JSON.stringify(error)"/></target>
<target state="translated">Fehler beim Löschen des Dokuments <x id="PH" equiv-text="error.error?.detail ?? error.message ?? JSON.stringify(error)"/></target>
</trans-unit>
<trans-unit id="7362691899087997122" datatype="html">
<source>Redo OCR confirm</source>
@@ -4578,7 +4578,7 @@
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
<context context-type="linenumber">140,142</context>
</context-group>
<target state="needs-translation"> Update checking works by pinging the public <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://api.github.com/repos/paperless-ngx/paperless-ngx/releases/latest&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;"/>Github API<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/> for the latest release to determine whether a new version is available.<x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/&gt;"/> Actual updating of the app must still be performed manually. </target>
<target state="translated"> Die Überprüfung auf Updates erfolgt über Anfragen an die öffentliche <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://api.github.com/repos/paperless-ngx/paperless-ngx/releases/latest&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;"/>Github API<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/>, um zu ermitteln, ob eine neue Version verfügbar ist.<x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/&gt;"/> Das eigentliche Update der Anwendung muss weiterhin manuell durchgeführt werden. </target>
</trans-unit>
<trans-unit id="5489945693955857309" datatype="html">
<source><x id="START_EMPHASISED_TEXT" ctype="x-em" equiv-text="No track"/>No tracking data is collected by the app in any way.<x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;/em&gt;"/></source>
@@ -5671,7 +5671,7 @@
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
<context context-type="linenumber">177</context>
</context-group>
<target state="needs-translation">Catalan</target>
<target state="translated">Katalanisch</target>
</trans-unit>
<trans-unit id="2719780722934172508" datatype="html">
<source>Czech</source>

View File

@@ -3076,7 +3076,7 @@
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">595,597</context>
</context-group>
<target state="needs-translation">Error deleting document: <x id="PH" equiv-text="error.error?.detail ?? error.message ?? JSON.stringify(error)"/></target>
<target state="translated">Virhe poistettaessa asiakirjaa: <x id="PH" equiv-text="error.error?.detail ?? error.message ?? JSON.stringify(error)"/></target>
</trans-unit>
<trans-unit id="7362691899087997122" datatype="html">
<source>Redo OCR confirm</source>
@@ -4578,7 +4578,7 @@
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
<context context-type="linenumber">140,142</context>
</context-group>
<target state="needs-translation"> Update checking works by pinging the public <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://api.github.com/repos/paperless-ngx/paperless-ngx/releases/latest&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;"/>Github API<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/> for the latest release to determine whether a new version is available.<x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/&gt;"/> Actual updating of the app must still be performed manually. </target>
<target state="translated"> Päivityksen tarkistaminen tapahtuu yhteydellä <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://api.github.com/repos/paperless-ngx/paperless-ngx/releases/latest&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;"/>Github API-palveluun<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/> viimeisimmän version tarkistamiseksi.<x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/&gt;"/> Sovelluksen varsinainen päivitys on silti suoritettava manuaalisesti. </target>
</trans-unit>
<trans-unit id="5489945693955857309" datatype="html">
<source><x id="START_EMPHASISED_TEXT" ctype="x-em" equiv-text="No track"/>No tracking data is collected by the app in any way.<x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;/em&gt;"/></source>
@@ -5671,7 +5671,7 @@
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
<context context-type="linenumber">177</context>
</context-group>
<target state="needs-translation">Catalan</target>
<target state="translated">Katalaani</target>
</trans-unit>
<trans-unit id="2719780722934172508" datatype="html">
<source>Czech</source>

View File

@@ -1327,21 +1327,21 @@
</context-group>
<target state="final">Mot de passe</target>
</trans-unit>
<trans-unit id="4249303448466017578" datatype="html">
<trans-unit id="4249303448466017578" datatype="html" approved="yes">
<source>Password is token</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-account-edit-dialog/mail-account-edit-dialog.component.html</context>
<context context-type="linenumber">18</context>
</context-group>
<target state="translated">Le mot de passe est le jeton d'authentification</target>
<target state="final">Le mot de passe est un jeton d'authentification</target>
</trans-unit>
<trans-unit id="8313198211675984619" datatype="html">
<trans-unit id="8313198211675984619" datatype="html" approved="yes">
<source>Check if the password above is a token used for authentication</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-account-edit-dialog/mail-account-edit-dialog.component.html</context>
<context context-type="linenumber">18</context>
</context-group>
<target state="translated">Vérifier si le mot de passe ci-dessus est un jeton utilisé pour l'authentification</target>
<target state="final">Cocher si le mot de passe ci-dessus est un jeton utilisé pour l'authentification</target>
</trans-unit>
<trans-unit id="6124167940736826613" datatype="html" approved="yes">
<source>Character Set</source>
@@ -1395,13 +1395,13 @@
</context-group>
<target state="final">Chargement ...</target>
</trans-unit>
<trans-unit id="6563391987554512024" datatype="html">
<trans-unit id="6563391987554512024" datatype="html" approved="yes">
<source>Test</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-account-edit-dialog/mail-account-edit-dialog.component.html</context>
<context context-type="linenumber">32</context>
</context-group>
<target state="translated">Test</target>
<target state="final">Tester</target>
</trans-unit>
<trans-unit id="451418349275958054" datatype="html" approved="yes">
<source>No encryption</source>
@@ -1443,21 +1443,21 @@
</context-group>
<target state="final">Éditer un compte de messagerie</target>
</trans-unit>
<trans-unit id="7726734777863565313" datatype="html">
<trans-unit id="7726734777863565313" datatype="html" approved="yes">
<source>Successfully connected to the mail server</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-account-edit-dialog/mail-account-edit-dialog.component.ts</context>
<context context-type="linenumber">88</context>
</context-group>
<target state="translated">Connexion réussie au serveur de courrier</target>
<target state="final">Connexion réussie au serveur de messagerie électronique</target>
</trans-unit>
<trans-unit id="6533084895896956145" datatype="html">
<trans-unit id="6533084895896956145" datatype="html" approved="yes">
<source>Unable to connect to the mail server</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/mail-account-edit-dialog/mail-account-edit-dialog.component.ts</context>
<context context-type="linenumber">89</context>
</context-group>
<target state="translated">Impossible de se connecter au serveur d'impression</target>
<target state="final">Impossible de se connecter au serveur de messagerie électronique</target>
</trans-unit>
<trans-unit id="4086606389696938932" datatype="html" approved="yes">
<source>Account</source>
@@ -2063,21 +2063,21 @@
</context-group>
<target state="translated">Tous</target>
</trans-unit>
<trans-unit id="6381578200008167206" datatype="html">
<trans-unit id="6381578200008167206" datatype="html" approved="yes">
<source>Include</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/filterable-dropdown/filterable-dropdown.component.html</context>
<context context-type="linenumber">24</context>
</context-group>
<target state="translated">Inclure</target>
<target state="final">Inclure</target>
</trans-unit>
<trans-unit id="5668077948386857930" datatype="html">
<trans-unit id="5668077948386857930" datatype="html" approved="yes">
<source>Exclude</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/filterable-dropdown/filterable-dropdown.component.html</context>
<context context-type="linenumber">26</context>
</context-group>
<target state="translated">Exclure</target>
<target state="final">Exclure</target>
</trans-unit>
<trans-unit id="4391289919356861627" datatype="html" approved="yes">
<source>Apply</source>
@@ -2273,7 +2273,7 @@
<note priority="1" from="description">Used for both types, correspondents, storage paths</note>
<target state="final">Ajouter un élément</target>
</trans-unit>
<trans-unit id="3686284950598311784" datatype="html">
<trans-unit id="3686284950598311784" datatype="html" approved="yes">
<source>Private</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/input/select/select.component.ts</context>
@@ -2287,7 +2287,7 @@
<context context-type="sourcefile">src/app/components/common/tag/tag.component.html</context>
<context context-type="linenumber">8</context>
</context-group>
<target state="translated">Privé</target>
<target state="final">Privé</target>
</trans-unit>
<trans-unit id="6560126119609945418" datatype="html" approved="yes">
<source>Add tag</source>
@@ -2351,13 +2351,13 @@
</context-group>
<target state="final"><x id="INTERPOLATION" equiv-text="{{action.key}}"/></target>
</trans-unit>
<trans-unit id="6895273602775249942" datatype="html">
<trans-unit id="6895273602775249942" datatype="html" approved="yes">
<source>Inherited from group</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/permissions-select/permissions-select.component.ts</context>
<context context-type="linenumber">62</context>
</context-group>
<target state="translated">Hérité du groupe</target>
<target state="final">Hérité du groupe</target>
</trans-unit>
<trans-unit id="3797570084942068182" datatype="html" approved="yes">
<source>Select</source>
@@ -2467,53 +2467,53 @@
</context-group>
<target state="final">Statistiques</target>
</trans-unit>
<trans-unit id="2028517964701399614" datatype="html">
<trans-unit id="2028517964701399614" datatype="html" approved="yes">
<source>Go to inbox</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html</context>
<context context-type="linenumber">4</context>
</context-group>
<target state="translated">Accéder à la boîte de réception</target>
<target state="final">Accéder à la boîte de réception</target>
</trans-unit>
<trans-unit id="3497361602348932709" datatype="html">
<trans-unit id="3497361602348932709" datatype="html" approved="yes">
<source>Documents in inbox</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html</context>
<context context-type="linenumber">5</context>
</context-group>
<target state="translated">Documents dans la boîte de réception</target>
<target state="final">Documents dans la boîte de réception</target>
</trans-unit>
<trans-unit id="8809281703097241399" datatype="html">
<trans-unit id="8809281703097241399" datatype="html" approved="yes">
<source>Go to documents</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html</context>
<context context-type="linenumber">8</context>
</context-group>
<target state="translated">Aller aux documents</target>
<target state="final">Aller aux documents</target>
</trans-unit>
<trans-unit id="3823413855067727192" datatype="html">
<trans-unit id="3823413855067727192" datatype="html" approved="yes">
<source>Total documents</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html</context>
<context context-type="linenumber">9</context>
</context-group>
<target state="translated">Nombre total de documents</target>
<target state="final">Nombre total de documents </target>
</trans-unit>
<trans-unit id="6503529145162789855" datatype="html">
<trans-unit id="6503529145162789855" datatype="html" approved="yes">
<source>Total characters</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html</context>
<context context-type="linenumber">13</context>
</context-group>
<target state="translated">Nombre total de caractères</target>
<target state="final">Nombre total de caractères </target>
</trans-unit>
<trans-unit id="8693603235657020323" datatype="html">
<trans-unit id="8693603235657020323" datatype="html" approved="yes">
<source>Other</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.ts</context>
<context context-type="linenumber">55</context>
</context-group>
<target state="translated">Autres</target>
<target state="final">Autres</target>
</trans-unit>
<trans-unit id="8187573012244728580" datatype="html" approved="yes">
<source>Upload new documents</source>
@@ -2962,13 +2962,13 @@
</context-group>
<target state="translated">Saisir le mot de passe</target>
</trans-unit>
<trans-unit id="8460995830263484763" datatype="html">
<trans-unit id="8460995830263484763" datatype="html" approved="yes">
<source>Notes <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span *ngIf=&quot;document?.notes.length&quot; class=&quot;badge text-bg-secondary ms-1&quot;&gt;"/><x id="INTERPOLATION" equiv-text="ngth}}"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/a&gt;"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">175,176</context>
</context-group>
<target state="translated">Notes <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span *ngIf=&quot;document?.notes.length&quot; class=&quot;badge text-bg-secondary ms-1&quot;&gt;"/><x id="INTERPOLATION" equiv-text="ngth}}"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/a&gt;"/></target>
<target state="final">Notes <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span *ngIf=&quot;document?.notes.length&quot; class=&quot;badge text-bg-secondary ms-1&quot;&gt;"/><x id="INTERPOLATION" equiv-text="ngth}}"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/a&gt;"/></target>
</trans-unit>
<trans-unit id="3823219296477075982" datatype="html" approved="yes">
<source>Discard</source>
@@ -2986,13 +2986,13 @@
</context-group>
<target state="final">Enregistrer &amp; suivant</target>
</trans-unit>
<trans-unit id="2218903673684131427" datatype="html">
<trans-unit id="2218903673684131427" datatype="html" approved="yes">
<source>An error occurred loading content: <x id="PH" equiv-text="err.message ?? err.toString()"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">226,228</context>
</context-group>
<target state="translated">Une erreur s'est produite lors du chargement du contenu : <x id="PH" equiv-text="err.message ?? err.toString()"/></target>
<target state="final">Une erreur s'est produite lors du chargement du contenu : <x id="PH" equiv-text="err.message ?? err.toString()"/></target>
</trans-unit>
<trans-unit id="5758784066858623886" datatype="html" approved="yes">
<source>Error retrieving metadata</source>
@@ -3010,7 +3010,7 @@
</context-group>
<target state="final">Erreur lors de la récupération des suggestions</target>
</trans-unit>
<trans-unit id="8348337312757497317" datatype="html">
<trans-unit id="8348337312757497317" datatype="html" approved="yes">
<source>Document saved successfully.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
@@ -3020,7 +3020,7 @@
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">492</context>
</context-group>
<target state="translated">Document enregistré avec succès.</target>
<target state="final">Document enregistré avec succès.</target>
</trans-unit>
<trans-unit id="448882439049417053" datatype="html" approved="yes">
<source>Error saving document</source>
@@ -3070,13 +3070,13 @@
</context-group>
<target state="final">Supprimer le document</target>
</trans-unit>
<trans-unit id="1844801255494293730" datatype="html">
<trans-unit id="1844801255494293730" datatype="html" approved="yes">
<source>Error deleting document: <x id="PH" equiv-text="error.error?.detail ?? error.message ?? JSON.stringify(error)"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">595,597</context>
</context-group>
<target state="needs-translation">Error deleting document: <x id="PH" equiv-text="error.error?.detail ?? error.message ?? JSON.stringify(error)"/></target>
<target state="final">Erreur lors de la suppression du document : <x id="PH" equiv-text="error.error?.detail ?? error.message ?? JSON.stringify(error)"/></target>
</trans-unit>
<trans-unit id="7362691899087997122" datatype="html" approved="yes">
<source>Redo OCR confirm</source>
@@ -3532,21 +3532,21 @@
</context-group>
<target state="final">Filtrer par étiquette</target>
</trans-unit>
<trans-unit id="106713086593101376" datatype="html">
<trans-unit id="106713086593101376" datatype="html" approved="yes">
<source>View notes</source>
<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="linenumber">70</context>
</context-group>
<target state="translated">Afficher les Notes</target>
<target state="final">Afficher les notes</target>
</trans-unit>
<trans-unit id="8778002102373462277" datatype="html">
<trans-unit id="8778002102373462277" datatype="html" approved="yes">
<source><x id="INTERPOLATION" equiv-text="otes.length}}"/> Notes</source>
<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="linenumber">74</context>
</context-group>
<target state="translated"><x id="INTERPOLATION" equiv-text="otes.length}}"/> Notes</target>
<target state="final"><x id="INTERPOLATION" equiv-text="otes.length}}"/> Notes</target>
</trans-unit>
<trans-unit id="78870852467682010" datatype="html" approved="yes">
<source>Filter by document type</source>
@@ -3740,13 +3740,13 @@
</context-group>
<target state="final">Erreur lors du téléchargement du document</target>
</trans-unit>
<trans-unit id="494022736054110363" datatype="html">
<trans-unit id="494022736054110363" datatype="html" approved="yes">
<source>Sort by ASN</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">126</context>
</context-group>
<target state="translated">Trier par ASN</target>
<target state="final">Trier par ASN</target>
</trans-unit>
<trans-unit id="7517688192215738656" datatype="html" approved="yes">
<source>ASN</source>
@@ -3764,31 +3764,31 @@
</context-group>
<target state="final">NSA</target>
</trans-unit>
<trans-unit id="6954625430271090777" datatype="html">
<trans-unit id="6954625430271090777" datatype="html" approved="yes">
<source>Sort by correspondent</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">133</context>
</context-group>
<target state="translated">Trier par correspondant</target>
<target state="final">Trier par correspondant</target>
</trans-unit>
<trans-unit id="2066713941761361709" datatype="html">
<trans-unit id="2066713941761361709" datatype="html" approved="yes">
<source>Sort by title</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">140</context>
</context-group>
<target state="translated">Trier par titre</target>
<target state="final">Trier par titre</target>
</trans-unit>
<trans-unit id="3557446856808034218" datatype="html">
<trans-unit id="3557446856808034218" datatype="html" approved="yes">
<source>Sort by notes</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">147</context>
</context-group>
<target state="translated">Trier par notes</target>
<target state="final">Trier par notes</target>
</trans-unit>
<trans-unit id="8104421162933956065" datatype="html">
<trans-unit id="8104421162933956065" datatype="html" approved="yes">
<source>Notes</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
@@ -3802,39 +3802,39 @@
<context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
<context context-type="linenumber">25</context>
</context-group>
<target state="translated">Notes</target>
<target state="final">Notes</target>
</trans-unit>
<trans-unit id="5499001829734502606" datatype="html">
<trans-unit id="5499001829734502606" datatype="html" approved="yes">
<source>Sort by document type</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">154</context>
</context-group>
<target state="translated">Trier par type de documents</target>
<target state="final">Trier par type de documents</target>
</trans-unit>
<trans-unit id="6213829731736042759" datatype="html">
<trans-unit id="6213829731736042759" datatype="html" approved="yes">
<source>Sort by storage path</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">161</context>
</context-group>
<target state="translated">Trier par chemin de stockage</target>
<target state="final">Trier par chemin de stockage</target>
</trans-unit>
<trans-unit id="3406167410329973166" datatype="html">
<trans-unit id="3406167410329973166" datatype="html" approved="yes">
<source>Sort by created date</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">168</context>
</context-group>
<target state="translated">Trier par la date de création</target>
<target state="final">Trier par date de création</target>
</trans-unit>
<trans-unit id="3769035778779263084" datatype="html">
<trans-unit id="3769035778779263084" datatype="html" approved="yes">
<source>Sort by added date</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">175</context>
</context-group>
<target state="translated">Trier par date d'ajout</target>
<target state="final">Trier par date d'ajout</target>
</trans-unit>
<trans-unit id="231679111972850796" datatype="html" approved="yes">
<source>Added</source>
@@ -4060,31 +4060,31 @@
</context-group>
<target state="final">L'erreur renvoyée était</target>
</trans-unit>
<trans-unit id="1044349881182559852" datatype="html">
<trans-unit id="1044349881182559852" datatype="html" approved="yes">
<source>Enter note</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-notes/document-notes.component.html</context>
<context context-type="linenumber">4</context>
</context-group>
<target state="translated">Saisir des notes</target>
<target state="final">Saisir une note</target>
</trans-unit>
<trans-unit id="7770536883443596194" datatype="html">
<trans-unit id="7770536883443596194" datatype="html" approved="yes">
<source> Please enter a note. </source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-notes/document-notes.component.html</context>
<context context-type="linenumber">5,7</context>
</context-group>
<target state="translated"> Veuillez saisir une note. </target>
<target state="final"> Veuillez saisir une note. </target>
</trans-unit>
<trans-unit id="8433732438274024544" datatype="html">
<trans-unit id="8433732438274024544" datatype="html" approved="yes">
<source>Add note</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-notes/document-notes.component.html</context>
<context context-type="linenumber">11</context>
</context-group>
<target state="translated">Ajouter une note</target>
<target state="final">Ajouter une note</target>
</trans-unit>
<trans-unit id="8428006099054244235" datatype="html">
<trans-unit id="8428006099054244235" datatype="html" approved="yes">
<source>Delete note</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-notes/document-notes.component.html</context>
@@ -4094,23 +4094,23 @@
<context context-type="sourcefile">src/app/components/document-notes/document-notes.component.html</context>
<context context-type="linenumber">25</context>
</context-group>
<target state="translated">Supprimer une note</target>
<target state="final">Supprimer une note</target>
</trans-unit>
<trans-unit id="207390237682956115" datatype="html">
<trans-unit id="207390237682956115" datatype="html" approved="yes">
<source>Error saving note: <x id="PH" equiv-text="e.toString()"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-notes/document-notes.component.ts</context>
<context context-type="linenumber">65</context>
</context-group>
<target state="translated">Erreur lors de l'enregistrement de la note: <x id="PH" equiv-text="e.toString()"/></target>
<target state="final">Erreur lors de l'enregistrement de la note : <x id="PH" equiv-text="e.toString()"/></target>
</trans-unit>
<trans-unit id="5682285129543775369" datatype="html">
<trans-unit id="5682285129543775369" datatype="html" approved="yes">
<source>Error deleting note: <x id="PH" equiv-text="e.toString()"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-notes/document-notes.component.ts</context>
<context context-type="linenumber">81</context>
</context-group>
<target state="translated">Erreur lors de l'enregistrement de la note: <x id="PH" equiv-text="e.toString()"/></target>
<target state="final">Une erreur s'est produite lors de la suppression de la note : <x id="PH" equiv-text="e.toString()"/></target>
</trans-unit>
<trans-unit id="6316128875819022658" datatype="html" approved="yes">
<source>correspondent</source>
@@ -4312,7 +4312,7 @@
</context-group>
<target state="final">Aucun</target>
</trans-unit>
<trans-unit id="6328828522970676938" datatype="html">
<trans-unit id="6328828522970676938" datatype="html" approved="yes">
<source>Error occurred while creating <x id="PH" equiv-text="this.typeName"/> : <x id="PH_1" equiv-text="activeModal.componentInstance.error"/>.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
@@ -4322,7 +4322,7 @@
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
<context context-type="linenumber">153,155</context>
</context-group>
<target state="translated">Une erreur s'est produite lors de la création de <x id="PH" equiv-text="this.typeName"/> : <x id="PH_1" equiv-text="activeModal.componentInstance.error"/>.</target>
<target state="final">Une erreur s'est produite lors de la création de <x id="PH" equiv-text="this.typeName"/> : <x id="PH_1" equiv-text="activeModal.componentInstance.error"/>.</target>
</trans-unit>
<trans-unit id="211408744872436427" datatype="html">
<source>Successfully created <x id="PH" equiv-text="this.typeName"/>.</source>
@@ -4332,13 +4332,13 @@
</context-group>
<target state="translated">Création de <x id="PH" equiv-text="this.typeName"/> réussie.</target>
</trans-unit>
<trans-unit id="1370653329436185913" datatype="html">
<trans-unit id="1370653329436185913" datatype="html" approved="yes">
<source>Error occurred while saving <x id="PH" equiv-text="this.typeName"/><x id="PH_1" equiv-text="errorDetail ? &apos;: &apos; + errorDetail : &apos;&apos;"/>.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
<context context-type="linenumber">174,176</context>
</context-group>
<target state="translated">Une erreur s'est produite lors de la sauvegarde de <x id="PH" equiv-text="this.typeName"/> : <x id="PH_1" equiv-text="errorDetail ? ': ' + errorDetail : ''"/>.</target>
<target state="final">Une erreur s'est produite lors de la sauvegarde de <x id="PH" equiv-text="this.typeName"/> : <x id="PH_1" equiv-text="errorDetail ? ': ' + errorDetail : ''"/>.</target>
</trans-unit>
<trans-unit id="2541368547549828690" datatype="html" approved="yes">
<source>Successfully updated <x id="PH" equiv-text="this.typeName"/>.</source>
@@ -4348,13 +4348,13 @@
</context-group>
<target state="final">Mise à jour de <x id="PH" equiv-text="this.typeName"/> réussie.</target>
</trans-unit>
<trans-unit id="6151710751857751783" datatype="html">
<trans-unit id="6151710751857751783" datatype="html" approved="yes">
<source>Error occurred while saving <x id="PH" equiv-text="this.typeName"/> : <x id="PH_1" equiv-text="e.toString()"/>.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
<context context-type="linenumber">187,189</context>
</context-group>
<target state="translated">Une erreur s'est produite lors de la sauvegarde de <x id="PH" equiv-text="this.typeName"/> : <x id="PH_1" equiv-text="e.toString()"/>.</target>
<target state="final">Une erreur s'est produite lors de la sauvegarde de <x id="PH" equiv-text="this.typeName"/> : <x id="PH_1" equiv-text="e.toString()"/>.</target>
</trans-unit>
<trans-unit id="4012132330507560812" datatype="html">
<source>Do you really want to delete the <x id="PH" equiv-text="this.typeName"/>?</source>
@@ -4572,13 +4572,13 @@
</context-group>
<target state="final">Vérification des mises à jour</target>
</trans-unit>
<trans-unit id="7578076359386888824" datatype="html">
<trans-unit id="7578076359386888824" datatype="html" approved="yes">
<source> Update checking works by pinging the public <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://api.github.com/repos/paperless-ngx/paperless-ngx/releases/latest&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;"/>Github API<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/> for the latest release to determine whether a new version is available.<x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/&gt;"/> Actual updating of the app must still be performed manually. </source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
<context context-type="linenumber">140,142</context>
</context-group>
<target state="needs-translation"> Update checking works by pinging the public <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://api.github.com/repos/paperless-ngx/paperless-ngx/releases/latest&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;"/>Github API<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/> for the latest release to determine whether a new version is available.<x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/&gt;"/> Actual updating of the app must still be performed manually. </target>
<target state="final"> La vérification des mises à jour fonctionne en faisant un ping sur l'API publique <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://api.github.com/repos/paperless-ngx/paperless-ngx/releases/latest&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;"/>Github<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/> pour la dernière version afin de déterminer si une nouvelle version est disponible.<x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/&gt;"/> La mise à jour réelle de l'application doit toujours être effectuée manuellement. </target>
</trans-unit>
<trans-unit id="5489945693955857309" datatype="html">
<source><x id="START_EMPHASISED_TEXT" ctype="x-em" equiv-text="No track"/>No tracking data is collected by the app in any way.<x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;/em&gt;"/></source>
@@ -4636,13 +4636,13 @@
</context-group>
<target state="final">Appliquer lors de la fermeture</target>
</trans-unit>
<trans-unit id="293524471897878391" datatype="html">
<trans-unit id="293524471897878391" datatype="html" approved="yes">
<source>Enable notes</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
<context context-type="linenumber">163</context>
</context-group>
<target state="translated">Activez les notes</target>
<target state="final">Activer les notes</target>
</trans-unit>
<trans-unit id="5851560788527570644" datatype="html" approved="yes">
<source>Notifications</source>
@@ -4884,13 +4884,13 @@
</context-group>
<target state="translated">Une erreur s'est produite lors de l'enregistrement des paramètres sur le serveur : <x id="PH" equiv-text="JSON.stringify( error.error )"/></target>
</trans-unit>
<trans-unit id="4510369340305901516" datatype="html">
<trans-unit id="4510369340305901516" datatype="html" approved="yes">
<source>Password has been changed, you will be logged out momentarily.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">659</context>
</context-group>
<target state="translated">Le mot de passe a été modifié, vous serez déconnecté momentanément.</target>
<target state="final">Le mot de passe a été modifié, vous serez déconnecté momentanément.</target>
</trans-unit>
<trans-unit id="2753185112875184719" datatype="html" approved="yes">
<source>Saved user &quot;<x id="PH" equiv-text="newUser.username"/>&quot;.</source>
@@ -5665,13 +5665,13 @@
</context-group>
<target state="final">Biélorusse</target>
</trans-unit>
<trans-unit id="1001043467371963032" datatype="html">
<trans-unit id="1001043467371963032" datatype="html" approved="yes">
<source>Catalan</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
<context context-type="linenumber">177</context>
</context-group>
<target state="needs-translation">Catalan</target>
<target state="final">Catalan</target>
</trans-unit>
<trans-unit id="2719780722934172508" datatype="html" approved="yes">
<source>Czech</source>

View File

@@ -3076,7 +3076,7 @@
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">595,597</context>
</context-group>
<target state="needs-translation">Error deleting document: <x id="PH" equiv-text="error.error?.detail ?? error.message ?? JSON.stringify(error)"/></target>
<target state="translated">Greška prilikom brisanja dokumenta: <x id="PH" equiv-text="error.error?.detail ?? error.message ?? JSON.stringify(error)"/></target>
</trans-unit>
<trans-unit id="7362691899087997122" datatype="html">
<source>Redo OCR confirm</source>
@@ -4578,7 +4578,7 @@
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
<context context-type="linenumber">140,142</context>
</context-group>
<target state="needs-translation"> Update checking works by pinging the public <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://api.github.com/repos/paperless-ngx/paperless-ngx/releases/latest&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;"/>Github API<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/> for the latest release to determine whether a new version is available.<x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/&gt;"/> Actual updating of the app must still be performed manually. </target>
<target state="translated"> Provera ažuriranja funkcioniše pingovanjem javnog <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://api.github.com/repos/paperless-ngx/paperless-ngx/releases/latest&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;"/>Github API<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/> za najnovije izdanje da bi se utvrdilo da li je nova verzija dostupna.<x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/&gt;"/> Stvarno ažuriranje aplikacije i dalje mora da se obavlja ručno. </target>
</trans-unit>
<trans-unit id="5489945693955857309" datatype="html">
<source><x id="START_EMPHASISED_TEXT" ctype="x-em" equiv-text="No track"/>No tracking data is collected by the app in any way.<x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;/em&gt;"/></source>
@@ -5671,7 +5671,7 @@
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
<context context-type="linenumber">177</context>
</context-group>
<target state="needs-translation">Catalan</target>
<target state="translated">Katalonski</target>
</trans-unit>
<trans-unit id="2719780722934172508" datatype="html">
<source>Czech</source>

View File

@@ -13,28 +13,24 @@ from .models import Tag
class CorrespondentAdmin(GuardedModelAdmin):
list_display = ("name", "match", "matching_algorithm")
list_filter = ("matching_algorithm",)
list_editable = ("match", "matching_algorithm")
class TagAdmin(GuardedModelAdmin):
list_display = ("name", "color", "match", "matching_algorithm")
list_filter = ("color", "matching_algorithm")
list_editable = ("color", "match", "matching_algorithm")
class DocumentTypeAdmin(GuardedModelAdmin):
list_display = ("name", "match", "matching_algorithm")
list_filter = ("matching_algorithm",)
list_editable = ("match", "matching_algorithm")
class DocumentAdmin(GuardedModelAdmin):
search_fields = ("correspondent__name", "title", "content", "tags__name")
readonly_fields = (
"added",
@@ -99,7 +95,6 @@ class RuleInline(admin.TabularInline):
class SavedViewAdmin(GuardedModelAdmin):
list_display = ("name", "owner")
inlines = [RuleInline]
@@ -116,7 +111,6 @@ class StoragePathAdmin(GuardedModelAdmin):
class TaskAdmin(admin.ModelAdmin):
list_display = ("task_id", "task_file_name", "task_name", "date_done", "status")
list_filter = ("status", "date_done", "task_file_name", "task_name")
search_fields = ("task_name", "task_id", "status")
@@ -133,7 +127,6 @@ class TaskAdmin(admin.ModelAdmin):
class NotesAdmin(GuardedModelAdmin):
list_display = ("user", "created", "note", "document")
list_filter = ("created", "user")
list_display_links = ("created",)

View File

@@ -3,22 +3,19 @@ from django.utils.translation import gettext_lazy as _
class DocumentsConfig(AppConfig):
name = "documents"
verbose_name = _("Documents")
def ready(self):
from .signals import document_consumption_finished
from .signals.handlers import (
add_inbox_tags,
set_log_entry,
set_correspondent,
set_document_type,
set_tags,
set_storage_path,
add_to_index,
)
from .signals.handlers import add_inbox_tags
from .signals.handlers import add_to_index
from .signals.handlers import set_correspondent
from .signals.handlers import set_document_type
from .signals.handlers import set_log_entry
from .signals.handlers import set_storage_path
from .signals.handlers import set_tags
document_consumption_finished.connect(add_inbox_tags)
document_consumption_finished.connect(set_correspondent)

View File

@@ -1,6 +1,7 @@
import itertools
from django.db.models import Q
from documents.models import Correspondent
from documents.models import Document
from documents.models import DocumentType
@@ -54,7 +55,6 @@ def set_document_type(doc_ids, document_type):
def add_tag(doc_ids, tag):
qs = Document.objects.filter(Q(id__in=doc_ids) & ~Q(tags__id=tag))
affected_docs = [doc.id for doc in qs]
@@ -70,7 +70,6 @@ def add_tag(doc_ids, tag):
def remove_tag(doc_ids, tag):
qs = Document.objects.filter(Q(id__in=doc_ids) & Q(tags__id=tag))
affected_docs = [doc.id for doc in qs]
@@ -122,7 +121,6 @@ def delete(doc_ids):
def redo_ocr(doc_ids):
for document_id in doc_ids:
update_document_archive_file.delay(
document_id=document_id,
@@ -132,7 +130,6 @@ def redo_ocr(doc_ids):
def set_permissions(doc_ids, set_permissions, owner=None):
qs = Document.objects.filter(id__in=doc_ids)
qs.update(owner=owner)

View File

@@ -6,6 +6,7 @@ from django.core.checks import register
from django.core.exceptions import FieldError
from django.db.utils import OperationalError
from django.db.utils import ProgrammingError
from documents.signals import document_consumer_declaration
@@ -22,7 +23,6 @@ def changed_password_check(app_configs, **kwargs):
return [] # No documents table yet
if encrypted_doc:
if not settings.PASSPHRASE:
return [
Error(
@@ -52,7 +52,6 @@ def changed_password_check(app_configs, **kwargs):
@register()
def parser_check(app_configs, **kwargs):
parsers = []
for response in document_consumer_declaration.send(None):
parsers.append(response[1])

View File

@@ -10,6 +10,7 @@ from typing import List
from typing import Optional
from django.conf import settings
from documents.models import Document
from documents.models import MatchingModel
@@ -59,7 +60,6 @@ def load_classifier() -> Optional["DocumentClassifier"]:
class DocumentClassifier:
# v7 - Updated scikit-learn package version
# v8 - Added storage path classifier
# v9 - Changed from hashing to time/ids for re-train check
@@ -140,7 +140,6 @@ class DocumentClassifier:
target_file_temp.rename(target_file)
def train(self):
# Get non-inbox documents
docs_queryset = Document.objects.exclude(
tags__is_inbox_tag=True,
@@ -159,7 +158,6 @@ class DocumentClassifier:
logger.debug("Gathering data from database...")
hasher = sha256()
for doc in docs_queryset:
y = -1
dt = doc.document_type
if dt and dt.matching_algorithm == MatchingModel.MATCH_AUTO:
@@ -334,12 +332,10 @@ class DocumentClassifier:
# If the NLTK language is supported, do further processing
if settings.NLTK_LANGUAGE is not None and settings.NLTK_ENABLED:
import nltk
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
from nltk.stem import SnowballStemmer
from nltk.tokenize import word_tokenize
# Not really hacky, since it isn't private and is documented, but
# set the search path for NLTK data to the single location it should be in

View File

@@ -31,9 +31,9 @@ from .models import DocumentType
from .models import FileInfo
from .models import Tag
from .parsers import DocumentParser
from .parsers import ParseError
from .parsers import get_parser_class_for_mime_type
from .parsers import parse_date
from .parsers import ParseError
from .signals import document_consumption_finished
from .signals import document_consumption_started
@@ -60,7 +60,6 @@ MESSAGE_FINISHED = "finished"
class Consumer(LoggingMixin):
logging_name = "paperless.consumer"
def _send_progress(
@@ -426,7 +425,6 @@ class Consumer(LoggingMixin):
# in the system. This will be a transaction and reasonably fast.
try:
with transaction.atomic():
# store the document.
document = self._store(text=text, date=date, mime_type=mime_type)
@@ -520,7 +518,6 @@ class Consumer(LoggingMixin):
date: Optional[datetime.datetime],
mime_type: str,
) -> Document:
# If someone gave us the original filename, use it instead of doc.
file_info = FileInfo.from_filename(self.filename)

View File

@@ -7,6 +7,7 @@ import pathvalidate
from django.conf import settings
from django.template.defaultfilters import slugify
from django.utils import timezone
from documents.models import Document
logger = logging.getLogger("paperless.filehandling")

View File

@@ -11,7 +11,6 @@ from .models import Log
from .models import StoragePath
from .models import Tag
CHAR_KWARGS = ["istartswith", "iendswith", "icontains", "iexact"]
ID_KWARGS = ["in", "exact"]
INT_KWARGS = ["exact", "gt", "gte", "lt", "lte", "isnull"]
@@ -83,7 +82,6 @@ class TitleContentFilter(Filter):
class DocumentFilterSet(FilterSet):
is_tagged = BooleanFilter(
label="Is tagged",
field_name="tags",

View File

@@ -6,8 +6,6 @@ from contextlib import contextmanager
from dateutil.parser import isoparse
from django.conf import settings
from django.utils import timezone
from documents.models import Document
from documents.models import Note
from guardian.shortcuts import get_users_with_perms
from whoosh import classify
from whoosh import highlight
@@ -16,8 +14,8 @@ from whoosh.fields import BOOLEAN
from whoosh.fields import DATETIME
from whoosh.fields import KEYWORD
from whoosh.fields import NUMERIC
from whoosh.fields import Schema
from whoosh.fields import TEXT
from whoosh.fields import Schema
from whoosh.highlight import HtmlFormatter
from whoosh.index import create_in
from whoosh.index import exists_in
@@ -28,6 +26,9 @@ from whoosh.searching import ResultsPage
from whoosh.searching import Searcher
from whoosh.writing import AsyncWriter
from documents.models import Document
from documents.models import Note
logger = logging.getLogger("paperless.index")
@@ -330,7 +331,7 @@ class DelayedMoreLikeThisQuery(DelayedQuery):
def autocomplete(ix, term, limit=10):
with ix.reader() as reader:
terms = []
for (score, t) in reader.most_distinctive_terms(
for score, t in reader.most_distinctive_terms(
"content",
number=limit,
prefix=term.lower(),

View File

@@ -3,7 +3,6 @@ import uuid
class LoggingMixin:
logging_group = None
logging_name = None

View File

@@ -3,19 +3,18 @@ import os
from django.conf import settings
from django.core.management.base import BaseCommand
from django.core.management.base import CommandError
from documents.models import Document
from paperless.db import GnuPG
class Command(BaseCommand):
help = (
"This is how you migrate your stored documents from an encrypted "
"state to an unencrypted one (or vice-versa)"
)
def add_arguments(self, parser):
parser.add_argument(
"--passphrase",
help="If PAPERLESS_PASSPHRASE isn't set already, you need to "
@@ -23,7 +22,6 @@ class Command(BaseCommand):
)
def handle(self, *args, **options):
try:
print(
"\n\nWARNING: This script is going to work directly on your "
@@ -48,13 +46,11 @@ class Command(BaseCommand):
@staticmethod
def __gpg_to_unencrypted(passphrase):
encrypted_files = Document.objects.filter(
storage_type=Document.STORAGE_TYPE_GPG,
)
for document in encrypted_files:
print(f"Decrypting {document}".encode())
old_paths = [document.source_path, document.thumbnail_path]

View File

@@ -6,15 +6,14 @@ import tqdm
from django import db
from django.conf import settings
from django.core.management.base import BaseCommand
from documents.models import Document
from documents.tasks import update_document_archive_file
logger = logging.getLogger("paperless.management.archiver")
class Command(BaseCommand):
help = """
Using the current classification model, assigns correspondents, tags
and document types to all documents, effectively allowing you to
@@ -51,7 +50,6 @@ class Command(BaseCommand):
)
def handle(self, *args, **options):
os.makedirs(settings.SCRATCH_DIR, exist_ok=True)
overwrite = options["overwrite"]
@@ -74,7 +72,6 @@ class Command(BaseCommand):
db.connections.close_all()
try:
logging.getLogger().handlers[0].level = logging.ERROR
with multiprocessing.Pool(processes=settings.TASK_WORKERS) as pool:
list(

View File

@@ -13,17 +13,19 @@ from typing import Set
from django.conf import settings
from django.core.management.base import BaseCommand
from django.core.management.base import CommandError
from watchdog.events import FileSystemEventHandler
from watchdog.observers.polling import PollingObserver
from documents.data_models import ConsumableDocument
from documents.data_models import DocumentMetadataOverrides
from documents.data_models import DocumentSource
from documents.models import Tag
from documents.parsers import is_file_ext_supported
from documents.tasks import consume_file
from watchdog.events import FileSystemEventHandler
from watchdog.observers.polling import PollingObserver
try:
from inotifyrecursive import INotify, flags
from inotifyrecursive import INotify
from inotifyrecursive import flags
except ImportError: # pragma: nocover
INotify = flags = None

View File

@@ -4,7 +4,6 @@ from documents.tasks import train_classifier
class Command(BaseCommand):
help = """
Trains the classifier on your data and saves the resulting models to a
file. The document consumer will then automatically use this new model.

View File

@@ -17,6 +17,10 @@ from django.core.management.base import BaseCommand
from django.core.management.base import CommandError
from django.db import transaction
from django.utils import timezone
from filelock import FileLock
from documents.file_handling import delete_empty_directories
from documents.file_handling import generate_filename
from documents.models import Correspondent
from documents.models import Document
from documents.models import DocumentType
@@ -29,18 +33,13 @@ from documents.models import UiSettings
from documents.settings import EXPORTER_ARCHIVE_NAME
from documents.settings import EXPORTER_FILE_NAME
from documents.settings import EXPORTER_THUMBNAIL_NAME
from filelock import FileLock
from paperless import version
from paperless.db import GnuPG
from paperless_mail.models import MailAccount
from paperless_mail.models import MailRule
from documents.file_handling import delete_empty_directories
from documents.file_handling import generate_filename
class Command(BaseCommand):
help = """
Decrypt and rename all files in our collection into a given target
directory. And include a manifest file containing document data for
@@ -144,7 +143,6 @@ class Command(BaseCommand):
self.no_thumbnail = False
def handle(self, *args, **options):
self.target = Path(options["target"]).resolve()
self.split_manifest = options["split_manifest"]
self.compare_checksums = options["compare_checksums"]

View File

@@ -14,16 +14,16 @@ from django.core.management.base import CommandError
from django.core.serializers.base import DeserializationError
from django.db.models.signals import m2m_changed
from django.db.models.signals import post_save
from filelock import FileLock
from documents.file_handling import create_source_path_directory
from documents.models import Document
from documents.parsers import run_convert
from documents.settings import EXPORTER_ARCHIVE_NAME
from documents.settings import EXPORTER_FILE_NAME
from documents.settings import EXPORTER_THUMBNAIL_NAME
from filelock import FileLock
from paperless import version
from documents.file_handling import create_source_path_directory
from documents.signals.handlers import update_filename_and_move_files
from paperless import version
@contextmanager
@@ -36,7 +36,6 @@ def disable_signal(sig, receiver, sender):
class Command(BaseCommand):
help = """
Using a manifest.json file, load the data from there, and import the
documents it refers to.
@@ -61,12 +60,11 @@ class Command(BaseCommand):
self.version = None
def handle(self, *args, **options):
logging.getLogger().handlers[0].level = logging.ERROR
self.source = options["source"]
self.source = Path(options["source"]).resolve()
if not os.path.exists(self.source):
if not self.source.exists():
raise CommandError("That path doesn't exist")
if not os.access(self.source, os.R_OK):
@@ -74,39 +72,39 @@ class Command(BaseCommand):
manifest_paths = []
main_manifest_path = os.path.normpath(
os.path.join(self.source, "manifest.json"),
)
main_manifest_path = self.source / "manifest.json"
self._check_manifest_exists(main_manifest_path)
with open(main_manifest_path) as f:
self.manifest = json.load(f)
with main_manifest_path.open() as infile:
self.manifest = json.load(infile)
manifest_paths.append(main_manifest_path)
for file in Path(self.source).glob("**/*-manifest.json"):
with open(file) as f:
self.manifest += json.load(f)
with file.open() as infile:
self.manifest += json.load(infile)
manifest_paths.append(file)
version_path = os.path.normpath(os.path.join(self.source, "version.json"))
if os.path.exists(version_path):
with open(version_path) as f:
self.version = json.load(f)["version"]
# Provide an initial warning if needed to the user
if self.version != version.__full_version_str__:
self.stdout.write(
self.style.WARNING(
"Version mismatch: "
f"Currently {version.__full_version_str__},"
f" importing {self.version}."
" Continuing, but import may fail.",
),
)
version_path = self.source / "version.json"
if version_path.exists():
with version_path.open() as infile:
self.version = json.load(infile)["version"]
# Provide an initial warning if needed to the user
if self.version != version.__full_version_str__:
self.stdout.write(
self.style.WARNING(
"Version mismatch: "
f"Currently {version.__full_version_str__},"
f" importing {self.version}."
" Continuing, but import may fail.",
),
)
else:
self.stdout.write(self.style.NOTICE("No version.json file located"))
self._check_manifest()
self._check_manifest_valid()
with disable_signal(
post_save,
receiver=update_filename_and_move_files,
@@ -150,16 +148,19 @@ class Command(BaseCommand):
)
@staticmethod
def _check_manifest_exists(path):
if not os.path.exists(path):
def _check_manifest_exists(path: Path):
if not path.exists():
raise CommandError(
"That directory doesn't appear to contain a manifest.json file.",
)
def _check_manifest(self):
def _check_manifest_valid(self):
"""
Attempts to verify the manifest is valid. Namely checking the files
referred to exist and the files can be read from
"""
self.stdout.write("Checking the manifest")
for record in self.manifest:
if record["model"] != "documents.document":
continue
@@ -170,22 +171,37 @@ class Command(BaseCommand):
)
doc_file = record[EXPORTER_FILE_NAME]
if not os.path.exists(os.path.join(self.source, doc_file)):
doc_path = self.source / doc_file
if not doc_path.exists():
raise CommandError(
'The manifest file refers to "{}" which does not '
"appear to be in the source directory.".format(doc_file),
)
try:
with doc_path.open(mode="rb") as infile:
infile.read(1)
except Exception as e:
raise CommandError(
f"Failed to read from original file {doc_path}",
) from e
if EXPORTER_ARCHIVE_NAME in record:
archive_file = record[EXPORTER_ARCHIVE_NAME]
if not os.path.exists(os.path.join(self.source, archive_file)):
doc_archive_path = self.source / archive_file
if not doc_archive_path.exists():
raise CommandError(
f"The manifest file refers to {archive_file} which "
f"does not appear to be in the source directory.",
)
try:
with doc_archive_path.open(mode="rb") as infile:
infile.read(1)
except Exception as e:
raise CommandError(
f"Failed to read from archive file {doc_archive_path}",
) from e
def _import_files_from_manifest(self, progress_bar_disable):
os.makedirs(settings.ORIGINALS_DIR, exist_ok=True)
os.makedirs(settings.THUMBNAIL_DIR, exist_ok=True)
os.makedirs(settings.ARCHIVE_DIR, exist_ok=True)
@@ -197,7 +213,6 @@ class Command(BaseCommand):
)
for record in tqdm.tqdm(manifest_documents, disable=progress_bar_disable):
document = Document.objects.get(pk=record["pk"])
doc_file = record[EXPORTER_FILE_NAME]

View File

@@ -1,11 +1,11 @@
from django.core.management import BaseCommand
from django.db import transaction
from documents.tasks import index_optimize
from documents.tasks import index_reindex
class Command(BaseCommand):
help = "Manages the document index."
def add_arguments(self, parser):

View File

@@ -3,11 +3,11 @@ import logging
import tqdm
from django.core.management.base import BaseCommand
from django.db.models.signals import post_save
from documents.models import Document
class Command(BaseCommand):
help = """
This will rename all documents to match the latest filename format.
""".replace(
@@ -24,7 +24,6 @@ class Command(BaseCommand):
)
def handle(self, *args, **options):
logging.getLogger().handlers[0].level = logging.ERROR
for document in tqdm.tqdm(

View File

@@ -2,20 +2,18 @@ import logging
import tqdm
from django.core.management.base import BaseCommand
from documents.classifier import load_classifier
from documents.models import Document
from documents.signals.handlers import set_correspondent
from documents.signals.handlers import set_document_type
from documents.signals.handlers import set_storage_path
from documents.signals.handlers import set_tags
logger = logging.getLogger("paperless.management.retagger")
class Command(BaseCommand):
help = """
Using the current classification model, assigns correspondents, tags
and document types to all documents, effectively allowing you to
@@ -79,7 +77,6 @@ class Command(BaseCommand):
classifier = load_classifier()
for document in tqdm.tqdm(documents, disable=options["no_progress_bar"]):
if options["correspondent"]:
set_correspondent(
sender=None,

View File

@@ -1,9 +1,9 @@
from django.core.management.base import BaseCommand
from documents.sanity_checker import check_sanity
class Command(BaseCommand):
help = """
This command checks your document archive for issues.
""".replace(
@@ -20,7 +20,6 @@ class Command(BaseCommand):
)
def handle(self, *args, **options):
messages = check_sanity(progress=not options["no_progress_bar"])
messages.log_messages()

View File

@@ -5,8 +5,8 @@ import shutil
import tqdm
from django import db
from django.core.management.base import BaseCommand
from documents.models import Document
from documents.models import Document
from documents.parsers import get_parser_class_for_mime_type
@@ -21,7 +21,6 @@ def _process_document(doc_in):
return
try:
thumb = parser.get_thumbnail(
document.source_path,
document.mime_type,
@@ -34,7 +33,6 @@ def _process_document(doc_in):
class Command(BaseCommand):
help = """
This will regenerate the thumbnails for all documents.
""".replace(

View File

@@ -4,12 +4,10 @@ import os
from django.contrib.auth.models import User
from django.core.management.base import BaseCommand
logger = logging.getLogger("paperless.management.superuser")
class Command(BaseCommand):
help = """
Creates a Django superuser:
User named: admin
@@ -25,7 +23,6 @@ class Command(BaseCommand):
)
def handle(self, *args, **options):
username = os.getenv("PAPERLESS_ADMIN_USER", "admin")
mail = os.getenv("PAPERLESS_ADMIN_MAIL", "root@localhost")
password = os.getenv("PAPERLESS_ADMIN_PASSWORD")

View File

@@ -8,7 +8,6 @@ from documents.models import StoragePath
from documents.models import Tag
from documents.permissions import get_objects_for_user_owner_aware
logger = logging.getLogger("paperless.matching")
@@ -23,6 +22,9 @@ def log_reason(matching_model, document, reason):
def match_correspondents(document, classifier, user=None):
pred_id = classifier.predict_correspondent(document.content) if classifier else None
if user is None and document.owner is not None:
user = document.owner
if user is not None:
correspondents = get_objects_for_user_owner_aware(
user,
@@ -40,6 +42,9 @@ def match_correspondents(document, classifier, user=None):
def match_document_types(document, classifier, user=None):
pred_id = classifier.predict_document_type(document.content) if classifier else None
if user is None and document.owner is not None:
user = document.owner
if user is not None:
document_types = get_objects_for_user_owner_aware(
user,
@@ -57,6 +62,9 @@ def match_document_types(document, classifier, user=None):
def match_tags(document, classifier, user=None):
predicted_tag_ids = classifier.predict_tags(document.content) if classifier else []
if user is None and document.owner is not None:
user = document.owner
if user is not None:
tags = get_objects_for_user_owner_aware(user, "documents.view_tag", Tag)
else:
@@ -70,6 +78,9 @@ def match_tags(document, classifier, user=None):
def match_storage_paths(document, classifier, user=None):
pred_id = classifier.predict_storage_path(document.content) if classifier else None
if user is None and document.owner is not None:
user = document.owner
if user is not None:
storage_paths = get_objects_for_user_owner_aware(
user,

View File

@@ -1,11 +1,11 @@
# Generated by Django 1.9 on 2015-12-20 19:10
from django.db import migrations, models
from django.conf import settings
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
initial = True
dependencies = []

View File

@@ -1,11 +1,11 @@
# Generated by Django 1.9 on 2015-12-26 13:16
from django.db import migrations, models
import django.utils.timezone
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0001_initial"),
]

View File

@@ -1,16 +1,14 @@
# Generated by Django 1.9 on 2016-01-11 12:21
from django.db import migrations, models
from django.template.defaultfilters import slugify
import django.db.models.deletion
from django.db import migrations
from django.db import models
from django.template.defaultfilters import slugify
DOCUMENT_SENDER_MAP = {}
def move_sender_strings_to_sender_model(apps, schema_editor):
sender_model = apps.get_model("documents", "Sender")
document_model = apps.get_model("documents", "Document")

View File

@@ -1,11 +1,11 @@
# Generated by Django 1.9 on 2016-01-14 18:44
from django.db import migrations, models
import django.db.models.deletion
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0003_sender"),
]

View File

@@ -4,7 +4,6 @@ from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("documents", "0004_auto_20160114_1844"),
]

View File

@@ -1,10 +1,10 @@
# Generated by Django 1.9 on 2016-01-23 04:30
from django.db import migrations, models
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0005_auto_20160123_0313"),
]

View File

@@ -1,10 +1,10 @@
# Generated by Django 1.9 on 2016-01-26 21:14
from django.db import migrations, models
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0006_auto_20160123_0430"),
]

View File

@@ -1,10 +1,10 @@
# Generated by Django 1.9 on 2016-01-29 22:58
from django.db import migrations, models
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0007_auto_20160126_2114"),
]

View File

@@ -1,10 +1,10 @@
# Generated by Django 1.9 on 2016-02-14 00:40
from django.db import migrations, models
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0008_document_file_type"),
]

View File

@@ -1,10 +1,10 @@
# Generated by Django 1.9 on 2016-02-27 17:54
from django.db import migrations, models
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0009_auto_20160214_0040"),
]

View File

@@ -1,12 +1,12 @@
# Generated by Django 1.9.2 on 2016-03-05 00:40
import gnupg
import os
import re
import shutil
import subprocess
import tempfile
import gnupg
from django.conf import settings
from django.db import migrations
from django.utils.termcolors import colorize as colourise # Spelling hurts me
@@ -34,7 +34,6 @@ class GnuPG:
def move_documents_and_create_thumbnails(apps, schema_editor):
os.makedirs(
os.path.join(settings.MEDIA_ROOT, "documents", "originals"),
exist_ok=True,
@@ -67,7 +66,6 @@ def move_documents_and_create_thumbnails(apps, schema_editor):
pass
for f in sorted(documents):
if not f.endswith("gpg"):
continue

View File

@@ -1,11 +1,11 @@
# Generated by Django 1.9.4 on 2016-03-25 21:11
from django.db import migrations, models
import django.utils.timezone
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0012_auto_20160305_0040"),
]

View File

@@ -1,12 +1,13 @@
# Generated by Django 1.9.4 on 2016-03-28 19:09
import gnupg
import hashlib
import os
import django.utils.timezone
import gnupg
from django.conf import settings
from django.db import migrations, models
from django.db import migrations
from django.db import models
from django.template.defaultfilters import slugify
from django.utils.termcolors import colorize as colourise # Spelling hurts me
@@ -74,7 +75,6 @@ class Document:
def set_checksums(apps, schema_editor):
document_model = apps.get_model("documents", "Document")
if not document_model.objects.all().exists():
@@ -94,7 +94,6 @@ def set_checksums(apps, schema_editor):
sums = {}
for d in document_model.objects.all():
document = Document(d)
print(

View File

@@ -1,10 +1,10 @@
# Generated by Django 1.10.2 on 2016-10-05 21:38
from django.db import migrations, models
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0014_document_checksum"),
]

View File

@@ -1,11 +1,11 @@
# Generated by Django 1.10.5 on 2017-03-25 15:58
from django.db import migrations, models
from django.conf import settings
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0015_add_insensitive_to_match"),
]

View File

@@ -1,10 +1,10 @@
# Generated by Django 1.10.5 on 2017-05-12 05:07
from django.db import migrations, models
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0016_auto_20170325_1558"),
]

View File

@@ -1,11 +1,11 @@
# Generated by Django 1.10.5 on 2017-07-15 17:12
from django.db import migrations, models
import django.db.models.deletion
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0017_auto_20170512_0507"),
]

View File

@@ -1,5 +1,6 @@
from django.db import migrations, models
import django.utils.timezone
from django.db import migrations
from django.db import models
def set_added_time_to_created_time(apps, schema_editor):

View File

@@ -1,10 +1,10 @@
# Generated by Django 1.11.10 on 2018-02-04 13:07
from django.db import migrations, models
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0020_document_added"),
]

View File

@@ -1,6 +1,7 @@
# Generated by Django 2.0.8 on 2018-10-07 14:20
from django.db import migrations, models
from django.db import migrations
from django.db import models
from django.utils.text import slugify
@@ -19,7 +20,6 @@ def re_slug_all_the_things(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
("documents", "0021_document_storage_type"),
]

View File

@@ -1,6 +1,7 @@
# Generated by Django 2.0.10 on 2019-04-26 18:57
from django.db import migrations, models
from django.db import migrations
from django.db import models
def set_filename(apps, schema_editor):
@@ -18,7 +19,6 @@ def set_filename(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
("documents", "0022_auto_20181007_1420"),
]

View File

@@ -1,8 +1,9 @@
# Generated by Django 3.1.3 on 2020-11-07 12:35
import uuid
from django.db import migrations, models
import django.db.models.deletion
from django.db import migrations
from django.db import models
def logs_set_default_group(apps, schema_editor):
@@ -14,7 +15,6 @@ def logs_set_default_group(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
("documents", "0023_document_current_filename"),
]

View File

@@ -4,7 +4,6 @@ from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("documents", "1000_update_paperless_all"),
]

View File

@@ -1,10 +1,10 @@
# Generated by Django 3.1.3 on 2020-11-11 11:05
from django.db import migrations, models
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "1001_auto_20201109_1636"),
]

View File

@@ -3,7 +3,8 @@ import os
import magic
from django.conf import settings
from django.db import migrations, models
from django.db import migrations
from django.db import models
from paperless.db import GnuPG
@@ -29,7 +30,6 @@ def add_mime_types(apps, schema_editor):
for d in documents:
f = open(source_path(d), "rb")
if d.storage_type == STORAGE_TYPE_GPG:
data = GnuPG.decrypted(f)
else:
data = f.read(1024)
@@ -50,7 +50,6 @@ def add_file_extensions(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
("documents", "1002_auto_20201111_1105"),
]

View File

@@ -5,7 +5,6 @@ from django.db.migrations import RunPython
class Migration(migrations.Migration):
dependencies = [
("documents", "1003_mime_types"),
]

View File

@@ -1,10 +1,10 @@
# Generated by Django 3.1.3 on 2020-11-29 00:48
from django.db import migrations, models
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "1004_sanity_check_schedule"),
]

View File

@@ -4,7 +4,6 @@ from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("documents", "1005_checksums"),
]

View File

@@ -1,12 +1,12 @@
# Generated by Django 3.1.4 on 2020-12-12 14:41
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
from django.conf import settings
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("documents", "1006_auto_20201208_2209"),

View File

@@ -1,11 +1,10 @@
# Generated by Django 3.1.4 on 2020-12-16 17:36
from django.db import migrations
import django.db.models.functions.text
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("documents", "1007_savedview_savedviewfilterrule"),
]

View File

@@ -4,7 +4,6 @@ from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("documents", "1008_auto_20201216_1736"),
]

View File

@@ -1,10 +1,10 @@
# Generated by Django 3.1.4 on 2021-01-01 21:59
from django.db import migrations, models
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "1009_auto_20201216_2005"),
]

View File

@@ -1,13 +1,13 @@
# Generated by Django 3.1.4 on 2021-01-01 23:40
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
from django.conf import settings
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("documents", "1010_auto_20210101_2159"),

View File

@@ -8,11 +8,12 @@ from time import sleep
import pathvalidate
from django.conf import settings
from django.db import migrations, models
from django.db import migrations
from django.db import models
from django.template.defaultfilters import slugify
from documents.file_handling import defaultdictNoStr, many_to_dictionary
from documents.file_handling import defaultdictNoStr
from documents.file_handling import many_to_dictionary
logger = logging.getLogger("paperless.migrations")
@@ -160,11 +161,9 @@ def parse_wrapper(parser, path, mime_type, file_name):
def create_archive_version(doc, retry_count=3):
from documents.parsers import (
get_parser_class_for_mime_type,
DocumentParser,
ParseError,
)
from documents.parsers import DocumentParser
from documents.parsers import ParseError
from documents.parsers import get_parser_class_for_mime_type
logger.info(f"Regenerating archive document for document ID:{doc.id}")
parser_class = get_parser_class_for_mime_type(doc.mime_type)
@@ -255,7 +254,6 @@ def move_old_to_new_locations(apps, schema_editor):
)
for doc in Document.objects.filter(archive_checksum__isnull=False):
if doc.id in affected_document_ids:
old_path = archive_path_old(doc)
# remove affected archive versions
@@ -305,7 +303,6 @@ def move_new_to_old_locations(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
("documents", "1011_auto_20210101_2340"),
]

View File

@@ -1,6 +1,7 @@
# Generated by Django 3.1.4 on 2020-12-02 21:43
from django.db import migrations, models
from django.db import migrations
from django.db import models
COLOURS_OLD = {
1: "#a6cee3",
@@ -46,7 +47,6 @@ def reverse(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
("documents", "1012_fix_archive_files"),
]

View File

@@ -1,10 +1,10 @@
# Generated by Django 3.1.7 on 2021-02-28 15:14
from django.db import migrations, models
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "1013_migrate_tag_colour"),
]

View File

@@ -3,7 +3,6 @@ import logging
from django.db import migrations
logger = logging.getLogger("paperless.migrations")
@@ -19,7 +18,6 @@ def remove_null_characters(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
("documents", "1014_auto_20210228_1614"),
]

View File

@@ -1,10 +1,10 @@
# Generated by Django 3.1.7 on 2021-03-17 12:51
from django.db import migrations, models
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "1015_remove_null_characters"),
]

View File

@@ -1,10 +1,10 @@
# Generated by Django 3.2.12 on 2022-03-17 11:59
from django.db import migrations, models
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "1016_auto_20210317_1351"),
]

View File

@@ -1,10 +1,10 @@
# Generated by Django 4.0.3 on 2022-04-01 22:50
from django.db import migrations, models
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "1017_alter_savedviewfilterrule_rule_type"),
]

Some files were not shown because too many files have changed in this diff Show More