Index: head/deskutils/py-paperless/Makefile =================================================================== --- head/deskutils/py-paperless/Makefile (revision 521890) +++ head/deskutils/py-paperless/Makefile (revision 521891) @@ -1,128 +1,127 @@ # $FreeBSD$ PORTNAME= paperless PORTVERSION= 2.7.0 -PORTREVISION= 2 +PORTREVISION= 3 CATEGORIES= deskutils python PKGNAMEPREFIX= ${PYTHON_PKGNAMEPREFIX} MAINTAINER= grembo@FreeBSD.org COMMENT= Index and archive scanned paper documents LICENSE= GPLv3 LICENSE_FILE= ${WRKSRC}/LICENSE BUILD_DEPENDS= ${PYTHON_PKGNAMEPREFIX}dateparser>=0.7.1:devel/py-dateparser@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}dj22-django-cors-headers>=2.4.0:www/py-dj22-django-cors-headers@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}dj22-django-crispy-forms>=1.7.2:www/py-dj22-django-crispy-forms@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}dj22-django-extensions>=2.1.6:www/py-dj22-django-extensions@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}dj22-django-filter>=2.0.0:www/py-dj22-django-filter@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}dj22-djangoql>=0.12.4:www/py-dj22-djangoql@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}dj22-djangorestframework>=3.9.0:www/py-dj22-djangorestframework@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}fuzzywuzzy>=0.15.1:devel/py-fuzzywuzzy@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}langdetect>=1.0.7:textproc/py-langdetect@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}pdftotext>=2.1.1:textproc/py-pdftotext@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}pyocr>=0.5.3:graphics/py-pyocr@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}python-dotenv>=0.10.1:www/py-python-dotenv@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}python-gnupg>=0.4.3:security/py-python-gnupg@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}python-magic>=0.4.10:devel/py-python-magic@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}sqlite3>0:databases/py-sqlite3@${PY_FLAVOR} RUN_DEPENDS:= ${BUILD_DEPENDS} RUN_DEPENDS+= gpg2:security/gnupg \ optipng:graphics/optipng \ tesseract:graphics/tesseract \ unpaper:graphics/unpaper USES= python:3.5+ shebangfix USE_GITHUB= yes GH_ACCOUNT= the-paperless-project GH_PROJECT= paperless USE_RC_SUBR= paperless-consumer SHEBANG_FILES= ${WRKSRC}/src/manage.py SUB_FILES= README nginx.conf paperless.7 pkg-message sshd_config uwsgi.ini SUB_LIST= PKGBASE=${PKGBASE} PYTHON_CMD=${PYTHON_CMD} \ PYTHONPREFIX_SITELIBDIR=${PYTHONPREFIX_SITELIBDIR} \ ECHO=${ECHO} EGREP=${EGREP} TOUCH=${TOUCH} \ CHOWN=${CHOWN} RM=${RM:Q} NO_ARCH= yes USERS= paperless GROUPS= paperless OPTIONS_DEFINE= DOCS EXAMPLES OPTIONS_SINGLE= IMAGICK OPTIONS_SINGLE_IMAGICK= IMAGICK6_NOX11 IMAGICK6_X11 IMAGICK7_NOX11 IMAGICK7_X11 OPTIONS_DEFAULT= IMAGICK6_X11 IMAGICK_DESC= ${IMAGEMAGICK_DESC} IMAGICK6_NOX11_DESC= ImageMagick6 without X11 support IMAGICK6_X11_DESC= ImageMagick6 with X11 support IMAGICK7_NOX11_DESC= ImageMagick7 without X11 support IMAGICK7_X11_DESC= ImageMagick7 with X11 support DOCS_BUILD_DEPENDS= ${PYTHON_PKGNAMEPREFIX}sphinx>=0:textproc/py-sphinx@${PY_FLAVOR} DOCS_USES= gmake IMAGICK6_X11_RUN_DEPENDS= convert:graphics/ImageMagick6 IMAGICK6_NOX11_RUN_DEPENDS= convert:graphics/ImageMagick6-nox11 IMAGICK7_X11_RUN_DEPENDS= convert:graphics/ImageMagick7 IMAGICK7_NOX11_RUN_DEPENDS= convert:graphics/ImageMagick7-nox11 PAPERLESS_STATICDIR= ${WRKSRC}/static do-build: @${PYTHON_CMD} ${PYTHON_LIBDIR}/compileall.py \ -d ${PYTHONPREFIX_SITELIBDIR} \ -f ${WRKSRC}/src @${PYTHON_CMD} -O ${PYTHON_LIBDIR}/compileall.py \ -d ${PYTHONPREFIX_SITELIBDIR} \ -f ${WRKSRC}/src @${RM} -r ${PAPERLESS_STATICDIR} @${SETENV} \ PAPERLESS_STATICDIR=${PAPERLESS_STATICDIR} \ ${PYTHON_CMD} ${WRKSRC}/src/manage.py collectstatic do-build-DOCS-on: cd ${WRKSRC}/docs && ${SETENV} ${MAKE_ENV} \ ${MAKE_CMD} ${MAKE_ARGS} html SPHINXBUILD=sphinx-build-${PYTHON_VER} do-install: @${MKDIR} ${STAGEDIR}${PYTHON_SITELIBDIR}/paperless @cd ${WRKSRC}/resources && \ ${COPYTREE_SHARE} . ${STAGEDIR}${DATADIR} @cd ${WRKSRC}/src && \ ${COPYTREE_SHARE} . ${STAGEDIR}${PYTHON_SITELIBDIR}/paperless @${RLN} ${STAGEDIR}${PYTHON_SITELIBDIR}/paperless/manage.py \ ${STAGEDIR}${PREFIX}/bin/paperless @${MKDIR} ${STAGEDIR}${WWWDIR} @cd ${WRKSRC} && \ ${COPYTREE_SHARE} static ${STAGEDIR}${WWWDIR} @${SED} -e 's|%%WWWDIR%%|${WWWDIR}|g;' \ ${WRKSRC}/paperless.conf.example \ > ${STAGEDIR}${PREFIX}/etc/paperless.conf.sample @${MKDIR} ${STAGEDIR}/var/db/paperless/consume/input \ ${STAGEDIR}/var/db/paperless/media \ ${STAGEDIR}/var/db/paperless/sqlite ${INSTALL_MAN} ${WRKDIR}/paperless.7 ${STAGEDIR}${MANPREFIX}/man/man7 -# Klammern aussenrum? post-install-DOCS-on: @${MKDIR} ${STAGEDIR}${DOCSDIR}/presentation @cd ${WRKSRC}/docs/_build/html && \ ${COPYTREE_SHARE} . ${STAGEDIR}${DOCSDIR} @cd ${WRKSRC}/presentation && \ ${COPYTREE_SHARE} . ${STAGEDIR}${DOCSDIR}/presentation post-install-EXAMPLES-on: @${MKDIR} ${STAGEDIR}${EXAMPLESDIR} ${INSTALL_DATA} \ ${WRKDIR}/README \ ${WRKDIR}/nginx.conf \ ${WRKDIR}/sshd_config \ ${WRKDIR}/uwsgi.ini \ ${STAGEDIR}${EXAMPLESDIR} .include Index: head/deskutils/py-paperless/files/paperless.7.in =================================================================== --- head/deskutils/py-paperless/files/paperless.7.in (revision 521890) +++ head/deskutils/py-paperless/files/paperless.7.in (revision 521891) @@ -1,259 +1,259 @@ .\" .\" Copyright (c) 2019 Michael Gmelin .\" .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd March 30, 2019 +.Dd January 3, 2020 .Dt PAPERLESS 7 .Os .Sh NAME .Nm paperless .Nd Index and archive scanned paper documents - installation .Sh SYNOPSIS .Nm pkg install %%PKGBASE%% .Sh DESCRIPTION .Em Paperless is a simple Django application running in two parts: The consumer, which does the indexing and a web interface, which allows searching and downloading already-indexed documents. .Pp This man page documents how the .Fx FreeBSD port is installed and configured. It assumes that the paperless package was already installed, e.g., from the .Fx FreeBSD package repo as described in .Sx SYNOPSIS . .Pp For more information about using paperless, see .Dq the official paperless documentation .Pa ( file:/%%DOCSDIR%%/index.html or .Pa https://paperless.readthedocs.io ) . .Pp The package creates a symlink from .Pa %%PYTHONPREFIX_SITELIBDIR%%/paperless/manage.py to .Pa %%PREFIX%%/bin/paperless for convenience reasons, so whenever the official documentation mentions .Em manage.py it can be substituted with .Pa %%PREFIX%%/bin/paperless or simply .Pa paperless . .Pp .Em Paperless always needs to be run using the correct system user and an UTF-8 codepage. .Pp The package %%PKGBASE%% created a user .Em paperless with the following home directory layout, setting appropriate restrictive access permissions: .Bl -tag -width "/var" .It Pa /var/db/paperless home directory (only writeable by root) .Bl -tag -width "consume/" -compact .It Pa consume/ Consume directory writable by root, used as chroot directory for sftp access (see below). .Bl -tag -width "123" -compact .It Pa input/ Input files are dropped in there to be processed by the paperless document consumer - either directly or via a mechanism like sftp. .El .It Pa media/ Directory used by paperless to store original files and thumbnails. .It Pa sqlite/ Contains paperless' SQLite database. .El .El .Sh CONSUMER SETUP In case documents should be PGP encrypted, .Va PAPERLESS_PASSPHRASE needs to be configured in .Pa %%PREFIX%%/etc/paperless.conf first. .Pp Also, .Va PAPERLESS_OCR_THREADS can be tuned in the same configuration file to limit the impact on system performance. .Pp To use paperless, the consumer is enabled .Pp .Dl "sysrc paperless_consumer_enable=YES" .Pp and subsequently started .Pp .Dl "service paperless-consumer start" .Pp (which also creates/updates the paperless SQLite database). .Pp Therefore, restarting the consumer after updates .Pp .Dl "service paperless-consumer restart" .Pp updates the database before starting the new program version. .Sh WEB UI SETUP Before using the web ui, make sure to create a super user and assign a password .Pp .Dl "su -l paperless -c '%%PREFIX%%/bin/paperless createsuperuser'" .Pp It is recommended to host the web component using a real web server, e.g., nginx + uwsgi. .Pp Install and configure uwsgi: .Pp -.Dl "pkg install uwsgi-py36" +.Dl "pkg install uwsgi" .Dl "mkdir -p %%PREFIX%%/etc/uwsgi" .Dl "cp %%EXAMPLESDIR%%/uwsgi.ini \\" .Dl " %%PREFIX%%/etc/uwsgi/paperless.ini" .Dl "sysrc uwsgi_enable=YES" .Dl "sysrc uwsgi_profiles+=paperless" .Dl "sysrc uwsgi_paperless_socket_owner=paperless:www" .Dl "sysrc uwsgi_paperless_uid=paperless" .Dl "sysrc uwsgi_paperless_gid=paperless" .Dl "sysrc uwsgi_paperless_configfile=%%PREFIX%%/etc/uwsgi/paperless.ini" .Pp Start the uwsgi process: .Pp .Dl "service uwsgi start paperless" .Pp Install nginx: .Pp .Dl "pkg install nginx" .Pp Create a basic server configuration ( .Pa %%PREFIX%%/etc/nginx/nginx.conf ), example snippet: .Pp .Dl "server {" .Dl " listen 80;" .Dl " server_name localhost;" .Dl "" .Dl " location /static/ {" .Dl " alias %%WWWDIR%%/static/;" .Dl " }" .Dl "" .Dl " location / {" .Dl " uwsgi_pass unix:/tmp/uwsgi-paperless.sock;" .Dl " include uwsgi_params;" .Dl " }" .Dl "" .Dl " error_page 500 502 503 504 /50x.html;" .Dl " location = /50x.html {" .Dl " root %%PREFIX%%/www/nginx-dist;" .Dl " }" .Dl "}" .Pp Enable and start nginx: .Pp .Dl "sysrc nginx_enable=YES" .Dl "service nginx start" .Pp .Em \In the real world, nginx should be configured to use TLS .Em and (potentially) client certificates . .Sh SFTP SETUP Setting up .Em sftp enabled direct upload of files to be processed by the paperless consumer. Some scanners allow configuring sftp with key based authentication, which is convenient as it scans directly to the paperless processing pipeline. .Pp In case paperless is using a dedicated instance of .Xr sshd 8 , access can be limited to the paperless user by adding these lines to .Pa /etc/ssh/sshd_config : .Pp .Dl "# Only include if sshd is dedicated to paperless" .Dl "# otherwise you'll lock yourself out" .Dl "AllowUsers paperless" .Pp The following block limits the paperless user to using the .Xr sftp 1 protocol and locks it into the consume directory: .Pp .Dl "# paperless can only do sftp and is dropped into correct directory" .Dl "Match User paperless" .Dl " ChrootDirectory %h/consume" .Dl " ForceCommand internal-sftp -u 0077 -d /input" .Dl " AllowTcpForwarding no" .Dl " X11Forwarding no" .Dl " PasswordAuthentication no" .Pp The public keys of authorized users/devices need to be added to .Pa /var/db/paperless/.ssh/authorized_keys : .Pp .Dl "mkdir -p /var/db/paperless/.ssh" .Dl "cat path/to/pubkey >>/var/db/paperless/.ssh/authorized_keys" .Pp Make sure .Xr sshd 8 is enabled and restart (or reload) it: .Pp .Dl "sysrc sshd_enable=YES" .Dl "service sshd restart" .Pp The user will be dropped into the correct directory, so uploading a file is as simple as: .Pp .Dl "echo put file.pdf | sftp -b - paperless@host" .Sh FILES .Bl -tag -width ".Pa %%PREFIX%%/etc/paperless.conf" -compact .It Pa %%PREFIX%%/etc/paperless.conf See self-documented .Pa %%PREFIX%%/etc/paperless.conf.sample for example. .It Pa %%DOCSDIR%%/index.html Official documentation for the version installed. .It Pa %%DOCSDIR%%/presentation/index.html Presentation of the motivation for and technology behind paperless. .It Pa %%EXAMPLESDIR%% Configuration examples, complementary to this man page. .El .Sh SEE ALSO .Xr sftp 1 , .Xr sshd_config 5 , .Xr ports 7 , .Xr daemon 8 , .Xr service 8 , .Xr sysrc 8 .Pp .Rs .%B "Official paperless documentation" .Re .Pp .Pa https://paperless.readthedocs.io .Sh AUTHORS .An -nosplit This manual page was written by .An Michael Gmelin Aq Mt grembo@FreeBSD.org . Index: head/deskutils/py-paperless/files/patch-docs-guesswork.rst =================================================================== --- head/deskutils/py-paperless/files/patch-docs-guesswork.rst (nonexistent) +++ head/deskutils/py-paperless/files/patch-docs-guesswork.rst (revision 521891) @@ -0,0 +1,37 @@ +--- docs/guesswork.rst.orig 2019-01-27 13:48:05 UTC ++++ docs/guesswork.rst +@@ -54,6 +54,34 @@ filename as described above. + + .. _dateparser: https://github.com/scrapinghub/dateparser/blob/v0.7.0/docs/usage.rst#settings + ++Transforming filenames for parsing ++---------------------------------- ++Some devices can't produce filenames that can be parsed by the default ++parser. By configuring the option ``PAPERLESS_FILENAME_PARSE_TRANSFORMS`` in ++``paperless.conf`` one can add transformations that are applied to the filename ++before it's parsed. ++ ++The option contains a list of dictionaries of regular expressions (key: ++``pattern``) and replacements (key: ``repl``) in JSON format, which are ++applied in order by passing them to ``re.subn``. Transformation stops ++after the first match, so at most one transformation is applied. The general ++syntax is ++ ++.. code:: python ++ ++ [{"pattern":"pattern1", "repl":"repl1"}, {"pattern":"pattern2", "repl":"repl2"}, ..., {"pattern":"patternN", "repl":"replN"}] ++ ++The example below is for a Brother ADS-2400N, a scanner that allows ++different names to different hardware buttons (useful for handling ++multiple entities in one instance), but insists on adding ``_`` ++to the filename. ++ ++.. code:: python ++ ++ # Brother profile configuration, support "Name_Date_Count" (the default ++ # setting) and "Name_Count" (use "Name" as tag and "Count" as title). ++ PAPERLESS_FILENAME_PARSE_TRANSFORMS=[{"pattern":"^([a-z]+)_(\\d{8})_(\\d{6})_([0-9]+)\\.", "repl":"\\2\\3Z - \\4 - \\1."}, {"pattern":"^([a-z]+)_([0-9]+)\\.", "repl":" - \\2 - \\1."}] ++ + .. _guesswork-content: + + Reading the Document Contents Property changes on: head/deskutils/py-paperless/files/patch-docs-guesswork.rst ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/deskutils/py-paperless/files/patch-paperless.conf.example =================================================================== --- head/deskutils/py-paperless/files/patch-paperless.conf.example (revision 521890) +++ head/deskutils/py-paperless/files/patch-paperless.conf.example (revision 521891) @@ -1,38 +1,62 @@ --- paperless.conf.example.orig 2019-01-27 13:48:05 UTC +++ paperless.conf.example @@ -11,22 +11,22 @@ # This where your documents should go to be consumed. Make sure that it exists # and that the user running the paperless service can read/write its contents # before you start Paperless. -PAPERLESS_CONSUMPTION_DIR="" +PAPERLESS_CONSUMPTION_DIR="/var/db/paperless/consume/input" # You can specify where you want the SQLite database to be stored instead of # the default location of /data/ within the install directory. -#PAPERLESS_DBDIR=/path/to/database/file +PAPERLESS_DBDIR=/var/db/paperless/sqlite # Override the default MEDIA_ROOT here. This is where all files are stored. # The default location is /media/documents/ within the install folder. -#PAPERLESS_MEDIADIR=/path/to/media +PAPERLESS_MEDIADIR=/var/db/paperless/media # Override the default STATIC_ROOT here. This is where all static files # created using "collectstatic" manager command are stored. -#PAPERLESS_STATICDIR="" +PAPERLESS_STATICDIR=%%WWWDIR%%/static # Override the MEDIA_URL here. Unless you're hosting Paperless off a subdomain @@ -98,7 +98,7 @@ PAPERLESS_EMAIL_SECRET="" # servers to the list of allowed hosts that can do CORS calls. By default # Paperless allows calls from localhost:8080, but you'd like to change that, # you can set this value to a comma-separated list. -#PAPERLESS_CORS_ALLOWED_HOSTS="localhost:8080,example.com,localhost:8000" +#PAPERLESS_CORS_ALLOWED_HOSTS="http://localhost:8080,http://example.com,http://localhost:8000" # To host paperless under a subpath url like example.com/paperless you set # this value to /paperless. No trailing slash! +@@ -135,6 +135,23 @@ PAPERLESS_EMAIL_SECRET="" + # as normal. + #PAPERLESS_FILENAME_DATE_ORDER="YMD" + ++# Sometimes devices won't create filenames which can be parsed properly ++# by the filename parser (see ++# https://paperless.readthedocs.io/en/latest/guesswork.html). ++# ++# This setting allows to specify a list of transformations ++# in regular expression syntax, which are passed in order to re.sub. ++# Transformation stops after the first match, so at most one transformation ++# is applied. ++# ++# Syntax is a JSON array of dictionaries containing "pattern" and "repl" ++# as keys. ++# ++# The example below transforms filenames created by a Brother ADS-2400N ++# document scanner in its standard configuration `Name_Date_Count', so that ++# count is used as title, name as tag and date can be parsed by paperless. ++#PAPERLESS_FILENAME_PARSE_TRANSFORMS=[{"pattern":"^([a-z]+)_(\\d{8})_(\\d{6})_([0-9]+)\\.", "repl":"\\2\\3Z - \\4 - \\1."}] ++ + # + # The following values use sensible defaults for modern systems, but if you're + # running Paperless on a low-resource device (like a Raspberry Pi), modifying Index: head/deskutils/py-paperless/files/patch-src-documents-models.py =================================================================== --- head/deskutils/py-paperless/files/patch-src-documents-models.py (nonexistent) +++ head/deskutils/py-paperless/files/patch-src-documents-models.py (revision 521891) @@ -0,0 +1,18 @@ +--- src/documents/models.py.orig 2019-01-27 13:48:05 UTC ++++ src/documents/models.py +@@ -483,8 +483,14 @@ class FileInfo: + ".<suffix>" + """ + ++ filename = os.path.basename(path) ++ for (pattern, repl) in settings.FILENAME_PARSE_TRANSFORMS: ++ (filename, count) = pattern.subn(repl, filename) ++ if count: ++ break ++ + for regex in cls.REGEXES.values(): +- m = regex.match(os.path.basename(path)) ++ m = regex.match(filename) + if m: + properties = m.groupdict() + cls._mangle_property(properties, "created") Property changes on: head/deskutils/py-paperless/files/patch-src-documents-models.py ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/deskutils/py-paperless/files/patch-src-paperless-settings.py =================================================================== --- head/deskutils/py-paperless/files/patch-src-paperless-settings.py (revision 521890) +++ head/deskutils/py-paperless/files/patch-src-paperless-settings.py (revision 521891) @@ -1,11 +1,37 @@ --- src/paperless/settings.py.orig 2019-01-27 13:48:05 UTC +++ src/paperless/settings.py -@@ -104,7 +104,7 @@ MIDDLEWARE = [ +@@ -10,7 +10,9 @@ For the full list of settings and their + https://docs.djangoproject.com/en/1.10/ref/settings/ + """ + ++import json + import os ++import re + + from dotenv import load_dotenv + +@@ -102,7 +104,7 @@ MIDDLEWARE = [ ] # We allow CORS from localhost:8080 -CORS_ORIGIN_WHITELIST = tuple(os.getenv("PAPERLESS_CORS_ALLOWED_HOSTS", "localhost:8080").split(",")) +CORS_ORIGIN_WHITELIST = tuple(os.getenv("PAPERLESS_CORS_ALLOWED_HOSTS", "http://localhost:8080").split(",")) # If auth is disabled, we just use our "bypass" authentication middleware if bool(os.getenv("PAPERLESS_DISABLE_LOGIN", "false").lower() in ("yes", "y", "1", "t", "true")): +@@ -314,6 +316,15 @@ FY_END = os.getenv("PAPERLESS_FINANCIAL_ + DATE_ORDER = os.getenv("PAPERLESS_DATE_ORDER", "DMY") + FILENAME_DATE_ORDER = os.getenv("PAPERLESS_FILENAME_DATE_ORDER") + ++# Transformations applied before filename parsing ++FILENAME_PARSE_TRANSFORMS = [] ++_filename_parse_transforms = os.getenv("PAPERLESS_FILENAME_PARSE_TRANSFORMS") ++if _filename_parse_transforms: ++ FILENAME_PARSE_TRANSFORMS = [( ++ re.compile(t["pattern"]), t["repl"]) ++ for t in json.loads(_filename_parse_transforms) ++ ] ++ + # Specify for how many years a correspondent is considered recent. Recent + # correspondents will be shown in a separate "Recent correspondents" filter as + # well. Set to 0 to disable this filter.