Compare commits

...

26 Commits

Author SHA1 Message Date
Jonas Winkler
702b985ceb Merge pull request #558 from jonaswinkler/translations_src-locale-en-us-lc-messages-django-po--dev_de
Translate '/src/locale/en_US/LC_MESSAGES/django.po' in 'de'
2021-02-17 14:46:25 +01:00
Jonas Winkler
7d87bcbb98 Merge pull request #560 from jonaswinkler/translations_src-locale-en-us-lc-messages-django-po--dev_en_GB
Translate '/src/locale/en_US/LC_MESSAGES/django.po' in 'en_GB'
2021-02-17 14:46:14 +01:00
Jonas Winkler
340521aa0d Merge pull request #559 from jonaswinkler/translations_src-locale-en-us-lc-messages-django-po--dev_nl_NL
Translate '/src/locale/en_US/LC_MESSAGES/django.po' in 'nl_NL'
2021-02-17 14:46:03 +01:00
transifex-integration[bot]
7bc557a999 Apply translations in en_GB
translation completed for the source file '/src/locale/en_US/LC_MESSAGES/django.po'
on the 'en_GB' language.
2021-02-17 13:36:15 +00:00
jonaswinkler
dfa7cdf47e Merge branch 'dev' of github.com:jonaswinkler/paperless-ng into dev 2021-02-17 14:26:26 +01:00
jonaswinkler
0d78e58d77 fixed paperless not properly selecting en-gb 2021-02-17 14:26:06 +01:00
transifex-integration[bot]
58df3d5767 Apply translations in nl_NL
translation completed for the source file '/src/locale/en_US/LC_MESSAGES/django.po'
on the 'nl_NL' language.
2021-02-17 12:57:48 +00:00
Jonas Winkler
4e4d6e806c Update Crowdin configuration file 2021-02-17 13:22:45 +01:00
Jonas Winkler
6ff99945f3 Update Crowdin configuration file 2021-02-17 13:18:19 +01:00
transifex-integration[bot]
b7f1b9f8ad Apply translations in de
translation completed for the source file '/src/locale/en_US/LC_MESSAGES/django.po'
on the 'de' language.
2021-02-17 11:50:01 +00:00
jonaswinkler
08a44cf468 changelog and version 2021-02-17 12:31:19 +01:00
jonaswinkler
a1162d6d5a update requirements 2021-02-17 12:25:34 +01:00
jonaswinkler
1c81d88013 add support for iso 8601 date display 2021-02-17 12:15:22 +01:00
jonaswinkler
1e4ec7e29e added en-GB language 2021-02-16 14:54:18 +01:00
jonaswinkler
2c4e34dd0c changelog 2021-02-15 23:44:48 +01:00
jonaswinkler
cb308fae7b only show inbox statistics if inbox tags are defined 2021-02-15 23:14:54 +01:00
jonaswinkler
3f03d51b24 version bump 2021-02-15 16:52:45 +01:00
jonaswinkler
831db6ab87 note regarding Python 3.6 2021-02-15 16:46:06 +01:00
jonaswinkler
43fdf634f2 added a note regarding python 3.6 2021-02-15 16:37:44 +01:00
jonaswinkler
f07a6b4586 PAPERLESS_WEBSERVER_WORKERS option 2021-02-15 16:27:35 +01:00
jonaswinkler
2fcf484229 bugfix dismissing wrong status messages 2021-02-15 14:52:47 +01:00
jonaswinkler
8bf4241b16 some search index optimizations 2021-02-15 13:26:36 +01:00
jonaswinkler
56bd966c02 local import of ocrmypdf so that the webserver does not load that 2021-02-15 12:18:10 +01:00
jonaswinkler
416101d557 only import dateparser when required 2021-02-15 11:52:46 +01:00
jonaswinkler
c330cca2c9 remove unused imports 2021-02-15 11:26:13 +01:00
jonaswinkler
7e88085377 load sklearn modules only when training data has changed 2021-02-15 11:25:25 +01:00
34 changed files with 644 additions and 433 deletions

18
Pipfile.lock generated
View File

@@ -591,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": [
@@ -841,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": [
@@ -1837,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": [

View File

@@ -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

View File

@@ -5,6 +5,34 @@
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
##################

View File

@@ -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.

View File

@@ -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`.

View File

@@ -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

View File

@@ -53,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
@@ -71,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

View File

@@ -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": {

View File

@@ -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: [

View File

@@ -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>

View File

@@ -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>

View File

@@ -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() {

View File

@@ -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)
}
}
}

View File

@@ -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)

View File

@@ -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"}

View File

@@ -2,7 +2,7 @@ export const environment = {
production: true,
apiBaseUrl: "/api/",
appTitle: "Paperless-ng",
version: "1.1.2",
version: "1.1.4",
webSocketHost: window.location.host,
webSocketProtocol: (window.location.protocol == "https:" ? "wss:" : "ws:")
};

View File

@@ -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>

View File

@@ -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)

View File

@@ -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)

View File

@@ -95,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()
@@ -162,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(

View File

@@ -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)

View File

@@ -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={

View File

@@ -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)

View File

@@ -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")

View File

@@ -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):

View File

@@ -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)
@@ -501,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'])
@@ -525,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']
@@ -554,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,
@@ -570,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']
@@ -587,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):
@@ -595,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,
})

View File

@@ -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"

View File

@@ -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"

View File

@@ -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 ""

View File

@@ -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"

View File

@@ -288,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"))

View File

@@ -1 +1 @@
__version__ = (1, 1, 2)
__version__ = (1, 1, 4)

View File

@@ -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

View File

@@ -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):