mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-08-07 19:08:32 -05:00
Compare commits
42 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
702b985ceb | ||
![]() |
7d87bcbb98 | ||
![]() |
340521aa0d | ||
![]() |
7bc557a999 | ||
![]() |
dfa7cdf47e | ||
![]() |
0d78e58d77 | ||
![]() |
58df3d5767 | ||
![]() |
4e4d6e806c | ||
![]() |
6ff99945f3 | ||
![]() |
b7f1b9f8ad | ||
![]() |
08a44cf468 | ||
![]() |
a1162d6d5a | ||
![]() |
1c81d88013 | ||
![]() |
1e4ec7e29e | ||
![]() |
2c4e34dd0c | ||
![]() |
cb308fae7b | ||
![]() |
3f03d51b24 | ||
![]() |
831db6ab87 | ||
![]() |
43fdf634f2 | ||
![]() |
f07a6b4586 | ||
![]() |
2fcf484229 | ||
![]() |
8bf4241b16 | ||
![]() |
56bd966c02 | ||
![]() |
416101d557 | ||
![]() |
c330cca2c9 | ||
![]() |
7e88085377 | ||
![]() |
5e669534f2 | ||
![]() |
98b147b622 | ||
![]() |
df6c59bc4f | ||
![]() |
6e48da41e5 | ||
![]() |
5c8a01a6e8 | ||
![]() |
3d0a52c25f | ||
![]() |
43c729568b | ||
![]() |
62caeed283 | ||
![]() |
12836d4c68 | ||
![]() |
b48e67d714 | ||
![]() |
f91f4d71bb | ||
![]() |
0a1f264c71 | ||
![]() |
64d61ae2fa | ||
![]() |
5f0e800f6e | ||
![]() |
8b2965d55b | ||
![]() |
ed478a1d73 |
3
Pipfile
3
Pipfile
@@ -39,7 +39,7 @@ scikit-learn="==0.24.0"
|
||||
# Prevent scipy updates because 1.6 is incompatible with python 3.6
|
||||
scipy="~=1.5.4"
|
||||
whitenoise = "~=5.2.0"
|
||||
watchdog = "*"
|
||||
watchdog = "~=1.0.0"
|
||||
whoosh="~=2.7.4"
|
||||
inotifyrecursive = "~=0.3.4"
|
||||
ocrmypdf = "~=11.6"
|
||||
@@ -51,7 +51,6 @@ channels = "~=3.0"
|
||||
channels-redis = "*"
|
||||
uvicorn = {extras = ["standard"], version = "*"}
|
||||
concurrent-log-handler = "*"
|
||||
django-redis = "*"
|
||||
# uvloop 0.15+ incompatible with python 3.6
|
||||
uvloop = "~=0.14.0"
|
||||
# TODO: keep an eye on piwheel builds and update this once available (https://www.piwheels.org/project/cryptography/)
|
||||
|
127
Pipfile.lock
generated
127
Pipfile.lock
generated
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "b3bed0a6b8981e8fffc1b6aa3bc35a0b1472f28e6f745c62469eb8045740e57b"
|
||||
"sha256": "bd8b69979d91f4d8c52cac127c891d750c52959807220a98dcf74fed126bfa26"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
@@ -60,11 +60,11 @@
|
||||
},
|
||||
"autobahn": {
|
||||
"hashes": [
|
||||
"sha256:93df8fc9d1821c9dabff9fed52181a9ad6eea5e9989d53102c391607d7c1666e",
|
||||
"sha256:cceed2121b7a93024daa93c91fae33007f8346f0e522796421f36a6183abea99"
|
||||
"sha256:41a3a3f89cde48643baf4e105d9491c566295f9abee951379e59121784044b8b",
|
||||
"sha256:7e6b1bf95196b733978bab2d54a7ab8899c16ce11be369dc58422c07b7eea726"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==21.1.1"
|
||||
"version": "==21.2.1"
|
||||
},
|
||||
"automat": {
|
||||
"hashes": [
|
||||
@@ -90,47 +90,47 @@
|
||||
},
|
||||
"cffi": {
|
||||
"hashes": [
|
||||
"sha256:00a1ba5e2e95684448de9b89888ccd02c98d512064b4cb987d48f4b40aa0421e",
|
||||
"sha256:00e28066507bfc3fe865a31f325c8391a1ac2916219340f87dfad602c3e48e5d",
|
||||
"sha256:045d792900a75e8b1e1b0ab6787dd733a8190ffcf80e8c8ceb2fb10a29ff238a",
|
||||
"sha256:0638c3ae1a0edfb77c6765d487fee624d2b1ee1bdfeffc1f0b58c64d149e7eec",
|
||||
"sha256:105abaf8a6075dc96c1fe5ae7aae073f4696f2905fde6aeada4c9d2926752362",
|
||||
"sha256:155136b51fd733fa94e1c2ea5211dcd4c8879869008fc811648f16541bf99668",
|
||||
"sha256:1a465cbe98a7fd391d47dce4b8f7e5b921e6cd805ef421d04f5f66ba8f06086c",
|
||||
"sha256:1d2c4994f515e5b485fd6d3a73d05526aa0fcf248eb135996b088d25dfa1865b",
|
||||
"sha256:23f318bf74b170c6e9adb390e8bd282457f6de46c19d03b52f3fd042b5e19654",
|
||||
"sha256:2c24d61263f511551f740d1a065eb0212db1dbbbbd241db758f5244281590c06",
|
||||
"sha256:51a8b381b16ddd370178a65360ebe15fbc1c71cf6f584613a7ea08bfad946698",
|
||||
"sha256:594234691ac0e9b770aee9fcdb8fa02c22e43e5c619456efd0d6c2bf276f3eb2",
|
||||
"sha256:5cf4be6c304ad0b6602f5c4e90e2f59b47653ac1ed9c662ed379fe48a8f26b0c",
|
||||
"sha256:64081b3f8f6f3c3de6191ec89d7dc6c86a8a43911f7ecb422c60e90c70be41c7",
|
||||
"sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009",
|
||||
"sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03",
|
||||
"sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b",
|
||||
"sha256:7ef7d4ced6b325e92eb4d3502946c78c5367bc416398d387b39591532536734e",
|
||||
"sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909",
|
||||
"sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53",
|
||||
"sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35",
|
||||
"sha256:9f7a31251289b2ab6d4012f6e83e58bc3b96bd151f5b5262467f4bb6b34a7c26",
|
||||
"sha256:9ffb888f19d54a4d4dfd4b3f29bc2c16aa4972f1c2ab9c4ab09b8ab8685b9c2b",
|
||||
"sha256:a5ed8c05548b54b998b9498753fb9cadbfd92ee88e884641377d8a8b291bcc01",
|
||||
"sha256:a7711edca4dcef1a75257b50a2fbfe92a65187c47dab5a0f1b9b332c5919a3fb",
|
||||
"sha256:af5c59122a011049aad5dd87424b8e65a80e4a6477419c0c1015f73fb5ea0293",
|
||||
"sha256:b18e0a9ef57d2b41f5c68beefa32317d286c3d6ac0484efd10d6e07491bb95dd",
|
||||
"sha256:b4e248d1087abf9f4c10f3c398896c87ce82a9856494a7155823eb45a892395d",
|
||||
"sha256:ba4e9e0ae13fc41c6b23299545e5ef73055213e466bd107953e4a013a5ddd7e3",
|
||||
"sha256:be8661bcee1bc2fc4b033a6ab65bd1f87ce5008492601695d0b9a4e820c3bde5",
|
||||
"sha256:c6332685306b6417a91b1ff9fae889b3ba65c2292d64bd9245c093b1b284809d",
|
||||
"sha256:d5ff0621c88ce83a28a10d2ce719b2ee85635e85c515f12bac99a95306da4b2e",
|
||||
"sha256:d9efd8b7a3ef378dd61a1e77367f1924375befc2eba06168b6ebfa903a5e59ca",
|
||||
"sha256:df5169c4396adc04f9b0a05f13c074df878b6052430e03f50e68adf3a57aa28d",
|
||||
"sha256:ebb253464a5d0482b191274f1c8bf00e33f7e0b9c66405fbffc61ed2c839c775",
|
||||
"sha256:ec80dc47f54e6e9a78181ce05feb71a0353854cc26999db963695f950b5fb375",
|
||||
"sha256:f032b34669220030f905152045dfa27741ce1a6db3324a5bc0b96b6c7420c87b",
|
||||
"sha256:f60567825f791c6f8a592f3c6e3bd93dd2934e3f9dac189308426bd76b00ef3b",
|
||||
"sha256:f803eaa94c2fcda012c047e62bc7a51b0bdabda1cad7a92a522694ea2d76e49f"
|
||||
"sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813",
|
||||
"sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06",
|
||||
"sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea",
|
||||
"sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee",
|
||||
"sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396",
|
||||
"sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73",
|
||||
"sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315",
|
||||
"sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1",
|
||||
"sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49",
|
||||
"sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892",
|
||||
"sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482",
|
||||
"sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058",
|
||||
"sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5",
|
||||
"sha256:5560dbf8deedbffb638d8a2da31da91094db361cc07f8a501a339b2daae2cbcc",
|
||||
"sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53",
|
||||
"sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045",
|
||||
"sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3",
|
||||
"sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5",
|
||||
"sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e",
|
||||
"sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c",
|
||||
"sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369",
|
||||
"sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827",
|
||||
"sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053",
|
||||
"sha256:9338beed13d880320450d95c9e07ccf839faa3ea7b75d788f4ed46d845044a71",
|
||||
"sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa",
|
||||
"sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4",
|
||||
"sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322",
|
||||
"sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132",
|
||||
"sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62",
|
||||
"sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa",
|
||||
"sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0",
|
||||
"sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396",
|
||||
"sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e",
|
||||
"sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991",
|
||||
"sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6",
|
||||
"sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1",
|
||||
"sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406",
|
||||
"sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d",
|
||||
"sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"
|
||||
],
|
||||
"version": "==1.14.4"
|
||||
"version": "==1.14.5"
|
||||
},
|
||||
"channels": {
|
||||
"hashes": [
|
||||
@@ -273,15 +273,6 @@
|
||||
"index": "pypi",
|
||||
"version": "==1.3.4"
|
||||
},
|
||||
"django-redis": {
|
||||
"hashes": [
|
||||
"sha256:1133b26b75baa3664164c3f44b9d5d133d1b8de45d94d79f38d1adc5b1d502e5",
|
||||
"sha256:306589c7021e6468b2656edc89f62b8ba67e8d5a1c8877e2688042263daa7a63",
|
||||
"sha256:f2b25b62cc95b63b7059aaf8e81710e7eea94678e545d31c46e47a6f4af99e56"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.12.1"
|
||||
},
|
||||
"djangorestframework": {
|
||||
"hashes": [
|
||||
"sha256:0209bafcb7b5010fdfec784034f059d512256424de2a0f084cb82b096d6dd6a7",
|
||||
@@ -600,11 +591,11 @@
|
||||
},
|
||||
"ocrmypdf": {
|
||||
"hashes": [
|
||||
"sha256:a54634d017a2f44aa2115b0b6ae5aa41a7cec018f5c53d16ad3abec1e70b3db7",
|
||||
"sha256:d0e2da48d4abd90f48f0937b2cd4ba57503b56c603f5e3aa91e20e3b21a036cd"
|
||||
"sha256:0f624456a50be0b0bc8c0b59704d159f637616c093a1cabe8bb383706561bcf7",
|
||||
"sha256:b829ad640a6160423162012e094ee2f7cd074ec99efadd7f7486954ec9182985"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==11.6.0"
|
||||
"version": "==11.6.2"
|
||||
},
|
||||
"pathvalidate": {
|
||||
"hashes": [
|
||||
@@ -850,11 +841,11 @@
|
||||
},
|
||||
"python-magic": {
|
||||
"hashes": [
|
||||
"sha256:356efa93c8899047d1eb7d3eb91e871ba2f5b1376edbaf4cc305e3c872207355",
|
||||
"sha256:b757db2a5289ea3f1ced9e60f072965243ea43a2221430048fd8cacab17be0ce"
|
||||
"sha256:8551e804c09a3398790bd9e392acb26554ae2609f29c72abb0b9dee9a5571eae",
|
||||
"sha256:ca884349f2c92ce830e3f498c5b7c7051fe2942c3ee4332f65213b8ebff15a62"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.4.18"
|
||||
"version": "==0.4.22"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
@@ -1113,11 +1104,11 @@
|
||||
},
|
||||
"tqdm": {
|
||||
"hashes": [
|
||||
"sha256:2874fa525c051177583ec59c0fb4583e91f28ccd3f217ffad2acdb32d2c789ac",
|
||||
"sha256:ab9b659241d82b8b51b2269ee243ec95286046bf06015c4e15a947cc15914211"
|
||||
"sha256:11d544652edbdfc9cc41aa4c8a5c166513e279f3f2d9f1a9e1c89935b51de6ff",
|
||||
"sha256:a89be573bfddb81bb0b395a416d5e55e3ecc73ce95a368a4f6360bedea33195e"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.56.1"
|
||||
"version": "==4.56.2"
|
||||
},
|
||||
"twisted": {
|
||||
"extras": [
|
||||
@@ -1649,11 +1640,11 @@
|
||||
},
|
||||
"pygments": {
|
||||
"hashes": [
|
||||
"sha256:bc9591213a8f0e0ca1a5e68a479b4887fdc3e75d0774e5c71c31920c427de435",
|
||||
"sha256:df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337"
|
||||
"sha256:37a13ba168a02ac54cc5891a42b1caec333e59b66addb7fa633ea8a6d73445c0",
|
||||
"sha256:b21b072d0ccdf29297a82a2363359d99623597b8a265b8081760e4d0f7153c88"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==2.7.4"
|
||||
"version": "==2.8.0"
|
||||
},
|
||||
"pyparsing": {
|
||||
"hashes": [
|
||||
@@ -1846,11 +1837,11 @@
|
||||
},
|
||||
"tox": {
|
||||
"hashes": [
|
||||
"sha256:65d0e90ceb816638a50d64f4b47b11da767b284c0addda2294cb3cd69bd72425",
|
||||
"sha256:cf7fef81a3a2434df4d7af2a6d1bf606d2970220addfbe7dea2615bd4bb2c252"
|
||||
"sha256:89afa9c59c04beb55eda789c7a65feb1a70fde117f85f1bd1c27c66758456e60",
|
||||
"sha256:ed1e650cf6368bcbc4a071eeeba363c480920e0ed8a9ad1793c7caaa5ad33d49"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.21.4"
|
||||
"version": "==3.22.0"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
|
@@ -1,5 +1,5 @@
|
||||
files:
|
||||
- source: /src/locale/en-us/LC_MESSAGES/django.po
|
||||
translation: /src/locale/%two_letters_code%/LC_MESSAGES/django.po
|
||||
- source: /src/locale/en_US/LC_MESSAGES/django.po
|
||||
translation: /src/locale/%locale_with_underscore%/LC_MESSAGES/django.po
|
||||
- source: /src-ui/messages.xlf
|
||||
translation: /src-ui/src/locale/messages.%two_letters_code%.xlf
|
||||
translation: /src-ui/src/locale/messages.%locale_with_underscore%.xlf
|
||||
|
@@ -1,4 +1,4 @@
|
||||
for command in document_archiver document_exporter document_importer mail_fetcher document_create_classifier document_index document_renamer document_retagger document_thumbnails;
|
||||
for command in document_archiver document_exporter document_importer mail_fetcher document_create_classifier document_index document_renamer document_retagger document_thumbnails document_sanity_checker;
|
||||
do
|
||||
echo "installing $command..."
|
||||
sed "s/management_command/$command/g" management_script.sh > /usr/local/bin/$command
|
||||
|
@@ -410,6 +410,34 @@ the naming scheme.
|
||||
The command takes no arguments and processes all your documents at once.
|
||||
|
||||
|
||||
.. _utilities-sanity-checker:
|
||||
|
||||
Sanity checker
|
||||
==============
|
||||
|
||||
Paperless has a built-in sanity checker that inspects your document collection for issues.
|
||||
|
||||
The issues detected by the sanity checker are as follows:
|
||||
|
||||
* Missing original files.
|
||||
* Missing archive files.
|
||||
* Inaccessible original files due to improper permissions.
|
||||
* Inaccessible archive files due to improper permissions.
|
||||
* Corrupted original documents by comparing their checksum against what is stored in the database.
|
||||
* Corrupted archive documents by comparing their checksum against what is stored in the database.
|
||||
* Missing thumbnails.
|
||||
* Inaccessible thumbnails due to improper permissions.
|
||||
* Documents without any content (warning).
|
||||
* Orphaned files in the media directory (warning). These are files that are not referenced by any document im paperless.
|
||||
|
||||
|
||||
.. code::
|
||||
|
||||
document_sanity_checker
|
||||
|
||||
The command takes no arguments. Depending on the size of your document archive, this may take some time.
|
||||
|
||||
|
||||
Fetching e-mail
|
||||
===============
|
||||
|
||||
|
@@ -5,6 +5,50 @@
|
||||
Changelog
|
||||
*********
|
||||
|
||||
paperless-ng 1.1.4
|
||||
##################
|
||||
|
||||
* Added English (GB) locale.
|
||||
|
||||
* Added ISO-8601 date display option.
|
||||
|
||||
.. note::
|
||||
|
||||
Some packages that paperless depends on are slowly dropping Python 3.6
|
||||
support one after another, including the web server. Supporting Python
|
||||
3.6 means that I cannot update these packages anymore.
|
||||
|
||||
At some point, paperless will drop Python 3.6 support. If using a bare
|
||||
metal installation and you're still on Python 3.6, upgrade to 3.7 or newer.
|
||||
|
||||
If using docker, this does not affect you.
|
||||
|
||||
paperless-ng 1.1.3
|
||||
##################
|
||||
|
||||
* Added a docker-specific configuration option to adjust the number of
|
||||
worker processes of the web server. See :ref:`configuration-docker`.
|
||||
|
||||
* Some more memory usage optimizations.
|
||||
|
||||
* Don't show inbox statistics if no inbox tag is defined.
|
||||
|
||||
paperless-ng 1.1.2
|
||||
##################
|
||||
|
||||
* Always show top left corner of thumbnails, even for extra wide documents.
|
||||
|
||||
* Added a management command for executing the sanity checker directly.
|
||||
See :ref:`utilities-sanity-checker`.
|
||||
|
||||
* The weekly sanity check now reports messages in the log files.
|
||||
|
||||
* Fixed an issue with the metadata tab not reporting anything in case of missing files.
|
||||
|
||||
* Reverted a change from 1.1.0 that caused huge memory usage due to redis caching.
|
||||
|
||||
* Some memory usage optimizations.
|
||||
|
||||
paperless-ng 1.1.1
|
||||
##################
|
||||
|
||||
|
@@ -555,3 +555,65 @@ PAPERLESS_GS_BINARY=<path>
|
||||
|
||||
PAPERLESS_OPTIPNG_BINARY=<path>
|
||||
Defaults to "/usr/bin/optipng".
|
||||
|
||||
|
||||
.. _configuration-docker:
|
||||
|
||||
Docker-specific options
|
||||
#######################
|
||||
|
||||
These options don't have any effect in ``paperless.conf``. These options adjust
|
||||
the behavior of the docker container. Configure these in `docker-compose.env`.
|
||||
|
||||
PAPERLESS_WEBSERVER_WORKERS=<num>
|
||||
The number of worker processes the webserver should spawn. More worker processes
|
||||
usually result in the front end to load data much quicker. However, each worker process
|
||||
also loads the entire application into memory separately, so increasing this value
|
||||
will increase RAM usage.
|
||||
|
||||
Consider configuring this to 1 on low power devices with limited amount of RAM.
|
||||
|
||||
Defaults to 2.
|
||||
|
||||
USERMAP_UID=<uid>
|
||||
The ID of the paperless user in the container. Set this to your actual user ID on the
|
||||
host system, which you can get by executing
|
||||
|
||||
.. code:: shell-session
|
||||
|
||||
$ id -u
|
||||
|
||||
Paperless will change ownership on its folders to this user, so you need to get this right
|
||||
in order to be able to write to the consumption directory.
|
||||
|
||||
Defaults to 1000.
|
||||
|
||||
USERMAP_GID=<gid>
|
||||
The ID of the paperless Group in the container. Set this to your actual group ID on the
|
||||
host system, which you can get by executing
|
||||
|
||||
.. code:: shell-session
|
||||
|
||||
$ id -g
|
||||
|
||||
Paperless will change ownership on its folders to this group, so you need to get this right
|
||||
in order to be able to write to the consumption directory.
|
||||
|
||||
Defaults to 1000.
|
||||
|
||||
PAPERLESS_OCR_LANGUAGES=<list>
|
||||
Additional OCR languages to install. By default, paperless comes with
|
||||
English, German, Italian, Spanish and French. If your language is not in this list, install
|
||||
additional languages with this configuration option:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
PAPERLESS_OCR_LANGUAGES=tur ces
|
||||
|
||||
To actually use these languages, also set the default OCR language of paperless:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
PAPERLESS_OCR_LANGUAGE=tur
|
||||
|
||||
Defaults to none, which does not install any additional languages.
|
||||
|
@@ -763,7 +763,8 @@ configuring some options in paperless can help improve performance immensely:
|
||||
|
||||
* Stick with SQLite to save some resources.
|
||||
* Consider setting ``PAPERLESS_OCR_PAGES`` to 1, so that paperless will only OCR
|
||||
the first page of your documents.
|
||||
the first page of your documents. In most cases, this page contains enough
|
||||
information to be able to find it.
|
||||
* ``PAPERLESS_TASK_WORKERS`` and ``PAPERLESS_THREADS_PER_WORKER`` are configured
|
||||
to use all cores. The Raspberry Pi models 3 and up have 4 cores, meaning that
|
||||
paperless will use 2 workers and 2 threads per worker. This may result in
|
||||
@@ -776,6 +777,8 @@ configuring some options in paperless can help improve performance immensely:
|
||||
file generation for already ocr'ed documents entirely.
|
||||
* Set ``PAPERLESS_OPTIMIZE_THUMBNAILS`` to 'false' if you want faster consumption
|
||||
times. Thumbnails will be about 20% larger.
|
||||
* If using docker, consider setting ``PAPERLESS_WEBSERVER_WORKERS`` to
|
||||
1. This will save some memory.
|
||||
|
||||
For details, refer to :ref:`configuration`.
|
||||
|
||||
|
@@ -94,6 +94,30 @@ If you want to get rid of the warning or actually experience issues with automat
|
||||
the file ``classification_model.pickle`` in the data directory and let paperless recreate it.
|
||||
|
||||
|
||||
504 Server Error: Gateway Timeout when adding Office documents
|
||||
##############################################################
|
||||
|
||||
You may experience these errors when using the optional TIKA integration:
|
||||
|
||||
.. code::
|
||||
|
||||
requests.exceptions.HTTPError: 504 Server Error: Gateway Timeout for url: http://gotenberg:3000/convert/office
|
||||
|
||||
Gotenberg is a server that converts Office documents into PDF documents and has a default timeout of 10 seconds.
|
||||
When conversion takes longer, Gotenberg raises this error.
|
||||
|
||||
You can increase the timeout by configuring an environment variable for gotenberg (see also `here <https://thecodingmachine.github.io/gotenberg/#environment_variables.default_wait_timeout>`__).
|
||||
If using docker-compose, this is achieved by the following configuration change in the ``docker-compose.yml`` file:
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
gotenberg:
|
||||
image: thecodingmachine/gotenberg
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
DISABLE_GOOGLE_CHROME: 1
|
||||
DEFAULT_WAIT_TIMEOUT: 30
|
||||
|
||||
Permission denied errors in the consumption directory
|
||||
#####################################################
|
||||
|
||||
|
@@ -1,5 +1,7 @@
|
||||
import os
|
||||
|
||||
bind = '0.0.0.0:8000'
|
||||
workers = 2
|
||||
workers = int(os.getenv("PAPERLESS_WEBSERVER_WORKERS", 2))
|
||||
worker_class = 'uvicorn.workers.UvicornWorker'
|
||||
timeout = 120
|
||||
|
||||
|
@@ -12,11 +12,11 @@ arrow==0.17.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2,
|
||||
asgiref==3.3.1; python_version >= '3.5'
|
||||
async-timeout==3.0.1; python_full_version >= '3.5.3'
|
||||
attrs==20.3.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
||||
autobahn==21.1.1; python_version >= '3.6'
|
||||
autobahn==21.2.1; python_version >= '3.6'
|
||||
automat==20.2.0
|
||||
blessed==1.17.12
|
||||
certifi==2020.12.5
|
||||
cffi==1.14.4
|
||||
cffi==1.14.5
|
||||
channels-redis==3.2.0
|
||||
channels==3.0.3
|
||||
chardet==4.0.0; python_version >= '3.1'
|
||||
@@ -32,7 +32,6 @@ django-extensions==3.1.1
|
||||
django-filter==2.4.0
|
||||
django-picklefield==3.0.1; python_version >= '3'
|
||||
django-q==1.3.4
|
||||
django-redis==4.12.1
|
||||
django==3.1.6
|
||||
djangorestframework==3.12.2
|
||||
filelock==3.0.12
|
||||
@@ -54,7 +53,7 @@ langdetect==1.0.8
|
||||
lxml==4.6.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
||||
msgpack==1.0.2
|
||||
numpy==1.19.5
|
||||
ocrmypdf==11.6.0
|
||||
ocrmypdf==11.6.2
|
||||
pathvalidate==2.3.2
|
||||
pdfminer.six==20201018; python_version >= '3.4'
|
||||
pdftotext==2.1.5
|
||||
@@ -72,7 +71,7 @@ python-dateutil==2.8.1
|
||||
python-dotenv==0.15.0
|
||||
python-gnupg==0.4.6
|
||||
python-levenshtein==0.12.2
|
||||
python-magic==0.4.18
|
||||
python-magic==0.4.22
|
||||
pytz==2021.1
|
||||
pyyaml==5.4.1
|
||||
redis==3.5.3
|
||||
@@ -87,7 +86,7 @@ sortedcontainers==2.3.0
|
||||
sqlparse==0.4.1; python_version >= '3.5'
|
||||
threadpoolctl==2.1.0; python_version >= '3.5'
|
||||
tika==1.24
|
||||
tqdm==4.56.1
|
||||
tqdm==4.56.2
|
||||
twisted[tls]==20.3.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
||||
txaio==20.12.1; python_version >= '3.6'
|
||||
tzlocal==2.1
|
||||
|
@@ -18,7 +18,8 @@
|
||||
"locales": {
|
||||
"de": "src/locale/messages.de.xlf",
|
||||
"nl-NL": "src/locale/messages.nl_NL.xlf",
|
||||
"fr": "src/locale/messages.fr.xlf"
|
||||
"fr": "src/locale/messages.fr.xlf",
|
||||
"en-GB": "src/locale/messages.en_GB.xlf"
|
||||
}
|
||||
},
|
||||
"architect": {
|
||||
|
@@ -64,10 +64,12 @@ import { CustomDatePipe } from './pipes/custom-date.pipe';
|
||||
import localeFr from '@angular/common/locales/fr';
|
||||
import localeNl from '@angular/common/locales/nl';
|
||||
import localeDe from '@angular/common/locales/de';
|
||||
import localeEnGb from '@angular/common/locales/en-GB';
|
||||
|
||||
registerLocaleData(localeFr)
|
||||
registerLocaleData(localeNl)
|
||||
registerLocaleData(localeDe)
|
||||
registerLocaleData(localeEnGb)
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<app-widget-frame title="Statistics" i18n-title>
|
||||
<ng-container content>
|
||||
<p class="card-text" i18n>Documents in inbox: {{statistics.documents_inbox}}</p>
|
||||
<p class="card-text" i18n>Total documents: {{statistics.documents_total}}</p>
|
||||
<p class="card-text" i18n *ngIf="statistics?.documents_inbox != null">Documents in inbox: {{statistics?.documents_inbox}}</p>
|
||||
<p class="card-text" i18n>Total documents: {{statistics?.documents_total}}</p>
|
||||
</ng-container>
|
||||
</app-widget-frame>
|
||||
|
@@ -6,7 +6,7 @@
|
||||
|
||||
.doc-img {
|
||||
object-fit: cover;
|
||||
object-position: top;
|
||||
object-position: top left;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
mix-blend-mode: multiply;
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
.doc-img {
|
||||
object-fit: cover;
|
||||
object-position: top;
|
||||
object-position: top left;
|
||||
height: 200px;
|
||||
mix-blend-mode: multiply;
|
||||
}
|
||||
|
@@ -34,7 +34,7 @@
|
||||
<div class="col">
|
||||
|
||||
<select class="form-control" formControlName="dateLocale">
|
||||
<option *ngFor="let lang of dateLocaleOptions" [ngValue]="lang.code">{{lang.name}}<span *ngIf="lang.code"> - {{today | date:'shortDate':null:lang.code}}</span></option>
|
||||
<option *ngFor="let lang of dateLocaleOptions" [ngValue]="lang.code">{{lang.name}}<span *ngIf="lang.code"> - {{today | customDate:'shortDate':null:lang.code}}</span></option>
|
||||
</select>
|
||||
|
||||
</div>
|
||||
@@ -167,7 +167,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div [ngbNavOutlet]="nav" class="border-left border-right border-bottom p-3 mb-3 shadow"></div>
|
||||
<div [ngbNavOutlet]="nav" class="border-left border-right border-bottom p-3 mb-3 shadow-sm"></div>
|
||||
|
||||
<button type="submit" class="btn btn-primary" i18n>Save</button>
|
||||
</form>
|
||||
|
@@ -35,7 +35,7 @@ export class SettingsComponent implements OnInit {
|
||||
savedViews: PaperlessSavedView[]
|
||||
|
||||
get computedDateLocale(): string {
|
||||
return this.settingsForm.value.dateLocale || this.settingsForm.value.displayLanguage
|
||||
return this.settingsForm.value.dateLocale || this.settingsForm.value.displayLanguage || this.currentLocale
|
||||
}
|
||||
|
||||
constructor(
|
||||
@@ -92,7 +92,10 @@ export class SettingsComponent implements OnInit {
|
||||
}
|
||||
|
||||
get dateLocaleOptions(): LanguageOption[] {
|
||||
return [{code: "", name: $localize`Use date format of display language`}].concat(this.settings.getLanguageOptions())
|
||||
return [
|
||||
{code: "", name: $localize`Use date format of display language`},
|
||||
{code: "iso-8601", name: $localize`ISO 8601`}
|
||||
].concat(this.settings.getLanguageOptions())
|
||||
}
|
||||
|
||||
get today() {
|
||||
|
@@ -2,18 +2,29 @@ import { DatePipe } from '@angular/common';
|
||||
import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core';
|
||||
import { SettingsService, SETTINGS_KEYS } from '../services/settings.service';
|
||||
|
||||
const FORMAT_TO_ISO_FORMAT = {
|
||||
"longDate": "y-MM-dd",
|
||||
"mediumDate": "yy-MM-dd",
|
||||
"shortDate": "yy-MM-dd"
|
||||
}
|
||||
|
||||
@Pipe({
|
||||
name: 'customDate'
|
||||
})
|
||||
export class CustomDatePipe extends DatePipe implements PipeTransform {
|
||||
|
||||
constructor(@Inject(LOCALE_ID) locale: string, private settings: SettingsService) {
|
||||
super(settings.get(SETTINGS_KEYS.DATE_LOCALE) || locale)
|
||||
|
||||
super(locale)
|
||||
}
|
||||
|
||||
transform(value: any, format?: string, timezone?: string, locale?: string): string | null {
|
||||
return super.transform(value, format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT), timezone, locale)
|
||||
let l = locale || this.settings.get(SETTINGS_KEYS.DATE_LOCALE)
|
||||
let f = format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT)
|
||||
if (l == "iso-8601") {
|
||||
return super.transform(value, FORMAT_TO_ISO_FORMAT[f], timezone)
|
||||
} else {
|
||||
return super.transform(value, format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT), timezone, locale)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -169,7 +169,12 @@ export class ConsumerStatusService {
|
||||
}
|
||||
|
||||
dismiss(status: FileStatus) {
|
||||
let index = this.consumerStatus.findIndex(s => s.filename == status.filename)
|
||||
let index
|
||||
if (status.taskId != null) {
|
||||
index = this.consumerStatus.findIndex(s => s.taskId == status.taskId)
|
||||
} else {
|
||||
index = this.consumerStatus.findIndex(s => s.filename == status.filename)
|
||||
}
|
||||
|
||||
if (index > -1) {
|
||||
this.consumerStatus.splice(index, 1)
|
||||
|
@@ -79,7 +79,8 @@ export class SettingsService {
|
||||
|
||||
getLanguageOptions(): LanguageOption[] {
|
||||
return [
|
||||
{code: "en-US", name: $localize`English (US)`, englishName: "English (US)"},
|
||||
{code: "en-us", name: $localize`English (US)`, englishName: "English (US)"},
|
||||
{code: "en-gb", name: $localize`English (GB)`, englishName: "English (GB)"},
|
||||
{code: "de", name: $localize`German`, englishName: "German"},
|
||||
{code: "nl", name: $localize`Dutch`, englishName: "Dutch"},
|
||||
{code: "fr", name: $localize`French`, englishName: "French"}
|
||||
|
@@ -2,7 +2,7 @@ export const environment = {
|
||||
production: true,
|
||||
apiBaseUrl: "/api/",
|
||||
appTitle: "Paperless-ng",
|
||||
version: "1.1.1",
|
||||
version: "1.1.4",
|
||||
webSocketHost: window.location.host,
|
||||
webSocketProtocol: (window.location.protocol == "https:" ? "wss:" : "ws:")
|
||||
};
|
||||
|
@@ -515,7 +515,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit datatype="html" id="8fa4d523f7b91df4390120b85ed0406138273e1a">
|
||||
<source>Color</source>
|
||||
<target>Color</target>
|
||||
<target>Colour</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/manage/tag-list/tag-list.component.html</context>
|
||||
<context context-type="linenumber">20</context>
|
||||
|
@@ -1,10 +1,6 @@
|
||||
from django.contrib import admin
|
||||
from django.utils.html import format_html, format_html_join
|
||||
from django.utils.safestring import mark_safe
|
||||
from whoosh.writing import AsyncWriter
|
||||
|
||||
from . import index
|
||||
from .models import Correspondent, Document, DocumentType, Log, Tag, \
|
||||
from .models import Correspondent, Document, DocumentType, Tag, \
|
||||
SavedView, SavedViewFilterRule
|
||||
|
||||
|
||||
@@ -86,17 +82,21 @@ class DocumentAdmin(admin.ModelAdmin):
|
||||
created_.short_description = "Created"
|
||||
|
||||
def delete_queryset(self, request, queryset):
|
||||
ix = index.open_index()
|
||||
with AsyncWriter(ix) as writer:
|
||||
from documents import index
|
||||
|
||||
with index.open_index_writer() as writer:
|
||||
for o in queryset:
|
||||
index.remove_document(writer, o)
|
||||
|
||||
super(DocumentAdmin, self).delete_queryset(request, queryset)
|
||||
|
||||
def delete_model(self, request, obj):
|
||||
from documents import index
|
||||
index.remove_document_from_index(obj)
|
||||
super(DocumentAdmin, self).delete_model(request, obj)
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
from documents import index
|
||||
index.add_or_update_document(obj)
|
||||
super(DocumentAdmin, self).save_model(request, obj, form, change)
|
||||
|
||||
|
@@ -2,9 +2,7 @@ import itertools
|
||||
|
||||
from django.db.models import Q
|
||||
from django_q.tasks import async_task
|
||||
from whoosh.writing import AsyncWriter
|
||||
|
||||
from documents import index
|
||||
from documents.models import Document, Correspondent, DocumentType
|
||||
|
||||
|
||||
@@ -99,8 +97,9 @@ def modify_tags(doc_ids, add_tags, remove_tags):
|
||||
def delete(doc_ids):
|
||||
Document.objects.filter(id__in=doc_ids).delete()
|
||||
|
||||
ix = index.open_index()
|
||||
with AsyncWriter(ix) as writer:
|
||||
from documents import index
|
||||
|
||||
with index.open_index_writer() as writer:
|
||||
for id in doc_ids:
|
||||
index.remove_document_by_id(writer, id)
|
||||
|
||||
|
@@ -5,7 +5,6 @@ import pickle
|
||||
import re
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
|
||||
from documents.models import Document, MatchingModel
|
||||
|
||||
@@ -31,29 +30,23 @@ def load_classifier():
|
||||
)
|
||||
return None
|
||||
|
||||
version = os.stat(settings.MODEL_FILE).st_mtime
|
||||
classifier = DocumentClassifier()
|
||||
try:
|
||||
classifier.load()
|
||||
|
||||
classifier = cache.get("paperless-classifier", version=version)
|
||||
|
||||
if not classifier:
|
||||
classifier = DocumentClassifier()
|
||||
try:
|
||||
classifier.load()
|
||||
cache.set("paperless-classifier", classifier,
|
||||
version=version, timeout=86400)
|
||||
except (EOFError, IncompatibleClassifierVersionError) as e:
|
||||
# there's something wrong with the model file.
|
||||
logger.exception(
|
||||
f"Unrecoverable error while loading document "
|
||||
f"classification model, deleting model file."
|
||||
)
|
||||
os.unlink(settings.MODEL_FILE)
|
||||
classifier = None
|
||||
except OSError as e:
|
||||
logger.error(
|
||||
f"Error while loading document classification model: {str(e)}"
|
||||
)
|
||||
classifier = None
|
||||
except (EOFError, IncompatibleClassifierVersionError) as e:
|
||||
# there's something wrong with the model file.
|
||||
logger.exception(
|
||||
f"Unrecoverable error while loading document "
|
||||
f"classification model, deleting model file."
|
||||
)
|
||||
os.unlink(settings.MODEL_FILE)
|
||||
classifier = None
|
||||
except OSError as e:
|
||||
logger.error(
|
||||
f"Error while loading document classification model: {str(e)}"
|
||||
)
|
||||
classifier = None
|
||||
|
||||
return classifier
|
||||
|
||||
@@ -102,9 +95,6 @@ class DocumentClassifier(object):
|
||||
pickle.dump(self.document_type_classifier, f)
|
||||
|
||||
def train(self):
|
||||
from sklearn.feature_extraction.text import CountVectorizer
|
||||
from sklearn.neural_network import MLPClassifier
|
||||
from sklearn.preprocessing import MultiLabelBinarizer, LabelBinarizer
|
||||
|
||||
data = list()
|
||||
labels_tags = list()
|
||||
@@ -169,6 +159,10 @@ class DocumentClassifier(object):
|
||||
)
|
||||
)
|
||||
|
||||
from sklearn.feature_extraction.text import CountVectorizer
|
||||
from sklearn.neural_network import MLPClassifier
|
||||
from sklearn.preprocessing import MultiLabelBinarizer, LabelBinarizer
|
||||
|
||||
# Step 2: vectorize data
|
||||
logger.debug("Vectorizing data...")
|
||||
self.data_vectorizer = CountVectorizer(
|
||||
|
@@ -86,6 +86,22 @@ def open_index(recreate=False):
|
||||
return create_in(settings.INDEX_DIR, get_schema())
|
||||
|
||||
|
||||
@contextmanager
|
||||
def open_index_writer(ix=None, optimize=False):
|
||||
if ix:
|
||||
writer = AsyncWriter(ix)
|
||||
else:
|
||||
writer = AsyncWriter(open_index())
|
||||
|
||||
try:
|
||||
yield writer
|
||||
except Exception as e:
|
||||
logger.exception(str(e))
|
||||
writer.cancel()
|
||||
finally:
|
||||
writer.commit(optimize=optimize)
|
||||
|
||||
|
||||
def update_document(writer, doc):
|
||||
tags = ",".join([t.name for t in doc.tags.all()])
|
||||
writer.update_document(
|
||||
@@ -110,14 +126,12 @@ def remove_document_by_id(writer, doc_id):
|
||||
|
||||
|
||||
def add_or_update_document(document):
|
||||
ix = open_index()
|
||||
with AsyncWriter(ix) as writer:
|
||||
with open_index_writer() as writer:
|
||||
update_document(writer, document)
|
||||
|
||||
|
||||
def remove_document_from_index(document):
|
||||
ix = open_index()
|
||||
with AsyncWriter(ix) as writer:
|
||||
with open_index_writer() as writer:
|
||||
remove_document(writer, document)
|
||||
|
||||
|
||||
|
15
src/documents/management/commands/document_sanity_checker.py
Normal file
15
src/documents/management/commands/document_sanity_checker.py
Normal file
@@ -0,0 +1,15 @@
|
||||
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(" ", "")
|
||||
|
||||
def handle(self, *args, **options):
|
||||
|
||||
messages = check_sanity(progress=True)
|
||||
|
||||
messages.log_messages()
|
@@ -6,7 +6,6 @@ import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
import dateparser
|
||||
import magic
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
@@ -200,6 +199,8 @@ def parse_date(filename, text):
|
||||
"""
|
||||
Call dateparser.parse with a particular date ordering
|
||||
"""
|
||||
import dateparser
|
||||
|
||||
return dateparser.parse(
|
||||
ds,
|
||||
settings={
|
||||
|
@@ -1,45 +1,55 @@
|
||||
import hashlib
|
||||
import logging
|
||||
import os
|
||||
|
||||
from django.conf import settings
|
||||
from tqdm import tqdm
|
||||
|
||||
from documents.models import Document
|
||||
|
||||
|
||||
class SanityMessage:
|
||||
message = None
|
||||
class SanityCheckMessages:
|
||||
|
||||
def __init__(self):
|
||||
self._messages = []
|
||||
|
||||
def error(self, message):
|
||||
self._messages.append({"level": logging.ERROR, "message": message})
|
||||
|
||||
def warning(self, message):
|
||||
self._messages.append({"level": logging.WARNING, "message": message})
|
||||
|
||||
def info(self, message):
|
||||
self._messages.append({"level": logging.INFO, "message": message})
|
||||
|
||||
def log_messages(self):
|
||||
logger = logging.getLogger("paperless.sanity_checker")
|
||||
|
||||
if len(self._messages) == 0:
|
||||
logger.info("Sanity checker detected no issues.")
|
||||
else:
|
||||
for msg in self._messages:
|
||||
logger.log(msg['level'], msg['message'])
|
||||
|
||||
def __len__(self):
|
||||
return len(self._messages)
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self._messages[item]
|
||||
|
||||
def has_error(self):
|
||||
return any([msg['level'] == logging.ERROR for msg in self._messages])
|
||||
|
||||
def has_warning(self):
|
||||
return any([msg['level'] == logging.WARNING for msg in self._messages])
|
||||
|
||||
|
||||
class SanityWarning(SanityMessage):
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
|
||||
def __str__(self):
|
||||
return f"Warning: {self.message}"
|
||||
class SanityCheckFailedException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class SanityError(SanityMessage):
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
|
||||
def __str__(self):
|
||||
return f"ERROR: {self.message}"
|
||||
|
||||
|
||||
class SanityFailedError(Exception):
|
||||
|
||||
def __init__(self, messages):
|
||||
self.messages = messages
|
||||
|
||||
def __str__(self):
|
||||
message_string = "\n".join([str(m) for m in self.messages])
|
||||
return (
|
||||
f"The following issuse were found by the sanity checker:\n"
|
||||
f"{message_string}\n\n===============\n\n")
|
||||
|
||||
|
||||
def check_sanity():
|
||||
messages = []
|
||||
def check_sanity(progress=False):
|
||||
messages = SanityCheckMessages()
|
||||
|
||||
present_files = []
|
||||
for root, subdirs, files in os.walk(settings.MEDIA_ROOT):
|
||||
@@ -50,11 +60,15 @@ def check_sanity():
|
||||
if lockfile in present_files:
|
||||
present_files.remove(lockfile)
|
||||
|
||||
for doc in Document.objects.all():
|
||||
if progress:
|
||||
docs = tqdm(Document.objects.all())
|
||||
else:
|
||||
docs = Document.objects.all()
|
||||
|
||||
for doc in docs:
|
||||
# Check sanity of the thumbnail
|
||||
if not os.path.isfile(doc.thumbnail_path):
|
||||
messages.append(SanityError(
|
||||
f"Thumbnail of document {doc.pk} does not exist."))
|
||||
messages.error(f"Thumbnail of document {doc.pk} does not exist.")
|
||||
else:
|
||||
if os.path.normpath(doc.thumbnail_path) in present_files:
|
||||
present_files.remove(os.path.normpath(doc.thumbnail_path))
|
||||
@@ -62,15 +76,14 @@ def check_sanity():
|
||||
with doc.thumbnail_file as f:
|
||||
f.read()
|
||||
except OSError as e:
|
||||
messages.append(SanityError(
|
||||
messages.error(
|
||||
f"Cannot read thumbnail file of document {doc.pk}: {e}"
|
||||
))
|
||||
)
|
||||
|
||||
# Check sanity of the original file
|
||||
# TODO: extract method
|
||||
if not os.path.isfile(doc.source_path):
|
||||
messages.append(SanityError(
|
||||
f"Original of document {doc.pk} does not exist."))
|
||||
messages.error(f"Original of document {doc.pk} does not exist.")
|
||||
else:
|
||||
if os.path.normpath(doc.source_path) in present_files:
|
||||
present_files.remove(os.path.normpath(doc.source_path))
|
||||
@@ -78,31 +91,31 @@ def check_sanity():
|
||||
with doc.source_file as f:
|
||||
checksum = hashlib.md5(f.read()).hexdigest()
|
||||
except OSError as e:
|
||||
messages.append(SanityError(
|
||||
f"Cannot read original file of document {doc.pk}: {e}"))
|
||||
messages.error(
|
||||
f"Cannot read original file of document {doc.pk}: {e}")
|
||||
else:
|
||||
if not checksum == doc.checksum:
|
||||
messages.append(SanityError(
|
||||
messages.error(
|
||||
f"Checksum mismatch of document {doc.pk}. "
|
||||
f"Stored: {doc.checksum}, actual: {checksum}."
|
||||
))
|
||||
)
|
||||
|
||||
# Check sanity of the archive file.
|
||||
if doc.archive_checksum and not doc.archive_filename:
|
||||
messages.append(SanityError(
|
||||
messages.error(
|
||||
f"Document {doc.pk} has an archive file checksum, but no "
|
||||
f"archive filename."
|
||||
))
|
||||
)
|
||||
elif not doc.archive_checksum and doc.archive_filename:
|
||||
messages.append(SanityError(
|
||||
messages.error(
|
||||
f"Document {doc.pk} has an archive file, but its checksum is "
|
||||
f"missing."
|
||||
))
|
||||
)
|
||||
elif doc.has_archive_version:
|
||||
if not os.path.isfile(doc.archive_path):
|
||||
messages.append(SanityError(
|
||||
messages.error(
|
||||
f"Archived version of document {doc.pk} does not exist."
|
||||
))
|
||||
)
|
||||
else:
|
||||
if os.path.normpath(doc.archive_path) in present_files:
|
||||
present_files.remove(os.path.normpath(doc.archive_path))
|
||||
@@ -110,26 +123,23 @@ def check_sanity():
|
||||
with doc.archive_file as f:
|
||||
checksum = hashlib.md5(f.read()).hexdigest()
|
||||
except OSError as e:
|
||||
messages.append(SanityError(
|
||||
messages.error(
|
||||
f"Cannot read archive file of document {doc.pk}: {e}"
|
||||
))
|
||||
)
|
||||
else:
|
||||
if not checksum == doc.archive_checksum:
|
||||
messages.append(SanityError(
|
||||
messages.error(
|
||||
f"Checksum mismatch of archived document "
|
||||
f"{doc.pk}. "
|
||||
f"Stored: {doc.checksum}, actual: {checksum}."
|
||||
))
|
||||
f"Stored: {doc.archive_checksum}, "
|
||||
f"actual: {checksum}."
|
||||
)
|
||||
|
||||
# other document checks
|
||||
if not doc.content:
|
||||
messages.append(SanityWarning(
|
||||
f"Document {doc.pk} has no content."
|
||||
))
|
||||
messages.info(f"Document {doc.pk} has no content.")
|
||||
|
||||
for extra_file in present_files:
|
||||
messages.append(SanityWarning(
|
||||
f"Orphaned file in media dir: {extra_file}"
|
||||
))
|
||||
messages.warning(f"Orphaned file in media dir: {extra_file}")
|
||||
|
||||
return messages
|
||||
|
@@ -11,7 +11,7 @@ from django.dispatch import receiver
|
||||
from django.utils import timezone
|
||||
from filelock import FileLock
|
||||
|
||||
from .. import index, matching
|
||||
from .. import matching
|
||||
from ..file_handling import delete_empty_directories, \
|
||||
create_source_path_directory, \
|
||||
generate_unique_filename
|
||||
@@ -305,4 +305,6 @@ def set_log_entry(sender, document=None, logging_group=None, **kwargs):
|
||||
|
||||
|
||||
def add_to_index(sender, document, **kwargs):
|
||||
from documents import index
|
||||
|
||||
index.add_or_update_document(document)
|
||||
|
@@ -9,8 +9,7 @@ from documents import index, sanity_checker
|
||||
from documents.classifier import DocumentClassifier, load_classifier
|
||||
from documents.consumer import Consumer, ConsumerError
|
||||
from documents.models import Document, Tag, DocumentType, Correspondent
|
||||
from documents.sanity_checker import SanityFailedError
|
||||
|
||||
from documents.sanity_checker import SanityCheckFailedException
|
||||
|
||||
logger = logging.getLogger("paperless.tasks")
|
||||
|
||||
@@ -94,8 +93,15 @@ def consume_file(path,
|
||||
def sanity_check():
|
||||
messages = sanity_checker.check_sanity()
|
||||
|
||||
if len(messages) > 0:
|
||||
raise SanityFailedError(messages)
|
||||
messages.log_messages()
|
||||
|
||||
if messages.has_error():
|
||||
raise SanityCheckFailedException(
|
||||
"Sanity check failed with errors. See log.")
|
||||
elif messages.has_warning():
|
||||
return "Sanity check exited with warnings. See log."
|
||||
elif len(messages) > 0:
|
||||
return "Sanity check exited with infos. See log."
|
||||
else:
|
||||
return "No issues detected."
|
||||
|
||||
|
@@ -4,6 +4,7 @@ from django.contrib.admin.sites import AdminSite
|
||||
from django.test import TestCase
|
||||
from django.utils import timezone
|
||||
|
||||
from documents import index
|
||||
from documents.admin import DocumentAdmin
|
||||
from documents.models import Document
|
||||
from documents.tests.utils import DirectoriesMixin
|
||||
@@ -11,37 +12,52 @@ from documents.tests.utils import DirectoriesMixin
|
||||
|
||||
class TestDocumentAdmin(DirectoriesMixin, TestCase):
|
||||
|
||||
def get_document_from_index(self, doc):
|
||||
ix = index.open_index()
|
||||
with ix.searcher() as searcher:
|
||||
return searcher.document(id=doc.id)
|
||||
|
||||
def setUp(self) -> None:
|
||||
super(TestDocumentAdmin, self).setUp()
|
||||
self.doc_admin = DocumentAdmin(model=Document, admin_site=AdminSite())
|
||||
|
||||
@mock.patch("documents.admin.index.add_or_update_document")
|
||||
def test_save_model(self, m):
|
||||
def test_save_model(self):
|
||||
doc = Document.objects.create(title="test")
|
||||
|
||||
doc.title = "new title"
|
||||
self.doc_admin.save_model(None, doc, None, None)
|
||||
self.assertEqual(Document.objects.get(id=doc.id).title, "new title")
|
||||
m.assert_called_once()
|
||||
self.assertEqual(self.get_document_from_index(doc)['title'], "new title")
|
||||
|
||||
@mock.patch("documents.admin.index.remove_document")
|
||||
def test_delete_model(self, m):
|
||||
def test_delete_model(self):
|
||||
doc = Document.objects.create(title="test")
|
||||
self.doc_admin.delete_model(None, doc)
|
||||
self.assertRaises(Document.DoesNotExist, Document.objects.get, id=doc.id)
|
||||
m.assert_called_once()
|
||||
index.add_or_update_document(doc)
|
||||
self.assertIsNotNone(self.get_document_from_index(doc))
|
||||
|
||||
@mock.patch("documents.admin.index.remove_document")
|
||||
def test_delete_queryset(self, m):
|
||||
self.doc_admin.delete_model(None, doc)
|
||||
|
||||
self.assertRaises(Document.DoesNotExist, Document.objects.get, id=doc.id)
|
||||
self.assertIsNone(self.get_document_from_index(doc))
|
||||
|
||||
def test_delete_queryset(self):
|
||||
docs = []
|
||||
for i in range(42):
|
||||
Document.objects.create(title="Many documents with the same title", checksum=f"{i:02}")
|
||||
doc = Document.objects.create(title="Many documents with the same title", checksum=f"{i:02}")
|
||||
docs.append(doc)
|
||||
index.add_or_update_document(doc)
|
||||
|
||||
self.assertEqual(Document.objects.count(), 42)
|
||||
|
||||
for doc in docs:
|
||||
self.assertIsNotNone(self.get_document_from_index(doc))
|
||||
|
||||
self.doc_admin.delete_queryset(None, Document.objects.all())
|
||||
|
||||
self.assertEqual(m.call_count, 42)
|
||||
self.assertEqual(Document.objects.count(), 0)
|
||||
|
||||
for doc in docs:
|
||||
self.assertIsNone(self.get_document_from_index(doc))
|
||||
|
||||
def test_created(self):
|
||||
doc = Document.objects.create(title="test", created=timezone.datetime(2020, 4, 12))
|
||||
self.assertEqual(self.doc_admin.created_(doc), "2020-04-12")
|
||||
|
@@ -442,6 +442,13 @@ class TestDocumentApi(DirectoriesMixin, APITestCase):
|
||||
self.assertEqual(response.data['documents_total'], 3)
|
||||
self.assertEqual(response.data['documents_inbox'], 1)
|
||||
|
||||
def test_statistics_no_inbox_tag(self):
|
||||
Document.objects.create(title="none1", checksum="A")
|
||||
|
||||
response = self.client.get("/api/statistics/")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.data['documents_inbox'], None)
|
||||
|
||||
@mock.patch("documents.views.async_task")
|
||||
def test_upload(self, m):
|
||||
|
||||
@@ -577,8 +584,11 @@ class TestDocumentApi(DirectoriesMixin, APITestCase):
|
||||
def test_get_metadata(self):
|
||||
doc = Document.objects.create(title="test", filename="file.pdf", mime_type="image/png", archive_checksum="A", archive_filename="archive.pdf")
|
||||
|
||||
shutil.copy(os.path.join(os.path.dirname(__file__), "samples", "documents", "thumbnails", "0000001.png"), doc.source_path)
|
||||
shutil.copy(os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), doc.archive_path)
|
||||
source_file = os.path.join(os.path.dirname(__file__), "samples", "documents", "thumbnails", "0000001.png")
|
||||
archive_file = os.path.join(os.path.dirname(__file__), "samples", "simple.pdf")
|
||||
|
||||
shutil.copy(source_file, doc.source_path)
|
||||
shutil.copy(archive_file, doc.archive_path)
|
||||
|
||||
response = self.client.get(f"/api/documents/{doc.pk}/metadata/")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
@@ -591,6 +601,8 @@ class TestDocumentApi(DirectoriesMixin, APITestCase):
|
||||
self.assertGreater(len(meta['archive_metadata']), 0)
|
||||
self.assertEqual(meta['media_filename'], "file.pdf")
|
||||
self.assertEqual(meta['archive_media_filename'], "archive.pdf")
|
||||
self.assertEqual(meta['original_size'], os.stat(source_file).st_size)
|
||||
self.assertEqual(meta['archive_size'], os.stat(archive_file).st_size)
|
||||
|
||||
def test_get_metadata_invalid_doc(self):
|
||||
response = self.client.get(f"/api/documents/34576/metadata/")
|
||||
@@ -612,6 +624,21 @@ class TestDocumentApi(DirectoriesMixin, APITestCase):
|
||||
self.assertIsNone(meta['archive_metadata'])
|
||||
self.assertIsNone(meta['archive_media_filename'])
|
||||
|
||||
def test_get_metadata_missing_files(self):
|
||||
doc = Document.objects.create(title="test", filename="file.pdf", mime_type="application/pdf", archive_filename="file.pdf", archive_checksum="B", checksum="A")
|
||||
|
||||
response = self.client.get(f"/api/documents/{doc.pk}/metadata/")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
meta = response.data
|
||||
|
||||
self.assertTrue(meta['has_archive_version'])
|
||||
self.assertIsNone(meta['original_metadata'])
|
||||
self.assertIsNone(meta['original_size'])
|
||||
self.assertIsNone(meta['archive_metadata'])
|
||||
self.assertIsNone(meta['archive_size'])
|
||||
|
||||
|
||||
def test_get_empty_suggestions(self):
|
||||
doc = Document.objects.create(title="test", mime_type="application/pdf")
|
||||
|
||||
|
@@ -3,6 +3,7 @@ import tempfile
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from django.conf import settings
|
||||
from django.test import TestCase, override_settings
|
||||
|
||||
@@ -233,7 +234,6 @@ class TestClassifier(DirectoriesMixin, TestCase):
|
||||
self.assertFalse(os.path.exists(settings.MODEL_FILE))
|
||||
self.assertIsNone(load_classifier())
|
||||
|
||||
@override_settings(CACHES={'default': {'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}})
|
||||
@mock.patch("documents.classifier.DocumentClassifier.load")
|
||||
def test_load_classifier(self, load):
|
||||
Path(settings.MODEL_FILE).touch()
|
||||
@@ -242,6 +242,7 @@ class TestClassifier(DirectoriesMixin, TestCase):
|
||||
|
||||
@override_settings(CACHES={'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}})
|
||||
@override_settings(MODEL_FILE=os.path.join(os.path.dirname(__file__), "data", "model.pickle"))
|
||||
@pytest.mark.skip(reason="Disabled caching due to high memory usage - need to investigate.")
|
||||
def test_load_classifier_cached(self):
|
||||
classifier = load_classifier()
|
||||
self.assertIsNotNone(classifier)
|
||||
@@ -250,7 +251,6 @@ class TestClassifier(DirectoriesMixin, TestCase):
|
||||
classifier2 = load_classifier()
|
||||
load.assert_not_called()
|
||||
|
||||
@override_settings(CACHES={'default': {'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}})
|
||||
@mock.patch("documents.classifier.DocumentClassifier.load")
|
||||
def test_load_classifier_incompatible_version(self, load):
|
||||
Path(settings.MODEL_FILE).touch()
|
||||
@@ -260,7 +260,6 @@ class TestClassifier(DirectoriesMixin, TestCase):
|
||||
self.assertIsNone(load_classifier())
|
||||
self.assertFalse(os.path.exists(settings.MODEL_FILE))
|
||||
|
||||
@override_settings(CACHES={'default': {'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}})
|
||||
@mock.patch("documents.classifier.DocumentClassifier.load")
|
||||
def test_load_classifier_os_error(self, load):
|
||||
Path(settings.MODEL_FILE).touch()
|
||||
|
@@ -65,6 +65,7 @@ class TestArchiver(DirectoriesMixin, TestCase):
|
||||
self.assertEqual(doc1.archive_filename, "document.pdf")
|
||||
self.assertEqual(doc2.archive_filename, "document_01.pdf")
|
||||
|
||||
|
||||
class TestDecryptDocuments(TestCase):
|
||||
|
||||
@override_settings(
|
||||
@@ -154,3 +155,24 @@ class TestCreateClassifier(TestCase):
|
||||
call_command("document_create_classifier")
|
||||
|
||||
m.assert_called_once()
|
||||
|
||||
|
||||
class TestSanityChecker(DirectoriesMixin, TestCase):
|
||||
|
||||
def test_no_issues(self):
|
||||
with self.assertLogs() as capture:
|
||||
call_command("document_sanity_checker")
|
||||
|
||||
self.assertEqual(len(capture.output), 1)
|
||||
self.assertIn("Sanity checker detected no issues.", capture.output[0])
|
||||
|
||||
def test_errors(self):
|
||||
doc = Document.objects.create(title="test", content="test", filename="test.pdf", checksum="abc")
|
||||
Path(doc.source_path).touch()
|
||||
Path(doc.thumbnail_path).touch()
|
||||
|
||||
with self.assertLogs() as capture:
|
||||
call_command("document_sanity_checker")
|
||||
|
||||
self.assertEqual(len(capture.output), 1)
|
||||
self.assertIn("Checksum mismatch of document", capture.output[0])
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
@@ -7,10 +8,59 @@ from django.conf import settings
|
||||
from django.test import TestCase
|
||||
|
||||
from documents.models import Document
|
||||
from documents.sanity_checker import check_sanity, SanityFailedError
|
||||
from documents.sanity_checker import check_sanity, SanityCheckMessages
|
||||
from documents.tests.utils import DirectoriesMixin
|
||||
|
||||
|
||||
class TestSanityCheckMessages(TestCase):
|
||||
|
||||
def test_no_messages(self):
|
||||
messages = SanityCheckMessages()
|
||||
self.assertEqual(len(messages), 0)
|
||||
self.assertFalse(messages.has_error())
|
||||
self.assertFalse(messages.has_warning())
|
||||
with self.assertLogs() as capture:
|
||||
messages.log_messages()
|
||||
self.assertEqual(len(capture.output), 1)
|
||||
self.assertEqual(capture.records[0].levelno, logging.INFO)
|
||||
self.assertEqual(capture.records[0].message, "Sanity checker detected no issues.")
|
||||
|
||||
def test_info(self):
|
||||
messages = SanityCheckMessages()
|
||||
messages.info("Something might be wrong")
|
||||
self.assertEqual(len(messages), 1)
|
||||
self.assertFalse(messages.has_error())
|
||||
self.assertFalse(messages.has_warning())
|
||||
with self.assertLogs() as capture:
|
||||
messages.log_messages()
|
||||
self.assertEqual(len(capture.output), 1)
|
||||
self.assertEqual(capture.records[0].levelno, logging.INFO)
|
||||
self.assertEqual(capture.records[0].message, "Something might be wrong")
|
||||
|
||||
def test_warning(self):
|
||||
messages = SanityCheckMessages()
|
||||
messages.warning("Something is wrong")
|
||||
self.assertEqual(len(messages), 1)
|
||||
self.assertFalse(messages.has_error())
|
||||
self.assertTrue(messages.has_warning())
|
||||
with self.assertLogs() as capture:
|
||||
messages.log_messages()
|
||||
self.assertEqual(len(capture.output), 1)
|
||||
self.assertEqual(capture.records[0].levelno, logging.WARNING)
|
||||
self.assertEqual(capture.records[0].message, "Something is wrong")
|
||||
|
||||
def test_error(self):
|
||||
messages = SanityCheckMessages()
|
||||
messages.error("Something is seriously wrong")
|
||||
self.assertEqual(len(messages), 1)
|
||||
self.assertTrue(messages.has_error())
|
||||
self.assertFalse(messages.has_warning())
|
||||
with self.assertLogs() as capture:
|
||||
messages.log_messages()
|
||||
self.assertEqual(len(capture.output), 1)
|
||||
self.assertEqual(capture.records[0].levelno, logging.ERROR)
|
||||
self.assertEqual(capture.records[0].message, "Something is seriously wrong")
|
||||
|
||||
class TestSanityCheck(DirectoriesMixin, TestCase):
|
||||
|
||||
def make_test_data(self):
|
||||
@@ -23,6 +73,11 @@ class TestSanityCheck(DirectoriesMixin, TestCase):
|
||||
|
||||
return Document.objects.create(title="test", checksum="42995833e01aea9b3edee44bbfdd7ce1", archive_checksum="62acb0bcbfbcaa62ca6ad3668e4e404b", content="test", pk=1, filename="0000001.pdf", mime_type="application/pdf", archive_filename="0000001.pdf")
|
||||
|
||||
def assertSanityError(self, messageRegex):
|
||||
messages = check_sanity()
|
||||
self.assertTrue(messages.has_error())
|
||||
self.assertRegex(messages[0]['message'], messageRegex)
|
||||
|
||||
def test_no_docs(self):
|
||||
self.assertEqual(len(check_sanity()), 0)
|
||||
|
||||
@@ -33,72 +88,75 @@ class TestSanityCheck(DirectoriesMixin, TestCase):
|
||||
def test_no_thumbnail(self):
|
||||
doc = self.make_test_data()
|
||||
os.remove(doc.thumbnail_path)
|
||||
self.assertEqual(len(check_sanity()), 1)
|
||||
self.assertSanityError("Thumbnail of document .* does not exist")
|
||||
|
||||
def test_thumbnail_no_access(self):
|
||||
doc = self.make_test_data()
|
||||
os.chmod(doc.thumbnail_path, 0o000)
|
||||
self.assertEqual(len(check_sanity()), 1)
|
||||
self.assertSanityError("Cannot read thumbnail file of document")
|
||||
os.chmod(doc.thumbnail_path, 0o777)
|
||||
|
||||
def test_no_original(self):
|
||||
doc = self.make_test_data()
|
||||
os.remove(doc.source_path)
|
||||
self.assertEqual(len(check_sanity()), 1)
|
||||
self.assertSanityError("Original of document .* does not exist.")
|
||||
|
||||
def test_original_no_access(self):
|
||||
doc = self.make_test_data()
|
||||
os.chmod(doc.source_path, 0o000)
|
||||
self.assertEqual(len(check_sanity()), 1)
|
||||
self.assertSanityError("Cannot read original file of document")
|
||||
os.chmod(doc.source_path, 0o777)
|
||||
|
||||
def test_original_checksum_mismatch(self):
|
||||
doc = self.make_test_data()
|
||||
doc.checksum = "WOW"
|
||||
doc.save()
|
||||
self.assertEqual(len(check_sanity()), 1)
|
||||
self.assertSanityError("Checksum mismatch of document")
|
||||
|
||||
def test_no_archive(self):
|
||||
doc = self.make_test_data()
|
||||
os.remove(doc.archive_path)
|
||||
self.assertEqual(len(check_sanity()), 1)
|
||||
self.assertSanityError("Archived version of document .* does not exist.")
|
||||
|
||||
def test_archive_no_access(self):
|
||||
doc = self.make_test_data()
|
||||
os.chmod(doc.archive_path, 0o000)
|
||||
self.assertEqual(len(check_sanity()), 1)
|
||||
self.assertSanityError("Cannot read archive file of document")
|
||||
os.chmod(doc.archive_path, 0o777)
|
||||
|
||||
def test_archive_checksum_mismatch(self):
|
||||
doc = self.make_test_data()
|
||||
doc.archive_checksum = "WOW"
|
||||
doc.save()
|
||||
self.assertEqual(len(check_sanity()), 1)
|
||||
self.assertSanityError("Checksum mismatch of archived document")
|
||||
|
||||
def test_empty_content(self):
|
||||
doc = self.make_test_data()
|
||||
doc.content = ""
|
||||
doc.save()
|
||||
self.assertEqual(len(check_sanity()), 1)
|
||||
messages = check_sanity()
|
||||
self.assertFalse(messages.has_error())
|
||||
self.assertFalse(messages.has_warning())
|
||||
self.assertEqual(len(messages), 1)
|
||||
self.assertRegex(messages[0]['message'], "Document .* has no content.")
|
||||
|
||||
def test_orphaned_file(self):
|
||||
doc = self.make_test_data()
|
||||
Path(self.dirs.originals_dir, "orphaned").touch()
|
||||
self.assertEqual(len(check_sanity()), 1)
|
||||
|
||||
def test_error_tostring(self):
|
||||
Document.objects.create(title="test", checksum="dgfhj", archive_checksum="dfhg", content="", pk=1, filename="0000001.pdf", archive_filename="0000001.pdf")
|
||||
string = str(SanityFailedError(check_sanity()))
|
||||
self.assertIsNotNone(string)
|
||||
messages = check_sanity()
|
||||
self.assertFalse(messages.has_error())
|
||||
self.assertTrue(messages.has_warning())
|
||||
self.assertEqual(len(messages), 1)
|
||||
self.assertRegex(messages[0]['message'], "Orphaned file in media dir")
|
||||
|
||||
def test_archive_filename_no_checksum(self):
|
||||
doc = self.make_test_data()
|
||||
doc.archive_checksum = None
|
||||
doc.save()
|
||||
self.assertEqual(len(check_sanity()), 2)
|
||||
self.assertSanityError("has an archive file, but its checksum is missing.")
|
||||
|
||||
def test_archive_checksum_no_filename(self):
|
||||
doc = self.make_test_data()
|
||||
doc.archive_filename = None
|
||||
doc.save()
|
||||
self.assertEqual(len(check_sanity()), 2)
|
||||
self.assertSanityError("has an archive file checksum, but no archive filename.")
|
||||
|
@@ -2,12 +2,12 @@ import os
|
||||
from unittest import mock
|
||||
|
||||
from django.conf import settings
|
||||
from django.test import TestCase, override_settings
|
||||
from django.test import TestCase
|
||||
from django.utils import timezone
|
||||
|
||||
from documents import tasks
|
||||
from documents.models import Document, Tag, Correspondent, DocumentType
|
||||
from documents.sanity_checker import SanityError, SanityFailedError
|
||||
from documents.sanity_checker import SanityCheckMessages, SanityCheckFailedException
|
||||
from documents.tests.utils import DirectoriesMixin
|
||||
|
||||
|
||||
@@ -52,7 +52,6 @@ class TestTasks(DirectoriesMixin, TestCase):
|
||||
load_classifier.assert_called_once()
|
||||
self.assertFalse(os.path.isfile(settings.MODEL_FILE))
|
||||
|
||||
@override_settings(CACHES={'default': {'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}})
|
||||
def test_train_classifier(self):
|
||||
c = Correspondent.objects.create(matching_algorithm=Tag.MATCH_AUTO, name="test")
|
||||
doc = Document.objects.create(correspondent=c, content="test", title="test")
|
||||
@@ -75,13 +74,33 @@ class TestTasks(DirectoriesMixin, TestCase):
|
||||
self.assertNotEqual(mtime2, mtime3)
|
||||
|
||||
@mock.patch("documents.tasks.sanity_checker.check_sanity")
|
||||
def test_sanity_check(self, m):
|
||||
m.return_value = []
|
||||
tasks.sanity_check()
|
||||
def test_sanity_check_success(self, m):
|
||||
m.return_value = SanityCheckMessages()
|
||||
self.assertEqual(tasks.sanity_check(), "No issues detected.")
|
||||
m.assert_called_once()
|
||||
m.reset_mock()
|
||||
m.return_value = [SanityError("")]
|
||||
self.assertRaises(SanityFailedError, tasks.sanity_check)
|
||||
|
||||
@mock.patch("documents.tasks.sanity_checker.check_sanity")
|
||||
def test_sanity_check_error(self, m):
|
||||
messages = SanityCheckMessages()
|
||||
messages.error("Some error")
|
||||
m.return_value = messages
|
||||
self.assertRaises(SanityCheckFailedException, tasks.sanity_check)
|
||||
m.assert_called_once()
|
||||
|
||||
@mock.patch("documents.tasks.sanity_checker.check_sanity")
|
||||
def test_sanity_check_warning(self, m):
|
||||
messages = SanityCheckMessages()
|
||||
messages.warning("Some warning")
|
||||
m.return_value = messages
|
||||
self.assertEqual(tasks.sanity_check(), "Sanity check exited with warnings. See log.")
|
||||
m.assert_called_once()
|
||||
|
||||
@mock.patch("documents.tasks.sanity_checker.check_sanity")
|
||||
def test_sanity_check_info(self, m):
|
||||
messages = SanityCheckMessages()
|
||||
messages.info("Some info")
|
||||
m.return_value = messages
|
||||
self.assertEqual(tasks.sanity_check(), "Sanity check exited with infos. See log.")
|
||||
m.assert_called_once()
|
||||
|
||||
def test_bulk_update_documents(self):
|
||||
|
@@ -32,7 +32,6 @@ from rest_framework.viewsets import (
|
||||
ViewSet
|
||||
)
|
||||
|
||||
import documents.index as index
|
||||
from paperless.db import GnuPG
|
||||
from paperless.views import StandardPagination
|
||||
from .classifier import load_classifier
|
||||
@@ -176,10 +175,12 @@ class DocumentViewSet(RetrieveModelMixin,
|
||||
def update(self, request, *args, **kwargs):
|
||||
response = super(DocumentViewSet, self).update(
|
||||
request, *args, **kwargs)
|
||||
from documents import index
|
||||
index.add_or_update_document(self.get_object())
|
||||
return response
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
from documents import index
|
||||
index.remove_document_from_index(self.get_object())
|
||||
return super(DocumentViewSet, self).destroy(request, *args, **kwargs)
|
||||
|
||||
@@ -225,6 +226,12 @@ class DocumentViewSet(RetrieveModelMixin,
|
||||
else:
|
||||
return []
|
||||
|
||||
def get_filesize(self, filename):
|
||||
if os.path.isfile(filename):
|
||||
return os.stat(filename).st_size
|
||||
else:
|
||||
return None
|
||||
|
||||
@action(methods=['get'], detail=True)
|
||||
def metadata(self, request, pk=None):
|
||||
try:
|
||||
@@ -234,7 +241,7 @@ class DocumentViewSet(RetrieveModelMixin,
|
||||
|
||||
meta = {
|
||||
"original_checksum": doc.checksum,
|
||||
"original_size": os.stat(doc.source_path).st_size,
|
||||
"original_size": self.get_filesize(doc.source_path),
|
||||
"original_mime_type": doc.mime_type,
|
||||
"media_filename": doc.filename,
|
||||
"has_archive_version": doc.has_archive_version,
|
||||
@@ -245,7 +252,7 @@ class DocumentViewSet(RetrieveModelMixin,
|
||||
}
|
||||
|
||||
if doc.has_archive_version:
|
||||
meta['archive_size'] = os.stat(doc.archive_path).st_size,
|
||||
meta['archive_size'] = self.get_filesize(doc.archive_path)
|
||||
meta['archive_metadata'] = self.get_metadata(
|
||||
doc.archive_path, "application/pdf")
|
||||
else:
|
||||
@@ -495,10 +502,6 @@ class SearchView(APIView):
|
||||
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SearchView, self).__init__(*args, **kwargs)
|
||||
self.ix = index.open_index()
|
||||
|
||||
def add_infos_to_hit(self, r):
|
||||
try:
|
||||
doc = Document.objects.get(id=r['id'])
|
||||
@@ -519,6 +522,7 @@ class SearchView(APIView):
|
||||
}
|
||||
|
||||
def get(self, request, format=None):
|
||||
from documents import index
|
||||
|
||||
if 'query' in request.query_params:
|
||||
query = request.query_params['query']
|
||||
@@ -548,8 +552,10 @@ class SearchView(APIView):
|
||||
if page < 1:
|
||||
page = 1
|
||||
|
||||
ix = index.open_index()
|
||||
|
||||
try:
|
||||
with index.query_page(self.ix, page, query, more_like_id, more_like_content) as (result_page, corrected_query): # NOQA: E501
|
||||
with index.query_page(ix, page, query, more_like_id, more_like_content) as (result_page, corrected_query): # NOQA: E501
|
||||
return Response(
|
||||
{'count': len(result_page),
|
||||
'page': result_page.pagenum,
|
||||
@@ -564,10 +570,6 @@ class SearchAutoCompleteView(APIView):
|
||||
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SearchAutoCompleteView, self).__init__(*args, **kwargs)
|
||||
self.ix = index.open_index()
|
||||
|
||||
def get(self, request, format=None):
|
||||
if 'term' in request.query_params:
|
||||
term = request.query_params['term']
|
||||
@@ -581,7 +583,11 @@ class SearchAutoCompleteView(APIView):
|
||||
else:
|
||||
limit = 10
|
||||
|
||||
return Response(index.autocomplete(self.ix, term, limit))
|
||||
from documents import index
|
||||
|
||||
ix = index.open_index()
|
||||
|
||||
return Response(index.autocomplete(ix, term, limit))
|
||||
|
||||
|
||||
class StatisticsView(APIView):
|
||||
@@ -589,8 +595,14 @@ class StatisticsView(APIView):
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
def get(self, request, format=None):
|
||||
return Response({
|
||||
'documents_total': Document.objects.all().count(),
|
||||
'documents_inbox': Document.objects.filter(
|
||||
documents_total = Document.objects.all().count()
|
||||
if Tag.objects.filter(is_inbox_tag=True).exists():
|
||||
documents_inbox = Document.objects.filter(
|
||||
tags__is_inbox_tag=True).distinct().count()
|
||||
else:
|
||||
documents_inbox = None
|
||||
|
||||
return Response({
|
||||
'documents_total': documents_total,
|
||||
'documents_inbox': documents_inbox,
|
||||
})
|
||||
|
650
src/locale/cs/LC_MESSAGES/django.po
Normal file
650
src/locale/cs/LC_MESSAGES/django.po
Normal file
@@ -0,0 +1,650 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
# Translators:
|
||||
# Štěpán Šebestian <mys.orangeorange0123@gmail.com>, 2021
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-01-28 22:02+0100\n"
|
||||
"PO-Revision-Date: 2020-12-30 19:27+0000\n"
|
||||
"Last-Translator: Štěpán Šebestian <mys.orangeorange0123@gmail.com>, 2021\n"
|
||||
"Language-Team: Czech (https://www.transifex.com/paperless/teams/115905/cs/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: cs\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n"
|
||||
|
||||
#: documents/apps.py:10
|
||||
msgid "Documents"
|
||||
msgstr "Dokumenty"
|
||||
|
||||
#: documents/models.py:33
|
||||
msgid "Any word"
|
||||
msgstr "Jakékoliv slovo"
|
||||
|
||||
#: documents/models.py:34
|
||||
msgid "All words"
|
||||
msgstr "Všechna slova"
|
||||
|
||||
#: documents/models.py:35
|
||||
msgid "Exact match"
|
||||
msgstr "Přesná shoda"
|
||||
|
||||
#: documents/models.py:36
|
||||
msgid "Regular expression"
|
||||
msgstr "Regulární výraz"
|
||||
|
||||
#: documents/models.py:37
|
||||
msgid "Fuzzy word"
|
||||
msgstr "Fuzzy slovo"
|
||||
|
||||
#: documents/models.py:38
|
||||
msgid "Automatic"
|
||||
msgstr "Automatický"
|
||||
|
||||
#: documents/models.py:42 documents/models.py:352 paperless_mail/models.py:25
|
||||
#: paperless_mail/models.py:109
|
||||
msgid "name"
|
||||
msgstr "název"
|
||||
|
||||
#: documents/models.py:46
|
||||
msgid "match"
|
||||
msgstr "shoda"
|
||||
|
||||
#: documents/models.py:50
|
||||
msgid "matching algorithm"
|
||||
msgstr "algoritmus pro shodu"
|
||||
|
||||
#: documents/models.py:56
|
||||
msgid "is insensitive"
|
||||
msgstr "je ignorováno"
|
||||
|
||||
#: documents/models.py:75 documents/models.py:135
|
||||
msgid "correspondent"
|
||||
msgstr "korespondent"
|
||||
|
||||
#: documents/models.py:76
|
||||
msgid "correspondents"
|
||||
msgstr "korespondenti"
|
||||
|
||||
#: documents/models.py:98
|
||||
msgid "color"
|
||||
msgstr "barva"
|
||||
|
||||
#: documents/models.py:102
|
||||
msgid "is inbox tag"
|
||||
msgstr "tag přichozí"
|
||||
|
||||
#: documents/models.py:104
|
||||
msgid ""
|
||||
"Marks this tag as an inbox tag: All newly consumed documents will be tagged "
|
||||
"with inbox tags."
|
||||
msgstr ""
|
||||
"Označí tento tag jako tag pro příchozí: Všechny nově zkonzumované dokumenty "
|
||||
"budou označeny tagem pro přichozí"
|
||||
|
||||
#: documents/models.py:109
|
||||
msgid "tag"
|
||||
msgstr "tag"
|
||||
|
||||
#: documents/models.py:110 documents/models.py:166
|
||||
msgid "tags"
|
||||
msgstr "tagy"
|
||||
|
||||
#: documents/models.py:116 documents/models.py:148
|
||||
msgid "document type"
|
||||
msgstr "typ dokumentu"
|
||||
|
||||
#: documents/models.py:117
|
||||
msgid "document types"
|
||||
msgstr "typy dokumentu"
|
||||
|
||||
#: documents/models.py:125
|
||||
msgid "Unencrypted"
|
||||
msgstr "Nešifrované"
|
||||
|
||||
#: documents/models.py:126
|
||||
msgid "Encrypted with GNU Privacy Guard"
|
||||
msgstr "Šifrované pomocí GNU Privacy Guard"
|
||||
|
||||
#: documents/models.py:139
|
||||
msgid "title"
|
||||
msgstr "titulek"
|
||||
|
||||
#: documents/models.py:152
|
||||
msgid "content"
|
||||
msgstr "obsah"
|
||||
|
||||
#: documents/models.py:154
|
||||
msgid ""
|
||||
"The raw, text-only data of the document. This field is primarily used for "
|
||||
"searching."
|
||||
msgstr ""
|
||||
"Nezpracovaná, pouze textová data dokumentu. Toto pole je používáno především"
|
||||
" pro vyhledávání."
|
||||
|
||||
#: documents/models.py:159
|
||||
msgid "mime type"
|
||||
msgstr "mime typ"
|
||||
|
||||
#: documents/models.py:170
|
||||
msgid "checksum"
|
||||
msgstr "kontrolní součet"
|
||||
|
||||
#: documents/models.py:174
|
||||
msgid "The checksum of the original document."
|
||||
msgstr "Kontrolní součet původního dokumentu"
|
||||
|
||||
#: documents/models.py:178
|
||||
msgid "archive checksum"
|
||||
msgstr "kontrolní součet archivu"
|
||||
|
||||
#: documents/models.py:183
|
||||
msgid "The checksum of the archived document."
|
||||
msgstr "Kontrolní součet archivovaného dokumentu."
|
||||
|
||||
#: documents/models.py:187 documents/models.py:330
|
||||
msgid "created"
|
||||
msgstr "vytvořeno"
|
||||
|
||||
#: documents/models.py:191
|
||||
msgid "modified"
|
||||
msgstr "upraveno"
|
||||
|
||||
#: documents/models.py:195
|
||||
msgid "storage type"
|
||||
msgstr "typ úložiště"
|
||||
|
||||
#: documents/models.py:203
|
||||
msgid "added"
|
||||
msgstr "přidáno"
|
||||
|
||||
#: documents/models.py:207
|
||||
msgid "filename"
|
||||
msgstr "název souboru"
|
||||
|
||||
#: documents/models.py:212
|
||||
msgid "Current filename in storage"
|
||||
msgstr "Aktuální název souboru v úložišti"
|
||||
|
||||
#: documents/models.py:216
|
||||
msgid "archive serial number"
|
||||
msgstr "sériové číslo archivu"
|
||||
|
||||
#: documents/models.py:221
|
||||
msgid "The position of this document in your physical document archive."
|
||||
msgstr "Pozice dokumentu ve vašem archivu fyzických dokumentů"
|
||||
|
||||
#: documents/models.py:227
|
||||
msgid "document"
|
||||
msgstr "dokument"
|
||||
|
||||
#: documents/models.py:228
|
||||
msgid "documents"
|
||||
msgstr "dokumenty"
|
||||
|
||||
#: documents/models.py:313
|
||||
msgid "debug"
|
||||
msgstr "debug"
|
||||
|
||||
#: documents/models.py:314
|
||||
msgid "information"
|
||||
msgstr "informace"
|
||||
|
||||
#: documents/models.py:315
|
||||
msgid "warning"
|
||||
msgstr "varování"
|
||||
|
||||
#: documents/models.py:316
|
||||
msgid "error"
|
||||
msgstr "chyba"
|
||||
|
||||
#: documents/models.py:317
|
||||
msgid "critical"
|
||||
msgstr "kritická"
|
||||
|
||||
#: documents/models.py:321
|
||||
msgid "group"
|
||||
msgstr "skupina"
|
||||
|
||||
#: documents/models.py:324
|
||||
msgid "message"
|
||||
msgstr "zpráva"
|
||||
|
||||
#: documents/models.py:327
|
||||
msgid "level"
|
||||
msgstr "úroveň"
|
||||
|
||||
#: documents/models.py:334
|
||||
msgid "log"
|
||||
msgstr "záznam"
|
||||
|
||||
#: documents/models.py:335
|
||||
msgid "logs"
|
||||
msgstr "záznamy"
|
||||
|
||||
#: documents/models.py:346 documents/models.py:396
|
||||
msgid "saved view"
|
||||
msgstr "uložený pohled"
|
||||
|
||||
#: documents/models.py:347
|
||||
msgid "saved views"
|
||||
msgstr "uložené pohledy"
|
||||
|
||||
#: documents/models.py:350
|
||||
msgid "user"
|
||||
msgstr "uživatel"
|
||||
|
||||
#: documents/models.py:356
|
||||
msgid "show on dashboard"
|
||||
msgstr "zobrazit v dashboardu"
|
||||
|
||||
#: documents/models.py:359
|
||||
msgid "show in sidebar"
|
||||
msgstr "zobrazit v postranním menu"
|
||||
|
||||
#: documents/models.py:363
|
||||
msgid "sort field"
|
||||
msgstr "pole na řazení"
|
||||
|
||||
#: documents/models.py:366
|
||||
msgid "sort reverse"
|
||||
msgstr "třídit opačně"
|
||||
|
||||
#: documents/models.py:372
|
||||
msgid "title contains"
|
||||
msgstr "titulek obsahuje"
|
||||
|
||||
#: documents/models.py:373
|
||||
msgid "content contains"
|
||||
msgstr "obsah obsahuje"
|
||||
|
||||
#: documents/models.py:374
|
||||
msgid "ASN is"
|
||||
msgstr "ASN je"
|
||||
|
||||
#: documents/models.py:375
|
||||
msgid "correspondent is"
|
||||
msgstr "korespondent je"
|
||||
|
||||
#: documents/models.py:376
|
||||
msgid "document type is"
|
||||
msgstr "typ dokumentu je"
|
||||
|
||||
#: documents/models.py:377
|
||||
msgid "is in inbox"
|
||||
msgstr "je v příchozích"
|
||||
|
||||
#: documents/models.py:378
|
||||
msgid "has tag"
|
||||
msgstr "má tag"
|
||||
|
||||
#: documents/models.py:379
|
||||
msgid "has any tag"
|
||||
msgstr "má jakýkoliv tag"
|
||||
|
||||
#: documents/models.py:380
|
||||
msgid "created before"
|
||||
msgstr "vytvořeno před"
|
||||
|
||||
#: documents/models.py:381
|
||||
msgid "created after"
|
||||
msgstr "vytvořeno po"
|
||||
|
||||
#: documents/models.py:382
|
||||
msgid "created year is"
|
||||
msgstr "rok vytvoření je"
|
||||
|
||||
#: documents/models.py:383
|
||||
msgid "created month is"
|
||||
msgstr "měsíc vytvoření je"
|
||||
|
||||
#: documents/models.py:384
|
||||
msgid "created day is"
|
||||
msgstr "den vytvoření je"
|
||||
|
||||
#: documents/models.py:385
|
||||
msgid "added before"
|
||||
msgstr "přidáno před"
|
||||
|
||||
#: documents/models.py:386
|
||||
msgid "added after"
|
||||
msgstr "přidáno po"
|
||||
|
||||
#: documents/models.py:387
|
||||
msgid "modified before"
|
||||
msgstr "upraveno před"
|
||||
|
||||
#: documents/models.py:388
|
||||
msgid "modified after"
|
||||
msgstr "upraveno po"
|
||||
|
||||
#: documents/models.py:389
|
||||
msgid "does not have tag"
|
||||
msgstr "nemá tag"
|
||||
|
||||
#: documents/models.py:400
|
||||
msgid "rule type"
|
||||
msgstr "typ pravidla"
|
||||
|
||||
#: documents/models.py:404
|
||||
msgid "value"
|
||||
msgstr "hodnota"
|
||||
|
||||
#: documents/models.py:410
|
||||
msgid "filter rule"
|
||||
msgstr "filtrovací pravidlo"
|
||||
|
||||
#: documents/models.py:411
|
||||
msgid "filter rules"
|
||||
msgstr "filtrovací pravidla"
|
||||
|
||||
#: documents/serialisers.py:383
|
||||
#, python-format
|
||||
msgid "File type %(type)s not supported"
|
||||
msgstr "Typ souboru %(type)s není podporován"
|
||||
|
||||
#: documents/templates/index.html:20
|
||||
msgid "Paperless-ng is loading..."
|
||||
msgstr "Paperless-ng se načítá..."
|
||||
|
||||
#: documents/templates/registration/logged_out.html:13
|
||||
msgid "Paperless-ng signed out"
|
||||
msgstr "Odhlášeno od Paperless-ng"
|
||||
|
||||
#: documents/templates/registration/logged_out.html:41
|
||||
msgid "You have been successfully logged out. Bye!"
|
||||
msgstr "Byli jste úspěšně odhlášeni. Nashledanou!"
|
||||
|
||||
#: documents/templates/registration/logged_out.html:42
|
||||
msgid "Sign in again"
|
||||
msgstr "Přihlašte se znovu"
|
||||
|
||||
#: documents/templates/registration/login.html:13
|
||||
msgid "Paperless-ng sign in"
|
||||
msgstr "Paperless-ng přihlášení"
|
||||
|
||||
#: documents/templates/registration/login.html:42
|
||||
msgid "Please sign in."
|
||||
msgstr "Prosím přihlaste se."
|
||||
|
||||
#: documents/templates/registration/login.html:45
|
||||
msgid "Your username and password didn't match. Please try again."
|
||||
msgstr "Vaše uživatelské jméno a heslo se neshodují. Prosím, zkuste to znovu."
|
||||
|
||||
#: documents/templates/registration/login.html:48
|
||||
msgid "Username"
|
||||
msgstr "Uživatelské jméno"
|
||||
|
||||
#: documents/templates/registration/login.html:49
|
||||
msgid "Password"
|
||||
msgstr "Heslo"
|
||||
|
||||
#: documents/templates/registration/login.html:54
|
||||
msgid "Sign in"
|
||||
msgstr "Přihlásit se"
|
||||
|
||||
#: paperless/settings.py:286
|
||||
msgid "English"
|
||||
msgstr "Angličtina"
|
||||
|
||||
#: paperless/settings.py:287
|
||||
msgid "German"
|
||||
msgstr "Němčina"
|
||||
|
||||
#: paperless/settings.py:288
|
||||
msgid "Dutch"
|
||||
msgstr "Holandština"
|
||||
|
||||
#: paperless/settings.py:289
|
||||
msgid "French"
|
||||
msgstr "Francouzština"
|
||||
|
||||
#: paperless/urls.py:114
|
||||
msgid "Paperless-ng administration"
|
||||
msgstr "Správa Paperless-ng"
|
||||
|
||||
#: paperless_mail/admin.py:25
|
||||
msgid "Filter"
|
||||
msgstr "Filtr"
|
||||
|
||||
#: paperless_mail/admin.py:27
|
||||
msgid ""
|
||||
"Paperless will only process mails that match ALL of the filters given below."
|
||||
msgstr ""
|
||||
"Paperless zpracuje pouze emaily které odpovídají VŠEM níže zadaným filtrům."
|
||||
|
||||
#: paperless_mail/admin.py:37
|
||||
msgid "Actions"
|
||||
msgstr "Akce"
|
||||
|
||||
#: paperless_mail/admin.py:39
|
||||
msgid ""
|
||||
"The action applied to the mail. This action is only performed when documents"
|
||||
" were consumed from the mail. Mails without attachments will remain entirely"
|
||||
" untouched."
|
||||
msgstr ""
|
||||
"Akce provedena na emailu. Tato akce je provedena jen pokud byly dokumenty "
|
||||
"zkonzumovány z emailu. Emaily bez příloh zůstanou nedotčeny."
|
||||
|
||||
#: paperless_mail/admin.py:46
|
||||
msgid "Metadata"
|
||||
msgstr "Metadata"
|
||||
|
||||
#: paperless_mail/admin.py:48
|
||||
msgid ""
|
||||
"Assign metadata to documents consumed from this rule automatically. If you "
|
||||
"do not assign tags, types or correspondents here, paperless will still "
|
||||
"process all matching rules that you have defined."
|
||||
msgstr ""
|
||||
"Automaticky přiřadit metadata dokumentům zkonzumovaných z tohoto pravidla. "
|
||||
"Pokud zde nepřiřadíte tagy, typy nebo korespondenty, paperless stále "
|
||||
"zpracuje všechna shodující-se pravidla které jste definovali."
|
||||
|
||||
#: paperless_mail/apps.py:9
|
||||
msgid "Paperless mail"
|
||||
msgstr "Paperless pošta"
|
||||
|
||||
#: paperless_mail/models.py:11
|
||||
msgid "mail account"
|
||||
msgstr "emailový účet"
|
||||
|
||||
#: paperless_mail/models.py:12
|
||||
msgid "mail accounts"
|
||||
msgstr "emailové účty"
|
||||
|
||||
#: paperless_mail/models.py:19
|
||||
msgid "No encryption"
|
||||
msgstr "Žádné šifrování"
|
||||
|
||||
#: paperless_mail/models.py:20
|
||||
msgid "Use SSL"
|
||||
msgstr "Používat SSL"
|
||||
|
||||
#: paperless_mail/models.py:21
|
||||
msgid "Use STARTTLS"
|
||||
msgstr "Používat STARTTLS"
|
||||
|
||||
#: paperless_mail/models.py:29
|
||||
msgid "IMAP server"
|
||||
msgstr "IMAP server"
|
||||
|
||||
#: paperless_mail/models.py:33
|
||||
msgid "IMAP port"
|
||||
msgstr "IMAP port"
|
||||
|
||||
#: paperless_mail/models.py:36
|
||||
msgid ""
|
||||
"This is usually 143 for unencrypted and STARTTLS connections, and 993 for "
|
||||
"SSL connections."
|
||||
msgstr ""
|
||||
"Toto je většinou 143 pro nešifrovaná připojení/připojení používající "
|
||||
"STARTTLS a 993 pro SSL připojení."
|
||||
|
||||
#: paperless_mail/models.py:40
|
||||
msgid "IMAP security"
|
||||
msgstr "IMAP bezpečnost"
|
||||
|
||||
#: paperless_mail/models.py:46
|
||||
msgid "username"
|
||||
msgstr "uživatelské jméno"
|
||||
|
||||
#: paperless_mail/models.py:50
|
||||
msgid "password"
|
||||
msgstr "heslo"
|
||||
|
||||
#: paperless_mail/models.py:60
|
||||
msgid "mail rule"
|
||||
msgstr "mailové pravidlo"
|
||||
|
||||
#: paperless_mail/models.py:61
|
||||
msgid "mail rules"
|
||||
msgstr "mailová pravidla"
|
||||
|
||||
#: paperless_mail/models.py:67
|
||||
msgid "Only process attachments."
|
||||
msgstr "Zpracovávat jen přílohy"
|
||||
|
||||
#: paperless_mail/models.py:68
|
||||
msgid "Process all files, including 'inline' attachments."
|
||||
msgstr "Zpracovat všechny soubory, včetně vložených příloh"
|
||||
|
||||
#: paperless_mail/models.py:78
|
||||
msgid "Mark as read, don't process read mails"
|
||||
msgstr "Označit jako přečtené, nezpracovávat přečtené emaily"
|
||||
|
||||
#: paperless_mail/models.py:79
|
||||
msgid "Flag the mail, don't process flagged mails"
|
||||
msgstr "Označit email, nezpracovávat označené emaily"
|
||||
|
||||
#: paperless_mail/models.py:80
|
||||
msgid "Move to specified folder"
|
||||
msgstr "Přesunout do specifikované složky"
|
||||
|
||||
#: paperless_mail/models.py:81
|
||||
msgid "Delete"
|
||||
msgstr "Odstranit"
|
||||
|
||||
#: paperless_mail/models.py:88
|
||||
msgid "Use subject as title"
|
||||
msgstr "Použít předmět jako titulek"
|
||||
|
||||
#: paperless_mail/models.py:89
|
||||
msgid "Use attachment filename as title"
|
||||
msgstr "Použít název souboru u přílohy jako titulek"
|
||||
|
||||
#: paperless_mail/models.py:99
|
||||
msgid "Do not assign a correspondent"
|
||||
msgstr "Nepřiřazovat korespondenta"
|
||||
|
||||
#: paperless_mail/models.py:101
|
||||
msgid "Use mail address"
|
||||
msgstr "Použít emailovou adresu"
|
||||
|
||||
#: paperless_mail/models.py:103
|
||||
msgid "Use name (or mail address if not available)"
|
||||
msgstr "Použít jméno (nebo emailovou adresu pokud jméno není dostupné)"
|
||||
|
||||
#: paperless_mail/models.py:105
|
||||
msgid "Use correspondent selected below"
|
||||
msgstr "Použít korespondenta vybraného níže"
|
||||
|
||||
#: paperless_mail/models.py:113
|
||||
msgid "order"
|
||||
msgstr "pořadí"
|
||||
|
||||
#: paperless_mail/models.py:120
|
||||
msgid "account"
|
||||
msgstr "účet"
|
||||
|
||||
#: paperless_mail/models.py:124
|
||||
msgid "folder"
|
||||
msgstr "složka"
|
||||
|
||||
#: paperless_mail/models.py:128
|
||||
msgid "filter from"
|
||||
msgstr "filtrovat z"
|
||||
|
||||
#: paperless_mail/models.py:131
|
||||
msgid "filter subject"
|
||||
msgstr "název filtru"
|
||||
|
||||
#: paperless_mail/models.py:134
|
||||
msgid "filter body"
|
||||
msgstr "tělo filtru"
|
||||
|
||||
#: paperless_mail/models.py:138
|
||||
msgid "filter attachment filename"
|
||||
msgstr "název souboru u přílohy filtru"
|
||||
|
||||
#: paperless_mail/models.py:140
|
||||
msgid ""
|
||||
"Only consume documents which entirely match this filename if specified. "
|
||||
"Wildcards such as *.pdf or *invoice* are allowed. Case insensitive."
|
||||
msgstr ""
|
||||
"Konzumovat jen dokumenty které přesně odpovídají tomuto názvu souboru pokud "
|
||||
"specifikováno. Zástupné znaky jako *.pdf nebo *invoice* jsou povoleny. "
|
||||
"Nezáleží na velikosti písmen."
|
||||
|
||||
#: paperless_mail/models.py:146
|
||||
msgid "maximum age"
|
||||
msgstr "maximální stáří"
|
||||
|
||||
#: paperless_mail/models.py:148
|
||||
msgid "Specified in days."
|
||||
msgstr "Specifikováno ve dnech."
|
||||
|
||||
#: paperless_mail/models.py:151
|
||||
msgid "attachment type"
|
||||
msgstr "typ přílohy"
|
||||
|
||||
#: paperless_mail/models.py:154
|
||||
msgid ""
|
||||
"Inline attachments include embedded images, so it's best to combine this "
|
||||
"option with a filename filter."
|
||||
msgstr ""
|
||||
"Vložené přílohy zahrnují vložené obrázky, takže je nejlepší tuto možnost "
|
||||
"kombinovat s filtrem na název souboru"
|
||||
|
||||
#: paperless_mail/models.py:159
|
||||
msgid "action"
|
||||
msgstr "akce"
|
||||
|
||||
#: paperless_mail/models.py:165
|
||||
msgid "action parameter"
|
||||
msgstr "parametr akce"
|
||||
|
||||
#: paperless_mail/models.py:167
|
||||
msgid ""
|
||||
"Additional parameter for the action selected above, i.e., the target folder "
|
||||
"of the move to folder action."
|
||||
msgstr ""
|
||||
"Další parametr pro výše vybranou akci, napříkad cílová složka akce přesunutí"
|
||||
" do složky."
|
||||
|
||||
#: paperless_mail/models.py:173
|
||||
msgid "assign title from"
|
||||
msgstr "nastavit titulek z"
|
||||
|
||||
#: paperless_mail/models.py:183
|
||||
msgid "assign this tag"
|
||||
msgstr "přiřadit tento tag"
|
||||
|
||||
#: paperless_mail/models.py:191
|
||||
msgid "assign this document type"
|
||||
msgstr "přiřadit tento typ dokumentu"
|
||||
|
||||
#: paperless_mail/models.py:195
|
||||
msgid "assign correspondent from"
|
||||
msgstr "přiřadit korespondenta z"
|
||||
|
||||
#: paperless_mail/models.py:205
|
||||
msgid "assign this correspondent"
|
||||
msgstr "přiřadit tohoto korespondenta"
|
@@ -11,8 +11,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-01-28 22:02+0100\n"
|
||||
"PO-Revision-Date: 2020-12-30 19:27+0000\n"
|
||||
"POT-Creation-Date: 2021-02-16 14:52+0100\n"
|
||||
"PO-Revision-Date: 2021-02-16 18:37+0000\n"
|
||||
"Last-Translator: Jonas Winkler, 2021\n"
|
||||
"Language-Team: German (https://www.transifex.com/paperless/teams/115905/de/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -25,64 +25,64 @@ msgstr ""
|
||||
msgid "Documents"
|
||||
msgstr "Dokumente"
|
||||
|
||||
#: documents/models.py:33
|
||||
#: documents/models.py:32
|
||||
msgid "Any word"
|
||||
msgstr "Irgendein Wort"
|
||||
|
||||
#: documents/models.py:34
|
||||
#: documents/models.py:33
|
||||
msgid "All words"
|
||||
msgstr "Alle Wörter"
|
||||
|
||||
#: documents/models.py:35
|
||||
#: documents/models.py:34
|
||||
msgid "Exact match"
|
||||
msgstr "Exakte Übereinstimmung"
|
||||
|
||||
#: documents/models.py:36
|
||||
#: documents/models.py:35
|
||||
msgid "Regular expression"
|
||||
msgstr "Regulärer Ausdruck"
|
||||
|
||||
#: documents/models.py:37
|
||||
#: documents/models.py:36
|
||||
msgid "Fuzzy word"
|
||||
msgstr "Ungenaues Wort"
|
||||
|
||||
#: documents/models.py:38
|
||||
#: documents/models.py:37
|
||||
msgid "Automatic"
|
||||
msgstr "Automatisch"
|
||||
|
||||
#: documents/models.py:42 documents/models.py:352 paperless_mail/models.py:25
|
||||
#: documents/models.py:41 documents/models.py:364 paperless_mail/models.py:25
|
||||
#: paperless_mail/models.py:109
|
||||
msgid "name"
|
||||
msgstr "Name"
|
||||
|
||||
#: documents/models.py:46
|
||||
#: documents/models.py:45
|
||||
msgid "match"
|
||||
msgstr "Zuweisungsmuster"
|
||||
|
||||
#: documents/models.py:50
|
||||
#: documents/models.py:49
|
||||
msgid "matching algorithm"
|
||||
msgstr "Zuweisungsalgorithmus"
|
||||
|
||||
#: documents/models.py:56
|
||||
#: documents/models.py:55
|
||||
msgid "is insensitive"
|
||||
msgstr "Groß-/Kleinschreibung irrelevant"
|
||||
|
||||
#: documents/models.py:75 documents/models.py:135
|
||||
#: documents/models.py:74 documents/models.py:134
|
||||
msgid "correspondent"
|
||||
msgstr "Korrespondent"
|
||||
|
||||
#: documents/models.py:76
|
||||
#: documents/models.py:75
|
||||
msgid "correspondents"
|
||||
msgstr "Korrespondenten"
|
||||
|
||||
#: documents/models.py:98
|
||||
#: documents/models.py:97
|
||||
msgid "color"
|
||||
msgstr "Farbe"
|
||||
|
||||
#: documents/models.py:102
|
||||
#: documents/models.py:101
|
||||
msgid "is inbox tag"
|
||||
msgstr "Posteingangs-Tag"
|
||||
|
||||
#: documents/models.py:104
|
||||
#: documents/models.py:103
|
||||
msgid ""
|
||||
"Marks this tag as an inbox tag: All newly consumed documents will be tagged "
|
||||
"with inbox tags."
|
||||
@@ -90,39 +90,39 @@ msgstr ""
|
||||
"Markiert das Tag als Posteingangs-Tag. Neue Dokumente werden immer mit "
|
||||
"diesem Tag versehen."
|
||||
|
||||
#: documents/models.py:109
|
||||
#: documents/models.py:108
|
||||
msgid "tag"
|
||||
msgstr "Tag"
|
||||
|
||||
#: documents/models.py:110 documents/models.py:166
|
||||
#: documents/models.py:109 documents/models.py:165
|
||||
msgid "tags"
|
||||
msgstr "Tags"
|
||||
|
||||
#: documents/models.py:116 documents/models.py:148
|
||||
#: documents/models.py:115 documents/models.py:147
|
||||
msgid "document type"
|
||||
msgstr "Dokumenttyp"
|
||||
|
||||
#: documents/models.py:117
|
||||
#: documents/models.py:116
|
||||
msgid "document types"
|
||||
msgstr "Dokumenttypen"
|
||||
|
||||
#: documents/models.py:125
|
||||
#: documents/models.py:124
|
||||
msgid "Unencrypted"
|
||||
msgstr "Nicht verschlüsselt"
|
||||
|
||||
#: documents/models.py:126
|
||||
#: documents/models.py:125
|
||||
msgid "Encrypted with GNU Privacy Guard"
|
||||
msgstr "Verschlüsselt mit GNU Privacy Guard"
|
||||
|
||||
#: documents/models.py:139
|
||||
#: documents/models.py:138
|
||||
msgid "title"
|
||||
msgstr "Titel"
|
||||
|
||||
#: documents/models.py:152
|
||||
#: documents/models.py:151
|
||||
msgid "content"
|
||||
msgstr "Inhalt"
|
||||
|
||||
#: documents/models.py:154
|
||||
#: documents/models.py:153
|
||||
msgid ""
|
||||
"The raw, text-only data of the document. This field is primarily used for "
|
||||
"searching."
|
||||
@@ -130,43 +130,43 @@ msgstr ""
|
||||
"Der Inhalt des Dokuments in Textform. Dieses Feld wird primär für die Suche "
|
||||
"verwendet."
|
||||
|
||||
#: documents/models.py:159
|
||||
#: documents/models.py:158
|
||||
msgid "mime type"
|
||||
msgstr "MIME-Typ"
|
||||
|
||||
#: documents/models.py:170
|
||||
#: documents/models.py:169
|
||||
msgid "checksum"
|
||||
msgstr "Prüfsumme"
|
||||
|
||||
#: documents/models.py:174
|
||||
#: documents/models.py:173
|
||||
msgid "The checksum of the original document."
|
||||
msgstr "Die Prüfsumme des originalen Dokuments."
|
||||
|
||||
#: documents/models.py:178
|
||||
#: documents/models.py:177
|
||||
msgid "archive checksum"
|
||||
msgstr "Archiv-Prüfsumme"
|
||||
|
||||
#: documents/models.py:183
|
||||
#: documents/models.py:182
|
||||
msgid "The checksum of the archived document."
|
||||
msgstr "Die Prüfsumme des archivierten Dokuments."
|
||||
|
||||
#: documents/models.py:187 documents/models.py:330
|
||||
#: documents/models.py:186 documents/models.py:342
|
||||
msgid "created"
|
||||
msgstr "Ausgestellt"
|
||||
|
||||
#: documents/models.py:191
|
||||
#: documents/models.py:190
|
||||
msgid "modified"
|
||||
msgstr "Geändert"
|
||||
|
||||
#: documents/models.py:195
|
||||
#: documents/models.py:194
|
||||
msgid "storage type"
|
||||
msgstr "Speichertyp"
|
||||
|
||||
#: documents/models.py:203
|
||||
#: documents/models.py:202
|
||||
msgid "added"
|
||||
msgstr "Hinzugefügt"
|
||||
|
||||
#: documents/models.py:207
|
||||
#: documents/models.py:206
|
||||
msgid "filename"
|
||||
msgstr "Dateiname"
|
||||
|
||||
@@ -175,178 +175,186 @@ msgid "Current filename in storage"
|
||||
msgstr "Aktueller Dateiname im Datenspeicher"
|
||||
|
||||
#: documents/models.py:216
|
||||
msgid "archive filename"
|
||||
msgstr "Archiv-Dateiname"
|
||||
|
||||
#: documents/models.py:222
|
||||
msgid "Current archive filename in storage"
|
||||
msgstr "Aktueller Dateiname im Archiv"
|
||||
|
||||
#: documents/models.py:226
|
||||
msgid "archive serial number"
|
||||
msgstr "Archiv-Seriennummer"
|
||||
|
||||
#: documents/models.py:221
|
||||
#: documents/models.py:231
|
||||
msgid "The position of this document in your physical document archive."
|
||||
msgstr "Die Position dieses Dokuments in Ihrem physischen Dokumentenarchiv."
|
||||
|
||||
#: documents/models.py:227
|
||||
#: documents/models.py:237
|
||||
msgid "document"
|
||||
msgstr "Dokument"
|
||||
|
||||
#: documents/models.py:228
|
||||
#: documents/models.py:238
|
||||
msgid "documents"
|
||||
msgstr "Dokumente"
|
||||
|
||||
#: documents/models.py:313
|
||||
#: documents/models.py:325
|
||||
msgid "debug"
|
||||
msgstr "Debug"
|
||||
|
||||
#: documents/models.py:314
|
||||
#: documents/models.py:326
|
||||
msgid "information"
|
||||
msgstr "Information"
|
||||
|
||||
#: documents/models.py:315
|
||||
#: documents/models.py:327
|
||||
msgid "warning"
|
||||
msgstr "Warnung"
|
||||
|
||||
#: documents/models.py:316
|
||||
#: documents/models.py:328
|
||||
msgid "error"
|
||||
msgstr "Fehler"
|
||||
|
||||
#: documents/models.py:317
|
||||
#: documents/models.py:329
|
||||
msgid "critical"
|
||||
msgstr "Kritisch"
|
||||
|
||||
#: documents/models.py:321
|
||||
#: documents/models.py:333
|
||||
msgid "group"
|
||||
msgstr "Gruppe"
|
||||
|
||||
#: documents/models.py:324
|
||||
#: documents/models.py:336
|
||||
msgid "message"
|
||||
msgstr "Nachricht"
|
||||
|
||||
#: documents/models.py:327
|
||||
#: documents/models.py:339
|
||||
msgid "level"
|
||||
msgstr "Level"
|
||||
|
||||
#: documents/models.py:334
|
||||
#: documents/models.py:346
|
||||
msgid "log"
|
||||
msgstr "Protokoll"
|
||||
|
||||
#: documents/models.py:335
|
||||
#: documents/models.py:347
|
||||
msgid "logs"
|
||||
msgstr "Protokoll"
|
||||
|
||||
#: documents/models.py:346 documents/models.py:396
|
||||
#: documents/models.py:358 documents/models.py:408
|
||||
msgid "saved view"
|
||||
msgstr "Gespeicherte Ansicht"
|
||||
|
||||
#: documents/models.py:347
|
||||
#: documents/models.py:359
|
||||
msgid "saved views"
|
||||
msgstr "Gespeicherte Ansichten"
|
||||
|
||||
#: documents/models.py:350
|
||||
#: documents/models.py:362
|
||||
msgid "user"
|
||||
msgstr "Benutzer"
|
||||
|
||||
#: documents/models.py:356
|
||||
#: documents/models.py:368
|
||||
msgid "show on dashboard"
|
||||
msgstr "Auf Startseite zeigen"
|
||||
|
||||
#: documents/models.py:359
|
||||
#: documents/models.py:371
|
||||
msgid "show in sidebar"
|
||||
msgstr "In Seitenleiste zeigen"
|
||||
|
||||
#: documents/models.py:363
|
||||
#: documents/models.py:375
|
||||
msgid "sort field"
|
||||
msgstr "Sortierfeld"
|
||||
|
||||
#: documents/models.py:366
|
||||
#: documents/models.py:378
|
||||
msgid "sort reverse"
|
||||
msgstr "Umgekehrte Sortierung"
|
||||
|
||||
#: documents/models.py:372
|
||||
#: documents/models.py:384
|
||||
msgid "title contains"
|
||||
msgstr "Titel enthält"
|
||||
|
||||
#: documents/models.py:373
|
||||
#: documents/models.py:385
|
||||
msgid "content contains"
|
||||
msgstr "Inhalt enthält"
|
||||
|
||||
#: documents/models.py:374
|
||||
#: documents/models.py:386
|
||||
msgid "ASN is"
|
||||
msgstr "ASN ist"
|
||||
|
||||
#: documents/models.py:375
|
||||
#: documents/models.py:387
|
||||
msgid "correspondent is"
|
||||
msgstr "Korrespondent ist"
|
||||
|
||||
#: documents/models.py:376
|
||||
#: documents/models.py:388
|
||||
msgid "document type is"
|
||||
msgstr "Dokumenttyp ist"
|
||||
|
||||
#: documents/models.py:377
|
||||
#: documents/models.py:389
|
||||
msgid "is in inbox"
|
||||
msgstr "Ist im Posteingang"
|
||||
|
||||
#: documents/models.py:378
|
||||
#: documents/models.py:390
|
||||
msgid "has tag"
|
||||
msgstr "Hat Tag"
|
||||
|
||||
#: documents/models.py:379
|
||||
#: documents/models.py:391
|
||||
msgid "has any tag"
|
||||
msgstr "Hat irgendein Tag"
|
||||
|
||||
#: documents/models.py:380
|
||||
#: documents/models.py:392
|
||||
msgid "created before"
|
||||
msgstr "Ausgestellt vor"
|
||||
|
||||
#: documents/models.py:381
|
||||
#: documents/models.py:393
|
||||
msgid "created after"
|
||||
msgstr "Ausgestellt nach"
|
||||
|
||||
#: documents/models.py:382
|
||||
#: documents/models.py:394
|
||||
msgid "created year is"
|
||||
msgstr "Ausgestellt im Jahr"
|
||||
|
||||
#: documents/models.py:383
|
||||
#: documents/models.py:395
|
||||
msgid "created month is"
|
||||
msgstr "Ausgestellt im Monat"
|
||||
|
||||
#: documents/models.py:384
|
||||
#: documents/models.py:396
|
||||
msgid "created day is"
|
||||
msgstr "Ausgestellt am Tag"
|
||||
|
||||
#: documents/models.py:385
|
||||
#: documents/models.py:397
|
||||
msgid "added before"
|
||||
msgstr "Hinzugefügt vor"
|
||||
|
||||
#: documents/models.py:386
|
||||
#: documents/models.py:398
|
||||
msgid "added after"
|
||||
msgstr "Hinzugefügt nach"
|
||||
|
||||
#: documents/models.py:387
|
||||
#: documents/models.py:399
|
||||
msgid "modified before"
|
||||
msgstr "Geändert vor"
|
||||
|
||||
#: documents/models.py:388
|
||||
#: documents/models.py:400
|
||||
msgid "modified after"
|
||||
msgstr "Geändert nach"
|
||||
|
||||
#: documents/models.py:389
|
||||
#: documents/models.py:401
|
||||
msgid "does not have tag"
|
||||
msgstr "Hat nicht folgendes Tag"
|
||||
|
||||
#: documents/models.py:400
|
||||
#: documents/models.py:412
|
||||
msgid "rule type"
|
||||
msgstr "Regeltyp"
|
||||
|
||||
#: documents/models.py:404
|
||||
#: documents/models.py:416
|
||||
msgid "value"
|
||||
msgstr "Wert"
|
||||
|
||||
#: documents/models.py:410
|
||||
#: documents/models.py:422
|
||||
msgid "filter rule"
|
||||
msgstr "Filterregel"
|
||||
|
||||
#: documents/models.py:411
|
||||
#: documents/models.py:423
|
||||
msgid "filter rules"
|
||||
msgstr "Filterregeln"
|
||||
|
||||
#: documents/serialisers.py:383
|
||||
#: documents/serialisers.py:370
|
||||
#, python-format
|
||||
msgid "File type %(type)s not supported"
|
||||
msgstr "Dateityp %(type)s nicht unterstützt"
|
||||
@@ -393,19 +401,23 @@ msgstr "Passwort"
|
||||
msgid "Sign in"
|
||||
msgstr "Anmelden"
|
||||
|
||||
#: paperless/settings.py:286
|
||||
msgid "English"
|
||||
msgstr "Englisch"
|
||||
#: paperless/settings.py:291
|
||||
msgid "English (US)"
|
||||
msgstr "Englisch (US)"
|
||||
|
||||
#: paperless/settings.py:287
|
||||
#: paperless/settings.py:292
|
||||
msgid "English (GB)"
|
||||
msgstr "Englisch (UK)"
|
||||
|
||||
#: paperless/settings.py:293
|
||||
msgid "German"
|
||||
msgstr "Deutsch"
|
||||
|
||||
#: paperless/settings.py:288
|
||||
#: paperless/settings.py:294
|
||||
msgid "Dutch"
|
||||
msgstr "Niederländisch"
|
||||
|
||||
#: paperless/settings.py:289
|
||||
#: paperless/settings.py:295
|
||||
msgid "French"
|
||||
msgstr "Französisch"
|
||||
|
||||
|
@@ -4,16 +4,17 @@
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
# Translators:
|
||||
# Ali Bates <xadium@gmail.com>, 2021
|
||||
# Ali Bates, 2021
|
||||
# Jonas Winkler, 2021
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-01-28 22:02+0100\n"
|
||||
"PO-Revision-Date: 2020-12-30 19:27+0000\n"
|
||||
"Last-Translator: Ali Bates <xadium@gmail.com>, 2021\n"
|
||||
"POT-Creation-Date: 2021-02-16 14:52+0100\n"
|
||||
"PO-Revision-Date: 2021-02-16 18:37+0000\n"
|
||||
"Last-Translator: Jonas Winkler, 2021\n"
|
||||
"Language-Team: English (United Kingdom) (https://www.transifex.com/paperless/teams/115905/en_GB/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -25,64 +26,64 @@ msgstr ""
|
||||
msgid "Documents"
|
||||
msgstr "Documents"
|
||||
|
||||
#: documents/models.py:33
|
||||
#: documents/models.py:32
|
||||
msgid "Any word"
|
||||
msgstr "Any word"
|
||||
|
||||
#: documents/models.py:34
|
||||
#: documents/models.py:33
|
||||
msgid "All words"
|
||||
msgstr "All words"
|
||||
|
||||
#: documents/models.py:35
|
||||
#: documents/models.py:34
|
||||
msgid "Exact match"
|
||||
msgstr "Exact match"
|
||||
|
||||
#: documents/models.py:36
|
||||
#: documents/models.py:35
|
||||
msgid "Regular expression"
|
||||
msgstr "Regular expression"
|
||||
|
||||
#: documents/models.py:37
|
||||
#: documents/models.py:36
|
||||
msgid "Fuzzy word"
|
||||
msgstr "Fuzzy word"
|
||||
|
||||
#: documents/models.py:38
|
||||
#: documents/models.py:37
|
||||
msgid "Automatic"
|
||||
msgstr "Automatic"
|
||||
|
||||
#: documents/models.py:42 documents/models.py:352 paperless_mail/models.py:25
|
||||
#: documents/models.py:41 documents/models.py:364 paperless_mail/models.py:25
|
||||
#: paperless_mail/models.py:109
|
||||
msgid "name"
|
||||
msgstr "name"
|
||||
|
||||
#: documents/models.py:46
|
||||
#: documents/models.py:45
|
||||
msgid "match"
|
||||
msgstr "match"
|
||||
|
||||
#: documents/models.py:50
|
||||
#: documents/models.py:49
|
||||
msgid "matching algorithm"
|
||||
msgstr "matching algorithm"
|
||||
|
||||
#: documents/models.py:56
|
||||
#: documents/models.py:55
|
||||
msgid "is insensitive"
|
||||
msgstr "is insensitive"
|
||||
|
||||
#: documents/models.py:75 documents/models.py:135
|
||||
#: documents/models.py:74 documents/models.py:134
|
||||
msgid "correspondent"
|
||||
msgstr "correspondent"
|
||||
|
||||
#: documents/models.py:76
|
||||
#: documents/models.py:75
|
||||
msgid "correspondents"
|
||||
msgstr "correspondents"
|
||||
|
||||
#: documents/models.py:98
|
||||
#: documents/models.py:97
|
||||
msgid "color"
|
||||
msgstr "color"
|
||||
msgstr "colour"
|
||||
|
||||
#: documents/models.py:102
|
||||
#: documents/models.py:101
|
||||
msgid "is inbox tag"
|
||||
msgstr "is inbox tag"
|
||||
|
||||
#: documents/models.py:104
|
||||
#: documents/models.py:103
|
||||
msgid ""
|
||||
"Marks this tag as an inbox tag: All newly consumed documents will be tagged "
|
||||
"with inbox tags."
|
||||
@@ -90,39 +91,39 @@ msgstr ""
|
||||
"Marks this tag as an inbox tag: All newly consumed documents will be tagged "
|
||||
"with inbox tags."
|
||||
|
||||
#: documents/models.py:109
|
||||
#: documents/models.py:108
|
||||
msgid "tag"
|
||||
msgstr "tag"
|
||||
|
||||
#: documents/models.py:110 documents/models.py:166
|
||||
#: documents/models.py:109 documents/models.py:165
|
||||
msgid "tags"
|
||||
msgstr "tags"
|
||||
|
||||
#: documents/models.py:116 documents/models.py:148
|
||||
#: documents/models.py:115 documents/models.py:147
|
||||
msgid "document type"
|
||||
msgstr "document type"
|
||||
|
||||
#: documents/models.py:117
|
||||
#: documents/models.py:116
|
||||
msgid "document types"
|
||||
msgstr "document types"
|
||||
|
||||
#: documents/models.py:125
|
||||
#: documents/models.py:124
|
||||
msgid "Unencrypted"
|
||||
msgstr "Unencrypted"
|
||||
|
||||
#: documents/models.py:126
|
||||
#: documents/models.py:125
|
||||
msgid "Encrypted with GNU Privacy Guard"
|
||||
msgstr "Encrypted with GNU Privacy Guard"
|
||||
|
||||
#: documents/models.py:139
|
||||
#: documents/models.py:138
|
||||
msgid "title"
|
||||
msgstr "title"
|
||||
|
||||
#: documents/models.py:152
|
||||
#: documents/models.py:151
|
||||
msgid "content"
|
||||
msgstr "content"
|
||||
|
||||
#: documents/models.py:154
|
||||
#: documents/models.py:153
|
||||
msgid ""
|
||||
"The raw, text-only data of the document. This field is primarily used for "
|
||||
"searching."
|
||||
@@ -130,43 +131,43 @@ msgstr ""
|
||||
"The raw, text-only data of the document. This field is primarily used for "
|
||||
"searching."
|
||||
|
||||
#: documents/models.py:159
|
||||
#: documents/models.py:158
|
||||
msgid "mime type"
|
||||
msgstr "mime type"
|
||||
|
||||
#: documents/models.py:170
|
||||
#: documents/models.py:169
|
||||
msgid "checksum"
|
||||
msgstr "checksum"
|
||||
|
||||
#: documents/models.py:174
|
||||
#: documents/models.py:173
|
||||
msgid "The checksum of the original document."
|
||||
msgstr "The checksum of the original document."
|
||||
|
||||
#: documents/models.py:178
|
||||
#: documents/models.py:177
|
||||
msgid "archive checksum"
|
||||
msgstr "archive checksum"
|
||||
|
||||
#: documents/models.py:183
|
||||
#: documents/models.py:182
|
||||
msgid "The checksum of the archived document."
|
||||
msgstr "The checksum of the archived document."
|
||||
|
||||
#: documents/models.py:187 documents/models.py:330
|
||||
#: documents/models.py:186 documents/models.py:342
|
||||
msgid "created"
|
||||
msgstr "created"
|
||||
|
||||
#: documents/models.py:191
|
||||
#: documents/models.py:190
|
||||
msgid "modified"
|
||||
msgstr "modified"
|
||||
|
||||
#: documents/models.py:195
|
||||
#: documents/models.py:194
|
||||
msgid "storage type"
|
||||
msgstr "storage type"
|
||||
|
||||
#: documents/models.py:203
|
||||
#: documents/models.py:202
|
||||
msgid "added"
|
||||
msgstr "added"
|
||||
|
||||
#: documents/models.py:207
|
||||
#: documents/models.py:206
|
||||
msgid "filename"
|
||||
msgstr "filename"
|
||||
|
||||
@@ -175,178 +176,186 @@ msgid "Current filename in storage"
|
||||
msgstr "Current filename in storage"
|
||||
|
||||
#: documents/models.py:216
|
||||
msgid "archive filename"
|
||||
msgstr "archive filename"
|
||||
|
||||
#: documents/models.py:222
|
||||
msgid "Current archive filename in storage"
|
||||
msgstr "Current archive filename in storage"
|
||||
|
||||
#: documents/models.py:226
|
||||
msgid "archive serial number"
|
||||
msgstr "archive serial number"
|
||||
|
||||
#: documents/models.py:221
|
||||
#: documents/models.py:231
|
||||
msgid "The position of this document in your physical document archive."
|
||||
msgstr "The position of this document in your physical document archive."
|
||||
|
||||
#: documents/models.py:227
|
||||
#: documents/models.py:237
|
||||
msgid "document"
|
||||
msgstr "document"
|
||||
|
||||
#: documents/models.py:228
|
||||
#: documents/models.py:238
|
||||
msgid "documents"
|
||||
msgstr "documents"
|
||||
|
||||
#: documents/models.py:313
|
||||
#: documents/models.py:325
|
||||
msgid "debug"
|
||||
msgstr "debug"
|
||||
|
||||
#: documents/models.py:314
|
||||
#: documents/models.py:326
|
||||
msgid "information"
|
||||
msgstr "information"
|
||||
|
||||
#: documents/models.py:315
|
||||
#: documents/models.py:327
|
||||
msgid "warning"
|
||||
msgstr "warning"
|
||||
|
||||
#: documents/models.py:316
|
||||
#: documents/models.py:328
|
||||
msgid "error"
|
||||
msgstr "error"
|
||||
|
||||
#: documents/models.py:317
|
||||
#: documents/models.py:329
|
||||
msgid "critical"
|
||||
msgstr "critical"
|
||||
|
||||
#: documents/models.py:321
|
||||
#: documents/models.py:333
|
||||
msgid "group"
|
||||
msgstr "group"
|
||||
|
||||
#: documents/models.py:324
|
||||
#: documents/models.py:336
|
||||
msgid "message"
|
||||
msgstr "message"
|
||||
|
||||
#: documents/models.py:327
|
||||
#: documents/models.py:339
|
||||
msgid "level"
|
||||
msgstr "level"
|
||||
|
||||
#: documents/models.py:334
|
||||
#: documents/models.py:346
|
||||
msgid "log"
|
||||
msgstr "log"
|
||||
|
||||
#: documents/models.py:335
|
||||
#: documents/models.py:347
|
||||
msgid "logs"
|
||||
msgstr "logs"
|
||||
|
||||
#: documents/models.py:346 documents/models.py:396
|
||||
#: documents/models.py:358 documents/models.py:408
|
||||
msgid "saved view"
|
||||
msgstr "saved view"
|
||||
|
||||
#: documents/models.py:347
|
||||
#: documents/models.py:359
|
||||
msgid "saved views"
|
||||
msgstr "saved views"
|
||||
|
||||
#: documents/models.py:350
|
||||
#: documents/models.py:362
|
||||
msgid "user"
|
||||
msgstr "user"
|
||||
|
||||
#: documents/models.py:356
|
||||
#: documents/models.py:368
|
||||
msgid "show on dashboard"
|
||||
msgstr "show on dashboard"
|
||||
|
||||
#: documents/models.py:359
|
||||
#: documents/models.py:371
|
||||
msgid "show in sidebar"
|
||||
msgstr "show in sidebar"
|
||||
|
||||
#: documents/models.py:363
|
||||
#: documents/models.py:375
|
||||
msgid "sort field"
|
||||
msgstr "sort field"
|
||||
|
||||
#: documents/models.py:366
|
||||
#: documents/models.py:378
|
||||
msgid "sort reverse"
|
||||
msgstr "sort reverse"
|
||||
|
||||
#: documents/models.py:372
|
||||
#: documents/models.py:384
|
||||
msgid "title contains"
|
||||
msgstr "title contains"
|
||||
|
||||
#: documents/models.py:373
|
||||
#: documents/models.py:385
|
||||
msgid "content contains"
|
||||
msgstr "content contains"
|
||||
|
||||
#: documents/models.py:374
|
||||
#: documents/models.py:386
|
||||
msgid "ASN is"
|
||||
msgstr "ASN is"
|
||||
|
||||
#: documents/models.py:375
|
||||
#: documents/models.py:387
|
||||
msgid "correspondent is"
|
||||
msgstr "correspondent is"
|
||||
|
||||
#: documents/models.py:376
|
||||
#: documents/models.py:388
|
||||
msgid "document type is"
|
||||
msgstr "document type is"
|
||||
|
||||
#: documents/models.py:377
|
||||
#: documents/models.py:389
|
||||
msgid "is in inbox"
|
||||
msgstr "is in inbox"
|
||||
|
||||
#: documents/models.py:378
|
||||
#: documents/models.py:390
|
||||
msgid "has tag"
|
||||
msgstr "has tag"
|
||||
|
||||
#: documents/models.py:379
|
||||
#: documents/models.py:391
|
||||
msgid "has any tag"
|
||||
msgstr "has any tag"
|
||||
|
||||
#: documents/models.py:380
|
||||
#: documents/models.py:392
|
||||
msgid "created before"
|
||||
msgstr "created before"
|
||||
|
||||
#: documents/models.py:381
|
||||
#: documents/models.py:393
|
||||
msgid "created after"
|
||||
msgstr "created after"
|
||||
|
||||
#: documents/models.py:382
|
||||
#: documents/models.py:394
|
||||
msgid "created year is"
|
||||
msgstr "created year is"
|
||||
|
||||
#: documents/models.py:383
|
||||
#: documents/models.py:395
|
||||
msgid "created month is"
|
||||
msgstr "created month is"
|
||||
|
||||
#: documents/models.py:384
|
||||
#: documents/models.py:396
|
||||
msgid "created day is"
|
||||
msgstr "created day is"
|
||||
|
||||
#: documents/models.py:385
|
||||
#: documents/models.py:397
|
||||
msgid "added before"
|
||||
msgstr "added before"
|
||||
|
||||
#: documents/models.py:386
|
||||
#: documents/models.py:398
|
||||
msgid "added after"
|
||||
msgstr "added after"
|
||||
|
||||
#: documents/models.py:387
|
||||
#: documents/models.py:399
|
||||
msgid "modified before"
|
||||
msgstr "modified before"
|
||||
|
||||
#: documents/models.py:388
|
||||
#: documents/models.py:400
|
||||
msgid "modified after"
|
||||
msgstr "modified after"
|
||||
|
||||
#: documents/models.py:389
|
||||
#: documents/models.py:401
|
||||
msgid "does not have tag"
|
||||
msgstr "does not have tag"
|
||||
|
||||
#: documents/models.py:400
|
||||
#: documents/models.py:412
|
||||
msgid "rule type"
|
||||
msgstr "rule type"
|
||||
|
||||
#: documents/models.py:404
|
||||
#: documents/models.py:416
|
||||
msgid "value"
|
||||
msgstr "value"
|
||||
|
||||
#: documents/models.py:410
|
||||
#: documents/models.py:422
|
||||
msgid "filter rule"
|
||||
msgstr "filter rule"
|
||||
|
||||
#: documents/models.py:411
|
||||
#: documents/models.py:423
|
||||
msgid "filter rules"
|
||||
msgstr "filter rules"
|
||||
|
||||
#: documents/serialisers.py:383
|
||||
#: documents/serialisers.py:370
|
||||
#, python-format
|
||||
msgid "File type %(type)s not supported"
|
||||
msgstr "File type %(type)s not supported"
|
||||
@@ -391,19 +400,23 @@ msgstr "Password"
|
||||
msgid "Sign in"
|
||||
msgstr "Sign in"
|
||||
|
||||
#: paperless/settings.py:286
|
||||
msgid "English"
|
||||
msgstr "English"
|
||||
#: paperless/settings.py:291
|
||||
msgid "English (US)"
|
||||
msgstr "English (US)"
|
||||
|
||||
#: paperless/settings.py:287
|
||||
#: paperless/settings.py:292
|
||||
msgid "English (GB)"
|
||||
msgstr "English (GB)"
|
||||
|
||||
#: paperless/settings.py:293
|
||||
msgid "German"
|
||||
msgstr "German"
|
||||
|
||||
#: paperless/settings.py:288
|
||||
#: paperless/settings.py:294
|
||||
msgid "Dutch"
|
||||
msgstr "Dutch"
|
||||
|
||||
#: paperless/settings.py:289
|
||||
#: paperless/settings.py:295
|
||||
msgid "French"
|
||||
msgstr "French"
|
||||
|
||||
|
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-01-28 22:02+0100\n"
|
||||
"POT-Creation-Date: 2021-02-16 14:52+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -21,144 +21,144 @@ msgstr ""
|
||||
msgid "Documents"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:33
|
||||
#: documents/models.py:32
|
||||
msgid "Any word"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:34
|
||||
#: documents/models.py:33
|
||||
msgid "All words"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:35
|
||||
#: documents/models.py:34
|
||||
msgid "Exact match"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:36
|
||||
#: documents/models.py:35
|
||||
msgid "Regular expression"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:37
|
||||
#: documents/models.py:36
|
||||
msgid "Fuzzy word"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:38
|
||||
#: documents/models.py:37
|
||||
msgid "Automatic"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:42 documents/models.py:352 paperless_mail/models.py:25
|
||||
#: documents/models.py:41 documents/models.py:364 paperless_mail/models.py:25
|
||||
#: paperless_mail/models.py:109
|
||||
msgid "name"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:46
|
||||
#: documents/models.py:45
|
||||
msgid "match"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:50
|
||||
#: documents/models.py:49
|
||||
msgid "matching algorithm"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:56
|
||||
#: documents/models.py:55
|
||||
msgid "is insensitive"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:75 documents/models.py:135
|
||||
#: documents/models.py:74 documents/models.py:134
|
||||
msgid "correspondent"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:76
|
||||
#: documents/models.py:75
|
||||
msgid "correspondents"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:98
|
||||
#: documents/models.py:97
|
||||
msgid "color"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:102
|
||||
#: documents/models.py:101
|
||||
msgid "is inbox tag"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:104
|
||||
#: documents/models.py:103
|
||||
msgid ""
|
||||
"Marks this tag as an inbox tag: All newly consumed documents will be tagged "
|
||||
"with inbox tags."
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:109
|
||||
#: documents/models.py:108
|
||||
msgid "tag"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:110 documents/models.py:166
|
||||
#: documents/models.py:109 documents/models.py:165
|
||||
msgid "tags"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:116 documents/models.py:148
|
||||
#: documents/models.py:115 documents/models.py:147
|
||||
msgid "document type"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:117
|
||||
#: documents/models.py:116
|
||||
msgid "document types"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:125
|
||||
#: documents/models.py:124
|
||||
msgid "Unencrypted"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:126
|
||||
#: documents/models.py:125
|
||||
msgid "Encrypted with GNU Privacy Guard"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:139
|
||||
#: documents/models.py:138
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:152
|
||||
#: documents/models.py:151
|
||||
msgid "content"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:154
|
||||
#: documents/models.py:153
|
||||
msgid ""
|
||||
"The raw, text-only data of the document. This field is primarily used for "
|
||||
"searching."
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:159
|
||||
#: documents/models.py:158
|
||||
msgid "mime type"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:170
|
||||
#: documents/models.py:169
|
||||
msgid "checksum"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:174
|
||||
#: documents/models.py:173
|
||||
msgid "The checksum of the original document."
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:178
|
||||
#: documents/models.py:177
|
||||
msgid "archive checksum"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:183
|
||||
#: documents/models.py:182
|
||||
msgid "The checksum of the archived document."
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:187 documents/models.py:330
|
||||
#: documents/models.py:186 documents/models.py:342
|
||||
msgid "created"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:191
|
||||
#: documents/models.py:190
|
||||
msgid "modified"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:195
|
||||
#: documents/models.py:194
|
||||
msgid "storage type"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:203
|
||||
#: documents/models.py:202
|
||||
msgid "added"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:207
|
||||
#: documents/models.py:206
|
||||
msgid "filename"
|
||||
msgstr ""
|
||||
|
||||
@@ -167,178 +167,186 @@ msgid "Current filename in storage"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:216
|
||||
msgid "archive filename"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:222
|
||||
msgid "Current archive filename in storage"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:226
|
||||
msgid "archive serial number"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:221
|
||||
#: documents/models.py:231
|
||||
msgid "The position of this document in your physical document archive."
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:227
|
||||
#: documents/models.py:237
|
||||
msgid "document"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:228
|
||||
#: documents/models.py:238
|
||||
msgid "documents"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:313
|
||||
#: documents/models.py:325
|
||||
msgid "debug"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:314
|
||||
#: documents/models.py:326
|
||||
msgid "information"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:315
|
||||
#: documents/models.py:327
|
||||
msgid "warning"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:316
|
||||
#: documents/models.py:328
|
||||
msgid "error"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:317
|
||||
#: documents/models.py:329
|
||||
msgid "critical"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:321
|
||||
#: documents/models.py:333
|
||||
msgid "group"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:324
|
||||
#: documents/models.py:336
|
||||
msgid "message"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:327
|
||||
#: documents/models.py:339
|
||||
msgid "level"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:334
|
||||
#: documents/models.py:346
|
||||
msgid "log"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:335
|
||||
#: documents/models.py:347
|
||||
msgid "logs"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:346 documents/models.py:396
|
||||
#: documents/models.py:358 documents/models.py:408
|
||||
msgid "saved view"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:347
|
||||
#: documents/models.py:359
|
||||
msgid "saved views"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:350
|
||||
#: documents/models.py:362
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:356
|
||||
#: documents/models.py:368
|
||||
msgid "show on dashboard"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:359
|
||||
#: documents/models.py:371
|
||||
msgid "show in sidebar"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:363
|
||||
#: documents/models.py:375
|
||||
msgid "sort field"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:366
|
||||
#: documents/models.py:378
|
||||
msgid "sort reverse"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:372
|
||||
#: documents/models.py:384
|
||||
msgid "title contains"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:373
|
||||
#: documents/models.py:385
|
||||
msgid "content contains"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:374
|
||||
#: documents/models.py:386
|
||||
msgid "ASN is"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:375
|
||||
#: documents/models.py:387
|
||||
msgid "correspondent is"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:376
|
||||
#: documents/models.py:388
|
||||
msgid "document type is"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:377
|
||||
#: documents/models.py:389
|
||||
msgid "is in inbox"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:378
|
||||
#: documents/models.py:390
|
||||
msgid "has tag"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:379
|
||||
#: documents/models.py:391
|
||||
msgid "has any tag"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:380
|
||||
#: documents/models.py:392
|
||||
msgid "created before"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:381
|
||||
#: documents/models.py:393
|
||||
msgid "created after"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:382
|
||||
#: documents/models.py:394
|
||||
msgid "created year is"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:383
|
||||
#: documents/models.py:395
|
||||
msgid "created month is"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:384
|
||||
#: documents/models.py:396
|
||||
msgid "created day is"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:385
|
||||
#: documents/models.py:397
|
||||
msgid "added before"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:386
|
||||
#: documents/models.py:398
|
||||
msgid "added after"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:387
|
||||
#: documents/models.py:399
|
||||
msgid "modified before"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:388
|
||||
#: documents/models.py:400
|
||||
msgid "modified after"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:389
|
||||
#: documents/models.py:401
|
||||
msgid "does not have tag"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:400
|
||||
#: documents/models.py:412
|
||||
msgid "rule type"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:404
|
||||
#: documents/models.py:416
|
||||
msgid "value"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:410
|
||||
#: documents/models.py:422
|
||||
msgid "filter rule"
|
||||
msgstr ""
|
||||
|
||||
#: documents/models.py:411
|
||||
#: documents/models.py:423
|
||||
msgid "filter rules"
|
||||
msgstr ""
|
||||
|
||||
#: documents/serialisers.py:383
|
||||
#: documents/serialisers.py:370
|
||||
#, python-format
|
||||
msgid "File type %(type)s not supported"
|
||||
msgstr ""
|
||||
@@ -383,19 +391,23 @@ msgstr ""
|
||||
msgid "Sign in"
|
||||
msgstr ""
|
||||
|
||||
#: paperless/settings.py:286
|
||||
msgid "English"
|
||||
#: paperless/settings.py:291
|
||||
msgid "English (US)"
|
||||
msgstr ""
|
||||
|
||||
#: paperless/settings.py:287
|
||||
#: paperless/settings.py:292
|
||||
msgid "English (GB)"
|
||||
msgstr ""
|
||||
|
||||
#: paperless/settings.py:293
|
||||
msgid "German"
|
||||
msgstr ""
|
||||
|
||||
#: paperless/settings.py:288
|
||||
#: paperless/settings.py:294
|
||||
msgid "Dutch"
|
||||
msgstr ""
|
||||
|
||||
#: paperless/settings.py:289
|
||||
#: paperless/settings.py:295
|
||||
msgid "French"
|
||||
msgstr ""
|
||||
|
@@ -4,17 +4,17 @@
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
# Translators:
|
||||
# Jonas Winkler, 2021
|
||||
# Jo Vandeginste <jo.vandeginste@gmail.com>, 2021
|
||||
# Ben <bzweekhorst@gmail.com>, 2021
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-01-28 22:02+0100\n"
|
||||
"PO-Revision-Date: 2020-12-30 19:27+0000\n"
|
||||
"Last-Translator: Ben <bzweekhorst@gmail.com>, 2021\n"
|
||||
"POT-Creation-Date: 2021-02-16 14:52+0100\n"
|
||||
"PO-Revision-Date: 2021-02-16 18:37+0000\n"
|
||||
"Last-Translator: Jo Vandeginste <jo.vandeginste@gmail.com>, 2021\n"
|
||||
"Language-Team: Dutch (Netherlands) (https://www.transifex.com/paperless/teams/115905/nl_NL/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -26,64 +26,64 @@ msgstr ""
|
||||
msgid "Documents"
|
||||
msgstr "Documenten"
|
||||
|
||||
#: documents/models.py:33
|
||||
#: documents/models.py:32
|
||||
msgid "Any word"
|
||||
msgstr "Eender welk woord"
|
||||
|
||||
#: documents/models.py:34
|
||||
#: documents/models.py:33
|
||||
msgid "All words"
|
||||
msgstr "Alle woorden"
|
||||
|
||||
#: documents/models.py:35
|
||||
#: documents/models.py:34
|
||||
msgid "Exact match"
|
||||
msgstr "Exacte overeenkomst"
|
||||
|
||||
#: documents/models.py:36
|
||||
#: documents/models.py:35
|
||||
msgid "Regular expression"
|
||||
msgstr "Reguliere expressie"
|
||||
|
||||
#: documents/models.py:37
|
||||
#: documents/models.py:36
|
||||
msgid "Fuzzy word"
|
||||
msgstr "Gelijkaardig woord"
|
||||
|
||||
#: documents/models.py:38
|
||||
#: documents/models.py:37
|
||||
msgid "Automatic"
|
||||
msgstr "Automatisch"
|
||||
|
||||
#: documents/models.py:42 documents/models.py:352 paperless_mail/models.py:25
|
||||
#: documents/models.py:41 documents/models.py:364 paperless_mail/models.py:25
|
||||
#: paperless_mail/models.py:109
|
||||
msgid "name"
|
||||
msgstr "naam"
|
||||
|
||||
#: documents/models.py:46
|
||||
#: documents/models.py:45
|
||||
msgid "match"
|
||||
msgstr "Overeenkomst"
|
||||
|
||||
#: documents/models.py:50
|
||||
#: documents/models.py:49
|
||||
msgid "matching algorithm"
|
||||
msgstr "Algoritme voor het bepalen van de overeenkomst"
|
||||
|
||||
#: documents/models.py:56
|
||||
#: documents/models.py:55
|
||||
msgid "is insensitive"
|
||||
msgstr "is niet hoofdlettergevoelig"
|
||||
|
||||
#: documents/models.py:75 documents/models.py:135
|
||||
#: documents/models.py:74 documents/models.py:134
|
||||
msgid "correspondent"
|
||||
msgstr "correspondent"
|
||||
|
||||
#: documents/models.py:76
|
||||
#: documents/models.py:75
|
||||
msgid "correspondents"
|
||||
msgstr "correspondenten"
|
||||
|
||||
#: documents/models.py:98
|
||||
#: documents/models.py:97
|
||||
msgid "color"
|
||||
msgstr "Kleur"
|
||||
|
||||
#: documents/models.py:102
|
||||
#: documents/models.py:101
|
||||
msgid "is inbox tag"
|
||||
msgstr "is \"Postvak in\"-etiket"
|
||||
|
||||
#: documents/models.py:104
|
||||
#: documents/models.py:103
|
||||
msgid ""
|
||||
"Marks this tag as an inbox tag: All newly consumed documents will be tagged "
|
||||
"with inbox tags."
|
||||
@@ -91,39 +91,39 @@ msgstr ""
|
||||
"Markeer dit etiket als een \"Postvak in\"-etiket: alle nieuw verwerkte "
|
||||
"documenten krijgen de \"Postvak in\"-etiketten."
|
||||
|
||||
#: documents/models.py:109
|
||||
#: documents/models.py:108
|
||||
msgid "tag"
|
||||
msgstr "etiket"
|
||||
|
||||
#: documents/models.py:110 documents/models.py:166
|
||||
#: documents/models.py:109 documents/models.py:165
|
||||
msgid "tags"
|
||||
msgstr "etiketten"
|
||||
|
||||
#: documents/models.py:116 documents/models.py:148
|
||||
#: documents/models.py:115 documents/models.py:147
|
||||
msgid "document type"
|
||||
msgstr "documenttype"
|
||||
|
||||
#: documents/models.py:117
|
||||
#: documents/models.py:116
|
||||
msgid "document types"
|
||||
msgstr "documenttypen"
|
||||
|
||||
#: documents/models.py:125
|
||||
#: documents/models.py:124
|
||||
msgid "Unencrypted"
|
||||
msgstr "Niet versleuteld"
|
||||
|
||||
#: documents/models.py:126
|
||||
#: documents/models.py:125
|
||||
msgid "Encrypted with GNU Privacy Guard"
|
||||
msgstr "Versleuteld met GNU Privacy Guard"
|
||||
|
||||
#: documents/models.py:139
|
||||
#: documents/models.py:138
|
||||
msgid "title"
|
||||
msgstr "titel"
|
||||
|
||||
#: documents/models.py:152
|
||||
#: documents/models.py:151
|
||||
msgid "content"
|
||||
msgstr "inhoud"
|
||||
|
||||
#: documents/models.py:154
|
||||
#: documents/models.py:153
|
||||
msgid ""
|
||||
"The raw, text-only data of the document. This field is primarily used for "
|
||||
"searching."
|
||||
@@ -131,43 +131,43 @@ msgstr ""
|
||||
"De onbewerkte gegevens van het document. Dit veld wordt voornamelijk "
|
||||
"gebruikt om te zoeken."
|
||||
|
||||
#: documents/models.py:159
|
||||
#: documents/models.py:158
|
||||
msgid "mime type"
|
||||
msgstr "mimetype"
|
||||
|
||||
#: documents/models.py:170
|
||||
#: documents/models.py:169
|
||||
msgid "checksum"
|
||||
msgstr "checksum"
|
||||
|
||||
#: documents/models.py:174
|
||||
#: documents/models.py:173
|
||||
msgid "The checksum of the original document."
|
||||
msgstr "Het controlecijfer van het originele document."
|
||||
|
||||
#: documents/models.py:178
|
||||
#: documents/models.py:177
|
||||
msgid "archive checksum"
|
||||
msgstr "archief checksum"
|
||||
|
||||
#: documents/models.py:183
|
||||
#: documents/models.py:182
|
||||
msgid "The checksum of the archived document."
|
||||
msgstr "De checksum van het gearchiveerde document."
|
||||
|
||||
#: documents/models.py:187 documents/models.py:330
|
||||
#: documents/models.py:186 documents/models.py:342
|
||||
msgid "created"
|
||||
msgstr "aangemaakt"
|
||||
|
||||
#: documents/models.py:191
|
||||
#: documents/models.py:190
|
||||
msgid "modified"
|
||||
msgstr "gewijzigd"
|
||||
|
||||
#: documents/models.py:195
|
||||
#: documents/models.py:194
|
||||
msgid "storage type"
|
||||
msgstr "type opslag"
|
||||
|
||||
#: documents/models.py:203
|
||||
#: documents/models.py:202
|
||||
msgid "added"
|
||||
msgstr "toegevoegd"
|
||||
|
||||
#: documents/models.py:207
|
||||
#: documents/models.py:206
|
||||
msgid "filename"
|
||||
msgstr "bestandsnaam"
|
||||
|
||||
@@ -176,178 +176,186 @@ msgid "Current filename in storage"
|
||||
msgstr "Huidige bestandsnaam in opslag"
|
||||
|
||||
#: documents/models.py:216
|
||||
msgid "archive filename"
|
||||
msgstr "Bestandsnaam in archief"
|
||||
|
||||
#: documents/models.py:222
|
||||
msgid "Current archive filename in storage"
|
||||
msgstr "Huidige bestandsnaam in archief"
|
||||
|
||||
#: documents/models.py:226
|
||||
msgid "archive serial number"
|
||||
msgstr "serienummer in archief"
|
||||
|
||||
#: documents/models.py:221
|
||||
#: documents/models.py:231
|
||||
msgid "The position of this document in your physical document archive."
|
||||
msgstr "De positie van dit document in je fysieke documentenarchief."
|
||||
|
||||
#: documents/models.py:227
|
||||
#: documents/models.py:237
|
||||
msgid "document"
|
||||
msgstr "document"
|
||||
|
||||
#: documents/models.py:228
|
||||
#: documents/models.py:238
|
||||
msgid "documents"
|
||||
msgstr "documenten"
|
||||
|
||||
#: documents/models.py:313
|
||||
#: documents/models.py:325
|
||||
msgid "debug"
|
||||
msgstr "debug"
|
||||
|
||||
#: documents/models.py:314
|
||||
#: documents/models.py:326
|
||||
msgid "information"
|
||||
msgstr "informatie"
|
||||
|
||||
#: documents/models.py:315
|
||||
#: documents/models.py:327
|
||||
msgid "warning"
|
||||
msgstr "waarschuwing"
|
||||
|
||||
#: documents/models.py:316
|
||||
#: documents/models.py:328
|
||||
msgid "error"
|
||||
msgstr "fout"
|
||||
|
||||
#: documents/models.py:317
|
||||
#: documents/models.py:329
|
||||
msgid "critical"
|
||||
msgstr "kritisch"
|
||||
|
||||
#: documents/models.py:321
|
||||
#: documents/models.py:333
|
||||
msgid "group"
|
||||
msgstr "groep"
|
||||
|
||||
#: documents/models.py:324
|
||||
#: documents/models.py:336
|
||||
msgid "message"
|
||||
msgstr "bericht"
|
||||
|
||||
#: documents/models.py:327
|
||||
#: documents/models.py:339
|
||||
msgid "level"
|
||||
msgstr "niveau"
|
||||
|
||||
#: documents/models.py:334
|
||||
#: documents/models.py:346
|
||||
msgid "log"
|
||||
msgstr "bericht"
|
||||
|
||||
#: documents/models.py:335
|
||||
#: documents/models.py:347
|
||||
msgid "logs"
|
||||
msgstr "berichten"
|
||||
|
||||
#: documents/models.py:346 documents/models.py:396
|
||||
#: documents/models.py:358 documents/models.py:408
|
||||
msgid "saved view"
|
||||
msgstr "opgeslagen view"
|
||||
|
||||
#: documents/models.py:347
|
||||
#: documents/models.py:359
|
||||
msgid "saved views"
|
||||
msgstr "opgeslagen views"
|
||||
|
||||
#: documents/models.py:350
|
||||
#: documents/models.py:362
|
||||
msgid "user"
|
||||
msgstr "gebruiker"
|
||||
|
||||
#: documents/models.py:356
|
||||
#: documents/models.py:368
|
||||
msgid "show on dashboard"
|
||||
msgstr "weergeven op dashboard"
|
||||
|
||||
#: documents/models.py:359
|
||||
#: documents/models.py:371
|
||||
msgid "show in sidebar"
|
||||
msgstr "weergeven in zijbalk"
|
||||
|
||||
#: documents/models.py:363
|
||||
#: documents/models.py:375
|
||||
msgid "sort field"
|
||||
msgstr "sorteerveld"
|
||||
|
||||
#: documents/models.py:366
|
||||
#: documents/models.py:378
|
||||
msgid "sort reverse"
|
||||
msgstr "omgekeerd sorteren"
|
||||
|
||||
#: documents/models.py:372
|
||||
#: documents/models.py:384
|
||||
msgid "title contains"
|
||||
msgstr "titel bevat"
|
||||
|
||||
#: documents/models.py:373
|
||||
#: documents/models.py:385
|
||||
msgid "content contains"
|
||||
msgstr "inhoud bevat"
|
||||
|
||||
#: documents/models.py:374
|
||||
#: documents/models.py:386
|
||||
msgid "ASN is"
|
||||
msgstr "ASN is"
|
||||
|
||||
#: documents/models.py:375
|
||||
#: documents/models.py:387
|
||||
msgid "correspondent is"
|
||||
msgstr "correspondent is"
|
||||
|
||||
#: documents/models.py:376
|
||||
#: documents/models.py:388
|
||||
msgid "document type is"
|
||||
msgstr "documenttype is"
|
||||
|
||||
#: documents/models.py:377
|
||||
#: documents/models.py:389
|
||||
msgid "is in inbox"
|
||||
msgstr "zit in \"Postvak in\""
|
||||
|
||||
#: documents/models.py:378
|
||||
#: documents/models.py:390
|
||||
msgid "has tag"
|
||||
msgstr "heeft etiket"
|
||||
|
||||
#: documents/models.py:379
|
||||
#: documents/models.py:391
|
||||
msgid "has any tag"
|
||||
msgstr "heeft één van de etiketten"
|
||||
|
||||
#: documents/models.py:380
|
||||
#: documents/models.py:392
|
||||
msgid "created before"
|
||||
msgstr "aangemaakt voor"
|
||||
|
||||
#: documents/models.py:381
|
||||
#: documents/models.py:393
|
||||
msgid "created after"
|
||||
msgstr "aangemaakt na"
|
||||
|
||||
#: documents/models.py:382
|
||||
#: documents/models.py:394
|
||||
msgid "created year is"
|
||||
msgstr "aangemaakt jaar is"
|
||||
|
||||
#: documents/models.py:383
|
||||
#: documents/models.py:395
|
||||
msgid "created month is"
|
||||
msgstr "aangemaakte maand is"
|
||||
|
||||
#: documents/models.py:384
|
||||
#: documents/models.py:396
|
||||
msgid "created day is"
|
||||
msgstr "aangemaakte dag is"
|
||||
|
||||
#: documents/models.py:385
|
||||
#: documents/models.py:397
|
||||
msgid "added before"
|
||||
msgstr "toegevoegd voor"
|
||||
|
||||
#: documents/models.py:386
|
||||
#: documents/models.py:398
|
||||
msgid "added after"
|
||||
msgstr "toegevoegd na"
|
||||
|
||||
#: documents/models.py:387
|
||||
#: documents/models.py:399
|
||||
msgid "modified before"
|
||||
msgstr "gewijzigd voor"
|
||||
|
||||
#: documents/models.py:388
|
||||
#: documents/models.py:400
|
||||
msgid "modified after"
|
||||
msgstr "gewijzigd na"
|
||||
|
||||
#: documents/models.py:389
|
||||
#: documents/models.py:401
|
||||
msgid "does not have tag"
|
||||
msgstr "heeft geen etiket"
|
||||
|
||||
#: documents/models.py:400
|
||||
#: documents/models.py:412
|
||||
msgid "rule type"
|
||||
msgstr "type regel"
|
||||
|
||||
#: documents/models.py:404
|
||||
#: documents/models.py:416
|
||||
msgid "value"
|
||||
msgstr "waarde"
|
||||
|
||||
#: documents/models.py:410
|
||||
#: documents/models.py:422
|
||||
msgid "filter rule"
|
||||
msgstr "filterregel"
|
||||
|
||||
#: documents/models.py:411
|
||||
#: documents/models.py:423
|
||||
msgid "filter rules"
|
||||
msgstr "filterregels"
|
||||
|
||||
#: documents/serialisers.py:383
|
||||
#: documents/serialisers.py:370
|
||||
#, python-format
|
||||
msgid "File type %(type)s not supported"
|
||||
msgstr "Bestandstype %(type)s niet ondersteund"
|
||||
@@ -392,19 +400,23 @@ msgstr "Wachtwoord"
|
||||
msgid "Sign in"
|
||||
msgstr "Aanmelden"
|
||||
|
||||
#: paperless/settings.py:286
|
||||
msgid "English"
|
||||
msgstr "Engels"
|
||||
#: paperless/settings.py:291
|
||||
msgid "English (US)"
|
||||
msgstr "Engels (US)"
|
||||
|
||||
#: paperless/settings.py:287
|
||||
#: paperless/settings.py:292
|
||||
msgid "English (GB)"
|
||||
msgstr "Engels (Brits)"
|
||||
|
||||
#: paperless/settings.py:293
|
||||
msgid "German"
|
||||
msgstr "Duits"
|
||||
|
||||
#: paperless/settings.py:288
|
||||
#: paperless/settings.py:294
|
||||
msgid "Dutch"
|
||||
msgstr "Nederlands"
|
||||
|
||||
#: paperless/settings.py:289
|
||||
#: paperless/settings.py:295
|
||||
msgid "French"
|
||||
msgstr "Frans"
|
||||
|
||||
|
@@ -102,10 +102,11 @@ INSTALLED_APPS = [
|
||||
|
||||
"django_q",
|
||||
|
||||
"channels",
|
||||
|
||||
] + env_apps
|
||||
|
||||
if DEBUG:
|
||||
INSTALLED_APPS.append("channels")
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': [
|
||||
'rest_framework.authentication.BasicAuthentication',
|
||||
@@ -169,16 +170,6 @@ CHANNEL_LAYERS = {
|
||||
},
|
||||
}
|
||||
|
||||
CACHES = {
|
||||
"default": {
|
||||
"BACKEND": "django_redis.cache.RedisCache",
|
||||
"LOCATION": os.getenv("PAPERLESS_REDIS", "redis://localhost:6379"),
|
||||
"OPTIONS": {
|
||||
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Security #
|
||||
###############################################################################
|
||||
@@ -297,7 +288,8 @@ if os.getenv("PAPERLESS_DBHOST"):
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
LANGUAGES = [
|
||||
("en-us", _("English")),
|
||||
("en-us", _("English (US)")),
|
||||
("en-gb", _("English (GB)")),
|
||||
("de", _("German")),
|
||||
("nl-nl", _("Dutch")),
|
||||
("fr", _("French"))
|
||||
@@ -407,8 +399,9 @@ TASK_WORKERS = int(os.getenv("PAPERLESS_TASK_WORKERS", default_task_workers()))
|
||||
Q_CLUSTER = {
|
||||
'name': 'paperless',
|
||||
'catch_up': False,
|
||||
'recycle': 1,
|
||||
'workers': TASK_WORKERS,
|
||||
'django_redis': 'default'
|
||||
'redis': os.getenv("PAPERLESS_REDIS", "redis://localhost:6379")
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1 +1 @@
|
||||
__version__ = (1, 1, 1)
|
||||
__version__ = (1, 1, 4)
|
||||
|
@@ -2,12 +2,8 @@ import json
|
||||
import os
|
||||
import re
|
||||
|
||||
import ocrmypdf
|
||||
import pdftotext
|
||||
import pikepdf
|
||||
from PIL import Image
|
||||
from django.conf import settings
|
||||
from ocrmypdf import InputFileError, EncryptedPdfError
|
||||
|
||||
from documents.parsers import DocumentParser, ParseError, \
|
||||
make_thumbnail_from_pdf
|
||||
@@ -22,6 +18,8 @@ class RasterisedDocumentParser(DocumentParser):
|
||||
logging_name = "paperless.parsing.tesseract"
|
||||
|
||||
def extract_metadata(self, document_path, mime_type):
|
||||
import pikepdf
|
||||
|
||||
namespace_pattern = re.compile(r"\{(.*)\}(.*)")
|
||||
|
||||
result = []
|
||||
@@ -91,6 +89,9 @@ class RasterisedDocumentParser(DocumentParser):
|
||||
return None
|
||||
|
||||
def parse(self, document_path, mime_type, file_name=None):
|
||||
import ocrmypdf
|
||||
from ocrmypdf import InputFileError, EncryptedPdfError
|
||||
|
||||
mode = settings.OCR_MODE
|
||||
|
||||
text_original = get_text_from_pdf(document_path)
|
||||
@@ -223,6 +224,7 @@ def strip_excess_whitespace(text):
|
||||
|
||||
|
||||
def get_text_from_pdf(pdf_file):
|
||||
import pdftotext
|
||||
|
||||
if not os.path.isfile(pdf_file):
|
||||
return None
|
||||
|
@@ -164,17 +164,12 @@ class TestParser(DirectoriesMixin, TestCase):
|
||||
|
||||
self.assertRaises(ParseError, f)
|
||||
|
||||
@mock.patch("paperless_tesseract.parsers.ocrmypdf.ocr")
|
||||
def test_image_calc_a4_dpi(self, m):
|
||||
def test_image_calc_a4_dpi(self):
|
||||
parser = RasterisedDocumentParser(None)
|
||||
|
||||
parser.parse(os.path.join(self.SAMPLE_FILES, "simple-no-dpi.png"), "image/png")
|
||||
dpi = parser.calculate_a4_dpi(os.path.join(self.SAMPLE_FILES, "simple-no-dpi.png"))
|
||||
|
||||
m.assert_called_once()
|
||||
|
||||
args, kwargs = m.call_args
|
||||
|
||||
self.assertEqual(kwargs['image_dpi'], 62)
|
||||
self.assertEqual(dpi, 62)
|
||||
|
||||
@mock.patch("paperless_tesseract.parsers.RasterisedDocumentParser.calculate_a4_dpi")
|
||||
def test_image_dpi_fail(self, m):
|
||||
|
Reference in New Issue
Block a user