Merge remote-tracking branch 'paperless/dev' into feature-consume-eml

This commit is contained in:
phail 2022-11-03 21:00:01 +01:00
commit 82b2ba3cc2
45 changed files with 1426 additions and 971 deletions

View File

@ -249,10 +249,12 @@ class MainImageTagsCleaner(RegistryTagsCleaner):
will be removed, if the corresponding branch no longer exists. will be removed, if the corresponding branch no longer exists.
""" """
# Default to everything gets kept still
super().decide_what_tags_to_keep()
# Locate the feature branches # Locate the feature branches
feature_branches = {} feature_branches = {}
for branch in self.branch_api.get_branches( for branch in self.branch_api.get_branches(
owner=self.repo_owner,
repo=self.repo_name, repo=self.repo_name,
): ):
if branch.name.startswith("feature-"): if branch.name.startswith("feature-"):
@ -261,6 +263,10 @@ class MainImageTagsCleaner(RegistryTagsCleaner):
logger.info(f"Located {len(feature_branches)} feature branches") logger.info(f"Located {len(feature_branches)} feature branches")
if not len(feature_branches):
# Our work here is done, delete nothing
return
# Filter to packages which are tagged with feature-* # Filter to packages which are tagged with feature-*
packages_tagged_feature: List[ContainerPackage] = [] packages_tagged_feature: List[ContainerPackage] = []
for package in self.all_package_versions: for package in self.all_package_versions:

View File

