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.
"""
# Default to everything gets kept still
super().decide_what_tags_to_keep()
# Locate the feature branches
feature_branches = {}
for branch in self.branch_api.get_branches(
owner=self.repo_owner,
repo=self.repo_name,
):
if branch.name.startswith("feature-"):
@ -261,6 +263,10 @@ class MainImageTagsCleaner(RegistryTagsCleaner):
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-*
packages_tagged_feature: List[ContainerPackage] = []
for package in self.all_package_versions:

View File

@ -15,7 +15,7 @@ from typing import Dict
from typing import List
from typing import Optional
import requests
import httpx
logger = logging.getLogger("github-api")
@ -28,15 +28,15 @@ class _GithubApiBase:
def __init__(self, token: str) -> None:
self._token = token
self._session: Optional[requests.Session] = None
self._client: Optional[httpx.Client] = None
def __enter__(self) -> "_GithubApiBase":
"""
Sets up the required headers for auth and response
type from the API
"""
self._session = requests.Session()
self._session.headers.update(
self._client = httpx.Client()
self._client.headers.update(
{
"Accept": "application/vnd.github.v3+json",
"Authorization": f"token {self._token}",
@ -49,14 +49,14 @@ class _GithubApiBase:
Ensures the authorization token is cleaned up no matter
the reason for the exit
"""
if "Accept" in self._session.headers:
del self._session.headers["Accept"]
if "Authorization" in self._session.headers:
del self._session.headers["Authorization"]
if "Accept" in self._client.headers:
del self._client.headers["Accept"]
if "Authorization" in self._client.headers:
del self._client.headers["Authorization"]
# Close the session as well
self._session.close()
self._session = None
self._client.close()
self._client = None
def _read_all_pages(self, endpoint):
"""
@ -66,7 +66,7 @@ class _GithubApiBase:
internal_data = []
while True:
resp = self._session.get(endpoint)
resp = self._client.get(endpoint)
if resp.status_code == 200:
internal_data += resp.json()
if "next" in resp.links:
@ -76,7 +76,7 @@ class _GithubApiBase:
break
else:
logger.warning(f"Request to {endpoint} return HTTP {resp.status_code}")
break
resp.raise_for_status()
return internal_data
@ -113,14 +113,15 @@ class GithubBranchApi(_GithubApiBase):
def __init__(self, token: str) -> None:
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
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)
return [GithubBranch(branch) for branch in internal_data]
@ -247,7 +248,7 @@ class GithubContainerRegistryApi(_GithubApiBase):
"""
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:
logger.warning(
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,
)
resp = self._session.post(endpoint)
resp = self._client.post(endpoint)
if resp.status_code != 204:
logger.warning(
f"Request to delete {endpoint} returned HTTP {resp.status_code}",

View File

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

View File

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

View File

@ -50,6 +50,11 @@ jobs:
uses: actions/setup-python@v4
with:
python-version: "3.9"
-
name: Install jq
run: |
sudo apt-get update
sudo apt-get install jq
-
name: Setup qpdf image
id: qpdf-setup
@ -86,6 +91,18 @@ jobs:
echo ${build_json}
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:
@ -97,7 +114,11 @@ jobs:
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:
name: qpdf
@ -145,3 +166,5 @@ jobs:
REPO=${{ needs.prepare-docker-build.outputs.ghcr-repository }}
QPDF_VERSION=${{ fromJSON(needs.prepare-docker-build.outputs.qpdf-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"
djangorestframework = "~=3.13"
filelock = "*"
fuzzywuzzy = {extras = ["speedup"], version = "*"}
gunicorn = "*"
imap-tools = "*"
langdetect = "*"
pathvalidate = "*"
pillow = "~=9.2"
pillow = "~=9.3"
pikepdf = "*"
python-gnupg = "*"
python-dotenv = "*"
python-dateutil = "*"
python-magic = "*"
psycopg2 = "*"
rapidfuzz = "*"
redis = {extras = ["hiredis"], version = "*"}
scikit-learn = "~=1.1"
# 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": {
"hash": {
"sha256": "5558c489e948de1779e547beae0dd36a2e551aa6be8505c26b651fd87eac2834"
"sha256": "f8bdb4da9007a887c66a7e0243c486419676aa1a053c9a78e3760abb1f60e0a0"
},
"pipfile-spec": 6,
"requires": {},
@ -75,10 +75,10 @@
},
"automat": {
"hashes": [
"sha256:7979803c74610e11ef0c0d68a2942b152df52da55336e0c9d58daf1831cbdf33",
"sha256:b6feb6455337df834f6c9962d6ccf771515b7d939bca142b29c20c2376bc6111"
"sha256:c3164f8742b9dc440f3682482d32aaff7bb53f71740dd018533f9de286b64180",
"sha256:e56beb84edad19dcc11d30e8d9b895f75deeb5ef5e96b84a467066b3b84bb04e"
],
"version": "==20.2.0"
"version": "==22.10.0"
},
"backports.zoneinfo": {
"hashes": [
@ -109,14 +109,6 @@
],
"version": "==3.6.4.0"
},
"bleach": {
"hashes": [
"sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a",
"sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c"
],
"index": "pypi",
"version": "==5.0.1"
},
"celery": {
"extras": [
"redis"
@ -409,17 +401,6 @@
"index": "pypi",
"version": "==1.2.0"
},
"fuzzywuzzy": {
"extras": [
"speedup"
],
"hashes": [
"sha256:45016e92264780e58972dca1b3d939ac864b78437422beecebb3095f8efd00e8",
"sha256:928244b28db720d1e0ee7587acf660ea49d7e4c632569cad4f1cd7e68a5f0993"
],
"index": "pypi",
"version": "==0.18.0"
},
"gunicorn": {
"hashes": [
"sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e",
@ -630,114 +611,6 @@
"index": "pypi",
"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": {
"hashes": [
"sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318",
@ -1028,69 +901,68 @@
},
"pillow": {
"hashes": [
"sha256:0030fdbd926fb85844b8b92e2f9449ba89607231d3dd597a21ae72dc7fe26927",
"sha256:030e3460861488e249731c3e7ab59b07c7853838ff3b8e16aac9561bb345da14",
"sha256:0ed2c4ef2451de908c90436d6e8092e13a43992f1860275b4d8082667fbb2ffc",
"sha256:136659638f61a251e8ed3b331fc6ccd124590eeff539de57c5f80ef3a9594e58",
"sha256:13b725463f32df1bfeacbf3dd197fb358ae8ebcd8c5548faa75126ea425ccb60",
"sha256:1536ad017a9f789430fb6b8be8bf99d2f214c76502becc196c6f2d9a75b01b76",
"sha256:15928f824870535c85dbf949c09d6ae7d3d6ac2d6efec80f3227f73eefba741c",
"sha256:17d4cafe22f050b46d983b71c707162d63d796a1235cdf8b9d7a112e97b15bac",
"sha256:1802f34298f5ba11d55e5bb09c31997dc0c6aed919658dfdf0198a2fe75d5490",
"sha256:1cc1d2451e8a3b4bfdb9caf745b58e6c7a77d2e469159b0d527a4554d73694d1",
"sha256:1fd6f5e3c0e4697fa7eb45b6e93996299f3feee73a3175fa451f49a74d092b9f",
"sha256:254164c57bab4b459f14c64e93df11eff5ded575192c294a0c49270f22c5d93d",
"sha256:2ad0d4df0f5ef2247e27fc790d5c9b5a0af8ade9ba340db4a73bb1a4a3e5fb4f",
"sha256:2c58b24e3a63efd22554c676d81b0e57f80e0a7d3a5874a7e14ce90ec40d3069",
"sha256:2d33a11f601213dcd5718109c09a52c2a1c893e7461f0be2d6febc2879ec2402",
"sha256:336b9036127eab855beec9662ac3ea13a4544a523ae273cbf108b228ecac8437",
"sha256:337a74fd2f291c607d220c793a8135273c4c2ab001b03e601c36766005f36885",
"sha256:37ff6b522a26d0538b753f0b4e8e164fdada12db6c6f00f62145d732d8a3152e",
"sha256:3d1f14f5f691f55e1b47f824ca4fdcb4b19b4323fe43cc7bb105988cad7496be",
"sha256:408673ed75594933714482501fe97e055a42996087eeca7e5d06e33218d05aa8",
"sha256:4134d3f1ba5f15027ff5c04296f13328fecd46921424084516bdb1b2548e66ff",
"sha256:4ad2f835e0ad81d1689f1b7e3fbac7b01bb8777d5a985c8962bedee0cc6d43da",
"sha256:50dff9cc21826d2977ef2d2a205504034e3a4563ca6f5db739b0d1026658e004",
"sha256:510cef4a3f401c246cfd8227b300828715dd055463cdca6176c2e4036df8bd4f",
"sha256:5aed7dde98403cd91d86a1115c78d8145c83078e864c1de1064f52e6feb61b20",
"sha256:69bd1a15d7ba3694631e00df8de65a8cb031911ca11f44929c97fe05eb9b6c1d",
"sha256:6bf088c1ce160f50ea40764f825ec9b72ed9da25346216b91361eef8ad1b8f8c",
"sha256:6e8c66f70fb539301e064f6478d7453e820d8a2c631da948a23384865cd95544",
"sha256:727dd1389bc5cb9827cbd1f9d40d2c2a1a0c9b32dd2261db522d22a604a6eec9",
"sha256:74a04183e6e64930b667d321524e3c5361094bb4af9083db5c301db64cd341f3",
"sha256:75e636fd3e0fb872693f23ccb8a5ff2cd578801251f3a4f6854c6a5d437d3c04",
"sha256:7761afe0126d046974a01e030ae7529ed0ca6a196de3ec6937c11df0df1bc91c",
"sha256:7888310f6214f19ab2b6df90f3f06afa3df7ef7355fc025e78a3044737fab1f5",
"sha256:7b0554af24df2bf96618dac71ddada02420f946be943b181108cac55a7a2dcd4",
"sha256:7c7b502bc34f6e32ba022b4a209638f9e097d7a9098104ae420eb8186217ebbb",
"sha256:808add66ea764ed97d44dda1ac4f2cfec4c1867d9efb16a33d158be79f32b8a4",
"sha256:831e648102c82f152e14c1a0938689dbb22480c548c8d4b8b248b3e50967b88c",
"sha256:93689632949aff41199090eff5474f3990b6823404e45d66a5d44304e9cdc467",
"sha256:96b5e6874431df16aee0c1ba237574cb6dff1dcb173798faa6a9d8b399a05d0e",
"sha256:9a54614049a18a2d6fe156e68e188da02a046a4a93cf24f373bffd977e943421",
"sha256:a138441e95562b3c078746a22f8fca8ff1c22c014f856278bdbdd89ca36cff1b",
"sha256:a647c0d4478b995c5e54615a2e5360ccedd2f85e70ab57fbe817ca613d5e63b8",
"sha256:a9c9bc489f8ab30906d7a85afac4b4944a572a7432e00698a7239f44a44e6efb",
"sha256:ad2277b185ebce47a63f4dc6302e30f05762b688f8dc3de55dbae4651872cdf3",
"sha256:adabc0bce035467fb537ef3e5e74f2847c8af217ee0be0455d4fec8adc0462fc",
"sha256:b6d5e92df2b77665e07ddb2e4dbd6d644b78e4c0d2e9272a852627cdba0d75cf",
"sha256:bc431b065722a5ad1dfb4df354fb9333b7a582a5ee39a90e6ffff688d72f27a1",
"sha256:bdd0de2d64688ecae88dd8935012c4a72681e5df632af903a1dca8c5e7aa871a",
"sha256:c79698d4cd9318d9481d89a77e2d3fcaeff5486be641e60a4b49f3d2ecca4e28",
"sha256:cb6259196a589123d755380b65127ddc60f4c64b21fc3bb46ce3a6ea663659b0",
"sha256:d5b87da55a08acb586bad5c3aa3b86505f559b84f39035b233d5bf844b0834b1",
"sha256:dcd7b9c7139dc8258d164b55696ecd16c04607f1cc33ba7af86613881ffe4ac8",
"sha256:dfe4c1fedfde4e2fbc009d5ad420647f7730d719786388b7de0999bf32c0d9fd",
"sha256:ea98f633d45f7e815db648fd7ff0f19e328302ac36427343e4432c84432e7ff4",
"sha256:ec52c351b35ca269cb1f8069d610fc45c5bd38c3e91f9ab4cbbf0aebc136d9c8",
"sha256:eef7592281f7c174d3d6cbfbb7ee5984a671fcd77e3fc78e973d492e9bf0eb3f",
"sha256:f07f1f00e22b231dd3d9b9208692042e29792d6bd4f6639415d2f23158a80013",
"sha256:f3fac744f9b540148fa7715a435d2283b71f68bfb6d4aae24482a890aed18b59",
"sha256:fa768eff5f9f958270b081bb33581b4b569faabf8774726b283edb06617101dc",
"sha256:fac2d65901fb0fdf20363fbd345c01958a742f2dc62a8dd4495af66e3ff502a4"
"sha256:03150abd92771742d4a8cd6f2fa6246d847dcd2e332a18d0c15cc75bf6703040",
"sha256:073adb2ae23431d3b9bcbcff3fe698b62ed47211d0716b067385538a1b0f28b8",
"sha256:0b07fffc13f474264c336298d1b4ce01d9c5a011415b79d4ee5527bb69ae6f65",
"sha256:0b7257127d646ff8676ec8a15520013a698d1fdc48bc2a79ba4e53df792526f2",
"sha256:12ce4932caf2ddf3e41d17fc9c02d67126935a44b86df6a206cf0d7161548627",
"sha256:15c42fb9dea42465dfd902fb0ecf584b8848ceb28b41ee2b58f866411be33f07",
"sha256:18498994b29e1cf86d505edcb7edbe814d133d2232d256db8c7a8ceb34d18cef",
"sha256:1c7c8ae3864846fc95f4611c78129301e203aaa2af813b703c55d10cc1628535",
"sha256:22b012ea2d065fd163ca096f4e37e47cd8b59cf4b0fd47bfca6abb93df70b34c",
"sha256:276a5ca930c913f714e372b2591a22c4bd3b81a418c0f6635ba832daec1cbcfc",
"sha256:2e0918e03aa0c72ea56edbb00d4d664294815aa11291a11504a377ea018330d3",
"sha256:3033fbe1feb1b59394615a1cafaee85e49d01b51d54de0cbf6aa8e64182518a1",
"sha256:3168434d303babf495d4ba58fc22d6604f6e2afb97adc6a423e917dab828939c",
"sha256:3dd6caf940756101205dffc5367babf288a30043d35f80936f9bfb37f8355b32",
"sha256:40e1ce476a7804b0fb74bcfa80b0a2206ea6a882938eaba917f7a0f004b42502",
"sha256:41e0051336807468be450d52b8edd12ac60bebaa97fe10c8b660f116e50b30e4",
"sha256:4390e9ce199fc1951fcfa65795f239a8a4944117b5935a9317fb320e7767b40f",
"sha256:502526a2cbfa431d9fc2a079bdd9061a2397b842bb6bc4239bb176da00993812",
"sha256:51e0e543a33ed92db9f5ef69a0356e0b1a7a6b6a71b80df99f1d181ae5875636",
"sha256:57751894f6618fd4308ed8e0c36c333e2f5469744c34729a27532b3db106ee20",
"sha256:5d77adcd56a42d00cc1be30843d3426aa4e660cab4a61021dc84467123f7a00c",
"sha256:655a83b0058ba47c7c52e4e2df5ecf484c1b0b0349805896dd350cbc416bdd91",
"sha256:68943d632f1f9e3dce98908e873b3a090f6cba1cbb1b892a9e8d97c938871fbe",
"sha256:6c738585d7a9961d8c2821a1eb3dcb978d14e238be3d70f0a706f7fa9316946b",
"sha256:73bd195e43f3fadecfc50c682f5055ec32ee2c933243cafbfdec69ab1aa87cad",
"sha256:772a91fc0e03eaf922c63badeca75e91baa80fe2f5f87bdaed4280662aad25c9",
"sha256:77ec3e7be99629898c9a6d24a09de089fa5356ee408cdffffe62d67bb75fdd72",
"sha256:7db8b751ad307d7cf238f02101e8e36a128a6cb199326e867d1398067381bff4",
"sha256:801ec82e4188e935c7f5e22e006d01611d6b41661bba9fe45b60e7ac1a8f84de",
"sha256:82409ffe29d70fd733ff3c1025a602abb3e67405d41b9403b00b01debc4c9a29",
"sha256:828989c45c245518065a110434246c44a56a8b2b2f6347d1409c787e6e4651ee",
"sha256:829f97c8e258593b9daa80638aee3789b7df9da5cf1336035016d76f03b8860c",
"sha256:871b72c3643e516db4ecf20efe735deb27fe30ca17800e661d769faab45a18d7",
"sha256:89dca0ce00a2b49024df6325925555d406b14aa3efc2f752dbb5940c52c56b11",
"sha256:90fb88843d3902fe7c9586d439d1e8c05258f41da473952aa8b328d8b907498c",
"sha256:97aabc5c50312afa5e0a2b07c17d4ac5e865b250986f8afe2b02d772567a380c",
"sha256:9aaa107275d8527e9d6e7670b64aabaaa36e5b6bd71a1015ddd21da0d4e06448",
"sha256:9f47eabcd2ded7698106b05c2c338672d16a6f2a485e74481f524e2a23c2794b",
"sha256:a0a06a052c5f37b4ed81c613a455a81f9a3a69429b4fd7bb913c3fa98abefc20",
"sha256:ab388aaa3f6ce52ac1cb8e122c4bd46657c15905904b3120a6248b5b8b0bc228",
"sha256:ad58d27a5b0262c0c19b47d54c5802db9b34d38bbf886665b626aff83c74bacd",
"sha256:ae5331c23ce118c53b172fa64a4c037eb83c9165aba3a7ba9ddd3ec9fa64a699",
"sha256:af0372acb5d3598f36ec0914deed2a63f6bcdb7b606da04dc19a88d31bf0c05b",
"sha256:afa4107d1b306cdf8953edde0534562607fe8811b6c4d9a486298ad31de733b2",
"sha256:b03ae6f1a1878233ac620c98f3459f79fd77c7e3c2b20d460284e1fb370557d4",
"sha256:b0915e734b33a474d76c28e07292f196cdf2a590a0d25bcc06e64e545f2d146c",
"sha256:b4012d06c846dc2b80651b120e2cdd787b013deb39c09f407727ba90015c684f",
"sha256:b472b5ea442148d1c3e2209f20f1e0bb0eb556538690fa70b5e1f79fa0ba8dc2",
"sha256:b59430236b8e58840a0dfb4099a0e8717ffb779c952426a69ae435ca1f57210c",
"sha256:b90f7616ea170e92820775ed47e136208e04c967271c9ef615b6fbd08d9af0e3",
"sha256:b9a65733d103311331875c1dca05cb4606997fd33d6acfed695b1232ba1df193",
"sha256:bac18ab8d2d1e6b4ce25e3424f709aceef668347db8637c2296bcf41acb7cf48",
"sha256:bca31dd6014cb8b0b2db1e46081b0ca7d936f856da3b39744aef499db5d84d02",
"sha256:be55f8457cd1eac957af0c3f5ece7bc3f033f89b114ef30f710882717670b2a8",
"sha256:c7025dce65566eb6e89f56c9509d4f628fddcedb131d9465cacd3d8bac337e7e",
"sha256:c935a22a557a560108d780f9a0fc426dd7459940dc54faa49d83249c8d3e760f",
"sha256:dbb8e7f2abee51cef77673be97760abff1674ed32847ce04b4af90f610144c7b",
"sha256:ebf2029c1f464c59b8bdbe5143c79fa2045a581ac53679733d3a91d400ff9efb",
"sha256:f1ff2ee69f10f13a9596480335f406dd1f70c3650349e2be67ca3139280cade0"
],
"index": "pypi",
"version": "==9.2.0"
"version": "==9.3.0"
},
"pluggy": {
"hashes": [
@ -1223,13 +1095,6 @@
"index": "pypi",
"version": "==0.5.0"
},
"python-levenshtein": {
"hashes": [
"sha256:88a58b95e3340a918489dac0c78f731323c0a4d8f5564f839ffea80155574e77",
"sha256:9228af5523f797f0798f045dc4a95ed1f46df72bc2186e52b530a33998a51b37"
],
"version": "==0.20.7"
},
"python-magic": {
"hashes": [
"sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b",
@ -1240,10 +1105,10 @@
},
"pytz": {
"hashes": [
"sha256:335ab46900b1465e714b4fda4963d87363264eb662aab5e65da039c25f1f5b22",
"sha256:c4d88f472f54d615e9cd582a5004d1e5f624854a6a27a6211591c251f22a6914"
"sha256:222439474e9c98fced559f1709d89e6c9cbf8d79c794ff3eb9f8800064291427",
"sha256:e89512406b793ca39f5971bc999cc538ce125c0e51c27941bef4568b460095e2"
],
"version": "==2022.5"
"version": "==2022.6"
},
"pytz-deprecation-shim": {
"hashes": [
@ -1309,111 +1174,98 @@
},
"rapidfuzz": {
"hashes": [
"sha256:036f904bcac16d726273eee7ec0636978af31d151f30c95b611240e22592ab79",
"sha256:0429a7a51d1372afaca969ee3170f9975f2fe6e187b485aeef55d3e8d7d934e0",
"sha256:09de4fd3dbcc73f61b85af006372f48fee7d4324de227702b9da0d2572445d26",
"sha256:0c8a5e65cab629ca5bb4b1d2b410f8444384b60364ab528508200acfdf9e659d",
"sha256:0e64ab58b19866ad3df53e651a429871d744f8794cca25c553396b25d679a1ac",
"sha256:0f09ff49b28e557615a9ad4d5eedbfd5b886fccb3ec35d85dd34c51348c4bf98",
"sha256:12e14b0c43e3bc0c679ef09bfcbcaf9397534e03b8854c417086779a79e08bb2",
"sha256:134a467692216e05a8806efe40e3bcae9aa81b9e051b209a4244b639a168c78e",
"sha256:13ce1019ddce7419502fac43b62ac166d3d6d290b727050e3de5bda79a6beb59",
"sha256:16a2edf3ea888c9d3582761a2bbaa734e03f6db25d96e73edd4dcef6883897ee",
"sha256:17ba5fb474515356608cdb8d750f95c12f3e4dc9a0e2c9d7caca3d4cee55048e",
"sha256:2183fc91971c0853f6170225577d24d81b865d416104b433de53e55a6d2a476a",
"sha256:24569412e1aac1ac008548cdcd40da771e14467f4bacab9f9abfe5bbb5dfe8be",
"sha256:254d5a800de54c416fa9b220e442a4861b272c1223139ae3dee0aea1c9f27c9c",
"sha256:2bc3ec87df5eaad59e6e02e6517047fb268a48866f3531c4b8b59c2c78069fe5",
"sha256:2d3652804ae17920eaa965b1e057ee0ea32d5bb02f50147c82a1d350a86fc3f1",
"sha256:30773e23bebe27ddcf7644d6ebb143bf7c9adeb18019a963172174ef522c0831",
"sha256:3b6573607568438dfc3d4341b0b00d326ac2cf86281df97e7f8c0348e2f89b5e",
"sha256:3d50a2ca8cd1cea13afd2ff8e052ba49860c64cc3e617398670fd6a8d11e450f",
"sha256:3f1c030e2d61d77cb14814640618e29cf13e4554340a3baa9191d162a4dfcd9e",
"sha256:40e8d37d67a6e4713ddb6053eb3007a3ca15eddd23f2e4a5039c39e666c10b3a",
"sha256:41c9e2acfa25c7667b70913d63887f76e981badc1e95a2878257d28b96f5a10c",
"sha256:42d18db6f7e1e6ef85a8e673b2fa3352727cc56e60e48e7c9268fe0286ab9f91",
"sha256:475aacad5d5c4f9ad920b4232cc196d79a1777fe1eada9122103c30154d18af4",
"sha256:47e163d6a6676be9a3a7e93d5a2c3c65a43c1530b680903ebdba951e07ee7999",
"sha256:5080ad715e39b8a2d82339cf4170785e9092c7625ec2095ff3590fdb0a532a41",
"sha256:52639268dffc8900892a5e57964228fb187512b0f249de9a45ba37c6f2bc52a5",
"sha256:54264d70af59224d6874fcc5828da50d99668055574fe254849cab96f3b80e43",
"sha256:553e8e3dce321ed33e8b437586e7765d78e6d8fbb236b02768b46e1b2b91b41e",
"sha256:56aa67bf938e8dcc5e940f183538f09041441f1c4c5a86abe748416950db9d27",
"sha256:578934d7524f8378175295e6411b737d35d393d91d4661c739daa8ea2b185836",
"sha256:588dd5f520683af53a9d9d0cabde0987788c0ea9adfda3b058a9c27f448b2b3f",
"sha256:5aff0ac1723f7c8d751869a51e6b12d703fd6e6153228d68d8773f19bd5bd968",
"sha256:5e3164736ed071dc743994b9228ead52b63010aba24b1621de81b3ac39d490b9",
"sha256:5e89f50f5f3be2b851e9714015e1a26c6546e6b42f3df69b86200af8eacf9d8c",
"sha256:61152fa1e3df04b4e748f09338f36ca32f7953829f4e630d26f7f564f4cb527b",
"sha256:64133c9f45cb88b508d52427339b796c76e1790300c7ea4d2ed210f224e0698d",
"sha256:65b8611c9f5385a2986e11e85137cdecf40610e5d5f250d96a9ed32b7e995c4a",
"sha256:6803ef01f4056d61120e37acba8953e6b3149363e85caaba40ee8d49753fe7bd",
"sha256:68d46ad148c9cb8be532b5dd7bc246b067e81d4cfabad19b4cb6ac4031cab124",
"sha256:6b12420d5b769cd7e1478a8085aeea1ad0ffc8f7fedc86c48b8d598e1602f5ad",
"sha256:705ccd8de2b7b5295c6a230a3919fc9db8da9d2a6347c15c871fcb2202abd237",
"sha256:7478341137e65a0227fda4f3e39b3d50e6ec7dd4f767077dd435b412c2f2c129",
"sha256:769cf4099f53507231ba04cbf9ee16bea3c193767efc9bdf5e6c59e67e6b5cea",
"sha256:7750b950a6987bce114b9f36413399712422f4f49b2ad43f4b4ee3af34968b99",
"sha256:7c457f779992a0f5527455cdc17c387268ae9f712d4e29d691704c83c6e58c2d",
"sha256:7dd6a439fb09dc9ba463de3f5c8e20f097225816b33a66380b68c8561a08045c",
"sha256:804c7c67dc316f77b01b9bef5e75f727b73ff1015ff0514972b59dc05eec4d81",
"sha256:86038b9777b2aa0ebf8c586b81cba166ccde7e6d744aad576cd98c1a07be4c53",
"sha256:86c34175830cacac1c16d2182a0f725afbd40042955b7572c8475e3b6a5d8ada",
"sha256:8a11b70ebb2d7317d69bdb1f692a0eda292a4cddfe9ccb760a8d1a9e763811dd",
"sha256:8b402e99593483a8b05a09fb2a20379ecaa9b0d1f1cf32957b42134bd3305731",
"sha256:8b480a78227457a0b65e0b23afbda9c152dee4e1b41ccc058db8c41ea7a82ab0",
"sha256:8bc00bd6b6407dc7a8eb31964bcc38862c25e7f5f5982f912f265eb3c4d83140",
"sha256:8d6fa1d009fcb9a9169548c29d65a1f05c0fcf1ac966f40e35035307d6a17050",
"sha256:9081542fea2baeebda8caa43a54ecd8a152a05ff3271c38ac8eae447377cef54",
"sha256:931a939ba5e5574f769507038fdf400dbbc46aab2866d4e5e96d83a29f081712",
"sha256:984d40ecda0bc0109c4239d782dfe87362d02b286548672f8a2468eabbf48a69",
"sha256:9924497dec6a30b5158ef7cc9c60a87c6c46d9f7b7bb7254d4f157b57b531fb8",
"sha256:a48ff6b6258a32f50f876a6c74fa2f506c1de3b11773d6bf31b6715255807a48",
"sha256:a7f5a77466c4701062469bce29358ca0797db2bc6d8f6c3cd4e13f418cca10bc",
"sha256:a98c63d1f5ec2c15adf5dc81c461c8d88c16395956f4518b78e2e04b3285b1e5",
"sha256:adc7c6cb3dde5c284d84c7c6f4602b1545ba89c6ebb857b337d0428befb344e5",
"sha256:b4f577ded3e40695d5e0796e8b7f4fa78577d873627e0d0692f7060ad73af314",
"sha256:b5c7b0a4929bfd3945d9c2022cff0b683a39accf5594897fa9004cee4f402b06",
"sha256:b5cd1ea9fa396243d34f7bac5bb5787f89310f13fd2b092d11940c6cd7bd0bd8",
"sha256:bafd18a27dbe3197e460809468a7c47d9d29d1ebab6a878d5bb5a71fda2056d6",
"sha256:bd595bd23a4e1c72d5f5ac416ea49b9a3d87e11fb2db4b960378038ce9bb12f7",
"sha256:bd7a1992e91c90197c34ccc674bd64262262627083c99896b79e2c9f5fe28075",
"sha256:bd8f36d8bd399c7d695182e467b4428adb940a157014ab605bbe4d0ab0a1976e",
"sha256:bf5277ff74c9980245697ea227057d0f05b31c96bc73bae2697c1a48d4980e45",
"sha256:bfabc6130752f4f77584b2ecbba2adf6fe469b06c52cb974ba8304f1f63bb24f",
"sha256:c10724490b87fcb86161e5ceb17893626d13363e31efee77aa8e251ee16dcdd5",
"sha256:c1477455b82d6db7336ef769f507a55bba9fe9f1c96dc531d7c2c510630307d6",
"sha256:c288e239fc3aaae3865e43e1f35b606f92ee687a0801e4d46c45d7849aebbe35",
"sha256:c305ea5405f8615e6ecd39cb28acc7a362713ba3c17c7737b591b377d1afd9ec",
"sha256:c77cec595dc80f97a1b32413fb1b618e4da8ba132697e075ad8e4025c4058575",
"sha256:c822853e9d54979eb5fcf9e54c1f90e5c18eeb399571383ac768cff47d6d6ada",
"sha256:cad5088f1adb9161f2def653908328cfa1dc9bc57e7e41ccdc9339d31cc576d1",
"sha256:cc3103e31d27352afe4c5a71702e09185850187d299145d5e98f9fb99a3be498",
"sha256:ced719fcae6f2a348ac596b67f6d7c26ff3d9d2b7378237953ac5e162d8a4e2e",
"sha256:d181889218d80f6beb5ae3838bc23e201d2a1fae688baaa40d82ef9080594315",
"sha256:d1d8192820d8489a8e3ef160cbe38f5ff974db5263c76438cf44e7574743353b",
"sha256:d24181dfdfcc3d9b37333fea2f5bf9f51e034bd9e0ba67a871f18686b797c739",
"sha256:d51b9183ebce60d4795ceaef24b8db2df3ed04307ee787d6adafcc196330a47c",
"sha256:dad6697c6b9e02dd45f73e22646913daad743afd27dadb0b6a430a1573fb4566",
"sha256:dafe8c6e74fea0fdcfec002bc77aee40b4891b14ea513e6092402609ac8dac00",
"sha256:dc0f695b32700b14f404cccaebc25eea6db323418385568297995aee8b5278f8",
"sha256:e2fe220d4b100b00734d9388e33296ac8f585c763548c372ca17b24affa178e0",
"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"
"sha256:028aa9edfa044629a0a9e924a168a01f61c8f570c9ea919e2ed214826ba1cdfb",
"sha256:02a5c8b780af49a4e5f08033450d3f7c696f6c04e57c67ecbb19c9944ea3ce20",
"sha256:07c623741958dd49d8c2c51f7c2e62472f41b8d795cc9c734e441e30de3f8330",
"sha256:0ae8c0c2f51f618d54579341c44ba198849d9cd845bb0dc85d1711fd8de9a159",
"sha256:129c93a76c4fed176b4eaaf78fecd290932971bca10315dee9feaf94a7b443b1",
"sha256:13ad87a539b13794292fb661b8c4f4c19e6c066400d9db991e3a1441f55fc29b",
"sha256:16426b441d28efb3b1fe10f2b81aa469020655cef068a32de6ec24433590ee5b",
"sha256:1a600b037a56a61111c01809b5e4c4b5aac12edf2769c094fefab02d496a95a4",
"sha256:1e0f6f878c20454a7e7ea2ed30970ae0334852c5e422e7014757821fa33c1588",
"sha256:20f2f0f0746ffc165168ca160c5b1a1485076bdde5b656cf3dbe532ef2ac57ff",
"sha256:2207927f42ae7b7fbcc1a4ff86f202647776200f3d8723603e7acf96af924e9f",
"sha256:22487992f4811c8aef449736f483514f0294d5593f5f9c95cbfb2474dbc363b9",
"sha256:22646f54d44d98d6f462fb3f1ac997ea53aaebdd1344039e8f75090f43e47a89",
"sha256:22e8b127abcf0b10ebf8a9b3351c3c980e5c27cb60a865632d90d6a698060a9a",
"sha256:238fddfb90fab858ced88d064608bff9aed83cec11a7630a4e95b7e49734d8b1",
"sha256:241912c4f7f232c7518384f8cea719cf2ff290f80735355a217e9c690d274f62",
"sha256:25db060ba8082c38f75da482ff15d3b60a4bc59f158b6d29a2c5bccadd2b71b0",
"sha256:2676f7ccd22a67638baff054a8e13924f20d87efb3a873f6ea248a395a80e2c8",
"sha256:27fa0e7d5e5291dc3e48c6512524f2f8e7ba3d397fa712a85a97639e3d6597e9",
"sha256:2c2cd1e01e8aef2bd1b5152e66e0b865f31eb2d00a8d28cbbbb802f42e2dbe43",
"sha256:2e9709a163ec3b890f9a4173261e9ef586046feee74bbece62595bf103421178",
"sha256:2fda8c003d9ae4f3674c783887b31ecb76f4ab58670a8f01b93efd0917c1e503",
"sha256:33cfd01cb7f8a48c8e057198e3814a120323c0360017dd5c4eba07d097b43b39",
"sha256:35737fd5766ca212d98e0598fb4d302f509e1cbf7b6dc42e2eddefd956150815",
"sha256:35b34f33a9f0a86fdba39053b203d8d517da76f3553230a55867c51f0d802b67",
"sha256:3abe9c25f9ba260a6828d24002a15112c5f21c6877c5f8c294ffe4b9d197c6d2",
"sha256:3c7f3c61e2d1530cf7e1647bdbb466f0f83fa30d2c579b6d75e444f88ff47913",
"sha256:3e8707e98b645f80834e24103e7cd67f1b772999bb979da6d61ca1fcdc07672a",
"sha256:3eae4c6880dbabee9f363950510c09d7e12dea8dbc6ebcd2ff58e594a78d9370",
"sha256:3f7b798807ac9c5f632e8f359adf1393f81d9211e4961eedb5e2d4ce311e0078",
"sha256:43398361d54fed476ccfdb52dc34d88c64461f0ec35f8abf10dd0413a3f19d8c",
"sha256:4581600ded8f37e8387d0eef93520fb33dafab6ccb37d005e20d05cd3fbdd9db",
"sha256:45def44f1140c6f5c7a5389645d02e8011d27a6e64f529f33cee687e7c25af07",
"sha256:475a551c43ba23b4ca328c9bbcae39205729f4751280eb9763da08d97d328953",
"sha256:4787d8e9f4b184d383ad000cdd48330ae75ec927c5832067a6b3617c5f6fb677",
"sha256:48539221026b0a84b6d2c2665c3dde784e3c0fac28975658c03fed352f8e1d7e",
"sha256:4f3f0ddfe3176e19c0a3cf6ad29e9ff216ff5fdec035b001ebabad91ef155107",
"sha256:4fc958b21416825c599e228278c69efb480169cd99d1a21787a54f53fbff026c",
"sha256:589464c49a332c644b750f2ebc3737d444427669323ace623bd4948e414a641a",
"sha256:5c6a9ada752149e23051852867596b35afc79015760e23676ac287bcad58e0b6",
"sha256:5dcd7bd175d870338fc9ae43d0184ecd45958f5ca2ee7ea0a7953eedc4d9718e",
"sha256:5e2c0a5a0346ce95a965ed6fa941edcf129cac22bf63314b684a3fe64078c95b",
"sha256:5fa88543c5744d725fc989afd79926c226e1c5f5c00904834851997f367da2b5",
"sha256:626eaa1b52a9dafa9bf377bcdcfdf1ea867dd51b5bb5dab1a05938c3303f317f",
"sha256:651664023726f28f7447e40fa2b8a015514f9db4b58654e9bf7d3729e2606eab",
"sha256:74f821370ac01f677b5a26e0606084f2eb671f7bb4f3e2e82d94a100b1c28457",
"sha256:7a67d93fd2e6e5a4e278eade2bbef16ba88d4efcb4eed106f075b0b21427a92f",
"sha256:7e34c996cc245a21f376c3b8eede1296339845f039c8c270297a455d3a1ad71b",
"sha256:7f2db0c684d9999c81084aa370e2e6b266b694e76c7e356bbeb3b282ca524475",
"sha256:7febf074f7de7ebc374100be0036fc592659af911b6efbc1135cdebfe939c57d",
"sha256:800b1498989bfb64118b219eeb42957b3d93ec7d6955dfc742a3cbf3be738f2f",
"sha256:8eadfb5394ab5b9c6e3d4bb00ef49e19f60a4e431190c103e647d4e4bff3332e",
"sha256:917e3e2ffc0e078cce4a632f65d32a339f18cad22b5536a32c641bf1900e7f96",
"sha256:96fe7da85d8721c3a5c362f6b1e7fd26ad74a76bebc369fb7ae62907cf069940",
"sha256:9836bea98f25a67c296f57cf6de420c88f46e430ee85d25ae5f397968c7adcdf",
"sha256:9c8295dd49582dfb6a29e5f9dfa1691a0edd2e0512377ceb2c8dd11e7fabd38a",
"sha256:9ceb8d6f1bd18a058cb8472c6e8cc84802413a65b029a7832589ba7b76c0eb11",
"sha256:9e239e404dbb9fec308409e174710b5e53ff8bd9647e8875e2ca245b1f762f89",
"sha256:9f849d4889a0f1bc2260b981b1ae8393938e8a2c92666e1757e69f947c6ce868",
"sha256:a6d78f967b7b162013fc85821a74cc7cd021fbf045f166629c9bd523799d8e51",
"sha256:a8d5787f5c52c00991032b976b69f5c1e181a3bddce76fd43c91b2c4901c96ce",
"sha256:a9a90ab26b12218d10d5f148e84e8facd62f562bc25d32e2c3cf3c743f7e0e67",
"sha256:ac6ce417174a086a496aefc7caa614640dc33d418a922ee0a184b093d84f2f6c",
"sha256:ac95a2ca4add04f349f8f5c05269d8b194a72ebdfc4f86a725c15d79a420d429",
"sha256:ad279e4892652583671a7ece977dd9b1eb17ae9752fbc9013c950095b044a315",
"sha256:ad5935f4a0ec3a2c3d19021fcd27addce4892ae00f71cc4180009bc4bed930ac",
"sha256:ae0519d01a05c6204c2d27ae49b2231787d9a6efc801d5dbf131b20065fd21e3",
"sha256:b1114da71974c86e64a98afff8d88cf3a3351b289d07f0218e67d56b506cb9e2",
"sha256:b2b81c6cb59b955b82a4853e3fbef7231da87c5522a69daaf9b01bd81d137ec3",
"sha256:b63402c5af2ad744c2c1ab2e7265eb317e75257fd27eb6f087fea76464b065db",
"sha256:b75fe7abf55e7da6d32174b5ac207a465d1bc69d777049c277776472c0b7d82c",
"sha256:c0006c6450d02efdfef8d3f81e6a87790572486046676fe29f4c5da8708ea11b",
"sha256:c1191a1c9f24134c6048770aabaa2f7def8d6d4c919da857d5e7dabdf63308f2",
"sha256:c43579c7a64f21c9b4d4c3106ace46a8ebfb8e704372e6c8cc45807d1b86462f",
"sha256:c62472a70c7f22f1ae9864c02554dbc234a1dfbac24388542bf87437a4169379",
"sha256:c6c4064b2324b86f7a035379928fe1f3aca4ca5ba75ebedc9ea0d821b0e05606",
"sha256:c6fa81c8d3c901d9f174482185f23b02052e71da015da3a613be98f28fd2672b",
"sha256:c74b960a1b93ac22e6cbf268ce509fb2c2338a29180c3d844df4a57bfff73273",
"sha256:c9c2b3b00033afdb745cc77b8c2ed858b08bb9a773c9a81a1160ece59a361545",
"sha256:c9fdbe8b1b32a731ee48a21a161358e55067c9cabd36ba0b8d844e5106056920",
"sha256:d0fc1e32353afef426488d2e19cd295f1f504323215275ec0871bdae2b052a70",
"sha256:d5b65d9f2860210087739adadc075bd9215b363d00c3c8e68369560683a4c3df",
"sha256:d6e6972c5bd1ee4f532029616dfe0f5133f7cc688ebc05dbbc03e19b4ec12199",
"sha256:e333bb6a69c515a1fce149002aaf7d8902fddab54db14fe14c89c6da402410d2",
"sha256:ef812c73fff460678defaab3a95ec9b7551ef14d424eb6af7b75e376050119d2",
"sha256:f030223aa618a48d2f8339fd674c4c03db88649313e2c65107e9c04e09edc7f2",
"sha256:f371453d0c1109e93ef569741a27171e602ef1fbea5c27a8f190f403234fd36b",
"sha256:f74636ca4a3ce700f4fe2dbe10d224ee4fb52ecab12ea3007a2bc2fcd0d53888",
"sha256:f96973d42caf0e4566882b6e7acbba753199d7acb4db486f14ab553c7b395cd5"
],
"markers": "python_version >= '3.6'",
"version": "==2.11.1"
"index": "pypi",
"version": "==2.12.0"
},
"redis": {
"extras": [
@ -1508,45 +1360,54 @@
},
"reportlab": {
"hashes": [
"sha256:03501aa3cffb93ec35ca01d66a70d38090e88080b16eb4efb015a0fdc94a48c9",
"sha256:04fc4420f0548815d0623e031c86a1f7f3f3003e699d9af7148742e2d72b024a",
"sha256:06a9a9b04083529e4204e0c0f4574b7795cc8364a49e66dac25d94588fdaf24a",
"sha256:32b3e10acdbbd2b91a8bb94134ed011af8e5c32ef5fe69f5481f83bbc89fd40e",
"sha256:384e51906d710cec7721ee4f074bc59131dbed9ef3b8e45408432caa752c1d5d",
"sha256:3e53e8222afc535cfdad3d73786c570ec6567b48e3e09bfadca606b170f3f46d",
"sha256:456b9e245dacfa0f676f2864b8981a61bb50aa3fe690fe54885dc41b2b2b402c",
"sha256:4c183a28a44bc03c0ab825fceab4a07a8b36d7f67a208dcf9e561dc4e343aec9",
"sha256:4e97028ea070199955cb50dd1e321177f7fd2fefe89fb328d016e510d60bfc9e",
"sha256:5104000c1f84066c452022316faecb7382eae23a878547cacfa6511f9fddfe02",
"sha256:55df316e227f876e88ba5979c2456e3be47988056e0053d1139f9fbaff968d24",
"sha256:60bcdefa9246e9dd26708d53fe4a51dcef74f9a387b8daa557804adf856a4fd5",
"sha256:689ecf2eea098afb4bba39c97994c6e9ab65a1cf8e5ca7f897942f8692af9932",
"sha256:68d118d8f4dabfde284237901a24b22e7827695cc74c8184b57828eb10e28090",
"sha256:74ca4e4221bb68403753a595a9d24899b2a559d42fd573d00d8884e6a54d0ba1",
"sha256:89c9ba175f72a2fd91836c414a09f91459f2e53b648f69300de6f8e0709a2de2",
"sha256:89f486c48a06655a7aec92b593be60f70d4cfed0b205038acc0c3263df3d8b4a",
"sha256:8e4d4133a2be465aae0826ae8e11319e6411e3119d16b4d6f40079fa89835c43",
"sha256:93864be3ae1dabfa66607734113cc08ac9f839e2b49632df60ede1f0893864ee",
"sha256:a62a856d5c6168f07d2c18e725f577bda5d4bbd4bf535d5c7c99d03b335effe1",
"sha256:a71f6f231e94f2e543a255aa98bf8db2936f7b132be456c70ccf3c98cd60c160",
"sha256:abb5d98541fc89c0d94627d82c83bdd464120c3422333e0f9f37a236ca1c44c8",
"sha256:ad2d649197971c52a8c074739b3aae3cf3db99971561a371a54d429c19a49050",
"sha256:b36e27adeb36fcf2854f8d9951e5e99fa655b4f03d2d15ba321bae42d65e2535",
"sha256:b5f30124b0f5dab69fa56d12b94a50656f030e547bb09ab03936fd8708f04afc",
"sha256:b6450ebf6fbbe826dd4e4837e7cc906a256e1383883ef21a143a5d39c7ce35cc",
"sha256:b6d8979e7769cb860dfffd8d1c303501fea4820f592b5e6836cba1b64aa82f10",
"sha256:c3988595e57c114c2cc93dd21b08f917c3d868bf57fd52bbb20008e3c26f023e",
"sha256:c3a4bdb586e6649bd2b7d452b79c09a819bcb848ac408f1f4b00155c91469ffd",
"sha256:c3d774f1d522579398ebfb5ad9129cc4a409c35a14f412e1ae20c0a7d42561f0",
"sha256:c894990d87b0c8eae1f60a747c5180f9abcc525f1c71435cbdcb1f5ee420d675",
"sha256:ca40c72a6c07ebd35a1b85d8cb3069b43587a589fe2ff2d16e33ea53b1ffe40f",
"sha256:cf0e362917ca2c00627828fce077fe364b7e0f70e795fb98e97c8befe8f96289",
"sha256:ea3dc427b6be0eb0966732e9e30bccec1c8b395aba0484430bc72d811a9e84ea",
"sha256:f73970f8c4ccb2c32cf350f1b86171af27ed7df79dc0cc529875bc40610b6bbd",
"sha256:fe5c2fcbe8f130c8913dad56d2513afb809491ad8a17b5c49b3951cfa070d4a3"
"sha256:07fdd968df7941c2bfb67b9bb4532f424992dfafc71b72a4e4b291ff707e6b0e",
"sha256:090ea99ff829d918f7b6140594373b1340a34e1e6876eddae5aa06662ec10d64",
"sha256:109009b02fc225882ea766a5ed8be0ef473fa1356e252a3f651a6aa89b4a195f",
"sha256:1dd0307b2b13b0482ac8314fd793fbbce263a428b189371addf0466784e1d597",
"sha256:236a6483210049205f6180d7a7595d0ca2e4ce343d83cc94ca719a4145809c6f",
"sha256:26c25ea4afa8b92a2c14f4edc41c8fc30505745ce84cae86538e80cacadd7ae2",
"sha256:2a0bc7a1d64fe754b62e175ba0cf47a630b529c0488ec9ac4e4c7655e295ea4d",
"sha256:2c9b0861d8f40d7a24b094b8834f6a489b9e8c70bceaa7fa98237eed229671ce",
"sha256:39e92fa4ab2a8f0f2cc051d9c1e3acb881340c07ef59c0c8b627861343d653c0",
"sha256:3a62e51a4a47616896bd0f1e9cc3fbfb174b713794a5031a34b84f69dbe01775",
"sha256:3fd1ffdd5204301eb4c290a5752ac62f44d2d0b262e02e35a1e5234c13e14662",
"sha256:498b4ec7e73426de64c6bf6ec03c5b3f10dedf5db8a9e13fdf195f95a3d065aa",
"sha256:4c599645af9b5b2241a23e977a82c965a59c24cd94b2600b8d34373c66cad763",
"sha256:4fa3cdf490f3828b055381e8c7dc7819b3e5f7a442d7af7a8f90e9806a7fff51",
"sha256:55a070206580e161b6bbe1a96abf816c18d4c2c225d49916654714c93d842835",
"sha256:666bdba4958b348460a765c48b8c0640e7085540846ed9494f47d8651604b33c",
"sha256:69f41295d696c822224334f0994f1f107df7efed72211d45a1118696f1427c84",
"sha256:6dfcf7bd6db5d80711cbbd0996b6e7a79cc414ca81457960367df11d2860f92a",
"sha256:71cf73f9907c444ef663ea653dbac24af07c307079572c3ff8f20ad1463af3b7",
"sha256:72ec333f089b4fce5a6d740ed0a1963a3994146be195722da0d8e14d4a7e1600",
"sha256:759495c2b8c15cb0d6b539c246896029e4cde42a896c3956f77e311c5f6b0807",
"sha256:7a7c3369fa618eca79f9554ce06c618a5e738e592d61d96aa09b2457ca3ea410",
"sha256:8b1215facead57cc5325aef4229ef886e85d270b2ba02080fb5809ce9d2b81b4",
"sha256:907f7cd4832bb295d0c1573de15cc5aab5988282caf2ee7a2b1276fb6cdf502b",
"sha256:93e229519d046491b798f2c12dbbf2f3e237e89589aa5cbb5e1d8c1a978816db",
"sha256:a12049314497d872f6788f811e2b331654db207937f8a2fb34ff3e3cd9897faa",
"sha256:a8dddc52e0e486291be0ad39184da0607fae9cc665fdba1881211de9cfc0b332",
"sha256:adf78ccb2defad5b6ecb2e2e9f2a672719b0a8e2278592a7d77f6c220a042388",
"sha256:b13cebf4e397bba14542bcd023338b6ff2c151a3a12aabca89eecbf972cb361a",
"sha256:b3648f3c340b6b6aabf9352341478c708cee6f00c5cd5c902311fcf4ce870f3c",
"sha256:b6a1b685da0b9a8000bb980e02d9d5be202d0cc539af113b661c76c051fca6f1",
"sha256:b777ddc57b2d3366cbc540616034cdc1089ca0a31fefc907028e1dd62a6bf16c",
"sha256:bb83df8f7840321d34cb5b24c972c617a8c1716c8a36e5050fff56adf5891b8c",
"sha256:c07ec796a2a5d44bf787f2b623b6e668a389b0cafb78af34cf74554ff3bc532b",
"sha256:c40e108072379ff83dd7442159ebc249d12eb8eec15b70614953fecd2c403792",
"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'",
"version": "==3.6.11"
"version": "==3.6.12"
},
"requests": {
"hashes": [
@ -1558,27 +1419,30 @@
},
"scikit-learn": {
"hashes": [
"sha256:1c8fecb7c9984d9ec2ea48898229f98aad681a0873e0935f2b7f724fbce4a047",
"sha256:2b8db962360c93554cab7bb3c096c4a24695da394dd4b3c3f13409f409b425bc",
"sha256:2f46c6e3ff1054a5ec701646dcfd61d43b8ecac4d416014daed8843cf4c33d4d",
"sha256:3e7d1fc817867a350133f937aaebcafbc06192517cbdf0cf7e5774ad4d1adb9f",
"sha256:407e9a1cb9e6ba458a539986a9bd25546a757088095b3aab91d465b79a760d37",
"sha256:567417dbbe6a6278399c3e6daf1654414a5a1a4d818d28f251fa7fc28730a1bf",
"sha256:589d46f28460469f444b898223b13d99db9463e1038dc581ba698111f612264b",
"sha256:5ec3ea40d467966821843210c02117d82b097b54276fdcfb50f4dfb5c60dbe39",
"sha256:6c840f662b5d3377c4ccb8be1fc21bb52cb5d8b8790f8d6bf021739f84e543cf",
"sha256:76800652fb6d6bf527bce36ecc2cc25738b28fe1a17bd294a218fff8e8bd6d50",
"sha256:7c22d1305b16f08d57751a4ea36071e2215efb4c09cb79183faa4e8e82a3dbf8",
"sha256:a682ec0f82b6f30fb07486daed1c8001b6683cc66b51877644dfc532bece6a18",
"sha256:a90ca42fe8242fd6ff56cda2fecc5fca586a88a24ab602d275d2d0dcc0b928fb",
"sha256:b1e706deca9b2ad87ae27dafd5ac4e8eff01b6db492ed5c12cef4735ec5f21ea",
"sha256:bbef6ea1c012ff9f3e6f6e9ca006b8772d8383e177b898091e68fbd9b3f840f9",
"sha256:c33e16e9a165af6012f5be530ccfbb672e2bc5f9b840238a05eb7f6694304e3f",
"sha256:d6f232779023c3b060b80b5c82e5823723bc424dcac1d1a148aa2492c54d245d",
"sha256:f94c0146bad51daef919c402a3da8c1c6162619653e1c00c92baa168fda292f2"
"sha256:23fb9e74b813cc2528b5167d82ed08950b11106ccf50297161875e45152fb311",
"sha256:250da993701da88bf475e7c5746abf1285ea0ae47e4d0917cd13afd6600bb162",
"sha256:28b2bd6a1419acd522ff45d282c8ba23dbccb5338802ab0ee12baa4ade0aba4c",
"sha256:2ee2c649f2231b68511aabb0dc827edd8936aad682acc6263c34aed11bc95dac",
"sha256:30e27721adc308e8fd9f419f43068e43490005f911edf4476a9e585059fa8a83",
"sha256:38814f66285318f2e241305cca545eaa9b4126c65aa5dd78c69371f235f78e2b",
"sha256:4d3a19166d4e1cdfcab975c68f471e046ce01e74c42a9a33fa89a14c2fcedf60",
"sha256:5699cded6c0685426433c7e5afe0fecad80ec831ec7fa264940e50c796775cc5",
"sha256:6785b8a3093329bf90ac01801be5525551728ae73edb11baa175df660820add4",
"sha256:6d1c1394e38a3319ace620381f6f23cc807d8780e9915c152449a86fc8f1db21",
"sha256:701181792a28c82fecae12adb5d15d0ecf57bffab7cf4bdbb52c7b3fd428d540",
"sha256:748f2bd632d6993e8918d43f1a26c380aeda4e122a88840d4c3a9af99d4239fe",
"sha256:8e9dd76c7274055d1acf4526b8efb16a3531c26dcda714a0c16da99bf9d41900",
"sha256:bef51978a51ec19977700fe7b86aecea49c825884f3811756b74a3b152bb4e35",
"sha256:cd55c6fbef7608dbce1f22baf289dfcc6eb323247daa3c3542f73d389c724786",
"sha256:da5a2e95fef9805b1750e4abda4e834bf8835d26fc709a391543b53feee7bd0e",
"sha256:ee47f68d973cee7009f06edb956f2f5588a0f230f24a2a70175fd0ecf36e2653",
"sha256:f4931f2a6c06e02c6c17a05f8ae397e2545965bc7a0a6cb38c8cd7d4fba8624d",
"sha256:f5644663987ee221f5d1f47a593271b966c271c236fe05634e6bdc06041b5a2b",
"sha256:f5d4231af7199531e77da1b78a4cc6b3d960a00b1ec672578ac818aae2b9c35d",
"sha256:fd3ee69d36d42a7dcbb17e355a5653af5fd241a7dfd9133080b3dde8d9e2aafb"
],
"index": "pypi",
"version": "==1.1.2"
"version": "==1.1.3"
},
"scipy": {
"hashes": [
@ -1759,11 +1623,11 @@
"tls"
],
"hashes": [
"sha256:8d4718d1e48dcc28933f8beb48dc71cfe77a125e37ad1eb7a3d0acc49baf6c99",
"sha256:e5b60de39f2d1da153fbe1874d885fe3fcbdb21fcc446fa759a53e8fc3513bed"
"sha256:32acbd40a94f5f46e7b42c109bfae2b302250945561783a8b7a059048f2d4d31",
"sha256:86c55f712cc5ab6f6d64e02503352464f0400f66d4f079096d744080afcccbd0"
],
"markers": "python_full_version >= '3.7.1'",
"version": "==22.8.0"
"version": "==22.10.0"
},
"txaio": {
"hashes": [
@ -1778,16 +1642,16 @@
"sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa",
"sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"
],
"markers": "python_version < '3.10'",
"markers": "python_version >= '3.7'",
"version": "==4.4.0"
},
"tzdata": {
"hashes": [
"sha256:323161b22b7802fdc78f20ca5f6073639c64f1a7227c40cd3e19fd1d0ce6650a",
"sha256:e15b2b3005e2546108af42a0eb4ccab4d9e225e2dfbf4f77aad50c70a4b1f3ab"
"sha256:04a680bdc5b15750c39c12a448885a51134a27ec9af83667663f0b3a1bf3f342",
"sha256:91f11db4503385928c15598c98573e3af07e7229181bee5375bd30f1695ddcae"
],
"markers": "python_version >= '3.6'",
"version": "==2022.5"
"version": "==2022.6"
},
"tzlocal": {
"hashes": [
@ -1920,65 +1784,79 @@
],
"version": "==0.2.5"
},
"webencodings": {
"hashes": [
"sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
"sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
],
"version": "==0.5.1"
},
"websockets": {
"hashes": [
"sha256:07cdc0a5b2549bcfbadb585ad8471ebdc7bdf91e32e34ae3889001c1c106a6af",
"sha256:210aad7fdd381c52e58777560860c7e6110b6174488ef1d4b681c08b68bf7f8c",
"sha256:28dd20b938a57c3124028680dc1600c197294da5db4292c76a0b48efb3ed7f76",
"sha256:2f94fa3ae454a63ea3a19f73b95deeebc9f02ba2d5617ca16f0bbdae375cda47",
"sha256:31564a67c3e4005f27815634343df688b25705cccb22bc1db621c781ddc64c69",
"sha256:347974105bbd4ea068106ec65e8e8ebd86f28c19e529d115d89bd8cc5cda3079",
"sha256:379e03422178436af4f3abe0aa8f401aa77ae2487843738542a75faf44a31f0c",
"sha256:3eda1cb7e9da1b22588cefff09f0951771d6ee9fa8dbe66f5ae04cc5f26b2b55",
"sha256:51695d3b199cd03098ae5b42833006a0f43dc5418d3102972addc593a783bc02",
"sha256:54c000abeaff6d8771a4e2cef40900919908ea7b6b6a30eae72752607c6db559",
"sha256:5b936bf552e4f6357f5727579072ff1e1324717902127ffe60c92d29b67b7be3",
"sha256:6075fd24df23133c1b078e08a9b04a3bc40b31a8def4ee0b9f2c8865acce913e",
"sha256:661f641b44ed315556a2fa630239adfd77bd1b11cb0b9d96ed8ad90b0b1e4978",
"sha256:6ea6b300a6bdd782e49922d690e11c3669828fe36fc2471408c58b93b5535a98",
"sha256:6ed1d6f791eabfd9808afea1e068f5e59418e55721db8b7f3bfc39dc831c42ae",
"sha256:7934e055fd5cd9dee60f11d16c8d79c4567315824bacb1246d0208a47eca9755",
"sha256:7ab36e17af592eec5747c68ef2722a74c1a4a70f3772bc661079baf4ae30e40d",
"sha256:7f6d96fdb0975044fdd7953b35d003b03f9e2bcf85f2d2cf86285ece53e9f991",
"sha256:83e5ca0d5b743cde3d29fda74ccab37bdd0911f25bd4cdf09ff8b51b7b4f2fa1",
"sha256:85506b3328a9e083cc0a0fb3ba27e33c8db78341b3eb12eb72e8afd166c36680",
"sha256:8af75085b4bc0b5c40c4a3c0e113fa95e84c60f4ed6786cbb675aeb1ee128247",
"sha256:8b1359aba0ff810d5830d5ab8e2c4a02bebf98a60aa0124fb29aa78cfdb8031f",
"sha256:8fbd7d77f8aba46d43245e86dd91a8970eac4fb74c473f8e30e9c07581f852b2",
"sha256:907e8247480f287aa9bbc9391bd6de23c906d48af54c8c421df84655eef66af7",
"sha256:93d5ea0b5da8d66d868b32c614d2b52d14304444e39e13a59566d4acb8d6e2e4",
"sha256:97bc9d41e69a7521a358f9b8e44871f6cdeb42af31815c17aed36372d4eec667",
"sha256:994cdb1942a7a4c2e10098d9162948c9e7b235df755de91ca33f6e0481366fdb",
"sha256:a141de3d5a92188234afa61653ed0bbd2dde46ad47b15c3042ffb89548e77094",
"sha256:a1e15b230c3613e8ea82c9fc6941b2093e8eb939dd794c02754d33980ba81e36",
"sha256:aad5e300ab32036eb3fdc350ad30877210e2f51bceaca83fb7fef4d2b6c72b79",
"sha256:b529fdfa881b69fe563dbd98acce84f3e5a67df13de415e143ef053ff006d500",
"sha256:b9c77f0d1436ea4b4dc089ed8335fa141e6a251a92f75f675056dac4ab47a71e",
"sha256:bb621ec2dbbbe8df78a27dbd9dd7919f9b7d32a73fafcb4d9252fc4637343582",
"sha256:c7250848ce69559756ad0086a37b82c986cd33c2d344ab87fea596c5ac6d9442",
"sha256:c8d1d14aa0f600b5be363077b621b1b4d1eb3fbf90af83f9281cda668e6ff7fd",
"sha256:d1655a6fc7aecd333b079d00fb3c8132d18988e47f19740c69303bf02e9883c6",
"sha256:d6353ba89cfc657a3f5beabb3b69be226adbb5c6c7a66398e17809b0ce3c4731",
"sha256:da4377904a3379f0c1b75a965fff23b28315bcd516d27f99a803720dfebd94d4",
"sha256:e49ea4c1a9543d2bd8a747ff24411509c29e4bdcde05b5b0895e2120cb1a761d",
"sha256:e4e08305bfd76ba8edab08dcc6496f40674f44eb9d5e23153efa0a35750337e8",
"sha256:e6fa05a680e35d0fcc1470cb070b10e6fe247af54768f488ed93542e71339d6f",
"sha256:e7e6f2d6fd48422071cc8a6f8542016f350b79cc782752de531577d35e9bd677",
"sha256:e904c0381c014b914136c492c8fa711ca4cced4e9b3d110e5e7d436d0fc289e8",
"sha256:ec2b0ab7edc8cd4b0eb428b38ed89079bdc20c6bdb5f889d353011038caac2f9",
"sha256:ef5ce841e102278c1c2e98f043db99d6755b1c58bde475516aef3a008ed7f28e",
"sha256:f351c7d7d92f67c0609329ab2735eee0426a03022771b00102816a72715bb00b",
"sha256:fab7c640815812ed5f10fbee7abbf58788d602046b7bb3af9b1ac753a6d5e916",
"sha256:fc06cc8073c8e87072138ba1e431300e2d408f054b27047d047b549455066ff4"
"sha256:00213676a2e46b6ebf6045bc11d0f529d9120baa6f58d122b4021ad92adabd41",
"sha256:00c870522cdb69cd625b93f002961ffb0c095394f06ba8c48f17eef7c1541f96",
"sha256:0154f7691e4fe6c2b2bc275b5701e8b158dae92a1ab229e2b940efe11905dff4",
"sha256:05a7233089f8bd355e8cbe127c2e8ca0b4ea55467861906b80d2ebc7db4d6b72",
"sha256:09a1814bb15eff7069e51fed0826df0bc0702652b5cb8f87697d469d79c23576",
"sha256:0cff816f51fb33c26d6e2b16b5c7d48eaa31dae5488ace6aae468b361f422b63",
"sha256:185929b4808b36a79c65b7865783b87b6841e852ef5407a2fb0c03381092fa3b",
"sha256:2fc8709c00704194213d45e455adc106ff9e87658297f72d544220e32029cd3d",
"sha256:33d69ca7612f0ddff3316b0c7b33ca180d464ecac2d115805c044bf0a3b0d032",
"sha256:389f8dbb5c489e305fb113ca1b6bdcdaa130923f77485db5b189de343a179393",
"sha256:38ea7b82bfcae927eeffc55d2ffa31665dc7fec7b8dc654506b8e5a518eb4d50",
"sha256:3d3cac3e32b2c8414f4f87c1b2ab686fa6284a980ba283617404377cd448f631",
"sha256:40e826de3085721dabc7cf9bfd41682dadc02286d8cf149b3ad05bff89311e4f",
"sha256:4239b6027e3d66a89446908ff3027d2737afc1a375f8fd3eea630a4842ec9a0c",
"sha256:45ec8e75b7dbc9539cbfafa570742fe4f676eb8b0d3694b67dabe2f2ceed8aa6",
"sha256:47a2964021f2110116cc1125b3e6d87ab5ad16dea161949e7244ec583b905bb4",
"sha256:48c08473563323f9c9debac781ecf66f94ad5a3680a38fe84dee5388cf5acaf6",
"sha256:4c6d2264f485f0b53adf22697ac11e261ce84805c232ed5dbe6b1bcb84b00ff0",
"sha256:4f72e5cd0f18f262f5da20efa9e241699e0cf3a766317a17392550c9ad7b37d8",
"sha256:56029457f219ade1f2fc12a6504ea61e14ee227a815531f9738e41203a429112",
"sha256:5c1289596042fad2cdceb05e1ebf7aadf9995c928e0da2b7a4e99494953b1b94",
"sha256:62e627f6b6d4aed919a2052efc408da7a545c606268d5ab5bfab4432734b82b4",
"sha256:74de2b894b47f1d21cbd0b37a5e2b2392ad95d17ae983e64727e18eb281fe7cb",
"sha256:7c584f366f46ba667cfa66020344886cf47088e79c9b9d39c84ce9ea98aaa331",
"sha256:7d27a7e34c313b3a7f91adcd05134315002aaf8540d7b4f90336beafaea6217c",
"sha256:7d3f0b61c45c3fa9a349cf484962c559a8a1d80dae6977276df8fd1fa5e3cb8c",
"sha256:82ff5e1cae4e855147fd57a2863376ed7454134c2bf49ec604dfe71e446e2193",
"sha256:84bc2a7d075f32f6ed98652db3a680a17a4edb21ca7f80fe42e38753a58ee02b",
"sha256:884be66c76a444c59f801ac13f40c76f176f1bfa815ef5b8ed44321e74f1600b",
"sha256:8a5cc00546e0a701da4639aa0bbcb0ae2bb678c87f46da01ac2d789e1f2d2038",
"sha256:8dc96f64ae43dde92530775e9cb169979f414dcf5cff670455d81a6823b42089",
"sha256:8f38706e0b15d3c20ef6259fd4bc1700cd133b06c3c1bb108ffe3f8947be15fa",
"sha256:90fcf8929836d4a0e964d799a58823547df5a5e9afa83081761630553be731f9",
"sha256:931c039af54fc195fe6ad536fde4b0de04da9d5916e78e55405436348cfb0e56",
"sha256:932af322458da7e4e35df32f050389e13d3d96b09d274b22a7aa1808f292fee4",
"sha256:942de28af58f352a6f588bc72490ae0f4ccd6dfc2bd3de5945b882a078e4e179",
"sha256:9bc42e8402dc5e9905fb8b9649f57efcb2056693b7e88faa8fb029256ba9c68c",
"sha256:a7a240d7a74bf8d5cb3bfe6be7f21697a28ec4b1a437607bae08ac7acf5b4882",
"sha256:a9f9a735deaf9a0cadc2d8c50d1a5bcdbae8b6e539c6e08237bc4082d7c13f28",
"sha256:ae5e95cfb53ab1da62185e23b3130e11d64431179debac6dc3c6acf08760e9b1",
"sha256:b029fb2032ae4724d8ae8d4f6b363f2cc39e4c7b12454df8df7f0f563ed3e61a",
"sha256:b0d15c968ea7a65211e084f523151dbf8ae44634de03c801b8bd070b74e85033",
"sha256:b343f521b047493dc4022dd338fc6db9d9282658862756b4f6fd0e996c1380e1",
"sha256:b627c266f295de9dea86bd1112ed3d5fafb69a348af30a2422e16590a8ecba13",
"sha256:b9968694c5f467bf67ef97ae7ad4d56d14be2751000c1207d31bf3bb8860bae8",
"sha256:ba089c499e1f4155d2a3c2a05d2878a3428cf321c848f2b5a45ce55f0d7d310c",
"sha256:bbccd847aa0c3a69b5f691a84d2341a4f8a629c6922558f2a70611305f902d74",
"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": {
"hashes": [
@ -2137,11 +2015,11 @@
},
"babel": {
"hashes": [
"sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51",
"sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb"
"sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe",
"sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6"
],
"markers": "python_version >= '3.6'",
"version": "==2.10.3"
"version": "==2.11.0"
},
"black": {
"hashes": [
@ -2204,11 +2082,11 @@
},
"colorama": {
"hashes": [
"sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da",
"sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"
"sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44",
"sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==0.4.5"
"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.6"
},
"coverage": {
"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'",
"version": "==0.17.1"
},
"exceptiongroup": {
"hashes": [
"sha256:2ac84b496be68464a2da60da518af3785fff8b7ec0d090a581604bc870bdee41",
"sha256:affbabf13fb6e98988c38d9c5650e701569fe3c1de3233cfb61c5f33774690ad"
],
"markers": "python_version < '3.11'",
"version": "==1.0.0"
},
"execnet": {
"hashes": [
"sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5",
@ -2332,11 +2218,11 @@
},
"identify": {
"hashes": [
"sha256:6c32dbd747aa4ceee1df33f25fed0b0f6e0d65721b15bd151307ff7056d50245",
"sha256:b276db7ec52d7e89f5bc4653380e33054ddc803d25875952ad90b0f012cbcdaa"
"sha256:48b7925fe122720088aeb7a6c34f17b27e706b72c61070f27fe3789094233440",
"sha256:7a214a10313b9489a0d61467db2856ae8d0b8306fc923e03a9effa53d8aedc58"
],
"markers": "python_version >= '3.7'",
"version": "==2.5.6"
"version": "==2.5.8"
},
"idna": {
"hashes": [
@ -2354,14 +2240,6 @@
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.4.1"
},
"importlib-metadata": {
"hashes": [
"sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab",
"sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"
],
"markers": "python_version < '3.10'",
"version": "==5.0.0"
},
"iniconfig": {
"hashes": [
"sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3",
@ -2550,11 +2428,11 @@
},
"pytest": {
"hashes": [
"sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7",
"sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"
"sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71",
"sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"
],
"index": "pypi",
"version": "==7.1.3"
"version": "==7.2.0"
},
"pytest-cov": {
"hashes": [
@ -2614,10 +2492,10 @@
},
"pytz": {
"hashes": [
"sha256:335ab46900b1465e714b4fda4963d87363264eb662aab5e65da039c25f1f5b22",
"sha256:c4d88f472f54d615e9cd582a5004d1e5f624854a6a27a6211591c251f22a6914"
"sha256:222439474e9c98fced559f1709d89e6c9cbf8d79c794ff3eb9f8800064291427",
"sha256:e89512406b793ca39f5971bc999cc538ce125c0e51c27941bef4568b460095e2"
],
"version": "==2022.5"
"version": "==2022.6"
},
"pyyaml": {
"hashes": [
@ -2769,11 +2647,11 @@
},
"termcolor": {
"hashes": [
"sha256:6b2cf769e93364a2676e1de56a7c0cff2cf5bd07f37e9cc80b0dd6320ebfe388",
"sha256:7e597f9de8e001a3208c4132938597413b9da45382b6f1d150cff8d062b7aaa3"
"sha256:91dd04fdf661b89d7169cefd35f609b19ca931eb033687eaa647cef1ff177c49",
"sha256:b80df54667ce4f48c03fe35df194f052dc27a541ebbf2544e4d6b47b5d6949c4"
],
"markers": "python_version >= '3.7'",
"version": "==2.0.1"
"version": "==2.1.0"
},
"toml": {
"hashes": [
@ -2788,7 +2666,7 @@
"sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
"sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"
],
"markers": "python_version >= '3.7'",
"markers": "python_version < '3.11'",
"version": "==2.0.1"
},
"tornado": {
@ -2810,18 +2688,18 @@
},
"tox": {
"hashes": [
"sha256:44f3c347c68c2c68799d7d44f1808f9d396fc8a1a500cbc624253375c7ae107e",
"sha256:bf037662d7c740d15c9924ba23bb3e587df20598697bb985ac2b49bdc2d847f6"
"sha256:89e4bc6df3854e9fc5582462e328dd3660d7d865ba625ae5881bbc63836a6324",
"sha256:d2c945f02a03d4501374a3d5430877380deb69b218b1df9b7f1d2f2a10befaf9"
],
"index": "pypi",
"version": "==3.26.0"
"version": "==3.27.0"
},
"typing-extensions": {
"hashes": [
"sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa",
"sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"
],
"markers": "python_version < '3.10'",
"markers": "python_version >= '3.7'",
"version": "==4.4.0"
},
"urllib3": {
@ -2834,19 +2712,11 @@
},
"virtualenv": {
"hashes": [
"sha256:227ea1b9994fdc5ea31977ba3383ef296d7472ea85be9d6732e42a91c04e80da",
"sha256:d07dfc5df5e4e0dbc92862350ad87a36ed505b978f6c39609dc489eadd5b0d27"
"sha256:186ca84254abcbde98180fd17092f9628c5fe742273c02724972a1d8a2035108",
"sha256:530b850b523c6449406dfba859d6345e48ef19b8439606c5d74d7d3c9e14d76e"
],
"markers": "python_version >= '3.6'",
"version": "==20.16.5"
},
"zipp": {
"hashes": [
"sha256:4fcb6f278987a6605757302a6e40e896257570d11c51628968ccb2a47e80c6c1",
"sha256:7a7262fd930bd3e36c50b9a64897aec3fafff3dfdeec9623ae22b40e93f99bb8"
],
"markers": "python_version < '3.9'",
"version": "==3.10.0"
"version": "==20.16.6"
}
}
}

View File

@ -23,6 +23,8 @@ fi
# Parse what we can from Pipfile.lock
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')
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
qpdf_version=$(jq ".qpdf.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 QPDF_VERSION="${qpdf_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}" .

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 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="\
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.
* ``{title}``: The title of the document.
* ``{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_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).
* ``{added}``: The full date (ISO format) the document was added to paperless.
* ``{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_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).

View File

@ -464,7 +464,7 @@
</context-group>
<context-group purpose="location">
<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 purpose="location">
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
@ -727,14 +727,14 @@
<source>Confirmation</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="9178182467454450952" datatype="html">
<source>Confirm</source>
<context-group purpose="location">
<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 purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@ -757,53 +757,53 @@
<source>After</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="8700121026680200191" datatype="html">
<source>Clear</source>
<context-group purpose="location">
<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 purpose="location">
<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>
</trans-unit>
<trans-unit id="1218334388194408974" datatype="html">
<source>Before</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="4873149362496451858" datatype="html">
<source>Last 7 days</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="4463380307954693363" datatype="html">
<source>Last month</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="8697368973702409683" datatype="html">
<source>Last 3 months</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="3566342898065860218" datatype="html">
<source>Last year</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="8953033926734869941" datatype="html">
@ -1240,7 +1240,7 @@
</context-group>
<context-group purpose="location">
<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 purpose="location">
<context context-type="sourcefile">src/app/components/manage/tasks/tasks.component.html</context>
@ -1284,7 +1284,7 @@
</context-group>
<context-group purpose="location">
<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 purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
@ -1311,11 +1311,11 @@
</context-group>
<context-group purpose="location">
<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 purpose="location">
<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 purpose="location">
<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="linenumber">43</context>
</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 id="4452427314943113135" datatype="html">
<source>Previous</source>
@ -1657,7 +1661,7 @@
</context-group>
<context-group purpose="location">
<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 purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
@ -1680,7 +1684,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">140</context>
<context context-type="linenumber">145</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
@ -1703,7 +1707,7 @@
</context-group>
<context-group purpose="location">
<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 purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
@ -2235,7 +2239,7 @@
</context-group>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="2784168796433474565" datatype="html">
@ -2246,7 +2250,7 @@
</context-group>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="7585826646011739428" datatype="html">
@ -2307,7 +2311,7 @@
</context-group>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="157572966557284263" datatype="html">
@ -2318,7 +2322,7 @@
</context-group>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="3727324658595204357" datatype="html">
@ -2421,60 +2425,60 @@
<source>Views</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="1233494216161906927" datatype="html">
<source>Save &quot;<x id="INTERPOLATION" equiv-text="{{list.activeSavedViewTitle}}"/>&quot;</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="2276119452079372898" datatype="html">
<source>Save as...</source>
<context-group purpose="location">
<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>
</trans-unit>
<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>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="6600548268163632449" datatype="html">
<source>{VAR_PLURAL, plural, =1 {One document} other {<x id="INTERPOLATION"/> documents}}</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="2243770355958919528" datatype="html">
<source>(filtered)</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="1559883523769732271" datatype="html">
<source>Error while loading documents</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="7517688192215738656" datatype="html">
<source>ASN</source>
<context-group purpose="location">
<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 purpose="location">
<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 purpose="location">
<context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
@ -2485,11 +2489,11 @@
<source>Added</source>
<context-group purpose="location">
<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 purpose="location">
<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 purpose="location">
<context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
@ -2500,140 +2504,140 @@
<source>Edit document</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="2155249406916744630" datatype="html">
<source>View &quot;<x id="PH" equiv-text="this.list.activeSavedViewTitle"/>&quot; saved successfully.</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="6837554170707123455" datatype="html">
<source>View &quot;<x id="PH" equiv-text="savedView.name"/>&quot; created successfully.</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="6849725902312323996" datatype="html">
<source>Reset filters</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="5195932016807797291" datatype="html">
<source>Correspondent: <x id="PH" equiv-text="this.correspondents.find((c) =&gt; c.id == +rule.value)?.name"/></source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="8170755470576301659" datatype="html">
<source>Without correspondent</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="8705701325879965907" datatype="html">
<source>Type: <x id="PH" equiv-text="this.documentTypes.find((dt) =&gt; dt.id == +rule.value)?.name"/></source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="4362173610367509215" datatype="html">
<source>Without document type</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="8180755793012580465" datatype="html">
<source>Tag: <x id="PH" equiv-text="this.tags.find((t) =&gt; t.id == +rule.value)?.name"/></source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="6494566478302448576" datatype="html">
<source>Without any tag</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="6523384805359286307" datatype="html">
<source>Title: <x id="PH" equiv-text="rule.value"/></source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="1872523635812236432" datatype="html">
<source>ASN: <x id="PH" equiv-text="rule.value"/></source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="3100631071441658964" datatype="html">
<source>Title &amp; content</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="1010505078885609376" datatype="html">
<source>Advanced search</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="2649431021108393503" datatype="html">
<source>More like</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="3697582909018473071" datatype="html">
<source>equals</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="5325481293405718739" datatype="html">
<source>is empty</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="6166785695326182482" datatype="html">
<source>is not empty</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="4686622206659266699" datatype="html">
<source>greater than</source>
<context-group purpose="location">
<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>
</trans-unit>
<trans-unit id="8014012170270529279" datatype="html">
<source>less than</source>
<context-group purpose="location">
<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>
</trans-unit>
<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="linenumber">18</context>
</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 context-type="sourcefile">src/app/services/open-documents.service.ts</context>
<context context-type="linenumber">116</context>
@ -3507,6 +3515,27 @@
<context context-type="linenumber">22</context>
</context-group>
</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">
<source>(no title)</source>
<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,
"dependencies": {
"@angular/common": "~14.2.4",
"@angular/compiler": "~14.2.4",
"@angular/core": "~14.2.4",
"@angular/forms": "~14.2.4",
"@angular/localize": "~14.2.4",
"@angular/platform-browser": "~14.2.4",
"@angular/platform-browser-dynamic": "~14.2.4",
"@angular/router": "~14.2.4",
"@angular/common": "~14.2.8",
"@angular/compiler": "~14.2.8",
"@angular/core": "~14.2.8",
"@angular/forms": "~14.2.8",
"@angular/localize": "~14.2.8",
"@angular/platform-browser": "~14.2.8",
"@angular/platform-browser-dynamic": "~14.2.8",
"@angular/router": "~14.2.8",
"@ng-bootstrap/ng-bootstrap": "^13.0.0",
"@ng-select/ng-select": "^9.0.2",
"@ngneat/dirty-check-forms": "^3.0.2",
@ -31,7 +31,7 @@
"ngx-color": "^8.0.3",
"ngx-cookie-service": "^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",
"tslib": "^2.3.1",
"uuid": "^9.0.0",
@ -39,15 +39,15 @@
},
"devDependencies": {
"@angular-builders/jest": "14.0.1",
"@angular-devkit/build-angular": "~14.2.4",
"@angular/cli": "~14.2.4",
"@angular/compiler-cli": "~14.2.4",
"@angular-devkit/build-angular": "~14.2.7",
"@angular/cli": "~14.2.7",
"@angular/compiler-cli": "~14.2.8",
"@types/jest": "28.1.6",
"@types/node": "^18.7.23",
"codelyzer": "^6.0.2",
"concurrently": "7.4.0",
"jest": "28.1.3",
"jest-environment-jsdom": "^29.1.2",
"jest-environment-jsdom": "^29.2.2",
"jest-preset-angular": "^12.2.2",
"ts-node": "~10.9.1",
"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 { TasksComponent } from './components/manage/tasks/tasks.component'
import { DirtyDocGuard } from './guards/dirty-doc.guard'
import { DirtySavedViewGuard } from './guards/dirty-saved-view.guard'
const routes: Routes = [
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
@ -24,8 +25,16 @@ const routes: Routes = [
canDeactivate: [DirtyDocGuard],
children: [
{ 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: 'asn/:id', component: DocumentAsnComponent },
{ 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 { DocumentTypeEditDialogComponent } from './components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.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 { AppFrameComponent } from './components/app-frame/app-frame.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 { DocumentCommentsComponent } from './components/document-comments/document-comments.component'
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 { StoragePathEditDialogComponent } from './components/common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component'
import { SettingsService } from './services/settings.service'
@ -141,6 +143,7 @@ function initializeApp(settings: SettingsService) {
DocumentTypeEditDialogComponent,
StoragePathEditDialogComponent,
TagComponent,
ClearableBadge,
PageHeaderComponent,
AppFrameComponent,
ToastsComponent,
@ -215,6 +218,7 @@ function initializeApp(settings: SettingsService) {
{ provide: NgbDateAdapter, useClass: ISODateAdapter },
{ provide: NgbDateParserFormatter, useClass: LocalizedDateParserFormatter },
DirtyDocGuard,
DirtySavedViewGuard,
],
bootstrap: [AppComponent],
})

View File

@ -16,7 +16,12 @@
<use xlink:href="assets/bootstrap-icons.svg#search"/>
</svg>
<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>
</div>
<ul ngbNav class="order-sm-3">

View File

@ -243,17 +243,18 @@ main {
form {
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 {
svg {
form > svg {
display: none;
}

View File

@ -93,6 +93,20 @@ export class AppFrameComponent implements OnInit, ComponentCanDeactivate {
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[] {
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>
<span class="visually-hidden">{{ seconds | number: '1.0-0' }} seconds</span>
</button>
<button *ngIf="alternativeBtnCaption" type="button" class="btn" [class]="alternativeBtnClass" (click)="alternative()" [disabled]="!alternativeButtonEnabled || !buttonsEnabled">
{{alternativeBtnCaption}}
</button>
</div>

View File

@ -13,6 +13,9 @@ export class ConfirmDialogComponent {
@Output()
public confirmClicked = new EventEmitter()
@Output()
public alternativeClicked = new EventEmitter()
@Input()
title = $localize`Confirmation`
@ -28,14 +31,22 @@ export class ConfirmDialogComponent {
@Input()
btnCaption = $localize`Confirm`
@Input()
alternativeBtnClass = 'btn-secondary'
@Input()
alternativeBtnCaption
@Input()
buttonsEnabled = true
confirmButtonEnabled = true
alternativeButtonEnabled = true
seconds = 0
secondsTotal = 0
confirmSubject: Subject<boolean>
alternativeSubject: Subject<boolean>
delayConfirm(seconds: number) {
const refreshInterval = 0.15 // s
@ -68,4 +79,10 @@ export class ConfirmDialogComponent {
this.confirmSubject?.next(true)
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">
<button class="btn btn-sm" id="dropdown{{title}}" ngbDropdownToggle [ngClass]="dateBefore || dateAfter ? 'btn-primary' : 'btn-outline-primary'">
{{title}}
<app-clearable-badge [selected]="isActive" (cleared)="reset()"></app-clearable-badge><span class="visually-hidden">selected</span>
</button>
<div class="dropdown-menu date-dropdown shadow pt-0" ngbDropdownMenu attr.aria-labelledby="dropdown{{title}}">
<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)">
{{qf.name}}
<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)">
<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>
<div class="list-group-item d-flex flex-column align-items-start" role="menuitem">

View File

@ -5,3 +5,8 @@
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 {
before?: string
after?: string
relativeDateID?: number
}
const LAST_7_DAYS = 0
const LAST_MONTH = 1
const LAST_3_MONTHS = 2
const LAST_YEAR = 3
export enum RelativeDate {
LAST_7_DAYS = 0,
LAST_MONTH = 1,
LAST_3_MONTHS = 2,
LAST_YEAR = 3,
}
@Component({
selector: 'app-date-dropdown',
@ -34,11 +37,23 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
this.datePlaceHolder = settings.getLocalizedDateInputFormat()
}
quickFilters = [
{ id: LAST_7_DAYS, name: $localize`Last 7 days` },
{ id: LAST_MONTH, name: $localize`Last month` },
{ id: LAST_3_MONTHS, name: $localize`Last 3 months` },
{ id: LAST_YEAR, name: $localize`Last year` },
relativeDates = [
{
date: RelativeDate.LAST_7_DAYS,
name: $localize`Last 7 days`,
},
{
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
@ -55,12 +70,26 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
@Output()
dateAfterChange = new EventEmitter<string>()
@Input()
relativeDate: RelativeDate
@Output()
relativeDateChange = new EventEmitter<number>()
@Input()
title: string
@Output()
datesSet = new EventEmitter<DateSelection>()
get isActive(): boolean {
return (
this.relativeDate !== null ||
this.dateAfter?.length > 0 ||
this.dateBefore?.length > 0
)
}
private datesSetDebounce$ = new Subject()
private sub: Subscription
@ -77,37 +106,33 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
}
}
setDateQuickFilter(qf: number) {
reset() {
this.dateBefore = null
let date = new Date()
switch (qf) {
case LAST_7_DAYS:
date.setDate(date.getDate() - 7)
break
this.dateAfter = null
this.relativeDate = null
this.onChange()
}
case LAST_MONTH:
date.setMonth(date.getMonth() - 1)
break
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')
setRelativeDate(rd: RelativeDate) {
this.dateBefore = null
this.dateAfter = null
this.relativeDate = this.relativeDate == rd ? null : rd
this.onChange()
}
onChange() {
this.dateAfterChange.emit(this.dateAfter)
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() {
this.relativeDate = null
this.datesSetDebounce$.next({
after: this.dateAfter,
before: this.dateBefore,

View File

@ -5,12 +5,7 @@
</svg>
<div class="d-none d-sm-inline">&nbsp;{{title}}</div>
<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">
{{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>
<app-clearable-badge [number]="multiple ? selectionModel.totalCount : undefined" [selected]="!multiple && selectionModel.selectionSize() > 0" (cleared)="reset()"></app-clearable-badge>
</ng-container>
</button>
<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)
}
}
reset() {
this.selectionModel.reset()
this.selectionModelChange.emit(this.selectionModel)
}
}

View File

@ -60,14 +60,19 @@
</div>
<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>
<ng-container *ngIf="!list.activeSavedViewId">
<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>
</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>
</div>
</div>

View File

@ -9,7 +9,11 @@ import {
import { ActivatedRoute, convertToParamMap, Router } from '@angular/router'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
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 { PaperlessDocument } from 'src/app/data/paperless-document'
import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'
@ -54,15 +58,36 @@ export class DocumentListComponent implements OnInit, OnDestroy {
displayMode = 'smallCards' // largeCards, smallCards, details
unmodifiedFilterRules: FilterRule[] = []
private unmodifiedSavedView: PaperlessSavedView
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() {
return this.list.filterRules?.length > 0
}
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() {
@ -122,7 +147,7 @@ export class DocumentListComponent implements OnInit, OnDestroy {
this.router.navigate(['404'])
return
}
this.unmodifiedSavedView = view
this.list.activateSavedViewWithQueryParams(
view,
convertToParamMap(this.route.snapshot.queryParams)
@ -165,7 +190,8 @@ export class DocumentListComponent implements OnInit, OnDestroy {
this.savedViewService
.patch(savedView)
.pipe(first())
.subscribe((result) => {
.subscribe((view) => {
this.unmodifiedSavedView = view
this.toastService.showInfo(
$localize`View "${this.list.activeSavedViewTitle}" saved successfully.`
)
@ -179,6 +205,7 @@ export class DocumentListComponent implements OnInit, OnDestroy {
.getCached(viewID)
.pipe(first())
.subscribe((view) => {
this.unmodifiedSavedView = view
this.list.activateSavedView(view)
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()">
<option *ngFor="let m of textFilterModifiers" ngbDropdownItem [value]="m.id">{{m.label}}</option>
</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>
@ -54,12 +59,14 @@
title="Created" i18n-title
(datesSet)="updateRules()"
[(dateBefore)]="dateCreatedBefore"
[(dateAfter)]="dateCreatedAfter"></app-date-dropdown>
[(dateAfter)]="dateCreatedAfter"
[(relativeDate)]="dateCreatedRelativeDate"></app-date-dropdown>
<app-date-dropdown class="mb-2 mb-xl-0"
title="Added" i18n-title
(datesSet)="updateRules()"
[(dateBefore)]="dateAddedBefore"
[(dateAfter)]="dateAddedAfter"
title="Added" i18n-title
(datesSet)="updateRules()"></app-date-dropdown>
[(relativeDate)]="dateAddedRelativeDate"></app-date-dropdown>
</div>
</div>
</div>

View File

@ -21,3 +21,7 @@
input[type="text"] {
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 { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
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_CONTENT = 'title-content'
@ -57,6 +58,27 @@ const TEXT_FILTER_MODIFIER_NOTNULL = 'not null'
const TEXT_FILTER_MODIFIER_GT = 'greater'
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({
selector: 'app-filter-editor',
templateUrl: './filter-editor.component.html',
@ -197,6 +219,8 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
dateCreatedAfter: string
dateAddedBefore: string
dateAddedAfter: string
dateCreatedRelativeDate: RelativeDate
dateAddedRelativeDate: RelativeDate
_unmodifiedFilterRules: FilterRule[] = []
_filterRules: FilterRule[] = []
@ -228,6 +252,8 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
this.dateAddedAfter = null
this.dateCreatedBefore = null
this.dateCreatedAfter = null
this.dateCreatedRelativeDate = null
this.dateAddedRelativeDate = null
this.textFilterModifier = TEXT_FILTER_MODIFIER_EQUALS
value.forEach((rule) => {
@ -245,8 +271,39 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
this.textFilterTarget = TEXT_FILTER_TARGET_ASN
break
case FILTER_FULLTEXT_QUERY:
this._textFilter = rule.value
this.textFilterTarget = TEXT_FILTER_TARGET_FULLTEXT_QUERY
let allQueryArgs = rule.value.split(',')
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
case FILTER_FULLTEXT_MORELIKE:
this._moreLikeId = +rule.value
@ -471,6 +528,89 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
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
}
@ -569,15 +709,23 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
this.updateRules()
}
textFilterEnter() {
const filterString = (
this.textFilterInput.nativeElement as HTMLInputElement
).value
if (filterString.length) {
this.updateTextFilter(filterString)
textFilterKeyup(event: KeyboardEvent) {
if (event.key == 'Enter') {
const filterString = (
this.textFilterInput.nativeElement as HTMLInputElement
).value
if (filterString.length) {
this.updateTextFilter(filterString)
}
} else if (event.key == 'Escape') {
this.resetTextField()
}
}
resetTextField() {
this.updateTextFilter('')
}
changeTextFilterTarget(target) {
if (
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()
if (!this.router.routerState.snapshot.url.includes('/view/')) {
this.router.navigate([], {
queryParams: { view: view.id },
})
this.router.navigate(['view', view.id])
}
}
loadFromQueryParams(queryParams: ParamMap) {
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 (newState == undefined) newState = this.defaultListViewState() // if nothing in local storage
@ -276,7 +276,6 @@ export class DocumentListViewService {
) {
this.activeListViewState.sortField = 'created'
}
this._activeSavedViewId = null
this.activeListViewState.filterRules = filterRules
this.reload()
this.reduceSelectionToFilter()
@ -288,7 +287,6 @@ export class DocumentListViewService {
}
set sortField(field: string) {
this._activeSavedViewId = null
this.activeListViewState.sortField = field
this.reload()
this.saveDocumentListView()
@ -299,7 +297,6 @@ export class DocumentListViewService {
}
set sortReverse(reverse: boolean) {
this._activeSavedViewId = null
this.activeListViewState.sortReverse = reverse
this.reload()
this.saveDocumentListView()

View File

@ -372,6 +372,10 @@ textarea,
&:hover, &:focus {
background-color: var(--bs-body-bg);
}
&:focus {
color: var(--bs-body-color);
}
}
.dropdown-menu {
@ -393,6 +397,10 @@ textarea,
background-color: var(--bs-primary);
color: var(--pngx-primary-text-contrast);
}
&.disabled, &:disabled {
opacity: 50%;
}
}
}
@ -579,7 +587,7 @@ a.badge {
border-radius: 0.15rem;
}
> .btn:not(:first-child) {
> .btn:not(:first-child):not(:nth-child(2)) {
border-top-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
# renaming logic to acquire the lock as well.
# This triggers things like file renaming
document.save()
# 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)
# Return the most up to date fields
document.refresh_from_db()
return document
def _store(self, text, date, mime_type) -> Document:

View File

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

View File

@ -142,14 +142,14 @@ def matches(matching_model, document):
return bool(match)
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)
text = re.sub(r"[^\w\s]", "", document_content)
if matching_model.is_insensitive:
match = match.lower()
text = text.lower()
if fuzz.partial_ratio(match, text) >= 90:
if fuzz.partial_ratio(match, text, score_cutoff=90):
# TODO: make this better
log_reason(
matching_model,

View File

@ -400,6 +400,13 @@ def update_filename_and_move_files(sender, instance, **kwargs):
with FileLock(settings.MEDIA_LOCK):
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_source_path = instance.source_path

View File

@ -14,6 +14,7 @@ except ImportError:
import backports.zoneinfo as zoneinfo
from django.conf import settings
from django.utils import timezone
from django.test import override_settings
from django.test import TestCase
@ -326,6 +327,12 @@ class TestConsumer(DirectoriesMixin, TestCase):
def testNormalOperation(self):
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)
self.assertEqual(document.content, "The Text")
@ -351,7 +358,20 @@ class TestConsumer(DirectoriesMixin, TestCase):
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)
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_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():
doc = Document.objects.create(

View File

@ -347,6 +347,13 @@ if os.getenv("PAPERLESS_DBHOST"):
if os.getenv("PAPERLESS_DBENGINE") == "mariadb":
engine = "django.db.backends.mysql"
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
engine = "django.db.backends.postgresql_psycopg2"
options = {"sslmode": os.getenv("PAPERLESS_DBSSLMODE", "prefer")}

View File

@ -1,10 +1,11 @@
import datetime
import os
import time
from pathlib import Path
from typing import Final
import pytest
from django.test import TestCase
from documents.parsers import ParseError
from paperless_tika.parsers import TikaDocumentParser
@ -24,6 +25,44 @@ class TestTikaParserAgainstServer(TestCase):
def tearDown(self) -> None:
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):
"""
GIVEN:
@ -36,7 +75,7 @@ class TestTikaParserAgainstServer(TestCase):
"""
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.parser.text,
@ -62,7 +101,7 @@ class TestTikaParserAgainstServer(TestCase):
"""
test_file = self.SAMPLE_DIR / Path("sample.docx")
self.parser.parse(
self.try_parse_with_wait(
test_file,
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
)