@ -15,7 +15,7 @@ from typing import Dict
from typing import List from typing import List
from typing import Optional from typing import Optional
import requests import httpx
logger = logging.getLogger("github-api") logger = logging.getLogger("github-api")
@ -28,15 +28,15 @@ class _GithubApiBase:
def __init__(self, token: str) -> None: def __init__(self, token: str) -> None:
self._token = token self._token = token
self._session: Optional[requests.Session] = None self._client: Optional[httpx.Client] = None
def __enter__(self) -> "_GithubApiBase": def __enter__(self) -> "_GithubApiBase":
""" """
Sets up the required headers for auth and response Sets up the required headers for auth and response
type from the API type from the API
""" """
self._session = requests.Session() self._client = httpx.Client()
self._session.headers.update( self._client.headers.update(
{ {
"Accept": "application/vnd.github.v3+json", "Accept": "application/vnd.github.v3+json",
"Authorization": f"token {self._token}", "Authorization": f"token {self._token}",
@ -49,14 +49,14 @@ class _GithubApiBase:
Ensures the authorization token is cleaned up no matter Ensures the authorization token is cleaned up no matter
the reason for the exit the reason for the exit
""" """
if "Accept" in self._session.headers: if "Accept" in self._client.headers:
del self._session.headers["Accept"] del self._client.headers["Accept"]
if "Authorization" in self._session.headers: if "Authorization" in self._client.headers:
del self._session.headers["Authorization"] del self._client.headers["Authorization"]
# Close the session as well # Close the session as well
self._session.close() self._client.close()
self._session = None self._client = None
def _read_all_pages(self, endpoint): def _read_all_pages(self, endpoint):
""" """
@ -66,7 +66,7 @@ class _GithubApiBase:
internal_data = [] internal_data = []
while True: while True:
resp = self._session.get(endpoint) resp = self._client.get(endpoint)
if resp.status_code == 200: if resp.status_code == 200:
internal_data += resp.json() internal_data += resp.json()
if "next" in resp.links: if "next" in resp.links:
@ -76,7 +76,7 @@ class _GithubApiBase:
break break
else: else:
logger.warning(f"Request to {endpoint} return HTTP {resp.status_code}") logger.warning(f"Request to {endpoint} return HTTP {resp.status_code}")
break resp.raise_for_status()
return internal_data return internal_data
@ -113,14 +113,15 @@ class GithubBranchApi(_GithubApiBase):
def __init__(self, token: str) -> None: def __init__(self, token: str) -> None:
super().__init__(token) super().__init__(token)
self._ENDPOINT = "https://api.github.com/repos/{OWNER}/{REPO}/branches" self._ENDPOINT = "https://api.github.com/repos/{REPO}/branches"
def get_branches(self, owner: str, repo: str) -> List[GithubBranch]: def get_branches(self, repo: str) -> List[GithubBranch]:
""" """
Returns all current branches of the given repository owned by the given Returns all current branches of the given repository owned by the given
owner or organization. owner or organization.
""" """
endpoint = self._ENDPOINT.format(OWNER=owner, REPO=repo) # The environment GITHUB_REPOSITORY already contains the owner in the correct location
endpoint = self._ENDPOINT.format(REPO=repo)
internal_data = self._read_all_pages(endpoint) internal_data = self._read_all_pages(endpoint)
return [GithubBranch(branch) for branch in internal_data] return [GithubBranch(branch) for branch in internal_data]
@ -247,7 +248,7 @@ class GithubContainerRegistryApi(_GithubApiBase):
""" """
Deletes the given package version from the GHCR Deletes the given package version from the GHCR
""" """
resp = self._session.delete(package_data.url) resp = self._client.delete(package_data.url)
if resp.status_code != 204: if resp.status_code != 204:
logger.warning( logger.warning(
f"Request to delete {package_data.url} returned HTTP {resp.status_code}", f"Request to delete {package_data.url} returned HTTP {resp.status_code}",
@ -266,7 +267,7 @@ class GithubContainerRegistryApi(_GithubApiBase):
PACKAGE_VERSION_ID=package_data.id, PACKAGE_VERSION_ID=package_data.id,
) )
resp = self._session.post(endpoint) resp = self._client.post(endpoint)
if resp.status_code != 204: if resp.status_code != 204:
logger.warning( logger.warning(
f"Request to delete {endpoint} returned HTTP {resp.status_code}", f"Request to delete {endpoint} returned HTTP {resp.status_code}",

View File

@ -139,7 +139,7 @@ jobs:
- -
name: Get changed files name: Get changed files
id: changed-files-specific id: changed-files-specific
uses: tj-actions/changed-files@v32 uses: tj-actions/changed-files@v34
with: with:
files: | files: |
src/** src/**

View File

@ -64,9 +64,9 @@ jobs:
with: with:
python-version: "3.10" python-version: "3.10"
- -
name: Install requests name: Install httpx
run: | run: |
python -m pip install requests python -m pip install httpx
# #
# Clean up primary package # Clean up primary package
# #

View File

@ -50,6 +50,11 @@ jobs:
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:
python-version: "3.9" python-version: "3.9"
-
name: Install jq
run: |
sudo apt-get update
sudo apt-get install jq
- -
name: Setup qpdf image name: Setup qpdf image
id: qpdf-setup id: qpdf-setup
@ -86,6 +91,18 @@ jobs:
echo ${build_json} echo ${build_json}
echo "jbig2enc-json=${build_json}" >> $GITHUB_OUTPUT echo "jbig2enc-json=${build_json}" >> $GITHUB_OUTPUT
-
name: Setup other versions
id: cache-bust-setup
run: |
pillow_version=$(jq ".default.pillow.version" Pipfile.lock | sed 's/=//g' | sed 's/"//g')
lxml_version=$(jq ".default.lxml.version" Pipfile.lock | sed 's/=//g' | sed 's/"//g')
echo "Pillow is ${pillow_version}"
echo "lxml is ${lxml_version}"
echo "pillow-version=${pillow_version}" >> $GITHUB_OUTPUT
echo "lxml-version=${lxml_version}" >> $GITHUB_OUTPUT
outputs: outputs:
@ -97,7 +114,11 @@ jobs:
psycopg2-json: ${{ steps.psycopg2-setup.outputs.psycopg2-json }} psycopg2-json: ${{ steps.psycopg2-setup.outputs.psycopg2-json }}
jbig2enc-json: ${{ steps.jbig2enc-setup.outputs.jbig2enc-json}} jbig2enc-json: ${{ steps.jbig2enc-setup.outputs.jbig2enc-json }}
pillow-version: ${{ steps.cache-bust-setup.outputs.pillow-version }}
lxml-version: ${{ steps.cache-bust-setup.outputs.lxml-version }}
build-qpdf-debs: build-qpdf-debs:
name: qpdf name: qpdf
@ -145,3 +166,5 @@ jobs:
REPO=${{ needs.prepare-docker-build.outputs.ghcr-repository }} REPO=${{ needs.prepare-docker-build.outputs.ghcr-repository }}
QPDF_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.qpdf-json).version }} QPDF_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.qpdf-json).version }}
PIKEPDF_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.pikepdf-json).version }} PIKEPDF_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.pikepdf-json).version }}
PILLOW_VERSION=${{ needs.prepare-docker-build.outputs.pillow-version }}
LXML_VERSION=${{ needs.prepare-docker-build.outputs.lxml-version }}

View File

@ -16,18 +16,18 @@ django-extensions = "*"
django-filter = "~=22.1" django-filter = "~=22.1"
djangorestframework = "~=3.13" djangorestframework = "~=3.13"
filelock = "*" filelock = "*"
fuzzywuzzy = {extras = ["speedup"], version = "*"}
gunicorn = "*" gunicorn = "*"
imap-tools = "*" imap-tools = "*"
langdetect = "*" langdetect = "*"
pathvalidate = "*" pathvalidate = "*"
pillow = "~=9.2" pillow = "~=9.3"
pikepdf = "*" pikepdf = "*"
python-gnupg = "*" python-gnupg = "*"
python-dotenv = "*" python-dotenv = "*"
python-dateutil = "*" python-dateutil = "*"
python-magic = "*" python-magic = "*"
psycopg2 = "*" psycopg2 = "*"
rapidfuzz = "*"
redis = {extras = ["hiredis"], version = "*"} redis = {extras = ["hiredis"], version = "*"}
scikit-learn = "~=1.1" scikit-learn = "~=1.1"
# Pin this until piwheels is building 1.9 (see https://www.piwheels.org/project/scipy/) # Pin this until piwheels is building 1.9 (see https://www.piwheels.org/project/scipy/)

806
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "5558c489e948de1779e547beae0dd36a2e551aa6be8505c26b651fd87eac2834" "sha256": "f8bdb4da9007a887c66a7e0243c486419676aa1a053c9a78e3760abb1f60e0a0"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": {}, "requires": {},
@ -75,10 +75,10 @@
}, },
"automat": { "automat": {
"hashes": [ "hashes": [
"sha256:7979803c74610e11ef0c0d68a2942b152df52da55336e0c9d58daf1831cbdf33", "sha256:c3164f8742b9dc440f3682482d32aaff7bb53f71740dd018533f9de286b64180",
"sha256:b6feb6455337df834f6c9962d6ccf771515b7d939bca142b29c20c2376bc6111" "sha256:e56beb84edad19dcc11d30e8d9b895f75deeb5ef5e96b84a467066b3b84bb04e"
], ],
"version": "==20.2.0" "version": "==22.10.0"
}, },
"backports.zoneinfo": { "backports.zoneinfo": {
"hashes": [ "hashes": [
@ -109,14 +109,6 @@
], ],
"version": "==3.6.4.0" "version": "==3.6.4.0"
}, },
"bleach": {
"hashes": [
"sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a",
"sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c"
],
"index": "pypi",
"version": "==5.0.1"
},
"celery": { "celery": {
"extras": [ "extras": [
"redis" "redis"
@ -409,17 +401,6 @@
"index": "pypi", "index": "pypi",
"version": "==1.2.0" "version": "==1.2.0"
}, },
"fuzzywuzzy": {
"extras": [
"speedup"
],
"hashes": [
"sha256:45016e92264780e58972dca1b3d939ac864b78437422beecebb3095f8efd00e8",
"sha256:928244b28db720d1e0ee7587acf660ea49d7e4c632569cad4f1cd7e68a5f0993"
],
"index": "pypi",
"version": "==0.18.0"
},
"gunicorn": { "gunicorn": {
"hashes": [ "hashes": [
"sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e", "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e",
@ -630,114 +611,6 @@
"index": "pypi", "index": "pypi",
"version": "==1.0.9" "version": "==1.0.9"
}, },
"levenshtein": {
"hashes": [
"sha256:019ae21de930d6077efa1eac746de4df5234e7c6c11ab10080c0935fc5abbecf",
"sha256:02688fff6d256afdd57da5359144ddab8e054b2ba98ddcf147fe191bdf996e88",
"sha256:0274b87df89d1dda8dce77cf05a9dfab7bd30045a09e0d9435ec8be622e374e6",
"sha256:0323e8dbeec4d63c27111796baa7e8a89b391c32d90e67d78f9404d0c8edeab4",
"sha256:053edbb52fe8b8a1a6698c4fee39590c9e44a602ace807291eb87e3b17f85f48",
"sha256:059027f5dd2aafb916301f46a619c7fe03ff5761cdb2d091cf80bf6dbc24bc29",
"sha256:05f11a4be4f668974238cff21208fbd9f629cab8a68b444b7d4a4cfd8081b1d6",
"sha256:0ab71cc5ea86f6685a7b2235edad65f1f2a4b6341109af259d758973d96eece5",
"sha256:0b439f4fb0b615bc0443cc83eaf5835bd480f680c69ed1be963bdb401b8159f8",
"sha256:0ec50d24a12e50857e94ac9035d3c06fd0827bb477b9ebcd83a2a49dd89e5e23",
"sha256:131fc50d52a52acc367ea8bccb028447b734243d00ba1cfc7d9ff8d0dc37fa38",
"sha256:17b5f1d1a4a5ac536283298c98cafc5632ae3897c8601fb2ec8babc6f47a1be9",
"sha256:183b8da9b870ad171a11a629c43e0587a228aea9d595a969231d59bf530b6c77",
"sha256:18888d50813b9df9b8dc8c1506ec40c783db25f130a6101eb89896b27076f751",
"sha256:25b88277832eb558305c3bb986ad61f19b5cb5a87aced289bce4a1701a92aa31",
"sha256:266cdab48e2242b6c010beb8b7af4164aa87f4ad8d6fbd9f4f531214f8ddb234",
"sha256:281bffb09b2e1620db4e99a9df96e38d939c341c7c43cd5191326fbdb4d42275",
"sha256:28cd002cf5a499e6e9bd69d992ffd501b8473948f3e97d6e075b774df1901e8e",
"sha256:2972c6c6a806e0c788f6ec39510abdb61b3a648fd141a5fa77becd2cc05ff551",
"sha256:2b4027b370cc46c4802ba32a979729209c0407d548723e809f19a50a9df27405",
"sha256:318c924e218be754427ce6bb4c630d9dcb5478eb00a8a3f8a0972086adc763b1",
"sha256:380accae56f8c9df99f34bc7e79d286fee37c3dd06b362c394b08ea96371b7c5",
"sha256:3c7784f9936292c9d3f92fc772d874edc071a16cd883ea0d997e5c4318f6362c",
"sha256:3ebd85fd6253abe89f852fc008294d490eb7a5f66913703148b8d263b048cc90",
"sha256:4126c8fe9d817ac3ab223ee5db41a09d0fa82dbd6bb59d207b6f7313d733f19b",
"sha256:4155f0ab246b6892110960f25989ab91073cd708b974f4732dca4d219a8be3e1",
"sha256:41f16267d8e6d916e06a6a1a0e151f643a6bab1277945a4bd494f359d4185dd2",
"sha256:4522f5d662d3ee55a072fad18e2af5dae480658d4e23b04b455c4b7542ce4327",
"sha256:46c900c807b0614c454ba89271ec6f59212403c54dc68ea493ab1ece2c510618",
"sha256:48291b25a904243f37c9aabbfed3eaba466c9a993f5f5946fe647163b7face07",
"sha256:5038a5e9e106087c117f0a7d6fd9d8a382b228da24bbd085b9f2b5d54ab11c3a",
"sha256:594a26bcf0cb720c16ac6db3fd4b3f411be756f9da7682f2f629089ff15aef18",
"sha256:59706135d3107939effe9f9263bd78c507f4abd7bfb96acc5a7f4176aa0a90d2",
"sha256:5a327d7581696c7a392a8f85cce7e54fa1303f5b79b3b2983abaab309b56cfd6",
"sha256:5eca8a45d38c916783c44e5da06a367b77234efa51d84dda8804654b99efecc9",
"sha256:5fa85f6789178ede5333568cbee5bac5fa9718d5f02406b65545e83368fa8fe9",
"sha256:65097e45ef7a942a9b92999b81d2e91fe80cbd0616215e625af39d2166692018",
"sha256:65cc9938cb9bd8862fc220e0719fd7f9c291d788f0a62bb8840820c46fa5a4d0",
"sha256:6a4c3607e2a0e66337d8ddf95ca7efe9b30ebf944119a4fb86503ea66f777263",
"sha256:72f11a136f148eb1218e7d1492749b8b5594302010db0cebd47423c4ac8c79ee",
"sha256:78b5a71de59e30c697a64c69fc48b032bb99c43b7437091b808a9ba20bb0235c",
"sha256:7b212edc9bf9d0c25cc3117483289b9e1a49a1ed134a02635baa987e9f0d89db",
"sha256:7e0f7045c420abdea249a28384baa846b87bad5c9f42af1957dc50c6e337fa1a",
"sha256:7e83cfec424f546dc3f0cc71896f8cc384a711f4116bc1abb0598302a9af3240",
"sha256:80c55bcc31d21bd07f7d1589e11f2ac1faf3359cf9f93026a1944ee76a40f954",
"sha256:863740d7f45adfd29b95658a680b16113721eaa89857c67e7e9573c61e87bbd8",
"sha256:88484b8c3f71dc9205d0d36da541e2cdcf4bc74474a2ee8d99c2e6411b659b89",
"sha256:8a08810e0bcc606d10cf1c5389c96fc92362244c0cf761358c495c2eb29df3dc",
"sha256:8c0637ae4fcb54d5c7fc9af24d348003b6f9dbaf7a06bf13f769d7b85903af39",
"sha256:8e9e3409338a42e3d4c30c224fdb678364542c77994f089fd6cc8131969eff48",
"sha256:902ea10ba85e014dc5d23a7bbb3ab70722349561e73783dd71571359e8867244",
"sha256:9533db74a2685169380db3db3ab59643453e7c486fffa9bf3ab60b73c4e174be",
"sha256:97f02ff49d1fa21308207a7743bec4fdd7aa90e8dd091539da660fc51e624c4d",
"sha256:9ea9a2a154dc7d8658930fa87cda0e6094235b5e130f037d9894eaf8722119a5",
"sha256:a0440d847b2c9986e4d27e8a59164714e5198530c69a5f9fb2e4620f9136d653",
"sha256:a6d39a27b542a781d691827b955d685d496fb6cccfc6eecc336a78b399032062",
"sha256:a7f4d3c478b1fcf412bf6c82914b02fed33ab359120df9172dda7bc855227461",
"sha256:ad297807bbdffce61b04e5e0c22f3c5d9e1905c1ee186f1f6d029f83bf0f18b8",
"sha256:add6778bb51efb80174937543754d2dfa0f4e504e7302d97896006a642c14f95",
"sha256:ae075ebf7bb5f48b3bd2fc9cd53346e4ff43e2515a4f822914bbc62a3cbd6e7e",
"sha256:b26fb439a7fbb522af63bbd781fbf51ec0c0659134a93f5bc8e9e68641df811e",
"sha256:b2bac59721d246939b21274229b9923aeae3db97b6118da739c658c17e110dd6",
"sha256:b314ad1f0667715e8d1b6197d5336ab579b13e801172721d62331bd40034a30c",
"sha256:b7317035875bd7c4705e2566848b2043b78e18f2f5675ea651f9f7805b5589eb",
"sha256:b8e936e620e5f336a207e08c0da9dace5d4dbcc8e64743ab1acaa77a64bbf060",
"sha256:b906da4e9a7ba4ec33ed2f7238343866932c1a6f84944c804252b2922708d0ee",
"sha256:ba690e4e33c360fcf0b8411ca90f8b9cc595e8deddd6a25a9a75a725b698cd6a",
"sha256:bb14da3d63da994c34cfa47cde469df8013ddf5f575455a22530c8c4a0ed8616",
"sha256:bbc2e1632f4a61fa171ddab3bc8368fb8475e7ce68733ca92fec862fdd8e0f60",
"sha256:bbdd3c896db09993b7879cd35e56da6ed8918d161d6e80f9d9c40d78d34e4784",
"sha256:bcaaa8e542cb7e1962d0a58ce6a25f6b4b6ca2e5ce743155fc1f6eb2fea52574",
"sha256:bee682ab1005aff597946234e47c95fcf0f44d2b1f38075f0aba26bbc4e7545a",
"sha256:bfec6543d60c57e7543d9cbccdd5dfcf562f2c05cd6b814df68108a20794e254",
"sha256:c2e50baf7be8831524a87beec6c1873539519a1948f907dc3d4b9be27ebacb80",
"sha256:c6c79a6138be017d85f3bab1df735669b669a38f9b3ff646a1f179afbacb7b63",
"sha256:c702fb7c8bfd87c9ce9c8bddfc9a5796a492bab35a52b1693adee413721e32f2",
"sha256:c9ba1725826f6571a6e4c1561bb1613711f0058b91927a147dc42c637ba087d9",
"sha256:cf205ac52cb6b45745c0a4891cdb6e709c10ad5b034aa736aff561fc4ce9828c",
"sha256:d0d03fc67499ee90feedfa2add4aaa1c091a7bf333535d847b10fffe390e58fe",
"sha256:d118d63f08fd6ac285cb8166e96c992a6ed0e7a1644e8790c39070b18779e688",
"sha256:d24c09f397c3ce55f20e0250da7ba5b0e5249cb5d21465e71ec15154a3a7e8e0",
"sha256:d41735c7a646dae8612e0552dfc53f45807eeb54364dfb1f0a65ac274bc56b3a",
"sha256:dd1696d91f2a37cece9bd22e507e7be7c37c59ecc61fd15f0d0f31e3b6888957",
"sha256:dfcad9c63a893c95ba1149481b9680ce68dd71211f08df0073ee62700790bc97",
"sha256:e384782608837d9aaf123e413679883091744664a2cd76f0ad0e0a1f12facc57",
"sha256:e5ea0abea338c617b753082f36f64c70ade853d88e91ab5732b301ae8ed16e3f",
"sha256:e6ff81c570413bcc35f1c16850eb66e2493a3259e68efe8672376533d2c82d38",
"sha256:e88951ad2831880405f3f055ab12a6aa72696c20a2815128eeccdc3bf914cd78",
"sha256:e98e16b6ce531b12100c01daac922e8ec5b991832a5f58003f13b7d45ea82dc0",
"sha256:eb0fd32e8e433797499571447d9f975b4744be79c0a3339413868d79517231ed",
"sha256:ee74a73e1f9e16b71f67329e99bb58aa4af9a2c3c4b3a5db9f26e92e7c39e161",
"sha256:f15ec5f825c283a5aa427d78759ab8f84e7b5441d15cfff476b548bce3764666",
"sha256:f296c7fe928ce0e29e313f85c43a5ab80542e096e1163c2605b8cc18aa2aff2b",
"sha256:f32df1b19f773bb41382e8b215955d248c9766e3d6ff5a1dd89709e7d96e4685",
"sha256:f3ed67279a4b317a808ac743d3a915f74187530c5f3d9c859e5d04d475b8c174",
"sha256:f5b972ca514898fb7131671c425a62ca38fdae2a8d6296e4b605ec8202349f8c",
"sha256:f961086c0dbba6c00cbd5c5b5646247efd0d0a4044444bfaa9efc7a6ba5e96a5",
"sha256:f9bd7d7a449667d6f17edd9045ec82a4ed2767afb91743d3d0b18c376a56dfe2",
"sha256:fbac4c8ffadb685189efa92fafdb2f5392e9cbd262eae3818bcdb1bd19acaaf2",
"sha256:fc43c8276d0a7c7b76f31d4f3f80f9eb820673628f1411770a70029c1d5f6a75",
"sha256:fcfded324f0710632e22050a2fd7b56b1cbcb2d21001630bcc26d536f54bffec",
"sha256:ff435abdcbfdf4a070f488830cd53aef77cf8649d0fd8ed76bf27d9566e80e78"
],
"markers": "python_version >= '3.6'",
"version": "==0.20.7"
},
"lxml": { "lxml": {
"hashes": [ "hashes": [
"sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318", "sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318",
@ -1028,69 +901,68 @@
}, },
"pillow": { "pillow": {
"hashes": [ "hashes": [
"sha256:0030fdbd926fb85844b8b92e2f9449ba89607231d3dd597a21ae72dc7fe26927", "sha256:03150abd92771742d4a8cd6f2fa6246d847dcd2e332a18d0c15cc75bf6703040",
"sha256:030e3460861488e249731c3e7ab59b07c7853838ff3b8e16aac9561bb345da14", "sha256:073adb2ae23431d3b9bcbcff3fe698b62ed47211d0716b067385538a1b0f28b8",
"sha256:0ed2c4ef2451de908c90436d6e8092e13a43992f1860275b4d8082667fbb2ffc", "sha256:0b07fffc13f474264c336298d1b4ce01d9c5a011415b79d4ee5527bb69ae6f65",
"sha256:136659638f61a251e8ed3b331fc6ccd124590eeff539de57c5f80ef3a9594e58", "sha256:0b7257127d646ff8676ec8a15520013a698d1fdc48bc2a79ba4e53df792526f2",
"sha256:13b725463f32df1bfeacbf3dd197fb358ae8ebcd8c5548faa75126ea425ccb60", "sha256:12ce4932caf2ddf3e41d17fc9c02d67126935a44b86df6a206cf0d7161548627",
"sha256:1536ad017a9f789430fb6b8be8bf99d2f214c76502becc196c6f2d9a75b01b76", "sha256:15c42fb9dea42465dfd902fb0ecf584b8848ceb28b41ee2b58f866411be33f07",
"sha256:15928f824870535c85dbf949c09d6ae7d3d6ac2d6efec80f3227f73eefba741c", "sha256:18498994b29e1cf86d505edcb7edbe814d133d2232d256db8c7a8ceb34d18cef",
"sha256:17d4cafe22f050b46d983b71c707162d63d796a1235cdf8b9d7a112e97b15bac", "sha256:1c7c8ae3864846fc95f4611c78129301e203aaa2af813b703c55d10cc1628535",
"sha256:1802f34298f5ba11d55e5bb09c31997dc0c6aed919658dfdf0198a2fe75d5490", "sha256:22b012ea2d065fd163ca096f4e37e47cd8b59cf4b0fd47bfca6abb93df70b34c",
"sha256:1cc1d2451e8a3b4bfdb9caf745b58e6c7a77d2e469159b0d527a4554d73694d1", "sha256:276a5ca930c913f714e372b2591a22c4bd3b81a418c0f6635ba832daec1cbcfc",
"sha256:1fd6f5e3c0e4697fa7eb45b6e93996299f3feee73a3175fa451f49a74d092b9f", "sha256:2e0918e03aa0c72ea56edbb00d4d664294815aa11291a11504a377ea018330d3",
"sha256:254164c57bab4b459f14c64e93df11eff5ded575192c294a0c49270f22c5d93d", "sha256:3033fbe1feb1b59394615a1cafaee85e49d01b51d54de0cbf6aa8e64182518a1",
"sha256:2ad0d4df0f5ef2247e27fc790d5c9b5a0af8ade9ba340db4a73bb1a4a3e5fb4f", "sha256:3168434d303babf495d4ba58fc22d6604f6e2afb97adc6a423e917dab828939c",
"sha256:2c58b24e3a63efd22554c676d81b0e57f80e0a7d3a5874a7e14ce90ec40d3069", "sha256:3dd6caf940756101205dffc5367babf288a30043d35f80936f9bfb37f8355b32",
"sha256:2d33a11f601213dcd5718109c09a52c2a1c893e7461f0be2d6febc2879ec2402", "sha256:40e1ce476a7804b0fb74bcfa80b0a2206ea6a882938eaba917f7a0f004b42502",
"sha256:336b9036127eab855beec9662ac3ea13a4544a523ae273cbf108b228ecac8437", "sha256:41e0051336807468be450d52b8edd12ac60bebaa97fe10c8b660f116e50b30e4",
"sha256:337a74fd2f291c607d220c793a8135273c4c2ab001b03e601c36766005f36885", "sha256:4390e9ce199fc1951fcfa65795f239a8a4944117b5935a9317fb320e7767b40f",
"sha256:37ff6b522a26d0538b753f0b4e8e164fdada12db6c6f00f62145d732d8a3152e", "sha256:502526a2cbfa431d9fc2a079bdd9061a2397b842bb6bc4239bb176da00993812",
"sha256:3d1f14f5f691f55e1b47f824ca4fdcb4b19b4323fe43cc7bb105988cad7496be", "sha256:51e0e543a33ed92db9f5ef69a0356e0b1a7a6b6a71b80df99f1d181ae5875636",
"sha256:408673ed75594933714482501fe97e055a42996087eeca7e5d06e33218d05aa8", "sha256:57751894f6618fd4308ed8e0c36c333e2f5469744c34729a27532b3db106ee20",
"sha256:4134d3f1ba5f15027ff5c04296f13328fecd46921424084516bdb1b2548e66ff", "sha256:5d77adcd56a42d00cc1be30843d3426aa4e660cab4a61021dc84467123f7a00c",
"sha256:4ad2f835e0ad81d1689f1b7e3fbac7b01bb8777d5a985c8962bedee0cc6d43da", "sha256:655a83b0058ba47c7c52e4e2df5ecf484c1b0b0349805896dd350cbc416bdd91",
"sha256:50dff9cc21826d2977ef2d2a205504034e3a4563ca6f5db739b0d1026658e004", "sha256:68943d632f1f9e3dce98908e873b3a090f6cba1cbb1b892a9e8d97c938871fbe",
"sha256:510cef4a3f401c246cfd8227b300828715dd055463cdca6176c2e4036df8bd4f", "sha256:6c738585d7a9961d8c2821a1eb3dcb978d14e238be3d70f0a706f7fa9316946b",
"sha256:5aed7dde98403cd91d86a1115c78d8145c83078e864c1de1064f52e6feb61b20", "sha256:73bd195e43f3fadecfc50c682f5055ec32ee2c933243cafbfdec69ab1aa87cad",
"sha256:69bd1a15d7ba3694631e00df8de65a8cb031911ca11f44929c97fe05eb9b6c1d", "sha256:772a91fc0e03eaf922c63badeca75e91baa80fe2f5f87bdaed4280662aad25c9",
"sha256:6bf088c1ce160f50ea40764f825ec9b72ed9da25346216b91361eef8ad1b8f8c", "sha256:77ec3e7be99629898c9a6d24a09de089fa5356ee408cdffffe62d67bb75fdd72",
"sha256:6e8c66f70fb539301e064f6478d7453e820d8a2c631da948a23384865cd95544", "sha256:7db8b751ad307d7cf238f02101e8e36a128a6cb199326e867d1398067381bff4",
"sha256:727dd1389bc5cb9827cbd1f9d40d2c2a1a0c9b32dd2261db522d22a604a6eec9", "sha256:801ec82e4188e935c7f5e22e006d01611d6b41661bba9fe45b60e7ac1a8f84de",
"sha256:74a04183e6e64930b667d321524e3c5361094bb4af9083db5c301db64cd341f3", "sha256:82409ffe29d70fd733ff3c1025a602abb3e67405d41b9403b00b01debc4c9a29",
"sha256:75e636fd3e0fb872693f23ccb8a5ff2cd578801251f3a4f6854c6a5d437d3c04", "sha256:828989c45c245518065a110434246c44a56a8b2b2f6347d1409c787e6e4651ee",
"sha256:7761afe0126d046974a01e030ae7529ed0ca6a196de3ec6937c11df0df1bc91c", "sha256:829f97c8e258593b9daa80638aee3789b7df9da5cf1336035016d76f03b8860c",
"sha256:7888310f6214f19ab2b6df90f3f06afa3df7ef7355fc025e78a3044737fab1f5", "sha256:871b72c3643e516db4ecf20efe735deb27fe30ca17800e661d769faab45a18d7",
"sha256:7b0554af24df2bf96618dac71ddada02420f946be943b181108cac55a7a2dcd4", "sha256:89dca0ce00a2b49024df6325925555d406b14aa3efc2f752dbb5940c52c56b11",
"sha256:7c7b502bc34f6e32ba022b4a209638f9e097d7a9098104ae420eb8186217ebbb", "sha256:90fb88843d3902fe7c9586d439d1e8c05258f41da473952aa8b328d8b907498c",
"sha256:808add66ea764ed97d44dda1ac4f2cfec4c1867d9efb16a33d158be79f32b8a4", "sha256:97aabc5c50312afa5e0a2b07c17d4ac5e865b250986f8afe2b02d772567a380c",
"sha256:831e648102c82f152e14c1a0938689dbb22480c548c8d4b8b248b3e50967b88c", "sha256:9aaa107275d8527e9d6e7670b64aabaaa36e5b6bd71a1015ddd21da0d4e06448",
"sha256:93689632949aff41199090eff5474f3990b6823404e45d66a5d44304e9cdc467", "sha256:9f47eabcd2ded7698106b05c2c338672d16a6f2a485e74481f524e2a23c2794b",
"sha256:96b5e6874431df16aee0c1ba237574cb6dff1dcb173798faa6a9d8b399a05d0e", "sha256:a0a06a052c5f37b4ed81c613a455a81f9a3a69429b4fd7bb913c3fa98abefc20",
"sha256:9a54614049a18a2d6fe156e68e188da02a046a4a93cf24f373bffd977e943421", "sha256:ab388aaa3f6ce52ac1cb8e122c4bd46657c15905904b3120a6248b5b8b0bc228",
"sha256:a138441e95562b3c078746a22f8fca8ff1c22c014f856278bdbdd89ca36cff1b", "sha256:ad58d27a5b0262c0c19b47d54c5802db9b34d38bbf886665b626aff83c74bacd",
"sha256:a647c0d4478b995c5e54615a2e5360ccedd2f85e70ab57fbe817ca613d5e63b8", "sha256:ae5331c23ce118c53b172fa64a4c037eb83c9165aba3a7ba9ddd3ec9fa64a699",
"sha256:a9c9bc489f8ab30906d7a85afac4b4944a572a7432e00698a7239f44a44e6efb", "sha256:af0372acb5d3598f36ec0914deed2a63f6bcdb7b606da04dc19a88d31bf0c05b",
"sha256:ad2277b185ebce47a63f4dc6302e30f05762b688f8dc3de55dbae4651872cdf3", "sha256:afa4107d1b306cdf8953edde0534562607fe8811b6c4d9a486298ad31de733b2",
"sha256:adabc0bce035467fb537ef3e5e74f2847c8af217ee0be0455d4fec8adc0462fc", "sha256:b03ae6f1a1878233ac620c98f3459f79fd77c7e3c2b20d460284e1fb370557d4",
"sha256:b6d5e92df2b77665e07ddb2e4dbd6d644b78e4c0d2e9272a852627cdba0d75cf", "sha256:b0915e734b33a474d76c28e07292f196cdf2a590a0d25bcc06e64e545f2d146c",
"sha256:bc431b065722a5ad1dfb4df354fb9333b7a582a5ee39a90e6ffff688d72f27a1", "sha256:b4012d06c846dc2b80651b120e2cdd787b013deb39c09f407727ba90015c684f",
"sha256:bdd0de2d64688ecae88dd8935012c4a72681e5df632af903a1dca8c5e7aa871a", "sha256:b472b5ea442148d1c3e2209f20f1e0bb0eb556538690fa70b5e1f79fa0ba8dc2",
"sha256:c79698d4cd9318d9481d89a77e2d3fcaeff5486be641e60a4b49f3d2ecca4e28", "sha256:b59430236b8e58840a0dfb4099a0e8717ffb779c952426a69ae435ca1f57210c",
"sha256:cb6259196a589123d755380b65127ddc60f4c64b21fc3bb46ce3a6ea663659b0", "sha256:b90f7616ea170e92820775ed47e136208e04c967271c9ef615b6fbd08d9af0e3",
"sha256:d5b87da55a08acb586bad5c3aa3b86505f559b84f39035b233d5bf844b0834b1", "sha256:b9a65733d103311331875c1dca05cb4606997fd33d6acfed695b1232ba1df193",
"sha256:dcd7b9c7139dc8258d164b55696ecd16c04607f1cc33ba7af86613881ffe4ac8", "sha256:bac18ab8d2d1e6b4ce25e3424f709aceef668347db8637c2296bcf41acb7cf48",
"sha256:dfe4c1fedfde4e2fbc009d5ad420647f7730d719786388b7de0999bf32c0d9fd", "sha256:bca31dd6014cb8b0b2db1e46081b0ca7d936f856da3b39744aef499db5d84d02",
"sha256:ea98f633d45f7e815db648fd7ff0f19e328302ac36427343e4432c84432e7ff4", "sha256:be55f8457cd1eac957af0c3f5ece7bc3f033f89b114ef30f710882717670b2a8",
"sha256:ec52c351b35ca269cb1f8069d610fc45c5bd38c3e91f9ab4cbbf0aebc136d9c8", "sha256:c7025dce65566eb6e89f56c9509d4f628fddcedb131d9465cacd3d8bac337e7e",
"sha256:eef7592281f7c174d3d6cbfbb7ee5984a671fcd77e3fc78e973d492e9bf0eb3f", "sha256:c935a22a557a560108d780f9a0fc426dd7459940dc54faa49d83249c8d3e760f",
"sha256:f07f1f00e22b231dd3d9b9208692042e29792d6bd4f6639415d2f23158a80013", "sha256:dbb8e7f2abee51cef77673be97760abff1674ed32847ce04b4af90f610144c7b",
"sha256:f3fac744f9b540148fa7715a435d2283b71f68bfb6d4aae24482a890aed18b59", "sha256:ebf2029c1f464c59b8bdbe5143c79fa2045a581ac53679733d3a91d400ff9efb",
"sha256:fa768eff5f9f958270b081bb33581b4b569faabf8774726b283edb06617101dc", "sha256:f1ff2ee69f10f13a9596480335f406dd1f70c3650349e2be67ca3139280cade0"
"sha256:fac2d65901fb0fdf20363fbd345c01958a742f2dc62a8dd4495af66e3ff502a4"
], ],
"index": "pypi", "index": "pypi",
"version": "==9.2.0" "version": "==9.3.0"
}, },
"pluggy": { "pluggy": {
"hashes": [ "hashes": [
@ -1223,13 +1095,6 @@
"index": "pypi", "index": "pypi",
"version": "==0.5.0" "version": "==0.5.0"
}, },
"python-levenshtein": {
"hashes": [
"sha256:88a58b95e3340a918489dac0c78f731323c0a4d8f5564f839ffea80155574e77",
"sha256:9228af5523f797f0798f045dc4a95ed1f46df72bc2186e52b530a33998a51b37"
],
"version": "==0.20.7"
},
"python-magic": { "python-magic": {
"hashes": [ "hashes": [
"sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b", "sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b",
@ -1240,10 +1105,10 @@
}, },
"pytz": { "pytz": {
"hashes": [ "hashes": [
"sha256:335ab46900b1465e714b4fda4963d87363264eb662aab5e65da039c25f1f5b22", "sha256:222439474e9c98fced559f1709d89e6c9cbf8d79c794ff3eb9f8800064291427",
"sha256:c4d88f472f54d615e9cd582a5004d1e5f624854a6a27a6211591c251f22a6914" "sha256:e89512406b793ca39f5971bc999cc538ce125c0e51c27941bef4568b460095e2"
], ],
"version": "==2022.5" "version": "==2022.6"
}, },
"pytz-deprecation-shim": { "pytz-deprecation-shim": {
"hashes": [ "hashes": [
@ -1309,111 +1174,98 @@
}, },
"rapidfuzz": { "rapidfuzz": {
"hashes": [ "hashes": [
"sha256:036f904bcac16d726273eee7ec0636978af31d151f30c95b611240e22592ab79", "sha256:028aa9edfa044629a0a9e924a168a01f61c8f570c9ea919e2ed214826ba1cdfb",
"sha256:0429a7a51d1372afaca969ee3170f9975f2fe6e187b485aeef55d3e8d7d934e0", "sha256:02a5c8b780af49a4e5f08033450d3f7c696f6c04e57c67ecbb19c9944ea3ce20",
"sha256:09de4fd3dbcc73f61b85af006372f48fee7d4324de227702b9da0d2572445d26", "sha256:07c623741958dd49d8c2c51f7c2e62472f41b8d795cc9c734e441e30de3f8330",
"sha256:0c8a5e65cab629ca5bb4b1d2b410f8444384b60364ab528508200acfdf9e659d", "sha256:0ae8c0c2f51f618d54579341c44ba198849d9cd845bb0dc85d1711fd8de9a159",
"sha256:0e64ab58b19866ad3df53e651a429871d744f8794cca25c553396b25d679a1ac", "sha256:129c93a76c4fed176b4eaaf78fecd290932971bca10315dee9feaf94a7b443b1",
"sha256:0f09ff49b28e557615a9ad4d5eedbfd5b886fccb3ec35d85dd34c51348c4bf98", "sha256:13ad87a539b13794292fb661b8c4f4c19e6c066400d9db991e3a1441f55fc29b",
"sha256:12e14b0c43e3bc0c679ef09bfcbcaf9397534e03b8854c417086779a79e08bb2", "sha256:16426b441d28efb3b1fe10f2b81aa469020655cef068a32de6ec24433590ee5b",
"sha256:134a467692216e05a8806efe40e3bcae9aa81b9e051b209a4244b639a168c78e", "sha256:1a600b037a56a61111c01809b5e4c4b5aac12edf2769c094fefab02d496a95a4",
"sha256:13ce1019ddce7419502fac43b62ac166d3d6d290b727050e3de5bda79a6beb59", "sha256:1e0f6f878c20454a7e7ea2ed30970ae0334852c5e422e7014757821fa33c1588",
"sha256:16a2edf3ea888c9d3582761a2bbaa734e03f6db25d96e73edd4dcef6883897ee", "sha256:20f2f0f0746ffc165168ca160c5b1a1485076bdde5b656cf3dbe532ef2ac57ff",
"sha256:17ba5fb474515356608cdb8d750f95c12f3e4dc9a0e2c9d7caca3d4cee55048e", "sha256:2207927f42ae7b7fbcc1a4ff86f202647776200f3d8723603e7acf96af924e9f",
"sha256:2183fc91971c0853f6170225577d24d81b865d416104b433de53e55a6d2a476a", "sha256:22487992f4811c8aef449736f483514f0294d5593f5f9c95cbfb2474dbc363b9",
"sha256:24569412e1aac1ac008548cdcd40da771e14467f4bacab9f9abfe5bbb5dfe8be", "sha256:22646f54d44d98d6f462fb3f1ac997ea53aaebdd1344039e8f75090f43e47a89",
"sha256:254d5a800de54c416fa9b220e442a4861b272c1223139ae3dee0aea1c9f27c9c", "sha256:22e8b127abcf0b10ebf8a9b3351c3c980e5c27cb60a865632d90d6a698060a9a",
"sha256:2bc3ec87df5eaad59e6e02e6517047fb268a48866f3531c4b8b59c2c78069fe5", "sha256:238fddfb90fab858ced88d064608bff9aed83cec11a7630a4e95b7e49734d8b1",
"sha256:2d3652804ae17920eaa965b1e057ee0ea32d5bb02f50147c82a1d350a86fc3f1", "sha256:241912c4f7f232c7518384f8cea719cf2ff290f80735355a217e9c690d274f62",
"sha256:30773e23bebe27ddcf7644d6ebb143bf7c9adeb18019a963172174ef522c0831", "sha256:25db060ba8082c38f75da482ff15d3b60a4bc59f158b6d29a2c5bccadd2b71b0",
"sha256:3b6573607568438dfc3d4341b0b00d326ac2cf86281df97e7f8c0348e2f89b5e", "sha256:2676f7ccd22a67638baff054a8e13924f20d87efb3a873f6ea248a395a80e2c8",
"sha256:3d50a2ca8cd1cea13afd2ff8e052ba49860c64cc3e617398670fd6a8d11e450f", "sha256:27fa0e7d5e5291dc3e48c6512524f2f8e7ba3d397fa712a85a97639e3d6597e9",
"sha256:3f1c030e2d61d77cb14814640618e29cf13e4554340a3baa9191d162a4dfcd9e", "sha256:2c2cd1e01e8aef2bd1b5152e66e0b865f31eb2d00a8d28cbbbb802f42e2dbe43",
"sha256:40e8d37d67a6e4713ddb6053eb3007a3ca15eddd23f2e4a5039c39e666c10b3a", "sha256:2e9709a163ec3b890f9a4173261e9ef586046feee74bbece62595bf103421178",
"sha256:41c9e2acfa25c7667b70913d63887f76e981badc1e95a2878257d28b96f5a10c", "sha256:2fda8c003d9ae4f3674c783887b31ecb76f4ab58670a8f01b93efd0917c1e503",
"sha256:42d18db6f7e1e6ef85a8e673b2fa3352727cc56e60e48e7c9268fe0286ab9f91", "sha256:33cfd01cb7f8a48c8e057198e3814a120323c0360017dd5c4eba07d097b43b39",
"sha256:475aacad5d5c4f9ad920b4232cc196d79a1777fe1eada9122103c30154d18af4", "sha256:35737fd5766ca212d98e0598fb4d302f509e1cbf7b6dc42e2eddefd956150815",
"sha256:47e163d6a6676be9a3a7e93d5a2c3c65a43c1530b680903ebdba951e07ee7999", "sha256:35b34f33a9f0a86fdba39053b203d8d517da76f3553230a55867c51f0d802b67",
"sha256:5080ad715e39b8a2d82339cf4170785e9092c7625ec2095ff3590fdb0a532a41", "sha256:3abe9c25f9ba260a6828d24002a15112c5f21c6877c5f8c294ffe4b9d197c6d2",
"sha256:52639268dffc8900892a5e57964228fb187512b0f249de9a45ba37c6f2bc52a5", "sha256:3c7f3c61e2d1530cf7e1647bdbb466f0f83fa30d2c579b6d75e444f88ff47913",
"sha256:54264d70af59224d6874fcc5828da50d99668055574fe254849cab96f3b80e43", "sha256:3e8707e98b645f80834e24103e7cd67f1b772999bb979da6d61ca1fcdc07672a",
"sha256:553e8e3dce321ed33e8b437586e7765d78e6d8fbb236b02768b46e1b2b91b41e", "sha256:3eae4c6880dbabee9f363950510c09d7e12dea8dbc6ebcd2ff58e594a78d9370",
"sha256:56aa67bf938e8dcc5e940f183538f09041441f1c4c5a86abe748416950db9d27", "sha256:3f7b798807ac9c5f632e8f359adf1393f81d9211e4961eedb5e2d4ce311e0078",
"sha256:578934d7524f8378175295e6411b737d35d393d91d4661c739daa8ea2b185836", "sha256:43398361d54fed476ccfdb52dc34d88c64461f0ec35f8abf10dd0413a3f19d8c",
"sha256:588dd5f520683af53a9d9d0cabde0987788c0ea9adfda3b058a9c27f448b2b3f", "sha256:4581600ded8f37e8387d0eef93520fb33dafab6ccb37d005e20d05cd3fbdd9db",
"sha256:5aff0ac1723f7c8d751869a51e6b12d703fd6e6153228d68d8773f19bd5bd968", "sha256:45def44f1140c6f5c7a5389645d02e8011d27a6e64f529f33cee687e7c25af07",
"sha256:5e3164736ed071dc743994b9228ead52b63010aba24b1621de81b3ac39d490b9", "sha256:475a551c43ba23b4ca328c9bbcae39205729f4751280eb9763da08d97d328953",
"sha256:5e89f50f5f3be2b851e9714015e1a26c6546e6b42f3df69b86200af8eacf9d8c", "sha256:4787d8e9f4b184d383ad000cdd48330ae75ec927c5832067a6b3617c5f6fb677",
"sha256:61152fa1e3df04b4e748f09338f36ca32f7953829f4e630d26f7f564f4cb527b", "sha256:48539221026b0a84b6d2c2665c3dde784e3c0fac28975658c03fed352f8e1d7e",
"sha256:64133c9f45cb88b508d52427339b796c76e1790300c7ea4d2ed210f224e0698d", "sha256:4f3f0ddfe3176e19c0a3cf6ad29e9ff216ff5fdec035b001ebabad91ef155107",
"sha256:65b8611c9f5385a2986e11e85137cdecf40610e5d5f250d96a9ed32b7e995c4a", "sha256:4fc958b21416825c599e228278c69efb480169cd99d1a21787a54f53fbff026c",
"sha256:6803ef01f4056d61120e37acba8953e6b3149363e85caaba40ee8d49753fe7bd", "sha256:589464c49a332c644b750f2ebc3737d444427669323ace623bd4948e414a641a",
"sha256:68d46ad148c9cb8be532b5dd7bc246b067e81d4cfabad19b4cb6ac4031cab124", "sha256:5c6a9ada752149e23051852867596b35afc79015760e23676ac287bcad58e0b6",
"sha256:6b12420d5b769cd7e1478a8085aeea1ad0ffc8f7fedc86c48b8d598e1602f5ad", "sha256:5dcd7bd175d870338fc9ae43d0184ecd45958f5ca2ee7ea0a7953eedc4d9718e",
"sha256:705ccd8de2b7b5295c6a230a3919fc9db8da9d2a6347c15c871fcb2202abd237", "sha256:5e2c0a5a0346ce95a965ed6fa941edcf129cac22bf63314b684a3fe64078c95b",
"sha256:7478341137e65a0227fda4f3e39b3d50e6ec7dd4f767077dd435b412c2f2c129", "sha256:5fa88543c5744d725fc989afd79926c226e1c5f5c00904834851997f367da2b5",
"sha256:769cf4099f53507231ba04cbf9ee16bea3c193767efc9bdf5e6c59e67e6b5cea", "sha256:626eaa1b52a9dafa9bf377bcdcfdf1ea867dd51b5bb5dab1a05938c3303f317f",
"sha256:7750b950a6987bce114b9f36413399712422f4f49b2ad43f4b4ee3af34968b99", "sha256:651664023726f28f7447e40fa2b8a015514f9db4b58654e9bf7d3729e2606eab",
"sha256:7c457f779992a0f5527455cdc17c387268ae9f712d4e29d691704c83c6e58c2d", "sha256:74f821370ac01f677b5a26e0606084f2eb671f7bb4f3e2e82d94a100b1c28457",
"sha256:7dd6a439fb09dc9ba463de3f5c8e20f097225816b33a66380b68c8561a08045c", "sha256:7a67d93fd2e6e5a4e278eade2bbef16ba88d4efcb4eed106f075b0b21427a92f",
"sha256:804c7c67dc316f77b01b9bef5e75f727b73ff1015ff0514972b59dc05eec4d81", "sha256:7e34c996cc245a21f376c3b8eede1296339845f039c8c270297a455d3a1ad71b",
"sha256:86038b9777b2aa0ebf8c586b81cba166ccde7e6d744aad576cd98c1a07be4c53", "sha256:7f2db0c684d9999c81084aa370e2e6b266b694e76c7e356bbeb3b282ca524475",
"sha256:86c34175830cacac1c16d2182a0f725afbd40042955b7572c8475e3b6a5d8ada", "sha256:7febf074f7de7ebc374100be0036fc592659af911b6efbc1135cdebfe939c57d",
"sha256:8a11b70ebb2d7317d69bdb1f692a0eda292a4cddfe9ccb760a8d1a9e763811dd", "sha256:800b1498989bfb64118b219eeb42957b3d93ec7d6955dfc742a3cbf3be738f2f",
"sha256:8b402e99593483a8b05a09fb2a20379ecaa9b0d1f1cf32957b42134bd3305731", "sha256:8eadfb5394ab5b9c6e3d4bb00ef49e19f60a4e431190c103e647d4e4bff3332e",
"sha256:8b480a78227457a0b65e0b23afbda9c152dee4e1b41ccc058db8c41ea7a82ab0", "sha256:917e3e2ffc0e078cce4a632f65d32a339f18cad22b5536a32c641bf1900e7f96",
"sha256:8bc00bd6b6407dc7a8eb31964bcc38862c25e7f5f5982f912f265eb3c4d83140", "sha256:96fe7da85d8721c3a5c362f6b1e7fd26ad74a76bebc369fb7ae62907cf069940",
"sha256:8d6fa1d009fcb9a9169548c29d65a1f05c0fcf1ac966f40e35035307d6a17050", "sha256:9836bea98f25a67c296f57cf6de420c88f46e430ee85d25ae5f397968c7adcdf",
"sha256:9081542fea2baeebda8caa43a54ecd8a152a05ff3271c38ac8eae447377cef54", "sha256:9c8295dd49582dfb6a29e5f9dfa1691a0edd2e0512377ceb2c8dd11e7fabd38a",
"sha256:931a939ba5e5574f769507038fdf400dbbc46aab2866d4e5e96d83a29f081712", "sha256:9ceb8d6f1bd18a058cb8472c6e8cc84802413a65b029a7832589ba7b76c0eb11",
"sha256:984d40ecda0bc0109c4239d782dfe87362d02b286548672f8a2468eabbf48a69", "sha256:9e239e404dbb9fec308409e174710b5e53ff8bd9647e8875e2ca245b1f762f89",
"sha256:9924497dec6a30b5158ef7cc9c60a87c6c46d9f7b7bb7254d4f157b57b531fb8", "sha256:9f849d4889a0f1bc2260b981b1ae8393938e8a2c92666e1757e69f947c6ce868",
"sha256:a48ff6b6258a32f50f876a6c74fa2f506c1de3b11773d6bf31b6715255807a48", "sha256:a6d78f967b7b162013fc85821a74cc7cd021fbf045f166629c9bd523799d8e51",
"sha256:a7f5a77466c4701062469bce29358ca0797db2bc6d8f6c3cd4e13f418cca10bc", "sha256:a8d5787f5c52c00991032b976b69f5c1e181a3bddce76fd43c91b2c4901c96ce",
"sha256:a98c63d1f5ec2c15adf5dc81c461c8d88c16395956f4518b78e2e04b3285b1e5", "sha256:a9a90ab26b12218d10d5f148e84e8facd62f562bc25d32e2c3cf3c743f7e0e67",
"sha256:adc7c6cb3dde5c284d84c7c6f4602b1545ba89c6ebb857b337d0428befb344e5", "sha256:ac6ce417174a086a496aefc7caa614640dc33d418a922ee0a184b093d84f2f6c",
"sha256:b4f577ded3e40695d5e0796e8b7f4fa78577d873627e0d0692f7060ad73af314", "sha256:ac95a2ca4add04f349f8f5c05269d8b194a72ebdfc4f86a725c15d79a420d429",
"sha256:b5c7b0a4929bfd3945d9c2022cff0b683a39accf5594897fa9004cee4f402b06", "sha256:ad279e4892652583671a7ece977dd9b1eb17ae9752fbc9013c950095b044a315",
"sha256:b5cd1ea9fa396243d34f7bac5bb5787f89310f13fd2b092d11940c6cd7bd0bd8", "sha256:ad5935f4a0ec3a2c3d19021fcd27addce4892ae00f71cc4180009bc4bed930ac",
"sha256:bafd18a27dbe3197e460809468a7c47d9d29d1ebab6a878d5bb5a71fda2056d6", "sha256:ae0519d01a05c6204c2d27ae49b2231787d9a6efc801d5dbf131b20065fd21e3",
"sha256:bd595bd23a4e1c72d5f5ac416ea49b9a3d87e11fb2db4b960378038ce9bb12f7", "sha256:b1114da71974c86e64a98afff8d88cf3a3351b289d07f0218e67d56b506cb9e2",
"sha256:bd7a1992e91c90197c34ccc674bd64262262627083c99896b79e2c9f5fe28075", "sha256:b2b81c6cb59b955b82a4853e3fbef7231da87c5522a69daaf9b01bd81d137ec3",
"sha256:bd8f36d8bd399c7d695182e467b4428adb940a157014ab605bbe4d0ab0a1976e", "sha256:b63402c5af2ad744c2c1ab2e7265eb317e75257fd27eb6f087fea76464b065db",
"sha256:bf5277ff74c9980245697ea227057d0f05b31c96bc73bae2697c1a48d4980e45", "sha256:b75fe7abf55e7da6d32174b5ac207a465d1bc69d777049c277776472c0b7d82c",
"sha256:bfabc6130752f4f77584b2ecbba2adf6fe469b06c52cb974ba8304f1f63bb24f", "sha256:c0006c6450d02efdfef8d3f81e6a87790572486046676fe29f4c5da8708ea11b",
"sha256:c10724490b87fcb86161e5ceb17893626d13363e31efee77aa8e251ee16dcdd5", "sha256:c1191a1c9f24134c6048770aabaa2f7def8d6d4c919da857d5e7dabdf63308f2",
"sha256:c1477455b82d6db7336ef769f507a55bba9fe9f1c96dc531d7c2c510630307d6", "sha256:c43579c7a64f21c9b4d4c3106ace46a8ebfb8e704372e6c8cc45807d1b86462f",
"sha256:c288e239fc3aaae3865e43e1f35b606f92ee687a0801e4d46c45d7849aebbe35", "sha256:c62472a70c7f22f1ae9864c02554dbc234a1dfbac24388542bf87437a4169379",
"sha256:c305ea5405f8615e6ecd39cb28acc7a362713ba3c17c7737b591b377d1afd9ec", "sha256:c6c4064b2324b86f7a035379928fe1f3aca4ca5ba75ebedc9ea0d821b0e05606",
"sha256:c77cec595dc80f97a1b32413fb1b618e4da8ba132697e075ad8e4025c4058575", "sha256:c6fa81c8d3c901d9f174482185f23b02052e71da015da3a613be98f28fd2672b",
"sha256:c822853e9d54979eb5fcf9e54c1f90e5c18eeb399571383ac768cff47d6d6ada", "sha256:c74b960a1b93ac22e6cbf268ce509fb2c2338a29180c3d844df4a57bfff73273",
"sha256:cad5088f1adb9161f2def653908328cfa1dc9bc57e7e41ccdc9339d31cc576d1", "sha256:c9c2b3b00033afdb745cc77b8c2ed858b08bb9a773c9a81a1160ece59a361545",
"sha256:cc3103e31d27352afe4c5a71702e09185850187d299145d5e98f9fb99a3be498", "sha256:c9fdbe8b1b32a731ee48a21a161358e55067c9cabd36ba0b8d844e5106056920",
"sha256:ced719fcae6f2a348ac596b67f6d7c26ff3d9d2b7378237953ac5e162d8a4e2e", "sha256:d0fc1e32353afef426488d2e19cd295f1f504323215275ec0871bdae2b052a70",
"sha256:d181889218d80f6beb5ae3838bc23e201d2a1fae688baaa40d82ef9080594315", "sha256:d5b65d9f2860210087739adadc075bd9215b363d00c3c8e68369560683a4c3df",
"sha256:d1d8192820d8489a8e3ef160cbe38f5ff974db5263c76438cf44e7574743353b", "sha256:d6e6972c5bd1ee4f532029616dfe0f5133f7cc688ebc05dbbc03e19b4ec12199",
"sha256:d24181dfdfcc3d9b37333fea2f5bf9f51e034bd9e0ba67a871f18686b797c739", "sha256:e333bb6a69c515a1fce149002aaf7d8902fddab54db14fe14c89c6da402410d2",
"sha256:d51b9183ebce60d4795ceaef24b8db2df3ed04307ee787d6adafcc196330a47c", "sha256:ef812c73fff460678defaab3a95ec9b7551ef14d424eb6af7b75e376050119d2",
"sha256:dad6697c6b9e02dd45f73e22646913daad743afd27dadb0b6a430a1573fb4566", "sha256:f030223aa618a48d2f8339fd674c4c03db88649313e2c65107e9c04e09edc7f2",
"sha256:dafe8c6e74fea0fdcfec002bc77aee40b4891b14ea513e6092402609ac8dac00", "sha256:f371453d0c1109e93ef569741a27171e602ef1fbea5c27a8f190f403234fd36b",
"sha256:dc0f695b32700b14f404cccaebc25eea6db323418385568297995aee8b5278f8", "sha256:f74636ca4a3ce700f4fe2dbe10d224ee4fb52ecab12ea3007a2bc2fcd0d53888",
"sha256:e2fe220d4b100b00734d9388e33296ac8f585c763548c372ca17b24affa178e0", "sha256:f96973d42caf0e4566882b6e7acbba753199d7acb4db486f14ab553c7b395cd5"
"sha256:e459287f0daaee3ee0108123d7e9a1c1c136e94d4382533a93cb509d54dc1ea3",
"sha256:ea4107a5cc00a05c92be47047662000296d2ccc7ba93aaa030cd5ecab8d5ffaf",
"sha256:ea4f0d056a95cfdabde667a1796f9ba5296d2776bce2fd4d4cb5674e0e10671f",
"sha256:ea5bc5bae1cf447b79be04f05e73b6ea39a5df63374f70cc5d6862337462d4d9",
"sha256:ecfe2fe942edabcd1553701237710de296d3eb45472f9128662c95da98e9ed43",
"sha256:eec5ad2f06701e57a2cb483c849704bdf8ea76195918550ab2fc4287970f1c76",
"sha256:f2f91b867d7eca3b99c25e06e7e3a6f84cd4ccb99f390721670ba956f79167c9",
"sha256:f5ed8d4e1545f08bd3745cc47742b3689f1a652b00590caeb32caf3297d01e06",
"sha256:f6e6395404b0239cff7873a18a94839343a44429624f2a70a27b914cc5059580",
"sha256:f71edc8503d08bc5d35187eb72f13b7ec78647f1c14bb90a758ae795b049f788",
"sha256:f72d33b0d76a658d8b692b3e42c45539939bac26ff5b71b516cb20fa6d8ff7f6",
"sha256:f9226824c132d38f2337d2c76e3009acc036f0b05f20e95e82f8195400e1e366",
"sha256:faba219b270b78e9494cfe3d955d7b45c10799c18ee47ec24b1ada93978d491b"
], ],
"markers": "python_version >= '3.6'", "index": "pypi",
"version": "==2.11.1" "version": "==2.12.0"
}, },
"redis": { "redis": {
"extras": [ "extras": [
@ -1508,45 +1360,54 @@
}, },
"reportlab": { "reportlab": {
"hashes": [ "hashes": [
"sha256:03501aa3cffb93ec35ca01d66a70d38090e88080b16eb4efb015a0fdc94a48c9", "sha256:07fdd968df7941c2bfb67b9bb4532f424992dfafc71b72a4e4b291ff707e6b0e",
"sha256:04fc4420f0548815d0623e031c86a1f7f3f3003e699d9af7148742e2d72b024a", "sha256:090ea99ff829d918f7b6140594373b1340a34e1e6876eddae5aa06662ec10d64",
"sha256:06a9a9b04083529e4204e0c0f4574b7795cc8364a49e66dac25d94588fdaf24a", "sha256:109009b02fc225882ea766a5ed8be0ef473fa1356e252a3f651a6aa89b4a195f",
"sha256:32b3e10acdbbd2b91a8bb94134ed011af8e5c32ef5fe69f5481f83bbc89fd40e", "sha256:1dd0307b2b13b0482ac8314fd793fbbce263a428b189371addf0466784e1d597",
"sha256:384e51906d710cec7721ee4f074bc59131dbed9ef3b8e45408432caa752c1d5d", "sha256:236a6483210049205f6180d7a7595d0ca2e4ce343d83cc94ca719a4145809c6f",
"sha256:3e53e8222afc535cfdad3d73786c570ec6567b48e3e09bfadca606b170f3f46d", "sha256:26c25ea4afa8b92a2c14f4edc41c8fc30505745ce84cae86538e80cacadd7ae2",
"sha256:456b9e245dacfa0f676f2864b8981a61bb50aa3fe690fe54885dc41b2b2b402c", "sha256:2a0bc7a1d64fe754b62e175ba0cf47a630b529c0488ec9ac4e4c7655e295ea4d",
"sha256:4c183a28a44bc03c0ab825fceab4a07a8b36d7f67a208dcf9e561dc4e343aec9", "sha256:2c9b0861d8f40d7a24b094b8834f6a489b9e8c70bceaa7fa98237eed229671ce",
"sha256:4e97028ea070199955cb50dd1e321177f7fd2fefe89fb328d016e510d60bfc9e", "sha256:39e92fa4ab2a8f0f2cc051d9c1e3acb881340c07ef59c0c8b627861343d653c0",
"sha256:5104000c1f84066c452022316faecb7382eae23a878547cacfa6511f9fddfe02", "sha256:3a62e51a4a47616896bd0f1e9cc3fbfb174b713794a5031a34b84f69dbe01775",
"sha256:55df316e227f876e88ba5979c2456e3be47988056e0053d1139f9fbaff968d24", "sha256:3fd1ffdd5204301eb4c290a5752ac62f44d2d0b262e02e35a1e5234c13e14662",
"sha256:60bcdefa9246e9dd26708d53fe4a51dcef74f9a387b8daa557804adf856a4fd5", "sha256:498b4ec7e73426de64c6bf6ec03c5b3f10dedf5db8a9e13fdf195f95a3d065aa",
"sha256:689ecf2eea098afb4bba39c97994c6e9ab65a1cf8e5ca7f897942f8692af9932", "sha256:4c599645af9b5b2241a23e977a82c965a59c24cd94b2600b8d34373c66cad763",
"sha256:68d118d8f4dabfde284237901a24b22e7827695cc74c8184b57828eb10e28090", "sha256:4fa3cdf490f3828b055381e8c7dc7819b3e5f7a442d7af7a8f90e9806a7fff51",
"sha256:74ca4e4221bb68403753a595a9d24899b2a559d42fd573d00d8884e6a54d0ba1", "sha256:55a070206580e161b6bbe1a96abf816c18d4c2c225d49916654714c93d842835",
"sha256:89c9ba175f72a2fd91836c414a09f91459f2e53b648f69300de6f8e0709a2de2", "sha256:666bdba4958b348460a765c48b8c0640e7085540846ed9494f47d8651604b33c",
"sha256:89f486c48a06655a7aec92b593be60f70d4cfed0b205038acc0c3263df3d8b4a", "sha256:69f41295d696c822224334f0994f1f107df7efed72211d45a1118696f1427c84",
"sha256:8e4d4133a2be465aae0826ae8e11319e6411e3119d16b4d6f40079fa89835c43", "sha256:6dfcf7bd6db5d80711cbbd0996b6e7a79cc414ca81457960367df11d2860f92a",
"sha256:93864be3ae1dabfa66607734113cc08ac9f839e2b49632df60ede1f0893864ee", "sha256:71cf73f9907c444ef663ea653dbac24af07c307079572c3ff8f20ad1463af3b7",
"sha256:a62a856d5c6168f07d2c18e725f577bda5d4bbd4bf535d5c7c99d03b335effe1", "sha256:72ec333f089b4fce5a6d740ed0a1963a3994146be195722da0d8e14d4a7e1600",
"sha256:a71f6f231e94f2e543a255aa98bf8db2936f7b132be456c70ccf3c98cd60c160", "sha256:759495c2b8c15cb0d6b539c246896029e4cde42a896c3956f77e311c5f6b0807",
"sha256:abb5d98541fc89c0d94627d82c83bdd464120c3422333e0f9f37a236ca1c44c8", "sha256:7a7c3369fa618eca79f9554ce06c618a5e738e592d61d96aa09b2457ca3ea410",
"sha256:ad2d649197971c52a8c074739b3aae3cf3db99971561a371a54d429c19a49050", "sha256:8b1215facead57cc5325aef4229ef886e85d270b2ba02080fb5809ce9d2b81b4",
"sha256:b36e27adeb36fcf2854f8d9951e5e99fa655b4f03d2d15ba321bae42d65e2535", "sha256:907f7cd4832bb295d0c1573de15cc5aab5988282caf2ee7a2b1276fb6cdf502b",
"sha256:b5f30124b0f5dab69fa56d12b94a50656f030e547bb09ab03936fd8708f04afc", "sha256:93e229519d046491b798f2c12dbbf2f3e237e89589aa5cbb5e1d8c1a978816db",
"sha256:b6450ebf6fbbe826dd4e4837e7cc906a256e1383883ef21a143a5d39c7ce35cc", "sha256:a12049314497d872f6788f811e2b331654db207937f8a2fb34ff3e3cd9897faa",
"sha256:b6d8979e7769cb860dfffd8d1c303501fea4820f592b5e6836cba1b64aa82f10", "sha256:a8dddc52e0e486291be0ad39184da0607fae9cc665fdba1881211de9cfc0b332",
"sha256:c3988595e57c114c2cc93dd21b08f917c3d868bf57fd52bbb20008e3c26f023e", "sha256:adf78ccb2defad5b6ecb2e2e9f2a672719b0a8e2278592a7d77f6c220a042388",
"sha256:c3a4bdb586e6649bd2b7d452b79c09a819bcb848ac408f1f4b00155c91469ffd", "sha256:b13cebf4e397bba14542bcd023338b6ff2c151a3a12aabca89eecbf972cb361a",
"sha256:c3d774f1d522579398ebfb5ad9129cc4a409c35a14f412e1ae20c0a7d42561f0", "sha256:b3648f3c340b6b6aabf9352341478c708cee6f00c5cd5c902311fcf4ce870f3c",
"sha256:c894990d87b0c8eae1f60a747c5180f9abcc525f1c71435cbdcb1f5ee420d675", "sha256:b6a1b685da0b9a8000bb980e02d9d5be202d0cc539af113b661c76c051fca6f1",
"sha256:ca40c72a6c07ebd35a1b85d8cb3069b43587a589fe2ff2d16e33ea53b1ffe40f", "sha256:b777ddc57b2d3366cbc540616034cdc1089ca0a31fefc907028e1dd62a6bf16c",
"sha256:cf0e362917ca2c00627828fce077fe364b7e0f70e795fb98e97c8befe8f96289", "sha256:bb83df8f7840321d34cb5b24c972c617a8c1716c8a36e5050fff56adf5891b8c",
"sha256:ea3dc427b6be0eb0966732e9e30bccec1c8b395aba0484430bc72d811a9e84ea", "sha256:c07ec796a2a5d44bf787f2b623b6e668a389b0cafb78af34cf74554ff3bc532b",
"sha256:f73970f8c4ccb2c32cf350f1b86171af27ed7df79dc0cc529875bc40610b6bbd", "sha256:c40e108072379ff83dd7442159ebc249d12eb8eec15b70614953fecd2c403792",
"sha256:fe5c2fcbe8f130c8913dad56d2513afb809491ad8a17b5c49b3951cfa070d4a3" "sha256:c4863c49602722237e35cbce5aa91af4539cc63a671f59504d2b3f3767d898cf",
"sha256:c56d701f7dc662e1d3d7fe364e66fa1339eafce54a488c2d16ec0ea49dc213c2",
"sha256:c84afd5bef6e407c80ba9f99b6abbe3ea78e8243b0f19897a871a7bcad1f749d",
"sha256:cdd206883e999278d2af656f988dfcc89eb0c175ce6d75e87b713cf1e792c0c4",
"sha256:ce85a204f46c871c8af6fa64b9bbed165456935c1d0bfb2f570a3194f6723ddb",
"sha256:cee3b6ebef5e4a8654ec5f0effeb1a2bb157ad87b0ac856871d25a805c0f2f90",
"sha256:d4cecfb48a6cfbfe2caf0fc280cecea999699e63bc98cb02254bd87b39eff677",
"sha256:db62bed0774778fdf82c609cb9efd0062f2fdcd285be527d01f6be9fd9755888",
"sha256:f51dcb39e910a853749250c0f82aced80bca3f7315e9c4ee14349eb7cab6a3f8",
"sha256:f5808e1dac6b66c109d6205ce2aebf84bb89e1a1493b7e6df38932df5ebfb9cf"
], ],
"markers": "python_version >= '3.7' and python_version < '4'", "markers": "python_version >= '3.7' and python_version < '4'",
"version": "==3.6.11" "version": "==3.6.12"
}, },
"requests": { "requests": {
"hashes": [ "hashes": [
@ -1558,27 +1419,30 @@
}, },
"scikit-learn": { "scikit-learn": {
"hashes": [ "hashes": [
"sha256:1c8fecb7c9984d9ec2ea48898229f98aad681a0873e0935f2b7f724fbce4a047", "sha256:23fb9e74b813cc2528b5167d82ed08950b11106ccf50297161875e45152fb311",
"sha256:2b8db962360c93554cab7bb3c096c4a24695da394dd4b3c3f13409f409b425bc", "sha256:250da993701da88bf475e7c5746abf1285ea0ae47e4d0917cd13afd6600bb162",
"sha256:2f46c6e3ff1054a5ec701646dcfd61d43b8ecac4d416014daed8843cf4c33d4d", "sha256:28b2bd6a1419acd522ff45d282c8ba23dbccb5338802ab0ee12baa4ade0aba4c",
"sha256:3e7d1fc817867a350133f937aaebcafbc06192517cbdf0cf7e5774ad4d1adb9f", "sha256:2ee2c649f2231b68511aabb0dc827edd8936aad682acc6263c34aed11bc95dac",
"sha256:407e9a1cb9e6ba458a539986a9bd25546a757088095b3aab91d465b79a760d37", "sha256:30e27721adc308e8fd9f419f43068e43490005f911edf4476a9e585059fa8a83",
"sha256:567417dbbe6a6278399c3e6daf1654414a5a1a4d818d28f251fa7fc28730a1bf", "sha256:38814f66285318f2e241305cca545eaa9b4126c65aa5dd78c69371f235f78e2b",
"sha256:589d46f28460469f444b898223b13d99db9463e1038dc581ba698111f612264b", "sha256:4d3a19166d4e1cdfcab975c68f471e046ce01e74c42a9a33fa89a14c2fcedf60",
"sha256:5ec3ea40d467966821843210c02117d82b097b54276fdcfb50f4dfb5c60dbe39", "sha256:5699cded6c0685426433c7e5afe0fecad80ec831ec7fa264940e50c796775cc5",
"sha256:6c840f662b5d3377c4ccb8be1fc21bb52cb5d8b8790f8d6bf021739f84e543cf", "sha256:6785b8a3093329bf90ac01801be5525551728ae73edb11baa175df660820add4",
"sha256:76800652fb6d6bf527bce36ecc2cc25738b28fe1a17bd294a218fff8e8bd6d50", "sha256:6d1c1394e38a3319ace620381f6f23cc807d8780e9915c152449a86fc8f1db21",
"sha256:7c22d1305b16f08d57751a4ea36071e2215efb4c09cb79183faa4e8e82a3dbf8", "sha256:701181792a28c82fecae12adb5d15d0ecf57bffab7cf4bdbb52c7b3fd428d540",
"sha256:a682ec0f82b6f30fb07486daed1c8001b6683cc66b51877644dfc532bece6a18", "sha256:748f2bd632d6993e8918d43f1a26c380aeda4e122a88840d4c3a9af99d4239fe",
"sha256:a90ca42fe8242fd6ff56cda2fecc5fca586a88a24ab602d275d2d0dcc0b928fb", "sha256:8e9dd76c7274055d1acf4526b8efb16a3531c26dcda714a0c16da99bf9d41900",
"sha256:b1e706deca9b2ad87ae27dafd5ac4e8eff01b6db492ed5c12cef4735ec5f21ea", "sha256:bef51978a51ec19977700fe7b86aecea49c825884f3811756b74a3b152bb4e35",
"sha256:bbef6ea1c012ff9f3e6f6e9ca006b8772d8383e177b898091e68fbd9b3f840f9", "sha256:cd55c6fbef7608dbce1f22baf289dfcc6eb323247daa3c3542f73d389c724786",
"sha256:c33e16e9a165af6012f5be530ccfbb672e2bc5f9b840238a05eb7f6694304e3f", "sha256:da5a2e95fef9805b1750e4abda4e834bf8835d26fc709a391543b53feee7bd0e",
"sha256:d6f232779023c3b060b80b5c82e5823723bc424dcac1d1a148aa2492c54d245d", "sha256:ee47f68d973cee7009f06edb956f2f5588a0f230f24a2a70175fd0ecf36e2653",
"sha256:f94c0146bad51daef919c402a3da8c1c6162619653e1c00c92baa168fda292f2" "sha256:f4931f2a6c06e02c6c17a05f8ae397e2545965bc7a0a6cb38c8cd7d4fba8624d",
"sha256:f5644663987ee221f5d1f47a593271b966c271c236fe05634e6bdc06041b5a2b",
"sha256:f5d4231af7199531e77da1b78a4cc6b3d960a00b1ec672578ac818aae2b9c35d",
"sha256:fd3ee69d36d42a7dcbb17e355a5653af5fd241a7dfd9133080b3dde8d9e2aafb"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.1.2" "version": "==1.1.3"
}, },
"scipy": { "scipy": {
"hashes": [ "hashes": [
@ -1759,11 +1623,11 @@
"tls" "tls"
], ],
"hashes": [ "hashes": [
"sha256:8d4718d1e48dcc28933f8beb48dc71cfe77a125e37ad1eb7a3d0acc49baf6c99", "sha256:32acbd40a94f5f46e7b42c109bfae2b302250945561783a8b7a059048f2d4d31",
"sha256:e5b60de39f2d1da153fbe1874d885fe3fcbdb21fcc446fa759a53e8fc3513bed" "sha256:86c55f712cc5ab6f6d64e02503352464f0400f66d4f079096d744080afcccbd0"
], ],
"markers": "python_full_version >= '3.7.1'", "markers": "python_full_version >= '3.7.1'",
"version": "==22.8.0" "version": "==22.10.0"
}, },
"txaio": { "txaio": {
"hashes": [ "hashes": [
@ -1778,16 +1642,16 @@
"sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa", "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa",
"sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e" "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"
], ],
"markers": "python_version < '3.10'", "markers": "python_version >= '3.7'",
"version": "==4.4.0" "version": "==4.4.0"
}, },
"tzdata": { "tzdata": {
"hashes": [ "hashes": [
"sha256:323161b22b7802fdc78f20ca5f6073639c64f1a7227c40cd3e19fd1d0ce6650a", "sha256:04a680bdc5b15750c39c12a448885a51134a27ec9af83667663f0b3a1bf3f342",
"sha256:e15b2b3005e2546108af42a0eb4ccab4d9e225e2dfbf4f77aad50c70a4b1f3ab" "sha256:91f11db4503385928c15598c98573e3af07e7229181bee5375bd30f1695ddcae"
], ],
"markers": "python_version >= '3.6'", "markers": "python_version >= '3.6'",
"version": "==2022.5" "version": "==2022.6"
}, },
"tzlocal": { "tzlocal": {
"hashes": [ "hashes": [
@ -1920,65 +1784,79 @@
], ],
"version": "==0.2.5" "version": "==0.2.5"
}, },
"webencodings": {
"hashes": [
"sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
"sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
],
"version": "==0.5.1"
},
"websockets": { "websockets": {
"hashes": [ "hashes": [
"sha256:07cdc0a5b2549bcfbadb585ad8471ebdc7bdf91e32e34ae3889001c1c106a6af", "sha256:00213676a2e46b6ebf6045bc11d0f529d9120baa6f58d122b4021ad92adabd41",
"sha256:210aad7fdd381c52e58777560860c7e6110b6174488ef1d4b681c08b68bf7f8c", "sha256:00c870522cdb69cd625b93f002961ffb0c095394f06ba8c48f17eef7c1541f96",
"sha256:28dd20b938a57c3124028680dc1600c197294da5db4292c76a0b48efb3ed7f76", "sha256:0154f7691e4fe6c2b2bc275b5701e8b158dae92a1ab229e2b940efe11905dff4",
"sha256:2f94fa3ae454a63ea3a19f73b95deeebc9f02ba2d5617ca16f0bbdae375cda47", "sha256:05a7233089f8bd355e8cbe127c2e8ca0b4ea55467861906b80d2ebc7db4d6b72",
"sha256:31564a67c3e4005f27815634343df688b25705cccb22bc1db621c781ddc64c69", "sha256:09a1814bb15eff7069e51fed0826df0bc0702652b5cb8f87697d469d79c23576",
"sha256:347974105bbd4ea068106ec65e8e8ebd86f28c19e529d115d89bd8cc5cda3079", "sha256:0cff816f51fb33c26d6e2b16b5c7d48eaa31dae5488ace6aae468b361f422b63",
"sha256:379e03422178436af4f3abe0aa8f401aa77ae2487843738542a75faf44a31f0c", "sha256:185929b4808b36a79c65b7865783b87b6841e852ef5407a2fb0c03381092fa3b",
"sha256:3eda1cb7e9da1b22588cefff09f0951771d6ee9fa8dbe66f5ae04cc5f26b2b55", "sha256:2fc8709c00704194213d45e455adc106ff9e87658297f72d544220e32029cd3d",
"sha256:51695d3b199cd03098ae5b42833006a0f43dc5418d3102972addc593a783bc02", "sha256:33d69ca7612f0ddff3316b0c7b33ca180d464ecac2d115805c044bf0a3b0d032",
"sha256:54c000abeaff6d8771a4e2cef40900919908ea7b6b6a30eae72752607c6db559", "sha256:389f8dbb5c489e305fb113ca1b6bdcdaa130923f77485db5b189de343a179393",
"sha256:5b936bf552e4f6357f5727579072ff1e1324717902127ffe60c92d29b67b7be3", "sha256:38ea7b82bfcae927eeffc55d2ffa31665dc7fec7b8dc654506b8e5a518eb4d50",
"sha256:6075fd24df23133c1b078e08a9b04a3bc40b31a8def4ee0b9f2c8865acce913e", "sha256:3d3cac3e32b2c8414f4f87c1b2ab686fa6284a980ba283617404377cd448f631",
"sha256:661f641b44ed315556a2fa630239adfd77bd1b11cb0b9d96ed8ad90b0b1e4978", "sha256:40e826de3085721dabc7cf9bfd41682dadc02286d8cf149b3ad05bff89311e4f",
"sha256:6ea6b300a6bdd782e49922d690e11c3669828fe36fc2471408c58b93b5535a98", "sha256:4239b6027e3d66a89446908ff3027d2737afc1a375f8fd3eea630a4842ec9a0c",
"sha256:6ed1d6f791eabfd9808afea1e068f5e59418e55721db8b7f3bfc39dc831c42ae", "sha256:45ec8e75b7dbc9539cbfafa570742fe4f676eb8b0d3694b67dabe2f2ceed8aa6",
"sha256:7934e055fd5cd9dee60f11d16c8d79c4567315824bacb1246d0208a47eca9755", "sha256:47a2964021f2110116cc1125b3e6d87ab5ad16dea161949e7244ec583b905bb4",
"sha256:7ab36e17af592eec5747c68ef2722a74c1a4a70f3772bc661079baf4ae30e40d", "sha256:48c08473563323f9c9debac781ecf66f94ad5a3680a38fe84dee5388cf5acaf6",
"sha256:7f6d96fdb0975044fdd7953b35d003b03f9e2bcf85f2d2cf86285ece53e9f991", "sha256:4c6d2264f485f0b53adf22697ac11e261ce84805c232ed5dbe6b1bcb84b00ff0",
"sha256:83e5ca0d5b743cde3d29fda74ccab37bdd0911f25bd4cdf09ff8b51b7b4f2fa1", "sha256:4f72e5cd0f18f262f5da20efa9e241699e0cf3a766317a17392550c9ad7b37d8",
"sha256:85506b3328a9e083cc0a0fb3ba27e33c8db78341b3eb12eb72e8afd166c36680", "sha256:56029457f219ade1f2fc12a6504ea61e14ee227a815531f9738e41203a429112",
"sha256:8af75085b4bc0b5c40c4a3c0e113fa95e84c60f4ed6786cbb675aeb1ee128247", "sha256:5c1289596042fad2cdceb05e1ebf7aadf9995c928e0da2b7a4e99494953b1b94",
"sha256:8b1359aba0ff810d5830d5ab8e2c4a02bebf98a60aa0124fb29aa78cfdb8031f", "sha256:62e627f6b6d4aed919a2052efc408da7a545c606268d5ab5bfab4432734b82b4",
"sha256:8fbd7d77f8aba46d43245e86dd91a8970eac4fb74c473f8e30e9c07581f852b2", "sha256:74de2b894b47f1d21cbd0b37a5e2b2392ad95d17ae983e64727e18eb281fe7cb",
"sha256:907e8247480f287aa9bbc9391bd6de23c906d48af54c8c421df84655eef66af7", "sha256:7c584f366f46ba667cfa66020344886cf47088e79c9b9d39c84ce9ea98aaa331",
"sha256:93d5ea0b5da8d66d868b32c614d2b52d14304444e39e13a59566d4acb8d6e2e4", "sha256:7d27a7e34c313b3a7f91adcd05134315002aaf8540d7b4f90336beafaea6217c",
"sha256:97bc9d41e69a7521a358f9b8e44871f6cdeb42af31815c17aed36372d4eec667", "sha256:7d3f0b61c45c3fa9a349cf484962c559a8a1d80dae6977276df8fd1fa5e3cb8c",
"sha256:994cdb1942a7a4c2e10098d9162948c9e7b235df755de91ca33f6e0481366fdb", "sha256:82ff5e1cae4e855147fd57a2863376ed7454134c2bf49ec604dfe71e446e2193",
"sha256:a141de3d5a92188234afa61653ed0bbd2dde46ad47b15c3042ffb89548e77094", "sha256:84bc2a7d075f32f6ed98652db3a680a17a4edb21ca7f80fe42e38753a58ee02b",
"sha256:a1e15b230c3613e8ea82c9fc6941b2093e8eb939dd794c02754d33980ba81e36", "sha256:884be66c76a444c59f801ac13f40c76f176f1bfa815ef5b8ed44321e74f1600b",
"sha256:aad5e300ab32036eb3fdc350ad30877210e2f51bceaca83fb7fef4d2b6c72b79", "sha256:8a5cc00546e0a701da4639aa0bbcb0ae2bb678c87f46da01ac2d789e1f2d2038",
"sha256:b529fdfa881b69fe563dbd98acce84f3e5a67df13de415e143ef053ff006d500", "sha256:8dc96f64ae43dde92530775e9cb169979f414dcf5cff670455d81a6823b42089",
"sha256:b9c77f0d1436ea4b4dc089ed8335fa141e6a251a92f75f675056dac4ab47a71e", "sha256:8f38706e0b15d3c20ef6259fd4bc1700cd133b06c3c1bb108ffe3f8947be15fa",
"sha256:bb621ec2dbbbe8df78a27dbd9dd7919f9b7d32a73fafcb4d9252fc4637343582", "sha256:90fcf8929836d4a0e964d799a58823547df5a5e9afa83081761630553be731f9",
"sha256:c7250848ce69559756ad0086a37b82c986cd33c2d344ab87fea596c5ac6d9442", "sha256:931c039af54fc195fe6ad536fde4b0de04da9d5916e78e55405436348cfb0e56",
"sha256:c8d1d14aa0f600b5be363077b621b1b4d1eb3fbf90af83f9281cda668e6ff7fd", "sha256:932af322458da7e4e35df32f050389e13d3d96b09d274b22a7aa1808f292fee4",
"sha256:d1655a6fc7aecd333b079d00fb3c8132d18988e47f19740c69303bf02e9883c6", "sha256:942de28af58f352a6f588bc72490ae0f4ccd6dfc2bd3de5945b882a078e4e179",
"sha256:d6353ba89cfc657a3f5beabb3b69be226adbb5c6c7a66398e17809b0ce3c4731", "sha256:9bc42e8402dc5e9905fb8b9649f57efcb2056693b7e88faa8fb029256ba9c68c",
"sha256:da4377904a3379f0c1b75a965fff23b28315bcd516d27f99a803720dfebd94d4", "sha256:a7a240d7a74bf8d5cb3bfe6be7f21697a28ec4b1a437607bae08ac7acf5b4882",
"sha256:e49ea4c1a9543d2bd8a747ff24411509c29e4bdcde05b5b0895e2120cb1a761d", "sha256:a9f9a735deaf9a0cadc2d8c50d1a5bcdbae8b6e539c6e08237bc4082d7c13f28",
"sha256:e4e08305bfd76ba8edab08dcc6496f40674f44eb9d5e23153efa0a35750337e8", "sha256:ae5e95cfb53ab1da62185e23b3130e11d64431179debac6dc3c6acf08760e9b1",
"sha256:e6fa05a680e35d0fcc1470cb070b10e6fe247af54768f488ed93542e71339d6f", "sha256:b029fb2032ae4724d8ae8d4f6b363f2cc39e4c7b12454df8df7f0f563ed3e61a",
"sha256:e7e6f2d6fd48422071cc8a6f8542016f350b79cc782752de531577d35e9bd677", "sha256:b0d15c968ea7a65211e084f523151dbf8ae44634de03c801b8bd070b74e85033",
"sha256:e904c0381c014b914136c492c8fa711ca4cced4e9b3d110e5e7d436d0fc289e8", "sha256:b343f521b047493dc4022dd338fc6db9d9282658862756b4f6fd0e996c1380e1",
"sha256:ec2b0ab7edc8cd4b0eb428b38ed89079bdc20c6bdb5f889d353011038caac2f9", "sha256:b627c266f295de9dea86bd1112ed3d5fafb69a348af30a2422e16590a8ecba13",
"sha256:ef5ce841e102278c1c2e98f043db99d6755b1c58bde475516aef3a008ed7f28e", "sha256:b9968694c5f467bf67ef97ae7ad4d56d14be2751000c1207d31bf3bb8860bae8",
"sha256:f351c7d7d92f67c0609329ab2735eee0426a03022771b00102816a72715bb00b", "sha256:ba089c499e1f4155d2a3c2a05d2878a3428cf321c848f2b5a45ce55f0d7d310c",
"sha256:fab7c640815812ed5f10fbee7abbf58788d602046b7bb3af9b1ac753a6d5e916", "sha256:bbccd847aa0c3a69b5f691a84d2341a4f8a629c6922558f2a70611305f902d74",
"sha256:fc06cc8073c8e87072138ba1e431300e2d408f054b27047d047b549455066ff4" "sha256:bc0b82d728fe21a0d03e65f81980abbbcb13b5387f733a1a870672c5be26edab",
"sha256:c57e4c1349fbe0e446c9fa7b19ed2f8a4417233b6984277cce392819123142d3",
"sha256:c94ae4faf2d09f7c81847c63843f84fe47bf6253c9d60b20f25edfd30fb12588",
"sha256:c9b27d6c1c6cd53dc93614967e9ce00ae7f864a2d9f99fe5ed86706e1ecbf485",
"sha256:d210abe51b5da0ffdbf7b43eed0cfdff8a55a1ab17abbec4301c9ff077dd0342",
"sha256:d58804e996d7d2307173d56c297cf7bc132c52df27a3efaac5e8d43e36c21c48",
"sha256:d6a4162139374a49eb18ef5b2f4da1dd95c994588f5033d64e0bbfda4b6b6fcf",
"sha256:da39dd03d130162deb63da51f6e66ed73032ae62e74aaccc4236e30edccddbb0",
"sha256:db3c336f9eda2532ec0fd8ea49fef7a8df8f6c804cdf4f39e5c5c0d4a4ad9a7a",
"sha256:dd500e0a5e11969cdd3320935ca2ff1e936f2358f9c2e61f100a1660933320ea",
"sha256:dd9becd5fe29773d140d68d607d66a38f60e31b86df75332703757ee645b6faf",
"sha256:e0cb5cc6ece6ffa75baccfd5c02cffe776f3f5c8bf486811f9d3ea3453676ce8",
"sha256:e23173580d740bf8822fd0379e4bf30aa1d5a92a4f252d34e893070c081050df",
"sha256:e3a686ecb4aa0d64ae60c9c9f1a7d5d46cab9bfb5d91a2d303d00e2cd4c4c5cc",
"sha256:e789376b52c295c4946403bd0efecf27ab98f05319df4583d3c48e43c7342c2f",
"sha256:edc344de4dac1d89300a053ac973299e82d3db56330f3494905643bb68801269",
"sha256:eef610b23933c54d5d921c92578ae5f89813438fded840c2e9809d378dc765d3",
"sha256:f2c38d588887a609191d30e902df2a32711f708abfd85d318ca9b367258cfd0c",
"sha256:f55b5905705725af31ccef50e55391621532cd64fbf0bc6f4bac935f0fccec46",
"sha256:f5fc088b7a32f244c519a048c170f14cf2251b849ef0e20cbbb0fdf0fdaf556f",
"sha256:fe10ddc59b304cb19a1bdf5bd0a7719cbbc9fbdd57ac80ed436b709fcf889106",
"sha256:ff64a1d38d156d429404aaa84b27305e957fd10c30e5880d1765c9480bea490f"
], ],
"version": "==10.3" "version": "==10.4"
}, },
"whitenoise": { "whitenoise": {
"hashes": [ "hashes": [
@ -2137,11 +2015,11 @@
}, },
"babel": { "babel": {
"hashes": [ "hashes": [
"sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51", "sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe",
"sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb" "sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6"
], ],
"markers": "python_version >= '3.6'", "markers": "python_version >= '3.6'",
"version": "==2.10.3" "version": "==2.11.0"
}, },
"black": { "black": {
"hashes": [ "hashes": [
@ -2204,11 +2082,11 @@
}, },
"colorama": { "colorama": {
"hashes": [ "hashes": [
"sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da", "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44",
"sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4" "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'",
"version": "==0.4.5" "version": "==0.4.6"
}, },
"coverage": { "coverage": {
"extras": [ "extras": [
@ -2298,6 +2176,14 @@
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==0.17.1" "version": "==0.17.1"
}, },
"exceptiongroup": {
"hashes": [
"sha256:2ac84b496be68464a2da60da518af3785fff8b7ec0d090a581604bc870bdee41",
"sha256:affbabf13fb6e98988c38d9c5650e701569fe3c1de3233cfb61c5f33774690ad"
],
"markers": "python_version < '3.11'",
"version": "==1.0.0"
},
"execnet": { "execnet": {
"hashes": [ "hashes": [
"sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5", "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5",
@ -2332,11 +2218,11 @@
}, },
"identify": { "identify": {
"hashes": [ "hashes": [
"sha256:6c32dbd747aa4ceee1df33f25fed0b0f6e0d65721b15bd151307ff7056d50245", "sha256:48b7925fe122720088aeb7a6c34f17b27e706b72c61070f27fe3789094233440",
"sha256:b276db7ec52d7e89f5bc4653380e33054ddc803d25875952ad90b0f012cbcdaa" "sha256:7a214a10313b9489a0d61467db2856ae8d0b8306fc923e03a9effa53d8aedc58"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==2.5.6" "version": "==2.5.8"
}, },
"idna": { "idna": {
"hashes": [ "hashes": [
@ -2354,14 +2240,6 @@
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.4.1" "version": "==1.4.1"
}, },
"importlib-metadata": {
"hashes": [
"sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab",
"sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"
],
"markers": "python_version < '3.10'",
"version": "==5.0.0"
},
"iniconfig": { "iniconfig": {
"hashes": [ "hashes": [
"sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3",
@ -2550,11 +2428,11 @@
}, },
"pytest": { "pytest": {
"hashes": [ "hashes": [
"sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7", "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71",
"sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39" "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"
], ],
"index": "pypi", "index": "pypi",
"version": "==7.1.3" "version": "==7.2.0"
}, },
"pytest-cov": { "pytest-cov": {
"hashes": [ "hashes": [
@ -2614,10 +2492,10 @@
}, },
"pytz": { "pytz": {
"hashes": [ "hashes": [
"sha256:335ab46900b1465e714b4fda4963d87363264eb662aab5e65da039c25f1f5b22", "sha256:222439474e9c98fced559f1709d89e6c9cbf8d79c794ff3eb9f8800064291427",
"sha256:c4d88f472f54d615e9cd582a5004d1e5f624854a6a27a6211591c251f22a6914" "sha256:e89512406b793ca39f5971bc999cc538ce125c0e51c27941bef4568b460095e2"
], ],
"version": "==2022.5" "version": "==2022.6"
}, },
"pyyaml": { "pyyaml": {
"hashes": [ "hashes": [
@ -2769,11 +2647,11 @@
}, },
"termcolor": { "termcolor": {
"hashes": [ "hashes": [
"sha256:6b2cf769e93364a2676e1de56a7c0cff2cf5bd07f37e9cc80b0dd6320ebfe388", "sha256:91dd04fdf661b89d7169cefd35f609b19ca931eb033687eaa647cef1ff177c49",
"sha256:7e597f9de8e001a3208c4132938597413b9da45382b6f1d150cff8d062b7aaa3" "sha256:b80df54667ce4f48c03fe35df194f052dc27a541ebbf2544e4d6b47b5d6949c4"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==2.0.1" "version": "==2.1.0"
}, },
"toml": { "toml": {
"hashes": [ "hashes": [
@ -2788,7 +2666,7 @@
"sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
"sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version < '3.11'",
"version": "==2.0.1" "version": "==2.0.1"
}, },
"tornado": { "tornado": {
@ -2810,18 +2688,18 @@
}, },
"tox": { "tox": {
"hashes": [ "hashes": [
"sha256:44f3c347c68c2c68799d7d44f1808f9d396fc8a1a500cbc624253375c7ae107e", "sha256:89e4bc6df3854e9fc5582462e328dd3660d7d865ba625ae5881bbc63836a6324",
"sha256:bf037662d7c740d15c9924ba23bb3e587df20598697bb985ac2b49bdc2d847f6" "sha256:d2c945f02a03d4501374a3d5430877380deb69b218b1df9b7f1d2f2a10befaf9"
], ],
"index": "pypi", "index": "pypi",
"version": "==3.26.0" "version": "==3.27.0"
}, },
"typing-extensions": { "typing-extensions": {
"hashes": [ "hashes": [
"sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa", "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa",
"sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e" "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"
], ],
"markers": "python_version < '3.10'", "markers": "python_version >= '3.7'",
"version": "==4.4.0" "version": "==4.4.0"
}, },
"urllib3": { "urllib3": {
@ -2834,19 +2712,11 @@
}, },
"virtualenv": { "virtualenv": {
"hashes": [ "hashes": [
"sha256:227ea1b9994fdc5ea31977ba3383ef296d7472ea85be9d6732e42a91c04e80da", "sha256:186ca84254abcbde98180fd17092f9628c5fe742273c02724972a1d8a2035108",
"sha256:d07dfc5df5e4e0dbc92862350ad87a36ed505b978f6c39609dc489eadd5b0d27" "sha256:530b850b523c6449406dfba859d6345e48ef19b8439606c5d74d7d3c9e14d76e"
], ],
"markers": "python_version >= '3.6'", "markers": "python_version >= '3.6'",
"version": "==20.16.5" "version": "==20.16.6"
},
"zipp": {
"hashes": [
"sha256:4fcb6f278987a6605757302a6e40e896257570d11c51628968ccb2a47e80c6c1",
"sha256:7a7262fd930bd3e36c50b9a64897aec3fafff3dfdeec9623ae22b40e93f99bb8"
],
"markers": "python_version < '3.9'",
"version": "==3.10.0"
} }
} }
} }

View File

@ -23,6 +23,8 @@ fi
# Parse what we can from Pipfile.lock # Parse what we can from Pipfile.lock
pikepdf_version=$(jq ".default.pikepdf.version" Pipfile.lock | sed 's/=//g' | sed 's/"//g') pikepdf_version=$(jq ".default.pikepdf.version" Pipfile.lock | sed 's/=//g' | sed 's/"//g')
psycopg2_version=$(jq ".default.psycopg2.version" Pipfile.lock | sed 's/=//g' | sed 's/"//g') psycopg2_version=$(jq ".default.psycopg2.version" Pipfile.lock | sed 's/=//g' | sed 's/"//g')
pillow_version=$(jq ".default.pillow.version" Pipfile.lock | sed 's/=//g' | sed 's/"//g')
lxml_version=$(jq ".default.lxml.version" Pipfile.lock | sed 's/=//g' | sed 's/"//g')
# Read this from the other config file # Read this from the other config file
qpdf_version=$(jq ".qpdf.version" .build-config.json | sed 's/"//g') qpdf_version=$(jq ".qpdf.version" .build-config.json | sed 's/"//g')
jbig2enc_version=$(jq ".jbig2enc.version" .build-config.json | sed 's/"//g') jbig2enc_version=$(jq ".jbig2enc.version" .build-config.json | sed 's/"//g')
@ -40,4 +42,6 @@ docker build --file "$1" \
--build-arg JBIG2ENC_VERSION="${jbig2enc_version}" \ --build-arg JBIG2ENC_VERSION="${jbig2enc_version}" \
--build-arg QPDF_VERSION="${qpdf_version}" \ --build-arg QPDF_VERSION="${qpdf_version}" \
--build-arg PIKEPDF_VERSION="${pikepdf_version}" \ --build-arg PIKEPDF_VERSION="${pikepdf_version}" \
--build-arg PILLOW_VERSION="${pillow_version}" \
--build-arg LXML_VERSION="${lxml_version}" \
--build-arg PSYCOPG2_VERSION="${psycopg2_version}" "${@:2}" . --build-arg PSYCOPG2_VERSION="${psycopg2_version}" "${@:2}" .

View File

@ -1,14 +0,0 @@
# This Dockerfile compiles the frontend
# Inputs: None
FROM node:16-bullseye-slim AS compile-frontend
COPY ./src /src/src
COPY ./src-ui /src/src-ui
WORKDIR /src/src-ui
RUN set -eux \
&& npm update npm -g \
&& npm ci --omit=optional
RUN set -eux \
&& ./node_modules/.bin/ng build --configuration production

View File

@ -18,6 +18,10 @@ LABEL org.opencontainers.image.description="A intermediate image with pikepdf wh
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
ARG PIKEPDF_VERSION ARG PIKEPDF_VERSION
# These are not used, but will still bust the cache if one changes
# Otherwise, the main image will try to build thing (and fail)
ARG PILLOW_VERSION
ARG LXML_VERSION
ARG BUILD_PACKAGES="\ ARG BUILD_PACKAGES="\
build-essential \ build-essential \

View File

@ -258,12 +258,18 @@ Paperless provides the following placeholders within filenames:
* ``{tag_list}``: A comma separated list of all tags assigned to the document. * ``{tag_list}``: A comma separated list of all tags assigned to the document.
* ``{title}``: The title of the document. * ``{title}``: The title of the document.
* ``{created}``: The full date (ISO format) the document was created. * ``{created}``: The full date (ISO format) the document was created.
* ``{created_year}``: Year created only. * ``{created_year}``: Year created only, formatted as the year with century.
* ``{created_year_short}``: Year created only, formatted as the year without century, zero padded.
* ``{created_month}``: Month created only (number 01-12). * ``{created_month}``: Month created only (number 01-12).
* ``{created_month_name}``: Month created name, as per locale
* ``{created_month_name_short}``: Month created abbreviated name, as per locale
* ``{created_day}``: Day created only (number 01-31). * ``{created_day}``: Day created only (number 01-31).
* ``{added}``: The full date (ISO format) the document was added to paperless. * ``{added}``: The full date (ISO format) the document was added to paperless.
* ``{added_year}``: Year added only. * ``{added_year}``: Year added only.
* ``{added_year_short}``: Year added only, formatted as the year without century, zero padded.
* ``{added_month}``: Month added only (number 01-12). * ``{added_month}``: Month added only (number 01-12).
* ``{added_month_name}``: Month added name, as per locale
* ``{added_month_name_short}``: Month added abbreviated name, as per locale
* ``{added_day}``: Day added only (number 01-31). * ``{added_day}``: Day added only (number 01-31).

View File

@ -464,7 +464,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.ts</context>
<context context-type="linenumber">65</context> <context context-type="linenumber">88</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context> <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
@ -727,14 +727,14 @@
<source>Confirmation</source> <source>Confirmation</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/confirm-dialog/confirm-dialog.component.ts</context> <context context-type="sourcefile">src/app/components/common/confirm-dialog/confirm-dialog.component.ts</context>
<context context-type="linenumber">17</context> <context context-type="linenumber">20</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="9178182467454450952" datatype="html"> <trans-unit id="9178182467454450952" datatype="html">
<source>Confirm</source> <source>Confirm</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/confirm-dialog/confirm-dialog.component.ts</context> <context context-type="sourcefile">src/app/components/common/confirm-dialog/confirm-dialog.component.ts</context>
<context context-type="linenumber">29</context> <context context-type="linenumber">32</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@ -757,53 +757,53 @@
<source>After</source> <source>After</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/date-dropdown/date-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/date-dropdown/date-dropdown.component.html</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">21</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8700121026680200191" datatype="html"> <trans-unit id="8700121026680200191" datatype="html">
<source>Clear</source> <source>Clear</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/date-dropdown/date-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/date-dropdown/date-dropdown.component.html</context>
<context context-type="linenumber">18</context> <context context-type="linenumber">26</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/date-dropdown/date-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/date-dropdown/date-dropdown.component.html</context>
<context context-type="linenumber">41</context> <context context-type="linenumber">49</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1218334388194408974" datatype="html"> <trans-unit id="1218334388194408974" datatype="html">
<source>Before</source> <source>Before</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/date-dropdown/date-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/date-dropdown/date-dropdown.component.html</context>
<context context-type="linenumber">36</context> <context context-type="linenumber">44</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4873149362496451858" datatype="html"> <trans-unit id="4873149362496451858" datatype="html">
<source>Last 7 days</source> <source>Last 7 days</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/date-dropdown/date-dropdown.component.ts</context> <context context-type="sourcefile">src/app/components/common/date-dropdown/date-dropdown.component.ts</context>
<context context-type="linenumber">38</context> <context context-type="linenumber">43</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4463380307954693363" datatype="html"> <trans-unit id="4463380307954693363" datatype="html">
<source>Last month</source> <source>Last month</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/date-dropdown/date-dropdown.component.ts</context> <context context-type="sourcefile">src/app/components/common/date-dropdown/date-dropdown.component.ts</context>
<context context-type="linenumber">39</context> <context context-type="linenumber">47</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8697368973702409683" datatype="html"> <trans-unit id="8697368973702409683" datatype="html">
<source>Last 3 months</source> <source>Last 3 months</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/date-dropdown/date-dropdown.component.ts</context> <context context-type="sourcefile">src/app/components/common/date-dropdown/date-dropdown.component.ts</context>
<context context-type="linenumber">40</context> <context context-type="linenumber">51</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3566342898065860218" datatype="html"> <trans-unit id="3566342898065860218" datatype="html">
<source>Last year</source> <source>Last year</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/date-dropdown/date-dropdown.component.ts</context> <context context-type="sourcefile">src/app/components/common/date-dropdown/date-dropdown.component.ts</context>
<context context-type="linenumber">41</context> <context context-type="linenumber">55</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8953033926734869941" datatype="html"> <trans-unit id="8953033926734869941" datatype="html">
@ -1240,7 +1240,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">88</context> <context context-type="linenumber">93</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/tasks/tasks.component.html</context> <context context-type="sourcefile">src/app/components/manage/tasks/tasks.component.html</context>
@ -1284,7 +1284,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">152</context> <context context-type="linenumber">157</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
@ -1311,11 +1311,11 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">134</context> <context context-type="linenumber">139</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">131</context> <context context-type="linenumber">153</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/services/rest/document.service.ts</context> <context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
@ -1609,6 +1609,10 @@
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">43</context> <context context-type="linenumber">43</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/guards/dirty-saved-view.guard.ts</context>
<context context-type="linenumber">32</context>
</context-group>
</trans-unit> </trans-unit>
<trans-unit id="4452427314943113135" datatype="html"> <trans-unit id="4452427314943113135" datatype="html">
<source>Previous</source> <source>Previous</source>
@ -1657,7 +1661,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">128</context> <context context-type="linenumber">133</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
@ -1680,7 +1684,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">140</context> <context context-type="linenumber">145</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
@ -1703,7 +1707,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">146</context> <context context-type="linenumber">151</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
@ -2235,7 +2239,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">173</context> <context context-type="linenumber">178</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2784168796433474565" datatype="html"> <trans-unit id="2784168796433474565" datatype="html">
@ -2246,7 +2250,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">178</context> <context context-type="linenumber">183</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="7585826646011739428" datatype="html"> <trans-unit id="7585826646011739428" datatype="html">
@ -2307,7 +2311,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">182</context> <context context-type="linenumber">187</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="157572966557284263" datatype="html"> <trans-unit id="157572966557284263" datatype="html">
@ -2318,7 +2322,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">187</context> <context context-type="linenumber">192</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3727324658595204357" datatype="html"> <trans-unit id="3727324658595204357" datatype="html">
@ -2421,60 +2425,60 @@
<source>Views</source> <source>Views</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">63</context> <context context-type="linenumber">64</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1233494216161906927" datatype="html"> <trans-unit id="1233494216161906927" datatype="html">
<source>Save &quot;<x id="INTERPOLATION" equiv-text="{{list.activeSavedViewTitle}}"/>&quot;</source> <source>Save &quot;<x id="INTERPOLATION" equiv-text="{{list.activeSavedViewTitle}}"/>&quot;</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">70</context> <context context-type="linenumber">75</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2276119452079372898" datatype="html"> <trans-unit id="2276119452079372898" datatype="html">
<source>Save as...</source> <source>Save as...</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">71</context> <context context-type="linenumber">76</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8786996283897742947" datatype="html"> <trans-unit id="8786996283897742947" datatype="html">
<source>{VAR_PLURAL, plural, =1 {Selected <x id="INTERPOLATION"/> of one document} other {Selected <x id="INTERPOLATION"/> of <x id="INTERPOLATION_1"/> documents}}</source> <source>{VAR_PLURAL, plural, =1 {Selected <x id="INTERPOLATION"/> of one document} other {Selected <x id="INTERPOLATION"/> of <x id="INTERPOLATION_1"/> documents}}</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">90</context> <context context-type="linenumber">95</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6600548268163632449" datatype="html"> <trans-unit id="6600548268163632449" datatype="html">
<source>{VAR_PLURAL, plural, =1 {One document} other {<x id="INTERPOLATION"/> documents}}</source> <source>{VAR_PLURAL, plural, =1 {One document} other {<x id="INTERPOLATION"/> documents}}</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">92</context> <context context-type="linenumber">97</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2243770355958919528" datatype="html"> <trans-unit id="2243770355958919528" datatype="html">
<source>(filtered)</source> <source>(filtered)</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">92</context> <context context-type="linenumber">97</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1559883523769732271" datatype="html"> <trans-unit id="1559883523769732271" datatype="html">
<source>Error while loading documents</source> <source>Error while loading documents</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">105</context> <context context-type="linenumber">110</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="7517688192215738656" datatype="html"> <trans-unit id="7517688192215738656" datatype="html">
<source>ASN</source> <source>ASN</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">122</context> <context context-type="linenumber">127</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">136</context> <context context-type="linenumber">158</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/services/rest/document.service.ts</context> <context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
@ -2485,11 +2489,11 @@
<source>Added</source> <source>Added</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">158</context> <context context-type="linenumber">163</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
<context context-type="linenumber">61</context> <context context-type="linenumber">60</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/services/rest/document.service.ts</context> <context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
@ -2500,140 +2504,140 @@
<source>Edit document</source> <source>Edit document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">177</context> <context context-type="linenumber">182</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2155249406916744630" datatype="html"> <trans-unit id="2155249406916744630" datatype="html">
<source>View &quot;<x id="PH" equiv-text="this.list.activeSavedViewTitle"/>&quot; saved successfully.</source> <source>View &quot;<x id="PH" equiv-text="this.list.activeSavedViewTitle"/>&quot; saved successfully.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.ts</context>
<context context-type="linenumber">170</context> <context context-type="linenumber">196</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6837554170707123455" datatype="html"> <trans-unit id="6837554170707123455" datatype="html">
<source>View &quot;<x id="PH" equiv-text="savedView.name"/>&quot; created successfully.</source> <source>View &quot;<x id="PH" equiv-text="savedView.name"/>&quot; created successfully.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.ts</context>
<context context-type="linenumber">210</context> <context context-type="linenumber">237</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6849725902312323996" datatype="html"> <trans-unit id="6849725902312323996" datatype="html">
<source>Reset filters</source> <source>Reset filters</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
<context context-type="linenumber">71</context> <context context-type="linenumber">73</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="5195932016807797291" datatype="html"> <trans-unit id="5195932016807797291" datatype="html">
<source>Correspondent: <x id="PH" equiv-text="this.correspondents.find((c) =&gt; c.id == +rule.value)?.name"/></source> <source>Correspondent: <x id="PH" equiv-text="this.correspondents.find((c) =&gt; c.id == +rule.value)?.name"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">72,74</context> <context context-type="linenumber">94,96</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8170755470576301659" datatype="html"> <trans-unit id="8170755470576301659" datatype="html">
<source>Without correspondent</source> <source>Without correspondent</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">76</context> <context context-type="linenumber">98</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8705701325879965907" datatype="html"> <trans-unit id="8705701325879965907" datatype="html">
<source>Type: <x id="PH" equiv-text="this.documentTypes.find((dt) =&gt; dt.id == +rule.value)?.name"/></source> <source>Type: <x id="PH" equiv-text="this.documentTypes.find((dt) =&gt; dt.id == +rule.value)?.name"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">81,83</context> <context context-type="linenumber">103,105</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4362173610367509215" datatype="html"> <trans-unit id="4362173610367509215" datatype="html">
<source>Without document type</source> <source>Without document type</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">85</context> <context context-type="linenumber">107</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8180755793012580465" datatype="html"> <trans-unit id="8180755793012580465" datatype="html">
<source>Tag: <x id="PH" equiv-text="this.tags.find((t) =&gt; t.id == +rule.value)?.name"/></source> <source>Tag: <x id="PH" equiv-text="this.tags.find((t) =&gt; t.id == +rule.value)?.name"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">89,91</context> <context context-type="linenumber">111,113</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6494566478302448576" datatype="html"> <trans-unit id="6494566478302448576" datatype="html">
<source>Without any tag</source> <source>Without any tag</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">95</context> <context context-type="linenumber">117</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6523384805359286307" datatype="html"> <trans-unit id="6523384805359286307" datatype="html">
<source>Title: <x id="PH" equiv-text="rule.value"/></source> <source>Title: <x id="PH" equiv-text="rule.value"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">99</context> <context context-type="linenumber">121</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1872523635812236432" datatype="html"> <trans-unit id="1872523635812236432" datatype="html">
<source>ASN: <x id="PH" equiv-text="rule.value"/></source> <source>ASN: <x id="PH" equiv-text="rule.value"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">102</context> <context context-type="linenumber">124</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3100631071441658964" datatype="html"> <trans-unit id="3100631071441658964" datatype="html">
<source>Title &amp; content</source> <source>Title &amp; content</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">134</context> <context context-type="linenumber">156</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1010505078885609376" datatype="html"> <trans-unit id="1010505078885609376" datatype="html">
<source>Advanced search</source> <source>Advanced search</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">139</context> <context context-type="linenumber">161</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2649431021108393503" datatype="html"> <trans-unit id="2649431021108393503" datatype="html">
<source>More like</source> <source>More like</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">145</context> <context context-type="linenumber">167</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3697582909018473071" datatype="html"> <trans-unit id="3697582909018473071" datatype="html">
<source>equals</source> <source>equals</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">164</context> <context context-type="linenumber">186</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="5325481293405718739" datatype="html"> <trans-unit id="5325481293405718739" datatype="html">
<source>is empty</source> <source>is empty</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">168</context> <context context-type="linenumber">190</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6166785695326182482" datatype="html"> <trans-unit id="6166785695326182482" datatype="html">
<source>is not empty</source> <source>is not empty</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">172</context> <context context-type="linenumber">194</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4686622206659266699" datatype="html"> <trans-unit id="4686622206659266699" datatype="html">
<source>greater than</source> <source>greater than</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">176</context> <context context-type="linenumber">198</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8014012170270529279" datatype="html"> <trans-unit id="8014012170270529279" datatype="html">
<source>less than</source> <source>less than</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">180</context> <context context-type="linenumber">202</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="7210076240260527720" datatype="html"> <trans-unit id="7210076240260527720" datatype="html">
@ -3473,6 +3477,10 @@
<context context-type="sourcefile">src/app/guards/dirty-form.guard.ts</context> <context context-type="sourcefile">src/app/guards/dirty-form.guard.ts</context>
<context context-type="linenumber">18</context> <context context-type="linenumber">18</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/guards/dirty-saved-view.guard.ts</context>
<context context-type="linenumber">24</context>
</context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/services/open-documents.service.ts</context> <context context-type="sourcefile">src/app/services/open-documents.service.ts</context>
<context context-type="linenumber">116</context> <context context-type="linenumber">116</context>
@ -3507,6 +3515,27 @@
<context context-type="linenumber">22</context> <context context-type="linenumber">22</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1649285023712919370" datatype="html">
<source>You have unsaved changes to the saved view</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/guards/dirty-saved-view.guard.ts</context>
<context context-type="linenumber">26</context>
</context-group>
</trans-unit>
<trans-unit id="7282050913165342352" datatype="html">
<source>Are you sure you want to close this saved view?</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/guards/dirty-saved-view.guard.ts</context>
<context context-type="linenumber">30</context>
</context-group>
</trans-unit>
<trans-unit id="856284624775342512" datatype="html">
<source>Save and close</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/guards/dirty-saved-view.guard.ts</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="7536524521722799066" datatype="html"> <trans-unit id="7536524521722799066" datatype="html">
<source>(no title)</source> <source>(no title)</source>
<context-group purpose="location"> <context-group purpose="location">

626
src-ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,14 +13,14 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/common": "~14.2.4", "@angular/common": "~14.2.8",
"@angular/compiler": "~14.2.4", "@angular/compiler": "~14.2.8",
"@angular/core": "~14.2.4", "@angular/core": "~14.2.8",
"@angular/forms": "~14.2.4", "@angular/forms": "~14.2.8",
"@angular/localize": "~14.2.4", "@angular/localize": "~14.2.8",
"@angular/platform-browser": "~14.2.4", "@angular/platform-browser": "~14.2.8",
"@angular/platform-browser-dynamic": "~14.2.4", "@angular/platform-browser-dynamic": "~14.2.8",
"@angular/router": "~14.2.4", "@angular/router": "~14.2.8",
"@ng-bootstrap/ng-bootstrap": "^13.0.0", "@ng-bootstrap/ng-bootstrap": "^13.0.0",
"@ng-select/ng-select": "^9.0.2", "@ng-select/ng-select": "^9.0.2",
"@ngneat/dirty-check-forms": "^3.0.2", "@ngneat/dirty-check-forms": "^3.0.2",
@ -31,7 +31,7 @@
"ngx-color": "^8.0.3", "ngx-color": "^8.0.3",
"ngx-cookie-service": "^14.0.1", "ngx-cookie-service": "^14.0.1",
"ngx-file-drop": "^14.0.1", "ngx-file-drop": "^14.0.1",
"ngx-ui-tour-ng-bootstrap": "^11.0.0", "ngx-ui-tour-ng-bootstrap": "^11.1.0",
"rxjs": "~7.5.7", "rxjs": "~7.5.7",
"tslib": "^2.3.1", "tslib": "^2.3.1",
"uuid": "^9.0.0", "uuid": "^9.0.0",
@ -39,15 +39,15 @@
}, },
"devDependencies": { "devDependencies": {
"@angular-builders/jest": "14.0.1", "@angular-builders/jest": "14.0.1",
"@angular-devkit/build-angular": "~14.2.4", "@angular-devkit/build-angular": "~14.2.7",
"@angular/cli": "~14.2.4", "@angular/cli": "~14.2.7",
"@angular/compiler-cli": "~14.2.4", "@angular/compiler-cli": "~14.2.8",
"@types/jest": "28.1.6", "@types/jest": "28.1.6",
"@types/node": "^18.7.23", "@types/node": "^18.7.23",
"codelyzer": "^6.0.2", "codelyzer": "^6.0.2",
"concurrently": "7.4.0", "concurrently": "7.4.0",
"jest": "28.1.3", "jest": "28.1.3",
"jest-environment-jsdom": "^29.1.2", "jest-environment-jsdom": "^29.2.2",
"jest-preset-angular": "^12.2.2", "jest-preset-angular": "^12.2.2",
"ts-node": "~10.9.1", "ts-node": "~10.9.1",
"tslint": "~6.1.3", "tslint": "~6.1.3",

View File

@ -15,6 +15,7 @@ import { DirtyFormGuard } from './guards/dirty-form.guard'
import { StoragePathListComponent } from './components/manage/storage-path-list/storage-path-list.component' import { StoragePathListComponent } from './components/manage/storage-path-list/storage-path-list.component'
import { TasksComponent } from './components/manage/tasks/tasks.component' import { TasksComponent } from './components/manage/tasks/tasks.component'
import { DirtyDocGuard } from './guards/dirty-doc.guard' import { DirtyDocGuard } from './guards/dirty-doc.guard'
import { DirtySavedViewGuard } from './guards/dirty-saved-view.guard'
const routes: Routes = [ const routes: Routes = [
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' }, { path: '', redirectTo: 'dashboard', pathMatch: 'full' },
@ -24,8 +25,16 @@ const routes: Routes = [
canDeactivate: [DirtyDocGuard], canDeactivate: [DirtyDocGuard],
children: [ children: [
{ path: 'dashboard', component: DashboardComponent }, { path: 'dashboard', component: DashboardComponent },
{ path: 'documents', component: DocumentListComponent }, {
{ path: 'view/:id', component: DocumentListComponent }, path: 'documents',
component: DocumentListComponent,
canDeactivate: [DirtySavedViewGuard],
},
{
path: 'view/:id',
component: DocumentListComponent,
canDeactivate: [DirtySavedViewGuard],
},
{ path: 'documents/:id', component: DocumentDetailComponent }, { path: 'documents/:id', component: DocumentDetailComponent },
{ path: 'asn/:id', component: DocumentAsnComponent }, { path: 'asn/:id', component: DocumentAsnComponent },
{ path: 'tags', component: TagListComponent }, { path: 'tags', component: TagListComponent },

View File

@ -24,6 +24,7 @@ import { CorrespondentEditDialogComponent } from './components/common/edit-dialo
import { TagEditDialogComponent } from './components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component' import { TagEditDialogComponent } from './components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component'
import { DocumentTypeEditDialogComponent } from './components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component' import { DocumentTypeEditDialogComponent } from './components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component'
import { TagComponent } from './components/common/tag/tag.component' import { TagComponent } from './components/common/tag/tag.component'
import { ClearableBadge } from './components/common/clearable-badge/clearable-badge.component'
import { PageHeaderComponent } from './components/common/page-header/page-header.component' import { PageHeaderComponent } from './components/common/page-header/page-header.component'
import { AppFrameComponent } from './components/app-frame/app-frame.component' import { AppFrameComponent } from './components/app-frame/app-frame.component'
import { ToastsComponent } from './components/common/toasts/toasts.component' import { ToastsComponent } from './components/common/toasts/toasts.component'
@ -69,6 +70,7 @@ import { ColorComponent } from './components/common/input/color/color.component'
import { DocumentAsnComponent } from './components/document-asn/document-asn.component' import { DocumentAsnComponent } from './components/document-asn/document-asn.component'
import { DocumentCommentsComponent } from './components/document-comments/document-comments.component' import { DocumentCommentsComponent } from './components/document-comments/document-comments.component'
import { DirtyDocGuard } from './guards/dirty-doc.guard' import { DirtyDocGuard } from './guards/dirty-doc.guard'
import { DirtySavedViewGuard } from './guards/dirty-saved-view.guard'
import { StoragePathListComponent } from './components/manage/storage-path-list/storage-path-list.component' import { StoragePathListComponent } from './components/manage/storage-path-list/storage-path-list.component'
import { StoragePathEditDialogComponent } from './components/common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component' import { StoragePathEditDialogComponent } from './components/common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component'
import { SettingsService } from './services/settings.service' import { SettingsService } from './services/settings.service'
@ -141,6 +143,7 @@ function initializeApp(settings: SettingsService) {
DocumentTypeEditDialogComponent, DocumentTypeEditDialogComponent,
StoragePathEditDialogComponent, StoragePathEditDialogComponent,
TagComponent, TagComponent,
ClearableBadge,
PageHeaderComponent, PageHeaderComponent,
AppFrameComponent, AppFrameComponent,
ToastsComponent, ToastsComponent,
@ -215,6 +218,7 @@ function initializeApp(settings: SettingsService) {
{ provide: NgbDateAdapter, useClass: ISODateAdapter }, { provide: NgbDateAdapter, useClass: ISODateAdapter },
{ provide: NgbDateParserFormatter, useClass: LocalizedDateParserFormatter }, { provide: NgbDateParserFormatter, useClass: LocalizedDateParserFormatter },
DirtyDocGuard, DirtyDocGuard,
DirtySavedViewGuard,
], ],
bootstrap: [AppComponent], bootstrap: [AppComponent],
}) })

View File

@ -16,7 +16,12 @@
<use xlink:href="assets/bootstrap-icons.svg#search"/> <use xlink:href="assets/bootstrap-icons.svg#search"/>
</svg> </svg>
<input class="form-control form-control-sm" type="text" placeholder="Search documents" aria-label="Search" <input class="form-control form-control-sm" type="text" placeholder="Search documents" aria-label="Search"
[formControl]="searchField" [ngbTypeahead]="searchAutoComplete" (selectItem)="itemSelected($event)" i18n-placeholder> [formControl]="searchField" [ngbTypeahead]="searchAutoComplete" (keyup)="searchFieldKeyup($event)" (selectItem)="itemSelected($event)" i18n-placeholder>
<button *ngIf="!searchFieldEmpty" class="btn btn-link btn-sm px-0 position-absolute top-0 end-0" (click)="resetSearchField()">
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-x me-1" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/>
</svg>
</button>
</form> </form>
</div> </div>
<ul ngbNav class="order-sm-3"> <ul ngbNav class="order-sm-3">

View File

@ -243,17 +243,18 @@ main {
form { form {
position: relative; position: relative;
> svg {
position: absolute;
left: 0.6rem;
top: 0.5rem;
color: rgba(255, 255, 255, 0.6);
}
} }
svg {
position: absolute;
left: 0.6rem;
top: 0.5rem;
color: rgba(255, 255, 255, 0.6);
}
&:focus-within { &:focus-within {
svg { form > svg {
display: none; display: none;
} }

View File

@ -93,6 +93,20 @@ export class AppFrameComponent implements OnInit, ComponentCanDeactivate {
searchField = new FormControl('') searchField = new FormControl('')
get searchFieldEmpty(): boolean {
return this.searchField.value.trim().length == 0
}
resetSearchField() {
this.searchField.reset('')
}
searchFieldKeyup(event: KeyboardEvent) {
if (event.key == 'Escape') {
this.resetSearchField()
}
}
get openDocuments(): PaperlessDocument[] { get openDocuments(): PaperlessDocument[] {
return this.openDocumentsService.getOpenDocuments() return this.openDocumentsService.getOpenDocuments()
} }

View File

@ -0,0 +1,9 @@
<button *ngIf="active" class="position-absolute top-0 start-100 translate-middle badge bg-secondary border border-light rounded-pill p-1" title="Clear" i18n-title (click)="onClick($event)">
<svg *ngIf="!isNumbered && selected" width="1em" height="1em" class="check m-0 p-0 opacity-75" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<use xlink:href="assets/bootstrap-icons.svg#check-lg"/>
</svg>
<div *ngIf="isNumbered" class="number">{{number}}<span class="visually-hidden">selected</span></div>
<svg width=".9em" height="1em" class="x m-0 p-0 opacity-75" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<use xlink:href="assets/bootstrap-icons.svg#x-lg"/>
</svg>
</button>

View File

@ -0,0 +1,28 @@
.badge {
min-width: 20px;
min-height: 20px;
}
.x {
display: none;
}
.number {
min-width: 1em;
min-height: 1em;
display: inline-block;
}
button:hover {
.check,
.number {
opacity: 0 !important;
}
.x {
display: inline-block;
position: absolute;
top: 5px;
left: calc(50% - 4px);
}
}

View File

@ -0,0 +1,33 @@
import { Component, Input, Output, EventEmitter } from '@angular/core'
@Component({
selector: 'app-clearable-badge',
templateUrl: './clearable-badge.component.html',
styleUrls: ['./clearable-badge.component.scss'],
})
export class ClearableBadge {
constructor() {}
@Input()
number: number
@Input()
selected: boolean
@Output()
cleared: EventEmitter<boolean> = new EventEmitter()
get active(): boolean {
return this.selected || this.number > -1
}
get isNumbered(): boolean {
return this.number > -1
}
onClick(event: PointerEvent) {
this.cleared.emit(true)
event.stopImmediatePropagation()
event.preventDefault()
}
}

View File

@ -16,4 +16,7 @@
<ngb-progressbar *ngIf="!confirmButtonEnabled" style="height: 1px;" type="dark" [max]="secondsTotal" [value]="seconds"></ngb-progressbar> <ngb-progressbar *ngIf="!confirmButtonEnabled" style="height: 1px;" type="dark" [max]="secondsTotal" [value]="seconds"></ngb-progressbar>
<span class="visually-hidden">{{ seconds | number: '1.0-0' }} seconds</span> <span class="visually-hidden">{{ seconds | number: '1.0-0' }} seconds</span>
</button> </button>
<button *ngIf="alternativeBtnCaption" type="button" class="btn" [class]="alternativeBtnClass" (click)="alternative()" [disabled]="!alternativeButtonEnabled || !buttonsEnabled">
{{alternativeBtnCaption}}
</button>
</div> </div>

View File

@ -13,6 +13,9 @@ export class ConfirmDialogComponent {
@Output() @Output()
public confirmClicked = new EventEmitter() public confirmClicked = new EventEmitter()
@Output()
public alternativeClicked = new EventEmitter()
@Input() @Input()
title = $localize`Confirmation` title = $localize`Confirmation`
@ -28,14 +31,22 @@ export class ConfirmDialogComponent {
@Input() @Input()
btnCaption = $localize`Confirm` btnCaption = $localize`Confirm`
@Input()
alternativeBtnClass = 'btn-secondary'
@Input()
alternativeBtnCaption
@Input() @Input()
buttonsEnabled = true buttonsEnabled = true
confirmButtonEnabled = true confirmButtonEnabled = true
alternativeButtonEnabled = true
seconds = 0 seconds = 0
secondsTotal = 0 secondsTotal = 0
confirmSubject: Subject<boolean> confirmSubject: Subject<boolean>
alternativeSubject: Subject<boolean>
delayConfirm(seconds: number) { delayConfirm(seconds: number) {
const refreshInterval = 0.15 // s const refreshInterval = 0.15 // s
@ -68,4 +79,10 @@ export class ConfirmDialogComponent {
this.confirmSubject?.next(true) this.confirmSubject?.next(true)
this.confirmSubject?.complete() this.confirmSubject?.complete()
} }
alternative() {
this.alternativeClicked.emit()
this.alternativeSubject?.next(true)
this.alternativeSubject?.complete()
}
} }

View File

@ -1,11 +1,17 @@
<div class="btn-group w-100" ngbDropdown role="group"> <div class="btn-group w-100" ngbDropdown role="group">
<button class="btn btn-sm" id="dropdown{{title}}" ngbDropdownToggle [ngClass]="dateBefore || dateAfter ? 'btn-primary' : 'btn-outline-primary'"> <button class="btn btn-sm" id="dropdown{{title}}" ngbDropdownToggle [ngClass]="dateBefore || dateAfter ? 'btn-primary' : 'btn-outline-primary'">
{{title}} {{title}}
<app-clearable-badge [selected]="isActive" (cleared)="reset()"></app-clearable-badge><span class="visually-hidden">selected</span>
</button> </button>
<div class="dropdown-menu date-dropdown shadow pt-0" ngbDropdownMenu attr.aria-labelledby="dropdown{{title}}"> <div class="dropdown-menu date-dropdown shadow pt-0" ngbDropdownMenu attr.aria-labelledby="dropdown{{title}}">
<div class="list-group list-group-flush"> <div class="list-group list-group-flush">
<button *ngFor="let qf of quickFilters" class="list-group-item small list-goup list-group-item-action d-flex p-2 ps-3" role="menuitem" (click)="setDateQuickFilter(qf.id)"> <button *ngFor="let rd of relativeDates" class="list-group-item small list-goup list-group-item-action d-flex p-2" role="menuitem" (click)="setRelativeDate(rd.date)">
{{qf.name}} <div _ngcontent-hga-c166="" class="selected-icon me-1">
<svg *ngIf="relativeDate === rd.date" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" class="bi bi-check" viewBox="0 0 16 16">
<path d="M10.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L4.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093 3.473-4.425a.267.267 0 0 1 .02-.022z"/>
</svg>
</div>
{{rd.name}}
</button> </button>
<div class="list-group-item d-flex flex-column align-items-start" role="menuitem"> <div class="list-group-item d-flex flex-column align-items-start" role="menuitem">

View File

@ -5,3 +5,8 @@
line-height: 1; line-height: 1;
} }
} }
.selected-icon {
min-width: 1em;
min-height: 1em;
}

View File

@ -16,12 +16,15 @@ import { ISODateAdapter } from 'src/app/utils/ngb-iso-date-adapter'
export interface DateSelection { export interface DateSelection {
before?: string before?: string
after?: string after?: string
relativeDateID?: number
} }
const LAST_7_DAYS = 0 export enum RelativeDate {
const LAST_MONTH = 1 LAST_7_DAYS = 0,
const LAST_3_MONTHS = 2 LAST_MONTH = 1,
const LAST_YEAR = 3 LAST_3_MONTHS = 2,
LAST_YEAR = 3,
}
@Component({ @Component({
selector: 'app-date-dropdown', selector: 'app-date-dropdown',
@ -34,11 +37,23 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
this.datePlaceHolder = settings.getLocalizedDateInputFormat() this.datePlaceHolder = settings.getLocalizedDateInputFormat()
} }
quickFilters = [ relativeDates = [
{ id: LAST_7_DAYS, name: $localize`Last 7 days` }, {
{ id: LAST_MONTH, name: $localize`Last month` }, date: RelativeDate.LAST_7_DAYS,
{ id: LAST_3_MONTHS, name: $localize`Last 3 months` }, name: $localize`Last 7 days`,
{ id: LAST_YEAR, name: $localize`Last year` }, },
{
date: RelativeDate.LAST_MONTH,
name: $localize`Last month`,
},
{
date: RelativeDate.LAST_3_MONTHS,
name: $localize`Last 3 months`,
},
{
date: RelativeDate.LAST_YEAR,
name: $localize`Last year`,
},
] ]
datePlaceHolder: string datePlaceHolder: string
@ -55,12 +70,26 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
@Output() @Output()
dateAfterChange = new EventEmitter<string>() dateAfterChange = new EventEmitter<string>()
@Input()
relativeDate: RelativeDate
@Output()
relativeDateChange = new EventEmitter<number>()
@Input() @Input()
title: string title: string
@Output() @Output()
datesSet = new EventEmitter<DateSelection>() datesSet = new EventEmitter<DateSelection>()
get isActive(): boolean {
return (
this.relativeDate !== null ||
this.dateAfter?.length > 0 ||
this.dateBefore?.length > 0
)
}
private datesSetDebounce$ = new Subject() private datesSetDebounce$ = new Subject()
private sub: Subscription private sub: Subscription
@ -77,37 +106,33 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
} }
} }
setDateQuickFilter(qf: number) { reset() {
this.dateBefore = null this.dateBefore = null
let date = new Date() this.dateAfter = null
switch (qf) { this.relativeDate = null
case LAST_7_DAYS: this.onChange()
date.setDate(date.getDate() - 7) }
break
case LAST_MONTH: setRelativeDate(rd: RelativeDate) {
date.setMonth(date.getMonth() - 1) this.dateBefore = null
break this.dateAfter = null
this.relativeDate = this.relativeDate == rd ? null : rd
case LAST_3_MONTHS:
date.setMonth(date.getMonth() - 3)
break
case LAST_YEAR:
date.setFullYear(date.getFullYear() - 1)
break
}
this.dateAfter = formatDate(date, 'yyyy-MM-dd', 'en-us', 'UTC')
this.onChange() this.onChange()
} }
onChange() { onChange() {
this.dateAfterChange.emit(this.dateAfter)
this.dateBeforeChange.emit(this.dateBefore) this.dateBeforeChange.emit(this.dateBefore)
this.datesSet.emit({ after: this.dateAfter, before: this.dateBefore }) this.dateAfterChange.emit(this.dateAfter)
this.relativeDateChange.emit(this.relativeDate)
this.datesSet.emit({
after: this.dateAfter,
before: this.dateBefore,
relativeDateID: this.relativeDate,
})
} }
onChangeDebounce() { onChangeDebounce() {
this.relativeDate = null
this.datesSetDebounce$.next({ this.datesSetDebounce$.next({
after: this.dateAfter, after: this.dateAfter,
before: this.dateBefore, before: this.dateBefore,

View File

@ -5,12 +5,7 @@
</svg> </svg>
<div class="d-none d-sm-inline">&nbsp;{{title}}</div> <div class="d-none d-sm-inline">&nbsp;{{title}}</div>
<ng-container *ngIf="!editing && selectionModel.selectionSize() > 0"> <ng-container *ngIf="!editing && selectionModel.selectionSize() > 0">
<div *ngIf="multiple" class="position-absolute top-0 start-100 translate-middle badge bg-secondary border border-light text-light rounded-pill"> <app-clearable-badge [number]="multiple ? selectionModel.totalCount : undefined" [selected]="!multiple && selectionModel.selectionSize() > 0" (cleared)="reset()"></app-clearable-badge>
{{selectionModel.totalCount}}<span class="visually-hidden">selected</span>
</div>
<div *ngIf="!multiple" class="position-absolute top-0 start-100 p-2 translate-middle badge bg-secondary border border-light rounded-circle">
<span class="visually-hidden">selected</span>
</div>
</ng-container> </ng-container>
</button> </button>
<div class="dropdown-menu py-0 shadow" ngbDropdownMenu attr.aria-labelledby="dropdown{{title}}"> <div class="dropdown-menu py-0 shadow" ngbDropdownMenu attr.aria-labelledby="dropdown{{title}}">

View File

@ -384,4 +384,9 @@ export class FilterableDropdownComponent {
this.selectionModel.exclude(itemID) this.selectionModel.exclude(itemID)
} }
} }
reset() {
this.selectionModel.reset()
this.selectionModelChange.emit(this.selectionModel)
}
} }

View File

@ -60,14 +60,19 @@
</div> </div>
<div class="btn-group ms-2 flex-fill" ngbDropdown role="group"> <div class="btn-group ms-2 flex-fill" ngbDropdown role="group">
<button class="btn btn-sm btn-outline-primary dropdown-toggle flex-fill" tourAnchor="tour.documents-views" ngbDropdownToggle i18n>Views</button> <button class="btn btn-sm btn-outline-primary dropdown-toggle flex-fill" tourAnchor="tour.documents-views" ngbDropdownToggle>
<ng-container i18n>Views</ng-container>
<div *ngIf="savedViewIsModified" class="position-absolute top-0 start-100 p-2 translate-middle badge bg-secondary border border-light rounded-circle">
<span class="visually-hidden">selected</span>
</div>
</button>
<div class="dropdown-menu shadow dropdown-menu-right" ngbDropdownMenu> <div class="dropdown-menu shadow dropdown-menu-right" ngbDropdownMenu>
<ng-container *ngIf="!list.activeSavedViewId"> <ng-container *ngIf="!list.activeSavedViewId">
<button ngbDropdownItem *ngFor="let view of savedViewService.allViews" (click)="loadViewConfig(view.id)">{{view.name}}</button> <button ngbDropdownItem *ngFor="let view of savedViewService.allViews" (click)="loadViewConfig(view.id)">{{view.name}}</button>
<div class="dropdown-divider" *ngIf="savedViewService.allViews.length > 0"></div> <div class="dropdown-divider" *ngIf="savedViewService.allViews.length > 0"></div>
</ng-container> </ng-container>
<button ngbDropdownItem (click)="saveViewConfig()" *ngIf="list.activeSavedViewId" i18n>Save "{{list.activeSavedViewTitle}}"</button> <button ngbDropdownItem (click)="saveViewConfig()" *ngIf="list.activeSavedViewId" [disabled]="!savedViewIsModified" i18n>Save "{{list.activeSavedViewTitle}}"</button>
<button ngbDropdownItem (click)="saveViewConfigAs()" i18n>Save as...</button> <button ngbDropdownItem (click)="saveViewConfigAs()" i18n>Save as...</button>
</div> </div>
</div> </div>

View File

@ -9,7 +9,11 @@ import {
import { ActivatedRoute, convertToParamMap, Router } from '@angular/router' import { ActivatedRoute, convertToParamMap, Router } from '@angular/router'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { filter, first, map, Subject, switchMap, takeUntil } from 'rxjs' import { filter, first, map, Subject, switchMap, takeUntil } from 'rxjs'
import { FilterRule, isFullTextFilterRule } from 'src/app/data/filter-rule' import {
FilterRule,
filterRulesDiffer,
isFullTextFilterRule,
} from 'src/app/data/filter-rule'
import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type' import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type'
import { PaperlessDocument } from 'src/app/data/paperless-document' import { PaperlessDocument } from 'src/app/data/paperless-document'
import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'
@ -54,15 +58,36 @@ export class DocumentListComponent implements OnInit, OnDestroy {
displayMode = 'smallCards' // largeCards, smallCards, details displayMode = 'smallCards' // largeCards, smallCards, details
unmodifiedFilterRules: FilterRule[] = [] unmodifiedFilterRules: FilterRule[] = []
private unmodifiedSavedView: PaperlessSavedView
private unsubscribeNotifier: Subject<any> = new Subject() private unsubscribeNotifier: Subject<any> = new Subject()
get savedViewIsModified(): boolean {
if (!this.list.activeSavedViewId || !this.unmodifiedSavedView) return false
else {
return (
this.unmodifiedSavedView.sort_field !== this.list.sortField ||
this.unmodifiedSavedView.sort_reverse !== this.list.sortReverse ||
filterRulesDiffer(
this.unmodifiedSavedView.filter_rules,
this.list.filterRules
)
)
}
}
get isFiltered() { get isFiltered() {
return this.list.filterRules?.length > 0 return this.list.filterRules?.length > 0
} }
getTitle() { getTitle() {
return this.list.activeSavedViewTitle || $localize`Documents` let title = this.list.activeSavedViewTitle
if (title && this.savedViewIsModified) {
title += '*'
} else if (!title) {
title = $localize`Documents`
}
return title
} }
getSortFields() { getSortFields() {
@ -122,7 +147,7 @@ export class DocumentListComponent implements OnInit, OnDestroy {
this.router.navigate(['404']) this.router.navigate(['404'])
return return
} }
this.unmodifiedSavedView = view
this.list.activateSavedViewWithQueryParams( this.list.activateSavedViewWithQueryParams(
view, view,
convertToParamMap(this.route.snapshot.queryParams) convertToParamMap(this.route.snapshot.queryParams)
@ -165,7 +190,8 @@ export class DocumentListComponent implements OnInit, OnDestroy {
this.savedViewService this.savedViewService
.patch(savedView) .patch(savedView)
.pipe(first()) .pipe(first())
.subscribe((result) => { .subscribe((view) => {
this.unmodifiedSavedView = view
this.toastService.showInfo( this.toastService.showInfo(
$localize`View "${this.list.activeSavedViewTitle}" saved successfully.` $localize`View "${this.list.activeSavedViewTitle}" saved successfully.`
) )
@ -179,6 +205,7 @@ export class DocumentListComponent implements OnInit, OnDestroy {
.getCached(viewID) .getCached(viewID)
.pipe(first()) .pipe(first())
.subscribe((view) => { .subscribe((view) => {
this.unmodifiedSavedView = view
this.list.activateSavedView(view) this.list.activateSavedView(view)
this.list.reload() this.list.reload()
}) })

View File

@ -11,7 +11,12 @@
<select *ngIf="textFilterTarget == 'asn'" class="form-select flex-grow-0 w-auto" [(ngModel)]="textFilterModifier" (change)="textFilterModifierChange()"> <select *ngIf="textFilterTarget == 'asn'" class="form-select flex-grow-0 w-auto" [(ngModel)]="textFilterModifier" (change)="textFilterModifierChange()">
<option *ngFor="let m of textFilterModifiers" ngbDropdownItem [value]="m.id">{{m.label}}</option> <option *ngFor="let m of textFilterModifiers" ngbDropdownItem [value]="m.id">{{m.label}}</option>
</select> </select>
<input #textFilterInput class="form-control form-control-sm" type="text" [disabled]="textFilterModifierIsNull" [(ngModel)]="textFilter" (keyup.enter)="textFilterEnter()" [readonly]="textFilterTarget == 'fulltext-morelike'"> <button *ngIf="_textFilter" class="btn btn-link btn-sm px-0 position-absolute top-0 end-0 z-10" (click)="resetTextField()">
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-x me-1" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/>
</svg>
</button>
<input #textFilterInput class="form-control form-control-sm" type="text" [disabled]="textFilterModifierIsNull" [(ngModel)]="textFilter" (keyup)="textFilterKeyup($event)" [readonly]="textFilterTarget == 'fulltext-morelike'">
</div> </div>
</div> </div>
</div> </div>
@ -54,12 +59,14 @@
title="Created" i18n-title title="Created" i18n-title
(datesSet)="updateRules()" (datesSet)="updateRules()"
[(dateBefore)]="dateCreatedBefore" [(dateBefore)]="dateCreatedBefore"
[(dateAfter)]="dateCreatedAfter"></app-date-dropdown> [(dateAfter)]="dateCreatedAfter"
[(relativeDate)]="dateCreatedRelativeDate"></app-date-dropdown>
<app-date-dropdown class="mb-2 mb-xl-0" <app-date-dropdown class="mb-2 mb-xl-0"
title="Added" i18n-title
(datesSet)="updateRules()"
[(dateBefore)]="dateAddedBefore" [(dateBefore)]="dateAddedBefore"
[(dateAfter)]="dateAddedAfter" [(dateAfter)]="dateAddedAfter"
title="Added" i18n-title [(relativeDate)]="dateAddedRelativeDate"></app-date-dropdown>
(datesSet)="updateRules()"></app-date-dropdown>
</div> </div>
</div> </div>
</div> </div>

View File

@ -21,3 +21,7 @@
input[type="text"] { input[type="text"] {
min-width: 120px; min-width: 120px;
} }
.z-10 {
z-index: 10;
}

View File

@ -44,6 +44,7 @@ import { DocumentService } from 'src/app/services/rest/document.service'
import { PaperlessDocument } from 'src/app/data/paperless-document' import { PaperlessDocument } from 'src/app/data/paperless-document'
import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path' import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
import { StoragePathService } from 'src/app/services/rest/storage-path.service' import { StoragePathService } from 'src/app/services/rest/storage-path.service'
import { RelativeDate } from '../../common/date-dropdown/date-dropdown.component'
const TEXT_FILTER_TARGET_TITLE = 'title' const TEXT_FILTER_TARGET_TITLE = 'title'
const TEXT_FILTER_TARGET_TITLE_CONTENT = 'title-content' const TEXT_FILTER_TARGET_TITLE_CONTENT = 'title-content'
@ -57,6 +58,27 @@ const TEXT_FILTER_MODIFIER_NOTNULL = 'not null'
const TEXT_FILTER_MODIFIER_GT = 'greater' const TEXT_FILTER_MODIFIER_GT = 'greater'
const TEXT_FILTER_MODIFIER_LT = 'less' const TEXT_FILTER_MODIFIER_LT = 'less'
const RELATIVE_DATE_QUERY_REGEXP_CREATED = /created:\[([^\]]+)\]/g
const RELATIVE_DATE_QUERY_REGEXP_ADDED = /added:\[([^\]]+)\]/g
const RELATIVE_DATE_QUERYSTRINGS = [
{
relativeDate: RelativeDate.LAST_7_DAYS,
dateQuery: '-1 week to now',
},
{
relativeDate: RelativeDate.LAST_MONTH,
dateQuery: '-1 month to now',
},
{
relativeDate: RelativeDate.LAST_3_MONTHS,
dateQuery: '-3 month to now',
},
{
relativeDate: RelativeDate.LAST_YEAR,
dateQuery: '-1 year to now',
},
]
@Component({ @Component({
selector: 'app-filter-editor', selector: 'app-filter-editor',
templateUrl: './filter-editor.component.html', templateUrl: './filter-editor.component.html',
@ -197,6 +219,8 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
dateCreatedAfter: string dateCreatedAfter: string
dateAddedBefore: string dateAddedBefore: string
dateAddedAfter: string dateAddedAfter: string
dateCreatedRelativeDate: RelativeDate
dateAddedRelativeDate: RelativeDate
_unmodifiedFilterRules: FilterRule[] = [] _unmodifiedFilterRules: FilterRule[] = []
_filterRules: FilterRule[] = [] _filterRules: FilterRule[] = []
@ -228,6 +252,8 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
this.dateAddedAfter = null this.dateAddedAfter = null
this.dateCreatedBefore = null this.dateCreatedBefore = null
this.dateCreatedAfter = null this.dateCreatedAfter = null
this.dateCreatedRelativeDate = null
this.dateAddedRelativeDate = null
this.textFilterModifier = TEXT_FILTER_MODIFIER_EQUALS this.textFilterModifier = TEXT_FILTER_MODIFIER_EQUALS
value.forEach((rule) => { value.forEach((rule) => {
@ -245,8 +271,39 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
this.textFilterTarget = TEXT_FILTER_TARGET_ASN this.textFilterTarget = TEXT_FILTER_TARGET_ASN
break break
case FILTER_FULLTEXT_QUERY: case FILTER_FULLTEXT_QUERY:
this._textFilter = rule.value let allQueryArgs = rule.value.split(',')
this.textFilterTarget = TEXT_FILTER_TARGET_FULLTEXT_QUERY let textQueryArgs = []
allQueryArgs.forEach((arg) => {
if (arg.match(RELATIVE_DATE_QUERY_REGEXP_CREATED)) {
;[...arg.matchAll(RELATIVE_DATE_QUERY_REGEXP_CREATED)].forEach(
(match) => {
if (match[1]?.length) {
this.dateCreatedRelativeDate =
RELATIVE_DATE_QUERYSTRINGS.find(
(qS) => qS.dateQuery == match[1]
)?.relativeDate
}
}
)
} else if (arg.match(RELATIVE_DATE_QUERY_REGEXP_ADDED)) {
;[...arg.matchAll(RELATIVE_DATE_QUERY_REGEXP_ADDED)].forEach(
(match) => {
if (match[1]?.length) {
this.dateAddedRelativeDate =
RELATIVE_DATE_QUERYSTRINGS.find(
(qS) => qS.dateQuery == match[1]
)?.relativeDate
}
}
)
} else {
textQueryArgs.push(arg)
}
})
if (textQueryArgs.length) {
this._textFilter = textQueryArgs.join(',')
this.textFilterTarget = TEXT_FILTER_TARGET_FULLTEXT_QUERY
}
break break
case FILTER_FULLTEXT_MORELIKE: case FILTER_FULLTEXT_MORELIKE:
this._moreLikeId = +rule.value this._moreLikeId = +rule.value
@ -471,6 +528,89 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
value: this.dateAddedAfter, value: this.dateAddedAfter,
}) })
} }
if (
this.dateAddedRelativeDate !== null ||
this.dateCreatedRelativeDate !== null
) {
let queryArgs: Array<string> = []
let existingRule = filterRules.find(
(fr) => fr.rule_type == FILTER_FULLTEXT_QUERY
)
// if had a title / content search and added a relative date we need to carry it over...
if (
!existingRule &&
this._textFilter?.length > 0 &&
(this.textFilterTarget == TEXT_FILTER_TARGET_TITLE_CONTENT ||
this.textFilterTarget == TEXT_FILTER_TARGET_TITLE)
) {
existingRule = filterRules.find(
(fr) =>
fr.rule_type == FILTER_TITLE_CONTENT || fr.rule_type == FILTER_TITLE
)
existingRule.rule_type = FILTER_FULLTEXT_QUERY
}
let existingRuleArgs = existingRule?.value.split(',')
if (this.dateCreatedRelativeDate !== null) {
queryArgs.push(
`created:[${
RELATIVE_DATE_QUERYSTRINGS.find(
(qS) => qS.relativeDate == this.dateCreatedRelativeDate
).dateQuery
}]`
)
if (existingRule) {
queryArgs = existingRuleArgs
.filter((arg) => !arg.match(RELATIVE_DATE_QUERY_REGEXP_CREATED))
.concat(queryArgs)
}
}
if (this.dateAddedRelativeDate !== null) {
queryArgs.push(
`added:[${
RELATIVE_DATE_QUERYSTRINGS.find(
(qS) => qS.relativeDate == this.dateAddedRelativeDate
).dateQuery
}]`
)
if (existingRule) {
queryArgs = existingRuleArgs
.filter((arg) => !arg.match(RELATIVE_DATE_QUERY_REGEXP_ADDED))
.concat(queryArgs)
}
}
if (existingRule) {
existingRule.value = queryArgs.join(',')
} else {
filterRules.push({
rule_type: FILTER_FULLTEXT_QUERY,
value: queryArgs.join(','),
})
}
}
if (
this.dateCreatedRelativeDate == null &&
this.dateAddedRelativeDate == null
) {
const existingRule = filterRules.find(
(fr) => fr.rule_type == FILTER_FULLTEXT_QUERY
)
if (
existingRule?.value.match(RELATIVE_DATE_QUERY_REGEXP_CREATED) ||
existingRule?.value.match(RELATIVE_DATE_QUERY_REGEXP_ADDED)
) {
// remove any existing date query
existingRule.value = existingRule.value
.replace(RELATIVE_DATE_QUERY_REGEXP_CREATED, '')
.replace(RELATIVE_DATE_QUERY_REGEXP_ADDED, '')
if (existingRule.value.replace(',', '').trim() === '') {
// if its empty now, remove it entirely
filterRules.splice(filterRules.indexOf(existingRule), 1)
}
}
}
return filterRules return filterRules
} }
@ -569,15 +709,23 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
this.updateRules() this.updateRules()
} }
textFilterEnter() { textFilterKeyup(event: KeyboardEvent) {
const filterString = ( if (event.key == 'Enter') {
this.textFilterInput.nativeElement as HTMLInputElement const filterString = (
).value this.textFilterInput.nativeElement as HTMLInputElement
if (filterString.length) { ).value
this.updateTextFilter(filterString) if (filterString.length) {
this.updateTextFilter(filterString)
}
} else if (event.key == 'Escape') {
this.resetTextField()
} }
} }
resetTextField() {
this.updateTextFilter('')
}
changeTextFilterTarget(target) { changeTextFilterTarget(target) {
if ( if (
this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_MORELIKE && this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_MORELIKE &&

View File

@ -0,0 +1,51 @@
import { CanDeactivate } from '@angular/router'
import { Injectable } from '@angular/core'
import { first, Observable, Subject } from 'rxjs'
import { DocumentListComponent } from '../components/document-list/document-list.component'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { ConfirmDialogComponent } from '../components/common/confirm-dialog/confirm-dialog.component'
@Injectable()
export class DirtySavedViewGuard
implements CanDeactivate<DocumentListComponent>
{
constructor(private modalService: NgbModal) {}
canDeactivate(
component: DocumentListComponent
): boolean | Observable<boolean> {
return component.savedViewIsModified ? this.warn(component) : true
}
warn(component: DocumentListComponent) {
let modal = this.modalService.open(ConfirmDialogComponent, {
backdrop: 'static',
})
modal.componentInstance.title = $localize`Unsaved Changes`
modal.componentInstance.messageBold =
$localize`You have unsaved changes to the saved view` +
' "' +
component.getTitle()
;('".')
modal.componentInstance.message = $localize`Are you sure you want to close this saved view?`
modal.componentInstance.btnClass = 'btn-secondary'
modal.componentInstance.btnCaption = $localize`Close`
modal.componentInstance.alternativeBtnClass = 'btn-primary'
modal.componentInstance.alternativeBtnCaption = $localize`Save and close`
modal.componentInstance.alternativeClicked.pipe(first()).subscribe(() => {
modal.componentInstance.buttonsEnabled = false
component.saveViewConfig()
modal.close()
})
modal.componentInstance.confirmClicked.pipe(first()).subscribe(() => {
modal.componentInstance.buttonsEnabled = false
modal.close()
})
const subject = new Subject<boolean>()
modal.componentInstance.confirmSubject = subject
modal.componentInstance.alternativeSubject = subject
return subject
}
}

View File

@ -171,15 +171,15 @@ export class DocumentListViewService {
this.reduceSelectionToFilter() this.reduceSelectionToFilter()
if (!this.router.routerState.snapshot.url.includes('/view/')) { if (!this.router.routerState.snapshot.url.includes('/view/')) {
this.router.navigate([], { this.router.navigate(['view', view.id])
queryParams: { view: view.id },
})
} }
} }
loadFromQueryParams(queryParams: ParamMap) { loadFromQueryParams(queryParams: ParamMap) {
const paramsEmpty: boolean = queryParams.keys.length == 0 const paramsEmpty: boolean = queryParams.keys.length == 0
let newState: ListViewState = this.listViewStates.get(null) let newState: ListViewState = this.listViewStates.get(
this._activeSavedViewId
)
if (!paramsEmpty) newState = paramsToViewState(queryParams) if (!paramsEmpty) newState = paramsToViewState(queryParams)
if (newState == undefined) newState = this.defaultListViewState() // if nothing in local storage if (newState == undefined) newState = this.defaultListViewState() // if nothing in local storage
@ -276,7 +276,6 @@ export class DocumentListViewService {
) { ) {
this.activeListViewState.sortField = 'created' this.activeListViewState.sortField = 'created'
} }
this._activeSavedViewId = null
this.activeListViewState.filterRules = filterRules this.activeListViewState.filterRules = filterRules
this.reload() this.reload()
this.reduceSelectionToFilter() this.reduceSelectionToFilter()
@ -288,7 +287,6 @@ export class DocumentListViewService {
} }
set sortField(field: string) { set sortField(field: string) {
this._activeSavedViewId = null
this.activeListViewState.sortField = field this.activeListViewState.sortField = field
this.reload() this.reload()
this.saveDocumentListView() this.saveDocumentListView()
@ -299,7 +297,6 @@ export class DocumentListViewService {
} }
set sortReverse(reverse: boolean) { set sortReverse(reverse: boolean) {
this._activeSavedViewId = null
this.activeListViewState.sortReverse = reverse this.activeListViewState.sortReverse = reverse
this.reload() this.reload()
this.saveDocumentListView() this.saveDocumentListView()

View File

@ -372,6 +372,10 @@ textarea,
&:hover, &:focus { &:hover, &:focus {
background-color: var(--bs-body-bg); background-color: var(--bs-body-bg);
} }
&:focus {
color: var(--bs-body-color);
}
} }
.dropdown-menu { .dropdown-menu {
@ -393,6 +397,10 @@ textarea,
background-color: var(--bs-primary); background-color: var(--bs-primary);
color: var(--pngx-primary-text-contrast); color: var(--pngx-primary-text-contrast);
} }
&.disabled, &:disabled {
opacity: 50%;
}
} }
} }
@ -579,7 +587,7 @@ a.badge {
border-radius: 0.15rem; border-radius: 0.15rem;
} }
> .btn:not(:first-child) { > .btn:not(:first-child):not(:nth-child(2)) {
border-top-left-radius: 0; border-top-left-radius: 0;
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
} }

View File

@ -405,6 +405,7 @@ class Consumer(LoggingMixin):
# Don't save with the lock active. Saving will cause the file # Don't save with the lock active. Saving will cause the file
# renaming logic to acquire the lock as well. # renaming logic to acquire the lock as well.
# This triggers things like file renaming
document.save() document.save()
# Delete the file only if it was successfully consumed # Delete the file only if it was successfully consumed
@ -438,6 +439,9 @@ class Consumer(LoggingMixin):
self._send_progress(100, 100, "SUCCESS", MESSAGE_FINISHED, document.id) self._send_progress(100, 100, "SUCCESS", MESSAGE_FINISHED, document.id)
# Return the most up to date fields
document.refresh_from_db()
return document return document
def _store(self, text, date, mime_type) -> Document: def _store(self, text, date, mime_type) -> Document:

View File

@ -1,4 +1,3 @@
import datetime
import logging import logging
import os import os
from collections import defaultdict from collections import defaultdict
@ -172,7 +171,7 @@ def generate_filename(doc, counter=0, append_gpg=True, archive_filename=False):
else: else:
asn = "-none-" asn = "-none-"
# Convert UTC database date to localized date # Convert UTC database datetime to localized date
local_added = timezone.localdate(doc.added) local_added = timezone.localdate(doc.added)
local_created = timezone.localdate(doc.created) local_created = timezone.localdate(doc.created)
@ -180,14 +179,20 @@ def generate_filename(doc, counter=0, append_gpg=True, archive_filename=False):
title=pathvalidate.sanitize_filename(doc.title, replacement_text="-"), title=pathvalidate.sanitize_filename(doc.title, replacement_text="-"),
correspondent=correspondent, correspondent=correspondent,
document_type=document_type, document_type=document_type,
created=datetime.date.isoformat(local_created), created=local_created.isoformat(),
created_year=local_created.year, created_year=local_created.strftime("%Y"),
created_month=f"{local_created.month:02}", created_year_short=local_created.strftime("%y"),
created_day=f"{local_created.day:02}", created_month=local_created.strftime("%m"),
added=datetime.date.isoformat(local_added), created_month_name=local_created.strftime("%B"),
added_year=local_added.year, created_month_name_short=local_created.strftime("%b"),
added_month=f"{local_added.month:02}", created_day=local_created.strftime("%d"),
added_day=f"{local_added.day:02}", added=local_added.isoformat(),
added_year=local_added.strftime("%Y"),
added_year_short=local_added.strftime("%y"),
added_month=local_added.strftime("%m"),
added_month_name=local_added.strftime("%B"),
added_month_name_short=local_added.strftime("%b"),
added_day=local_added.strftime("%d"),
asn=asn, asn=asn,
tags=tags, tags=tags,
tag_list=tag_list, tag_list=tag_list,

View File

@ -142,14 +142,14 @@ def matches(matching_model, document):
return bool(match) return bool(match)
elif matching_model.matching_algorithm == MatchingModel.MATCH_FUZZY: elif matching_model.matching_algorithm == MatchingModel.MATCH_FUZZY:
from fuzzywuzzy import fuzz from rapidfuzz import fuzz
match = re.sub(r"[^\w\s]", "", matching_model.match) match = re.sub(r"[^\w\s]", "", matching_model.match)
text = re.sub(r"[^\w\s]", "", document_content) text = re.sub(r"[^\w\s]", "", document_content)
if matching_model.is_insensitive: if matching_model.is_insensitive:
match = match.lower() match = match.lower()
text = text.lower() text = text.lower()
if fuzz.partial_ratio(match, text) >= 90: if fuzz.partial_ratio(match, text, score_cutoff=90):
# TODO: make this better # TODO: make this better
log_reason( log_reason(
matching_model, matching_model,

View File

@ -400,6 +400,13 @@ def update_filename_and_move_files(sender, instance, **kwargs):
with FileLock(settings.MEDIA_LOCK): with FileLock(settings.MEDIA_LOCK):
try: try:
# If this was waiting for the lock, the filename or archive_filename
# of this document may have been updated. This happens if multiple updates
# get queued from the UI for the same document
# So freshen up the data before doing anything
instance.refresh_from_db()
old_filename = instance.filename old_filename = instance.filename
old_source_path = instance.source_path old_source_path = instance.source_path

View File

@ -14,6 +14,7 @@ except ImportError:
import backports.zoneinfo as zoneinfo import backports.zoneinfo as zoneinfo
from django.conf import settings from django.conf import settings
from django.utils import timezone
from django.test import override_settings from django.test import override_settings
from django.test import TestCase from django.test import TestCase
@ -326,6 +327,12 @@ class TestConsumer(DirectoriesMixin, TestCase):
def testNormalOperation(self): def testNormalOperation(self):
filename = self.get_test_file() filename = self.get_test_file()
# Get the local time, as an aware datetime
# Roughly equal to file modification time
rough_create_date_local = timezone.localtime(timezone.now())
# Consume the file
document = self.consumer.try_consume_file(filename) document = self.consumer.try_consume_file(filename)
self.assertEqual(document.content, "The Text") self.assertEqual(document.content, "The Text")
@ -351,7 +358,20 @@ class TestConsumer(DirectoriesMixin, TestCase):
self._assert_first_last_send_progress() self._assert_first_last_send_progress()
self.assertEqual(document.created.tzinfo, zoneinfo.ZoneInfo("America/Chicago")) # Convert UTC time from DB to local time
document_date_local = timezone.localtime(document.created)
self.assertEqual(
document_date_local.tzinfo,
zoneinfo.ZoneInfo("America/Chicago"),
)
self.assertEqual(document_date_local.tzinfo, rough_create_date_local.tzinfo)
self.assertEqual(document_date_local.year, rough_create_date_local.year)
self.assertEqual(document_date_local.month, rough_create_date_local.month)
self.assertEqual(document_date_local.day, rough_create_date_local.day)
self.assertEqual(document_date_local.hour, rough_create_date_local.hour)
self.assertEqual(document_date_local.minute, rough_create_date_local.minute)
# Skipping seconds and more precise
@override_settings(FILENAME_FORMAT=None) @override_settings(FILENAME_FORMAT=None)
def testDeleteMacFiles(self): def testDeleteMacFiles(self):

View File

@ -1036,6 +1036,34 @@ class TestFilenameGeneration(TestCase):
self.assertEqual(generate_filename(doc_a), "0000002.pdf") self.assertEqual(generate_filename(doc_a), "0000002.pdf")
self.assertEqual(generate_filename(doc_b), "SomeImportantNone/2020-07-25.pdf") self.assertEqual(generate_filename(doc_b), "SomeImportantNone/2020-07-25.pdf")
@override_settings(
FILENAME_FORMAT="{created_year_short}/{created_month_name_short}/{created_month_name}/{title}",
)
def test_short_names_created(self):
doc = Document.objects.create(
title="The Title",
created=timezone.make_aware(
datetime.datetime(1989, 12, 21, 7, 36, 51, 153),
),
mime_type="application/pdf",
pk=2,
checksum="2",
)
self.assertEqual(generate_filename(doc), "89/Dec/December/The Title.pdf")
@override_settings(
FILENAME_FORMAT="{added_year_short}/{added_month_name}/{added_month_name_short}/{title}",
)
def test_short_names_added(self):
doc = Document.objects.create(
title="The Title",
added=timezone.make_aware(datetime.datetime(1984, 8, 21, 7, 36, 51, 153)),
mime_type="application/pdf",
pk=2,
checksum="2",
)
self.assertEqual(generate_filename(doc), "84/August/Aug/The Title.pdf")
def run(): def run():
doc = Document.objects.create( doc = Document.objects.create(

View File

@ -347,6 +347,13 @@ if os.getenv("PAPERLESS_DBHOST"):
if os.getenv("PAPERLESS_DBENGINE") == "mariadb": if os.getenv("PAPERLESS_DBENGINE") == "mariadb":
engine = "django.db.backends.mysql" engine = "django.db.backends.mysql"
options = {"read_default_file": "/etc/mysql/my.cnf", "charset": "utf8mb4"} options = {"read_default_file": "/etc/mysql/my.cnf", "charset": "utf8mb4"}
# Silence Django error on old MariaDB versions.
# VARCHAR can support > 255 in modern versions
# https://docs.djangoproject.com/en/4.1/ref/checks/#database
# https://mariadb.com/kb/en/innodb-system-variables/#innodb_large_prefix
SILENCED_SYSTEM_CHECKS = ["mysql.W003"]
else: # Default to PostgresDB else: # Default to PostgresDB
engine = "django.db.backends.postgresql_psycopg2" engine = "django.db.backends.postgresql_psycopg2"
options = {"sslmode": os.getenv("PAPERLESS_DBSSLMODE", "prefer")} options = {"sslmode": os.getenv("PAPERLESS_DBSSLMODE", "prefer")}

View File

@ -1,10 +1,11 @@
import datetime
import os import os
import time
from pathlib import Path from pathlib import Path
from typing import Final from typing import Final
import pytest import pytest
from django.test import TestCase from django.test import TestCase
from documents.parsers import ParseError
from paperless_tika.parsers import TikaDocumentParser from paperless_tika.parsers import TikaDocumentParser
@ -24,6 +25,44 @@ class TestTikaParserAgainstServer(TestCase):
def tearDown(self) -> None: def tearDown(self) -> None:
self.parser.cleanup() self.parser.cleanup()
def try_parse_with_wait(self, test_file, mime_type):
"""
For whatever reason, the image started during the test pipeline likes to
segfault sometimes, when run with the exact files that usually pass.
So, this function will retry the parsing up to 3 times, with larger backoff
periods between each attempt, in hopes the issue resolves itself during
one attempt to parse.
This will wait the following:
- Attempt 1 - 20s following failure
- Attempt 2 - 40s following failure
- Attempt 3 - 80s following failure
"""
succeeded = False
retry_time = 20.0
retry_count = 0
max_retry_count = 3
while retry_count < max_retry_count and not succeeded:
try:
self.parser.parse(test_file, mime_type)
succeeded = True
except Exception as e:
print(f"{e} during try #{retry_count}", flush=True)
retry_count = retry_count + 1
time.sleep(retry_time)
retry_time = retry_time * 2.0
self.assertTrue(
succeeded,
"Continued Tika server errors after multiple retries",
)
def test_basic_parse_odt(self): def test_basic_parse_odt(self):
""" """
GIVEN: GIVEN:
@ -36,7 +75,7 @@ class TestTikaParserAgainstServer(TestCase):
""" """
test_file = self.SAMPLE_DIR / Path("sample.odt") test_file = self.SAMPLE_DIR / Path("sample.odt")
self.parser.parse(test_file, "application/vnd.oasis.opendocument.text") self.try_parse_with_wait(test_file, "application/vnd.oasis.opendocument.text")
self.assertEqual( self.assertEqual(
self.parser.text, self.parser.text,
@ -62,7 +101,7 @@ class TestTikaParserAgainstServer(TestCase):
""" """
test_file = self.SAMPLE_DIR / Path("sample.docx") test_file = self.SAMPLE_DIR / Path("sample.docx")
self.parser.parse( self.try_parse_with_wait(
test_file, test_file,
"application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
) )