diff --git a/.gitignore b/.gitignore index f2229c3..c5fe8a2 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,6 @@ target/ # Vim swapfiles .*.sw? + +# VScode Docs +.vscode/ \ No newline at end of file diff --git a/AUTHORS.rst b/AUTHORS.rst index be1af34..289d9ef 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -11,3 +11,6 @@ Authors - Chiara Bigarella - Krzysztof Nowak - Thomas P. Robitaille +- Mattias Wångblad +- Mubdi Rahman + diff --git a/Dockerfile b/Dockerfile index 3e710fb..4abbfe1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,16 +4,16 @@ # # Asclepias Broker is free software; you can redistribute it and/or modify it # under the terms of the MIT License; see LICENSE file for more details. -FROM inveniosoftware/centos7-python:3.6 +FROM python:3.8 RUN mkdir /app WORKDIR /app COPY Pipfile Pipfile COPY Pipfile.lock Pipfile.lock -RUN pipenv install --deploy --system - +RUN pip install pipenv +RUN pipenv install --deploy --system --ignore-pipfile ADD . /app -RUN pip install . +RUN pipenv install . --ignore-pipfile CMD ["asclepias-broker", "shell"] diff --git a/Pipfile b/Pipfile index 3c61a26..e0a049f 100644 --- a/Pipfile +++ b/Pipfile @@ -4,23 +4,31 @@ verify_ssl = true name = "pypi" [packages] -celery = "<4.3" +celery = "==5.1.2" idutils = "*" -invenio = {version = ">=3.1.0,<3.2.0",extras = ["elasticsearch6", "postgresql"]} -invenio-accounts = ">=1.1.1,<1.2.0" -invenio-indexer = ">=1.0.1,<1.1.0" -invenio-logging = ">=1.1.0,<1.2.0" -invenio-oauth2server = ">=1.0.3,<1.1.0" -invenio-queues = "==1.0.0a1" -invenio-records-rest = ">=1.4.0,<1.5.0" -invenio-rest = ">=1.0.0,<1.1.0" +invenio = {version = "==3.4.1",extras = ["elasticsearch7", "postgresql"]} +invenio-app = "==1.3.3" +invenio-base = "==1.2.5" +invenio-celery = "==1.2.3" +invenio-accounts = "==1.4.9" +invenio-indexer = ">=1.2.1" +invenio-logging = "==1.3.0" +invenio-oauth2server = "==1.3.4" +invenio-queues = "==1.0.0a3" +invenio-records-rest = "==1.9.0" +invenio-search = "==1.4.2" +invenio-rest = ">=1.2.3" +invenio-theme = "==1.3.10" +flask = "==2.0.2" jsonschema = "*" -marshmallow = ">=2.0.0,<3.0.0" +marshmallow = ">=3.0.0,<4.0.0" raven = {version = "*",extras = ["flask"]} requests = "*" -uwsgi = "*" +uwsgi = ">= 2.0.19" uwsgi-tools = "*" uwsgitop = "*" +ipython = "*" +slackclient = "*" [dev-packages] check-manifest = "*" @@ -43,7 +51,7 @@ sphinxcontrib-httpdomain = "*" sphinxcontrib-httpexample = "*" [requires] -python_version = "3.6" +python_version = "3.8" [scripts] test = "python setup.py test" diff --git a/Pipfile.lock b/Pipfile.lock index 0eb7131..4008737 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "9c543d1a2eb7227fda20f718603979c56e07302978c69a7ff43a3ea78992c886" + "sha256": "0104512d3f40daebe9570fc71038668d74d067f114f89ebaa9e7bcd33f494b9e" }, "pipfile-spec": 6, "requires": { - "python_version": "3.6" + "python_version": "3.8" }, "sources": [ { @@ -16,79 +16,182 @@ ] }, "default": { + "aiohttp": { + "hashes": [ + "sha256:01d7bdb774a9acc838e6b8f1d114f45303841b89b95984cbb7d80ea41172a9e3", + "sha256:03a6d5349c9ee8f79ab3ff3694d6ce1cfc3ced1c9d36200cb8f08ba06bd3b782", + "sha256:04d48b8ce6ab3cf2097b1855e1505181bdd05586ca275f2505514a6e274e8e75", + "sha256:0770e2806a30e744b4e21c9d73b7bee18a1cfa3c47991ee2e5a65b887c49d5cf", + "sha256:07b05cd3305e8a73112103c834e91cd27ce5b4bd07850c4b4dbd1877d3f45be7", + "sha256:086f92daf51a032d062ec5f58af5ca6a44d082c35299c96376a41cbb33034675", + "sha256:099ebd2c37ac74cce10a3527d2b49af80243e2a4fa39e7bce41617fbc35fa3c1", + "sha256:0c7ebbbde809ff4e970824b2b6cb7e4222be6b95a296e46c03cf050878fc1785", + "sha256:102e487eeb82afac440581e5d7f8f44560b36cf0bdd11abc51a46c1cd88914d4", + "sha256:11691cf4dc5b94236ccc609b70fec991234e7ef8d4c02dd0c9668d1e486f5abf", + "sha256:11a67c0d562e07067c4e86bffc1553f2cf5b664d6111c894671b2b8712f3aba5", + "sha256:12de6add4038df8f72fac606dff775791a60f113a725c960f2bab01d8b8e6b15", + "sha256:13487abd2f761d4be7c8ff9080de2671e53fff69711d46de703c310c4c9317ca", + "sha256:15b09b06dae900777833fe7fc4b4aa426556ce95847a3e8d7548e2d19e34edb8", + "sha256:1c182cb873bc91b411e184dab7a2b664d4fea2743df0e4d57402f7f3fa644bac", + "sha256:1ed0b6477896559f17b9eaeb6d38e07f7f9ffe40b9f0f9627ae8b9926ae260a8", + "sha256:28d490af82bc6b7ce53ff31337a18a10498303fe66f701ab65ef27e143c3b0ef", + "sha256:2e5d962cf7e1d426aa0e528a7e198658cdc8aa4fe87f781d039ad75dcd52c516", + "sha256:2ed076098b171573161eb146afcb9129b5ff63308960aeca4b676d9d3c35e700", + "sha256:2f2f69dca064926e79997f45b2f34e202b320fd3782f17a91941f7eb85502ee2", + "sha256:31560d268ff62143e92423ef183680b9829b1b482c011713ae941997921eebc8", + "sha256:31d1e1c0dbf19ebccbfd62eff461518dcb1e307b195e93bba60c965a4dcf1ba0", + "sha256:37951ad2f4a6df6506750a23f7cbabad24c73c65f23f72e95897bb2cecbae676", + "sha256:3af642b43ce56c24d063325dd2cf20ee012d2b9ba4c3c008755a301aaea720ad", + "sha256:44db35a9e15d6fe5c40d74952e803b1d96e964f683b5a78c3cc64eb177878155", + "sha256:473d93d4450880fe278696549f2e7aed8cd23708c3c1997981464475f32137db", + "sha256:477c3ea0ba410b2b56b7efb072c36fa91b1e6fc331761798fa3f28bb224830dd", + "sha256:4a4a4e30bf1edcad13fb0804300557aedd07a92cabc74382fdd0ba6ca2661091", + "sha256:4aed991a28ea3ce320dc8ce655875e1e00a11bdd29fe9444dd4f88c30d558602", + "sha256:51467000f3647d519272392f484126aa716f747859794ac9924a7aafa86cd411", + "sha256:55c3d1072704d27401c92339144d199d9de7b52627f724a949fc7d5fc56d8b93", + "sha256:589c72667a5febd36f1315aa6e5f56dd4aa4862df295cb51c769d16142ddd7cd", + "sha256:5bfde62d1d2641a1f5173b8c8c2d96ceb4854f54a44c23102e2ccc7e02f003ec", + "sha256:5c23b1ad869653bc818e972b7a3a79852d0e494e9ab7e1a701a3decc49c20d51", + "sha256:61bfc23df345d8c9716d03717c2ed5e27374e0fe6f659ea64edcd27b4b044cf7", + "sha256:6ae828d3a003f03ae31915c31fa684b9890ea44c9c989056fea96e3d12a9fa17", + "sha256:6c7cefb4b0640703eb1069835c02486669312bf2f12b48a748e0a7756d0de33d", + "sha256:6d69f36d445c45cda7b3b26afef2fc34ef5ac0cdc75584a87ef307ee3c8c6d00", + "sha256:6f0d5f33feb5f69ddd57a4a4bd3d56c719a141080b445cbf18f238973c5c9923", + "sha256:6f8b01295e26c68b3a1b90efb7a89029110d3a4139270b24fda961893216c440", + "sha256:713ac174a629d39b7c6a3aa757b337599798da4c1157114a314e4e391cd28e32", + "sha256:718626a174e7e467f0558954f94af117b7d4695d48eb980146016afa4b580b2e", + "sha256:7187a76598bdb895af0adbd2fb7474d7f6025d170bc0a1130242da817ce9e7d1", + "sha256:71927042ed6365a09a98a6377501af5c9f0a4d38083652bcd2281a06a5976724", + "sha256:7d08744e9bae2ca9c382581f7dce1273fe3c9bae94ff572c3626e8da5b193c6a", + "sha256:7dadf3c307b31e0e61689cbf9e06be7a867c563d5a63ce9dca578f956609abf8", + "sha256:81e3d8c34c623ca4e36c46524a3530e99c0bc95ed068fd6e9b55cb721d408fb2", + "sha256:844a9b460871ee0a0b0b68a64890dae9c415e513db0f4a7e3cab41a0f2fedf33", + "sha256:8b7ef7cbd4fec9a1e811a5de813311ed4f7ac7d93e0fda233c9b3e1428f7dd7b", + "sha256:97ef77eb6b044134c0b3a96e16abcb05ecce892965a2124c566af0fd60f717e2", + "sha256:99b5eeae8e019e7aad8af8bb314fb908dd2e028b3cdaad87ec05095394cce632", + "sha256:a25fa703a527158aaf10dafd956f7d42ac6d30ec80e9a70846253dd13e2f067b", + "sha256:a2f635ce61a89c5732537a7896b6319a8fcfa23ba09bec36e1b1ac0ab31270d2", + "sha256:a79004bb58748f31ae1cbe9fa891054baaa46fb106c2dc7af9f8e3304dc30316", + "sha256:a996d01ca39b8dfe77440f3cd600825d05841088fd6bc0144cc6c2ec14cc5f74", + "sha256:b0e20cddbd676ab8a64c774fefa0ad787cc506afd844de95da56060348021e96", + "sha256:b6613280ccedf24354406caf785db748bebbddcf31408b20c0b48cb86af76866", + "sha256:b9d00268fcb9f66fbcc7cd9fe423741d90c75ee029a1d15c09b22d23253c0a44", + "sha256:bb01ba6b0d3f6c68b89fce7305080145d4877ad3acaed424bae4d4ee75faa950", + "sha256:c2aef4703f1f2ddc6df17519885dbfa3514929149d3ff900b73f45998f2532fa", + "sha256:c34dc4958b232ef6188c4318cb7b2c2d80521c9a56c52449f8f93ab7bc2a8a1c", + "sha256:c3630c3ef435c0a7c549ba170a0633a56e92629aeed0e707fec832dee313fb7a", + "sha256:c3d6a4d0619e09dcd61021debf7059955c2004fa29f48788a3dfaf9c9901a7cd", + "sha256:d15367ce87c8e9e09b0f989bfd72dc641bcd04ba091c68cd305312d00962addd", + "sha256:d2f9b69293c33aaa53d923032fe227feac867f81682f002ce33ffae978f0a9a9", + "sha256:e999f2d0e12eea01caeecb17b653f3713d758f6dcc770417cf29ef08d3931421", + "sha256:ea302f34477fda3f85560a06d9ebdc7fa41e82420e892fc50b577e35fc6a50b2", + "sha256:eaba923151d9deea315be1f3e2b31cc39a6d1d2f682f942905951f4e40200922", + "sha256:ef9612483cb35171d51d9173647eed5d0069eaa2ee812793a75373447d487aa4", + "sha256:f5315a2eb0239185af1bddb1abf472d877fede3cc8d143c6cddad37678293237", + "sha256:fa0ffcace9b3aa34d205d8130f7873fcfefcb6a4dd3dd705b0dab69af6712642", + "sha256:fc5471e1a54de15ef71c1bc6ebe80d4dc681ea600e68bfd1cbce40427f0b7578" + ], + "markers": "python_version >= '3.6'", + "version": "==3.8.1" + }, + "aiosignal": { + "hashes": [ + "sha256:26e62109036cd181df6e6ad646f91f0dcfd05fe16d0cb924138ff2ab75d64e3a", + "sha256:78ed67db6c7b7ced4f98e495e572106d5c432a93e1ddd1bf475e1dc05f5b7df2" + ], + "markers": "python_version >= '3.6'", + "version": "==1.2.0" + }, "alembic": { "hashes": [ - "sha256:5609afbb2ab142a991b15ae436347c475f8a517f1610f2fd1b09cdca7c311f3f" + "sha256:7c328694a2e68f03ee971e63c3bd885846470373a5b532cf2c9f1601c413b153", + "sha256:a9dde941534e3d7573d9644e8ea62a2953541e27bc1793e166f60b777ae098b4" ], - "version": "==1.2.0" + "markers": "python_version >= '3.6'", + "version": "==1.7.5" }, "amqp": { "hashes": [ - "sha256:19a917e260178b8d410122712bac69cb3e6db010d68f6101e7307508aded5e68", - "sha256:19d851b879a471fcfdcf01df9936cff924f422baa77653289f7095dedd5fb26a" + "sha256:03e16e94f2b34c31f8bf1206d8ddd3ccaa4c315f7f6a1879b7b1210d229568c2", + "sha256:493a2ac6788ce270a2f6a765b017299f60c1998f5a8617908ee9be082f7300fb" + ], + "markers": "python_version >= '3.6'", + "version": "==5.0.6" + }, + "appnope": { + "hashes": [ + "sha256:93aa393e9d6c54c5cd570ccadd8edad61ea0c4b9ea7a01409020c9aa019eb442", + "sha256:dd83cd4b5b460958838f6eb3000c660b1f9caf2a5b1de4264e941512f603258a" ], - "version": "==2.5.1" + "markers": "sys_platform == 'darwin'", + "version": "==0.1.2" }, "arrow": { "hashes": [ - "sha256:10257c5daba1a88db34afa284823382f4963feca7733b9107956bed041aff24f", - "sha256:c2325911fcd79972cf493cfd957072f9644af8ad25456201ae1ede3316576eb4" + "sha256:6b2914ef3997d1fd7b37a71ce9dd61a6e329d09e1c7b44f4d3099ca4a5c0933e", + "sha256:c2dde3c382d9f7e6922ce636bf0b318a7a853df40ecb383b29192e6c5cc82840" ], - "version": "==0.15.2" + "markers": "python_version >= '3.6'", + "version": "==1.2.1" }, - "asn1crypto": { + "async-timeout": { "hashes": [ - "sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87", - "sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49" + "sha256:a22c0b311af23337eb05fcf05a8b51c3ea53729d46fb5460af62bee033cec690", + "sha256:b930cb161a39042f9222f6efb7301399c87eeab394727ec5437924a36d6eef51" ], - "version": "==0.24.0" + "markers": "python_version >= '3.6'", + "version": "==4.0.1" }, "attrs": { "hashes": [ - "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", - "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" + "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", + "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" ], - "version": "==19.1.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==21.2.0" }, "autosemver": { "hashes": [ - "sha256:4f4e5c30a51acabd454eddb28fb958a6cd8ba93ce18ab9484bdcb8009e5163a0" + "sha256:0af1e8a9c3604545c067311f1c26403e8f0d60b5d9561c0217e14eee21c98b02" ], - "version": "==0.5.3" + "version": "==0.5.5" }, "babel": { "hashes": [ - "sha256:af92e6106cb7c55286b25b38ad7695f8b4efb36a90ba483d7f7a6628c46158ab", - "sha256:e86135ae101e31e2c8ec20a4e0c5220f4eed12487d5cf3f78be7e98d3a57fc28" + "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9", + "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0" ], - "version": "==2.7.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.9.1" }, "backcall": { "hashes": [ - "sha256:38ecd85be2c1e78f77fd91700c76e14667dc21e2713b63876c0eb901196e01e4", - "sha256:bbbf4b1e5cd2bdb08f915895b51081c041bac22394fdfcfdfbe9f14b77c08bf2" + "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e", + "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255" ], - "version": "==0.1.0" + "version": "==0.2.0" }, - "billiard": { + "base32-lib": { "hashes": [ - "sha256:42d9a227401ac4fba892918bba0a0c409def5435c4b483267ebfe821afaaba0e" + "sha256:09663df621bbc454079a54c92fa25d3bc33ea4a191053a09dd1e05ea4c0fe47c", + "sha256:f3cbc1c4b3df7af844c9b7ffc1638a688423db2b1e51082b2c014b3959b756ae" ], - "version": "==3.5.0.5" + "version": "==1.0.2" }, - "binaryornot": { + "billiard": { "hashes": [ - "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061", - "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4" + "sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547", + "sha256:87103ea78fa6ab4d5c751c4909bcff74617d985de7fa8b672cf8618afd5a875b" ], - "version": "==0.4.4" + "version": "==3.6.4.0" }, "bleach": { "hashes": [ - "sha256:213336e49e102af26d9cde77dd2d0397afabc5a6bf2fed985dc35b5d1e285a16", - "sha256:3fdf7f77adcf649c9911387df51254b813185e32b2c6619f690b593a617e19fa" + "sha256:0900d8b37eba61a802ee40ac0061f8c2b5dee29c1927dd1d233e075ebf5a71da", + "sha256:4d2651ab93271d1129ac9cbc679f524565cc8a1b791909c4a51eac4446a15994" ], - "version": "==3.1.0" + "markers": "python_version >= '3.6'", + "version": "==4.1.0" }, "blinker": { "hashes": [ @@ -96,143 +199,204 @@ ], "version": "==1.4" }, + "cachelib": { + "hashes": [ + "sha256:68e27dae1bb73ba02071f1cf413111d96f8175fd37176f35a5ccb9bdf6848c5c", + "sha256:b766ce83499652b1c7bf3fb09fedc26121533bf21249e8a9927f39445b939430" + ], + "markers": "python_version >= '3.6'", + "version": "==0.4.1" + }, "celery": { "hashes": [ - "sha256:373d6544c8d6ee66b9c1c9ba61ec4c74334c9a861306002662252bd5fd0ff6a1", - "sha256:b1b7da98be6b4082abfa6e18282ece450271f366bce81d0d521342a0db862506" + "sha256:8d9a3de9162965e97f8e8cc584c67aad83b3f7a267584fa47701ed11c3e0d4b0", + "sha256:9dab2170b4038f7bf10ef2861dbf486ddf1d20592290a1040f7b7a1259705d42" ], "index": "pypi", - "version": "==4.2.2" + "version": "==5.1.2" }, "certifi": { "hashes": [ - "sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50", - "sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef" + "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", + "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" ], - "version": "==2019.9.11" + "version": "==2021.10.8" }, "cffi": { "hashes": [ - "sha256:041c81822e9f84b1d9c401182e174996f0bae9991f33725d059b771744290774", - "sha256:046ef9a22f5d3eed06334d01b1e836977eeef500d9b78e9ef693f9380ad0b83d", - "sha256:066bc4c7895c91812eff46f4b1c285220947d4aa46fa0a2651ff85f2afae9c90", - "sha256:066c7ff148ae33040c01058662d6752fd73fbc8e64787229ea8498c7d7f4041b", - "sha256:2444d0c61f03dcd26dbf7600cf64354376ee579acad77aef459e34efcb438c63", - "sha256:300832850b8f7967e278870c5d51e3819b9aad8f0a2c8dbe39ab11f119237f45", - "sha256:34c77afe85b6b9e967bd8154e3855e847b70ca42043db6ad17f26899a3df1b25", - "sha256:46de5fa00f7ac09f020729148ff632819649b3e05a007d286242c4882f7b1dc3", - "sha256:4aa8ee7ba27c472d429b980c51e714a24f47ca296d53f4d7868075b175866f4b", - "sha256:4d0004eb4351e35ed950c14c11e734182591465a33e960a4ab5e8d4f04d72647", - "sha256:4e3d3f31a1e202b0f5a35ba3bc4eb41e2fc2b11c1eff38b362de710bcffb5016", - "sha256:50bec6d35e6b1aaeb17f7c4e2b9374ebf95a8975d57863546fa83e8d31bdb8c4", - "sha256:55cad9a6df1e2a1d62063f79d0881a414a906a6962bc160ac968cc03ed3efcfb", - "sha256:5662ad4e4e84f1eaa8efce5da695c5d2e229c563f9d5ce5b0113f71321bcf753", - "sha256:59b4dc008f98fc6ee2bb4fd7fc786a8d70000d058c2bbe2698275bc53a8d3fa7", - "sha256:73e1ffefe05e4ccd7bcea61af76f36077b914f92b76f95ccf00b0c1b9186f3f9", - "sha256:a1f0fd46eba2d71ce1589f7e50a9e2ffaeb739fb2c11e8192aa2b45d5f6cc41f", - "sha256:a2e85dc204556657661051ff4bab75a84e968669765c8a2cd425918699c3d0e8", - "sha256:a5457d47dfff24882a21492e5815f891c0ca35fefae8aa742c6c263dac16ef1f", - "sha256:a8dccd61d52a8dae4a825cdbb7735da530179fea472903eb871a5513b5abbfdc", - "sha256:ae61af521ed676cf16ae94f30fe202781a38d7178b6b4ab622e4eec8cefaff42", - "sha256:b012a5edb48288f77a63dba0840c92d0504aa215612da4541b7b42d849bc83a3", - "sha256:d2c5cfa536227f57f97c92ac30c8109688ace8fa4ac086d19d0af47d134e2909", - "sha256:d42b5796e20aacc9d15e66befb7a345454eef794fdb0737d1af593447c6c8f45", - "sha256:dee54f5d30d775f525894d67b1495625dd9322945e7fee00731952e0368ff42d", - "sha256:e070535507bd6aa07124258171be2ee8dfc19119c28ca94c9dfb7efd23564512", - "sha256:e1ff2748c84d97b065cc95429814cdba39bcbd77c9c85c89344b317dc0d9cbff", - "sha256:ed851c75d1e0e043cbf5ca9a8e1b13c4c90f3fbd863dacb01c0808e2b5204201" - ], - "version": "==1.12.3" - }, - "chardet": { - "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" - ], - "version": "==3.0.4" + "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3", + "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2", + "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636", + "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20", + "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728", + "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27", + "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66", + "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443", + "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0", + "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7", + "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39", + "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605", + "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a", + "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37", + "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029", + "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139", + "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc", + "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df", + "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14", + "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880", + "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2", + "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a", + "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e", + "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474", + "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024", + "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8", + "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0", + "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e", + "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a", + "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e", + "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032", + "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6", + "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e", + "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b", + "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e", + "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954", + "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962", + "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c", + "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4", + "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55", + "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962", + "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023", + "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c", + "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6", + "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8", + "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382", + "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7", + "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc", + "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997", + "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796" + ], + "version": "==1.15.0" + }, + "charset-normalizer": { + "hashes": [ + "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0", + "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b" + ], + "markers": "python_version >= '3'", + "version": "==2.0.7" }, "click": { "hashes": [ - "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", - "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" + "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", + "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" ], - "version": "==7.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==7.1.2" }, - "cookiecutter": { + "click-didyoumean": { "hashes": [ - "sha256:1316a52e1c1f08db0c9efbf7d876dbc01463a74b155a0d83e722be88beda9a3e", - "sha256:ed8f54a8fc79b6864020d773ce11539b5f08e4617f353de1f22d23226f6a0d36" + "sha256:a0713dc7a1de3f06bc0df5a9567ad19ead2d3d5689b434768a6145bff77c0667", + "sha256:f184f0d851d96b6d29297354ed981b7dd71df7ff500d82fa6d11f0856bee8035" ], - "version": "==1.6.0" + "markers": "python_full_version >= '3.6.2' and python_full_version < '4.0.0'", + "version": "==0.3.0" + }, + "click-plugins": { + "hashes": [ + "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b", + "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8" + ], + "version": "==1.1.1" + }, + "click-repl": { + "hashes": [ + "sha256:94b3fbbc9406a236f176e0506524b2937e4b23b6f4c0c0b2a0a83f8a64e9194b", + "sha256:cd12f68d745bf6151210790540b4cb064c7b13e571bc64b6957d98d120dacfd8" + ], + "version": "==0.2.0" }, "cryptography": { "hashes": [ - "sha256:24b61e5fcb506424d3ec4e18bca995833839bf13c59fc43e530e488f28d46b8c", - "sha256:25dd1581a183e9e7a806fe0543f485103232f940fcfc301db65e630512cce643", - "sha256:3452bba7c21c69f2df772762be0066c7ed5dc65df494a1d53a58b683a83e1216", - "sha256:41a0be220dd1ed9e998f5891948306eb8c812b512dc398e5a01846d855050799", - "sha256:5751d8a11b956fbfa314f6553d186b94aa70fdb03d8a4d4f1c82dcacf0cbe28a", - "sha256:5f61c7d749048fa6e3322258b4263463bfccefecb0dd731b6561cb617a1d9bb9", - "sha256:72e24c521fa2106f19623a3851e9f89ddfdeb9ac63871c7643790f872a305dfc", - "sha256:7b97ae6ef5cba2e3bb14256625423413d5ce8d1abb91d4f29b6d1a081da765f8", - "sha256:961e886d8a3590fd2c723cf07be14e2a91cf53c25f02435c04d39e90780e3b53", - "sha256:96d8473848e984184b6728e2c9d391482008646276c3ff084a1bd89e15ff53a1", - "sha256:ae536da50c7ad1e002c3eee101871d93abdc90d9c5f651818450a0d3af718609", - "sha256:b0db0cecf396033abb4a93c95d1602f268b3a68bb0a9cc06a7cff587bb9a7292", - "sha256:cfee9164954c186b191b91d4193989ca994703b2fff406f71cf454a2d3c7327e", - "sha256:e6347742ac8f35ded4a46ff835c60e68c22a536a8ae5c4422966d06946b6d4c6", - "sha256:f27d93f0139a3c056172ebb5d4f9056e770fdf0206c2f422ff2ebbad142e09ed", - "sha256:f57b76e46a58b63d1c6375017f4564a28f19a5ca912691fd2e4261b3414b618d" - ], - "version": "==2.7" + "sha256:07bb7fbfb5de0980590ddfc7f13081520def06dc9ed214000ad4372fb4e3c7f6", + "sha256:18d90f4711bf63e2fb21e8c8e51ed8189438e6b35a6d996201ebd98a26abbbe6", + "sha256:1ed82abf16df40a60942a8c211251ae72858b25b7421ce2497c2eb7a1cee817c", + "sha256:22a38e96118a4ce3b97509443feace1d1011d0571fae81fc3ad35f25ba3ea999", + "sha256:2d69645f535f4b2c722cfb07a8eab916265545b3475fdb34e0be2f4ee8b0b15e", + "sha256:4a2d0e0acc20ede0f06ef7aa58546eee96d2592c00f450c9acb89c5879b61992", + "sha256:54b2605e5475944e2213258e0ab8696f4f357a31371e538ef21e8d61c843c28d", + "sha256:7075b304cd567694dc692ffc9747f3e9cb393cc4aa4fb7b9f3abd6f5c4e43588", + "sha256:7b7ceeff114c31f285528ba8b390d3e9cfa2da17b56f11d366769a807f17cbaa", + "sha256:7eba2cebca600a7806b893cb1d541a6e910afa87e97acf2021a22b32da1df52d", + "sha256:928185a6d1ccdb816e883f56ebe92e975a262d31cc536429041921f8cb5a62fd", + "sha256:9933f28f70d0517686bd7de36166dda42094eac49415459d9bdf5e7df3e0086d", + "sha256:a688ebcd08250eab5bb5bca318cc05a8c66de5e4171a65ca51db6bd753ff8953", + "sha256:abb5a361d2585bb95012a19ed9b2c8f412c5d723a9836418fab7aaa0243e67d2", + "sha256:c10c797ac89c746e488d2ee92bd4abd593615694ee17b2500578b63cad6b93a8", + "sha256:ced40344e811d6abba00295ced98c01aecf0c2de39481792d87af4fa58b7b4d6", + "sha256:d57e0cdc1b44b6cdf8af1d01807db06886f10177469312fbde8f44ccbb284bc9", + "sha256:d99915d6ab265c22873f1b4d6ea5ef462ef797b4140be4c9d8b179915e0985c6", + "sha256:eb80e8a1f91e4b7ef8b33041591e6d89b2b8e122d787e87eeb2b08da71bb16ad", + "sha256:ebeddd119f526bcf323a89f853afb12e225902a24d29b55fe18dd6fcb2838a76" + ], + "markers": "python_version >= '3.6'", + "version": "==35.0.0" }, "decorator": { "hashes": [ - "sha256:86156361c50488b84a3f148056ea716ca587df2f0de1d34750d35c21312725de", - "sha256:f069f3a01830ca754ba5258fde2278454a0b5b79e0d7f5c13b3b97e57d4acff6" + "sha256:7b12e7c3c6ab203a29e157335e9122cb03de9ab7264b137594103fd4a683b374", + "sha256:e59913af105b9860aa2c8d3272d9de5a56a4e608db9a2f167a8480b323d529a7" ], - "version": "==4.4.0" + "markers": "python_version >= '3.5'", + "version": "==5.1.0" + }, + "dnspython": { + "hashes": [ + "sha256:95d12f6ef0317118d2a1a6fc49aac65ffec7eb8087474158f42f26a639135216", + "sha256:e4a87f0b573201a0f3727fa18a516b055fd1107e0e5477cded4a2de497df1dd4" + ], + "markers": "python_version >= '3.6'", + "version": "==2.1.0" }, "dulwich": { "hashes": [ - "sha256:0e442f6f96e6d97270a7cca4e75306b6b0228627bdf57dde3759e0e345a6b523", - "sha256:667f49536ccba09d3b90bac80d44048e45566f84b98a5e139cc8c70757a6ae60", - "sha256:82792a9d49b112fa2151fa0fb29b01667855a843ff99325b1c1578a4aec11b57", - "sha256:aa628449c5f594a9a282f4d9e5993fef65481ef5e3b9b6c52ff31200f8f5dc95", - "sha256:ab4668bc4e1996d12eb1910e123a09edcff8e166e7ec46db5aafb5c7e250b99f", - "sha256:c35ed2cd5b263ce0d67758ffba590c0466ff13b048457ff060b7d2e6cb55a40e", - "sha256:c8b48079a14850cbeb788b38e1061ae6db75061431c1c0f91382460be4c84bbe", - "sha256:dfcd9943c69f963dd61a027f480d16f548ea5905c2485be8f4b8f130df2c32de", - "sha256:e3693c3238c1a5fc1e4427281c4455d78549f4797f2a7107a5f4443b21efafb4" + "sha256:10699277c6268d0c16febe141a5b1c1a6e9744f3144c2d2de1706f4b1adafe63", + "sha256:267160904e9a1cb6c248c5efc53597a35d038ecc6f60bdc4546b3053bed11982", + "sha256:4e3aba5e4844e7c700721c1fc696987ea820ee3528a03604dc4e74eff4196826", + "sha256:60bb2c2c92f5025c1b53a556304008f0f624c98ae36f22d870e056b2d4236c11", + "sha256:dddae02d372fc3b5cfb0046d0f62246ef281fa0c088df7601ab5916607add94b", + "sha256:f00d132082b8fcc2eb0d722abc773d4aeb5558c1475d7edd1f0f571146c29db9", + "sha256:f74561c448bfb6f04c07de731c1181ae4280017f759b0bb04fa5770aa84ca850" ], - "version": "==0.19.13" + "version": "==0.19.16" }, "elasticsearch": { "hashes": [ - "sha256:1f0f633e3b500d5042424f75a505badf8c4b9962c1b4734cdfb3087fb67920be", - "sha256:fb5ab15ee283f104b5a7a5695c7e879cb2927e4eb5aed9c530811590b41259ad" + "sha256:52dda85f76eeb85ec873bf9ffe0ba6849e544e591f66d4048a5e48016de268e0", + "sha256:5920df0ab2630778680376d86bea349dc99860977eec9b6d2bd0860f337313f2" ], - "version": "==6.4.0" + "version": "==7.13.4" }, "elasticsearch-dsl": { "hashes": [ - "sha256:5114a38a88e93a4663782eae07a1e8084ba333c49887335c83de8b8043bc72b2", - "sha256:d6d974cd2289543a3350690494a43fe9996485b8dc6f1d8758cb56bee01244bd" + "sha256:046ea10820b94c075081b528b4526c5bc776bda4226d702f269a5f203232064b", + "sha256:c4a7b93882918a413b63bed54018a1685d7410ffd8facbc860ee7fd57f214a6d" ], - "version": "==6.1.0" + "version": "==7.4.0" }, - "flask": { + "email-validator": { "hashes": [ - "sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52", - "sha256:45eb5a6fd193d6cf7e0cf5d8a5b31f83d5faae0293695626f539a823e93b13f6" + "sha256:5675c8ceb7106a37e40e2698a57c056756bf3f272cfa8682a4f87ebd95d8440b", + "sha256:aa237a65f6f4da067119b7df3f13e89c25c051327b2b5b66dc075f33d62480d7" ], - "version": "==1.1.1" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==1.1.3" }, - "flask-admin": { + "flask": { "hashes": [ - "sha256:ca0be6ec11a6913b73f656c65c444ae5be416c57c75638dd3199376ce6bc7422" + "sha256:7b2fb8e934ddd50731893bdcdb00fc8c0315916f9fcd50d22c7cc1a95ab634e2", + "sha256:cb90f62f1d8e4dc4621f52106613488b5ba826b2e1e10a33eac92f723093ab6a" ], - "version": "==1.5.3" + "version": "==2.0.2" }, "flask-alembic": { "hashes": [ @@ -243,49 +407,60 @@ }, "flask-babelex": { "hashes": [ - "sha256:cf79cdedb5ce860166120136b0e059e9d97b8df07a3bc2411f6243de04b754b4" + "sha256:39a59ccee9386a9d52d80b9101224402036aedc2c7873b11deef6e4e21cace27", + "sha256:f744d0557cb04cafed733cfa96e7373b46263d4cf79a2c5988c65085f360d873" ], - "version": "==0.9.3" + "version": "==0.9.4" }, "flask-breadcrumbs": { "hashes": [ - "sha256:49bf108f448b4066eda20631d9ac699fb25310cfe05867c8d36ae67eafdf237c", - "sha256:95a5adf1df7eb76c910692cb7001f6d7247428d0ab3ad0fde51223fbc1bed62e" + "sha256:cb6fc89d7f76ff429fa4bb1fbc0bfe186f3f7ff8b4f5325c0a7b75946e2de98f", + "sha256:f95872a3baf46473febd0f5c0adea192e7c2576af60a84a2144068eca1559b45" ], - "version": "==0.4.0" + "version": "==0.5.1" }, "flask-caching": { "hashes": [ - "sha256:52e236cbc836c41a5ced0c0a67b48ad180c9e2b5cb69e881089bba766db5569e", - "sha256:b0daabd5249bebfbae3da4c22987bac22047fc8b18ea2716c4fc63d57d218946" + "sha256:bcda8acbc7508e31e50f63e9b1ab83185b446f6b6318bd9dd1d45626fba2e903", + "sha256:cf19b722fcebc2ba03e4ae7c55b532ed53f0cbf683ce36fafe5e881789a01c00" ], - "version": "==1.7.2" + "markers": "python_version >= '3.5'", + "version": "==1.10.1" }, "flask-celeryext": { "hashes": [ - "sha256:68bd3bda8a721199df0c69663f9ff92dd79a5023833ffa2ac2cd7169630ab68a", - "sha256:8b72cab1af721f39953dd547f6143f51f15f584bab6decf84f3190751217de67" + "sha256:1c84b35462d41d1317800d256b2ce30031b7d3d20dd8dc680ce4f4cc88029867", + "sha256:47d5d18daebad300b215faca0d1c6da24625f333020482e27591634c05792c98" ], - "version": "==0.3.2" + "version": "==0.3.4" + }, + "flask-collect-invenio": { + "hashes": [ + "sha256:52c8343773f6366bb1594905e5c8e1f92101ec06c20e966420237ddad2a7918a", + "sha256:cf969b7cddf27086ee19883e9660aeac2d455646cbad2a43799660b3cc0cbffb" + ], + "version": "==1.4.0" }, "flask-cors": { "hashes": [ - "sha256:72170423eb4612f0847318afff8c247b38bd516b7737adfc10d1c2cdbb382d16", - "sha256:f4d97201660e6bbcff2d89d082b5b6d31abee04b1b3003ee073a6fd25ad1d69a" + "sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438", + "sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de" ], - "version": "==3.0.8" + "version": "==3.0.10" }, - "flask-kvsession": { + "flask-kvsession-invenio": { "hashes": [ - "sha256:9c0ee93fae089c45baeda0a3fd3ae32a96ee81c34996017749f8b3fd06df936c" + "sha256:fe24405403fff9e3ab2c5a34d93362d63ada4c9e5e7afab850ea4f80efb92a85" ], - "version": "==0.6.2" + "version": "==0.6.3" }, "flask-limiter": { "hashes": [ - "sha256:8cce98dcf25bf2ddbb824c2b503b4fc8e1a139154240fd2c60d9306bad8a0db8" + "sha256:5831d6b5b9ef6a83dca4b89f216880a7aa204b5ce8b710b5bc02786bf21e11fd", + "sha256:905c35cd87bf60c92fd87922ae23fe27aa5fb31980bab31fc00807adee9f5a55", + "sha256:9087984ae7eeb862f93bf5b18477a5e5b1e0c907647ae74fba1c7e3f1de63d6f" ], - "version": "==1.0.1" + "version": "==1.1.0" }, "flask-login": { "hashes": [ @@ -301,17 +476,17 @@ }, "flask-menu": { "hashes": [ - "sha256:7374c3265c34a3fbb1ab5f1df6385f3b10fc0b05c142fd2f39217c9cece4df29", - "sha256:c30f767af3c008d3157a86533d20ea2bc7b73f5b5820ddca773584674f26517b" + "sha256:6aef705e2b12d04a5a4d7eed89901e1e386bc1e6eda69cc1d9b8b594e95a5839", + "sha256:adeb078a2c16ee63b63702b220de3f1be412920ad511a4ecb2c284f45c4026ee" ], - "version": "==0.7.1" + "version": "==0.7.2" }, "flask-oauthlib": { "hashes": [ - "sha256:cbfe835902569909a19828582c3381148995ad677243016ccad9c951acf69406", - "sha256:d3e8ea932df01177018c502e5a07eaeb5c27bcb5352b678f14e57f892272bb56" + "sha256:5bb79c8a8e670c2eb4cb553dfc3283b6c8d1202f674934676dc173cee94fe39c", + "sha256:a5c3b62959aa1922470a62b6ebf4273b75f1c29561a7eb4a69cde85d45a1d669" ], - "version": "==0.9.5" + "version": "==0.9.6" }, "flask-principal": { "hashes": [ @@ -335,140 +510,233 @@ }, "flask-sqlalchemy": { "hashes": [ - "sha256:0c9609b0d72871c540a7945ea559c8fdf5455192d2db67219509aed680a3d45a", - "sha256:8631bbea987bc3eb0f72b1f691d47bd37ceb795e73b59ab48586d76d75a7c605" + "sha256:05b31d2034dd3f2a685cbbae4cfc4ed906b2a733cff7964ada450fd5e462b84e", + "sha256:bfc7150eaf809b1c283879302f04c42791136060c6eeb12c0c6674fb1291fae5" ], - "version": "==2.4.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.4.4" }, "flask-talisman": { "hashes": [ - "sha256:5d77780b2220012a6748e0b603cbbf7889a2833c4e77157794e13dddb183e347", - "sha256:e4e3ccba66895e1f46d5b62a9cc0f273731da601bc92d2b9af908011298c0e2b" + "sha256:08a25360c771f7a79d6d4db2abfa71f7422e62a714418b671d69d6a201764d05", + "sha256:5d502ec0c51bf1755a797b8cffbe4e94f8684af712ba0b56f3d80b79277ef285" ], - "version": "==0.5.0" + "version": "==0.8.1" }, "flask-webpackext": { "hashes": [ - "sha256:8a5b9032ed707f920234fcc7c32d24962f17213eb66636a53f5d7d8aa7f18da4", - "sha256:92569ae05b6799a9eba791cc7877a39f1d5545cabd0d4c2cc5bfb5964dbf4958" + "sha256:36e4b2d19f3e12e0bb370248094e1631a0cf8e607e76ca8c437718395b90c7ad", + "sha256:6313903d5aad5f330cb14ce97e7fec22541da413d5fe71b33b1f1a2eb69e426f" ], - "version": "==1.0.0" + "version": "==1.0.2" }, "flask-wtf": { "hashes": [ - "sha256:5d14d55cfd35f613d99ee7cba0fc3fbbe63ba02f544d349158c14ca15561cc36", - "sha256:d9a9e366b32dcbb98ef17228e76be15702cd2600675668bca23f63a7947fd5ac" + "sha256:01feccfc395405cea48a3f36c23f0d766e2cc6fd2a5a065ad50ad3e5827ec797", + "sha256:872fbb17b5888bfc734edbdcf45bc08fb365ca39f69d25dc752465a455517b28" ], - "version": "==0.14.2" + "markers": "python_version >= '3.6'", + "version": "==1.0.0" + }, + "frozenlist": { + "hashes": [ + "sha256:01d79515ed5aa3d699b05f6bdcf1fe9087d61d6b53882aa599a10853f0479c6c", + "sha256:0a7c7cce70e41bc13d7d50f0e5dd175f14a4f1837a8549b0936ed0cbe6170bf9", + "sha256:11ff401951b5ac8c0701a804f503d72c048173208490c54ebb8d7bb7c07a6d00", + "sha256:14a5cef795ae3e28fb504b73e797c1800e9249f950e1c964bb6bdc8d77871161", + "sha256:16eef427c51cb1203a7c0ab59d1b8abccaba9a4f58c4bfca6ed278fc896dc193", + "sha256:16ef7dd5b7d17495404a2e7a49bac1bc13d6d20c16d11f4133c757dd94c4144c", + "sha256:181754275d5d32487431a0a29add4f897968b7157204bc1eaaf0a0ce80c5ba7d", + "sha256:1cf63243bc5f5c19762943b0aa9e0d3fb3723d0c514d820a18a9b9a5ef864315", + "sha256:1cfe6fef507f8bac40f009c85c7eddfed88c1c0d38c75e72fe10476cef94e10f", + "sha256:1fef737fd1388f9b93bba8808c5f63058113c10f4e3c0763ced68431773f72f9", + "sha256:25b358aaa7dba5891b05968dd539f5856d69f522b6de0bf34e61f133e077c1a4", + "sha256:26f602e380a5132880fa245c92030abb0fc6ff34e0c5500600366cedc6adb06a", + "sha256:28e164722ea0df0cf6d48c4d5bdf3d19e87aaa6dfb39b0ba91153f224b912020", + "sha256:2de5b931701257d50771a032bba4e448ff958076380b049fd36ed8738fdb375b", + "sha256:3457f8cf86deb6ce1ba67e120f1b0128fcba1332a180722756597253c465fc1d", + "sha256:351686ca020d1bcd238596b1fa5c8efcbc21bffda9d0efe237aaa60348421e2a", + "sha256:406aeb340613b4b559db78d86864485f68919b7141dec82aba24d1477fd2976f", + "sha256:41de4db9b9501679cf7cddc16d07ac0f10ef7eb58c525a1c8cbff43022bddca4", + "sha256:41f62468af1bd4e4b42b5508a3fe8cc46a693f0cdd0ca2f443f51f207893d837", + "sha256:4766632cd8a68e4f10f156a12c9acd7b1609941525569dd3636d859d79279ed3", + "sha256:47b2848e464883d0bbdcd9493c67443e5e695a84694efff0476f9059b4cb6257", + "sha256:4a495c3d513573b0b3f935bfa887a85d9ae09f0627cf47cad17d0cc9b9ba5c38", + "sha256:4ad065b2ebd09f32511ff2be35c5dfafee6192978b5a1e9d279a5c6e121e3b03", + "sha256:4c457220468d734e3077580a3642b7f682f5fd9507f17ddf1029452450912cdc", + "sha256:4f52d0732e56906f8ddea4bd856192984650282424049c956857fed43697ea43", + "sha256:54a1e09ab7a69f843cd28fefd2bcaf23edb9e3a8d7680032c8968b8ac934587d", + "sha256:5a72eecf37eface331636951249d878750db84034927c997d47f7f78a573b72b", + "sha256:5df31bb2b974f379d230a25943d9bf0d3bc666b4b0807394b131a28fca2b0e5f", + "sha256:66a518731a21a55b7d3e087b430f1956a36793acc15912e2878431c7aec54210", + "sha256:6790b8d96bbb74b7a6f4594b6f131bd23056c25f2aa5d816bd177d95245a30e3", + "sha256:68201be60ac56aff972dc18085800b6ee07973c49103a8aba669dee3d71079de", + "sha256:6e105013fa84623c057a4381dc8ea0361f4d682c11f3816cc80f49a1f3bc17c6", + "sha256:705c184b77565955a99dc360f359e8249580c6b7eaa4dc0227caa861ef46b27a", + "sha256:72cfbeab7a920ea9e74b19aa0afe3b4ad9c89471e3badc985d08756efa9b813b", + "sha256:735f386ec522e384f511614c01d2ef9cf799f051353876b4c6fb93ef67a6d1ee", + "sha256:82d22f6e6f2916e837c91c860140ef9947e31194c82aaeda843d6551cec92f19", + "sha256:83334e84a290a158c0c4cc4d22e8c7cfe0bba5b76d37f1c2509dabd22acafe15", + "sha256:84e97f59211b5b9083a2e7a45abf91cfb441369e8bb6d1f5287382c1c526def3", + "sha256:87521e32e18a2223311afc2492ef2d99946337da0779ddcda77b82ee7319df59", + "sha256:878ebe074839d649a1cdb03a61077d05760624f36d196884a5cafb12290e187b", + "sha256:89fdfc84c6bf0bff2ff3170bb34ecba8a6911b260d318d377171429c4be18c73", + "sha256:8b4c7665a17c3a5430edb663e4ad4e1ad457614d1b2f2b7f87052e2ef4fa45ca", + "sha256:8b54cdd2fda15467b9b0bfa78cee2ddf6dbb4585ef23a16e14926f4b076dfae4", + "sha256:94728f97ddf603d23c8c3dd5cae2644fa12d33116e69f49b1644a71bb77b89ae", + "sha256:954b154a4533ef28bd3e83ffdf4eadf39deeda9e38fb8feaf066d6069885e034", + "sha256:977a1438d0e0d96573fd679d291a1542097ea9f4918a8b6494b06610dfeefbf9", + "sha256:9ade70aea559ca98f4b1b1e5650c45678052e76a8ab2f76d90f2ac64180215a2", + "sha256:9b6e21e5770df2dea06cb7b6323fbc008b13c4a4e3b52cb54685276479ee7676", + "sha256:a0d3ffa8772464441b52489b985d46001e2853a3b082c655ec5fad9fb6a3d618", + "sha256:a37594ad6356e50073fe4f60aa4187b97d15329f2138124d252a5a19c8553ea4", + "sha256:a8d86547a5e98d9edd47c432f7a14b0c5592624b496ae9880fb6332f34af1edc", + "sha256:aa44c4740b4e23fcfa259e9dd52315d2b1770064cde9507457e4c4a65a04c397", + "sha256:acc4614e8d1feb9f46dd829a8e771b8f5c4b1051365d02efb27a3229048ade8a", + "sha256:af2a51c8a381d76eabb76f228f565ed4c3701441ecec101dd18be70ebd483cfd", + "sha256:b2ae2f5e9fa10805fb1c9adbfefaaecedd9e31849434be462c3960a0139ed729", + "sha256:b46f997d5ed6d222a863b02cdc9c299101ee27974d9bbb2fd1b3c8441311c408", + "sha256:bc93f5f62df3bdc1f677066327fc81f92b83644852a31c6aa9b32c2dde86ea7d", + "sha256:bfbaa08cf1452acad9cb1c1d7b89394a41e712f88df522cea1a0f296b57782a0", + "sha256:c1e8e9033d34c2c9e186e58279879d78c94dd365068a3607af33f2bc99357a53", + "sha256:c5328ed53fdb0a73c8a50105306a3bc013e5ca36cca714ec4f7bd31d38d8a97f", + "sha256:c6a9d84ee6427b65a81fc24e6ef589cb794009f5ca4150151251c062773e7ed2", + "sha256:c98d3c04701773ad60d9545cd96df94d955329efc7743fdb96422c4b669c633b", + "sha256:cb3957c39668d10e2b486acc85f94153520a23263b6401e8f59422ef65b9520d", + "sha256:e63ad0beef6ece06475d29f47d1f2f29727805376e09850ebf64f90777962792", + "sha256:e74f8b4d8677ebb4015ac01fcaf05f34e8a1f22775db1f304f497f2f88fdc697", + "sha256:e7d0dd3e727c70c2680f5f09a0775525229809f1a35d8552b92ff10b2b14f2c2", + "sha256:ec6cf345771cdb00791d271af9a0a6fbfc2b6dd44cb753f1eeaa256e21622adb", + "sha256:ed58803563a8c87cf4c0771366cf0ad1aa265b6b0ae54cbbb53013480c7ad74d", + "sha256:f0081a623c886197ff8de9e635528fd7e6a387dccef432149e25c13946cb0cd0", + "sha256:f025f1d6825725b09c0038775acab9ae94264453a696cc797ce20c0769a7b367", + "sha256:f5f3b2942c3b8b9bfe76b408bbaba3d3bb305ee3693e8b1d631fe0a0d4f93673", + "sha256:fbd4844ff111449f3bbe20ba24fbb906b5b1c2384d0f3287c9f7da2354ce6d23" + ], + "markers": "python_version >= '3.6'", + "version": "==1.2.0" }, "ftfy": { "hashes": [ - "sha256:3c0066db64a98436e751e56414f03f1cdea54f29364c0632c141c36cca6a5d94" + "sha256:ba71121a9c8d7790d3e833c6c1021143f3e5c4118293ec3afb5d43ed9ca8e72b" ], - "version": "==4.4.3" + "markers": "python_version >= '3.6'", + "version": "==6.0.3" }, "future": { "hashes": [ - "sha256:67045236dcfd6816dc439556d009594abf643e5eb48992e36beac09c2ca659b8" - ], - "version": "==0.17.1" - }, - "html5lib": { - "hashes": [ - "sha256:20b159aa3badc9d5ee8f5c647e5efd02ed2a66ab8d354930bd9ff139fc1dc0a3", - "sha256:66cb0dcfdbbc4f9c3ba1a63fdb511ffdbd4f513b2b6d81b80cd26ce6b3fb3736" + "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d" ], - "version": "==1.0.1" + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'", + "version": "==0.18.2" }, "idna": { "hashes": [ - "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e", - "sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16" + "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", + "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" ], - "version": "==2.7" + "markers": "python_version >= '3'", + "version": "==3.3" }, "idutils": { "hashes": [ - "sha256:1e92c4f4d2fa546ff7fb34d9a8e8be6cab44e4a7c735a5b2d28607b3b2aa03e3", - "sha256:a28ff017c431b1732d598d3b677409c60e3f770ac5803bf3b7ce25ed02cd658e" + "sha256:01edcde8394b73dc725958770e6e8d20088790345639982698715749f8213acc", + "sha256:80c10f2ecb5cf020aa788ea860fa1f450a5a6714a0e95ae62334d5d286b395be" ], "index": "pypi", - "version": "==1.1.3" + "version": "==1.1.9" }, "importlib-metadata": { "hashes": [ - "sha256:aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26", - "sha256:d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af" + "sha256:53ccfd5c134223e497627b9815d5030edf77d2ed573922f7a0b8f8bb81a1c100", + "sha256:75bdec14c397f528724c1bfd9709d660b33a4d2e77387a3358f20b848bb5e5fb" ], - "markers": "python_version < '3.8'", - "version": "==0.23" + "markers": "python_version < '3.9'", + "version": "==4.8.2" + }, + "importlib-resources": { + "hashes": [ + "sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45", + "sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b" + ], + "markers": "python_version < '3.9' and python_version < '3.9'", + "version": "==5.4.0" }, "infinity": { "hashes": [ - "sha256:dc4aa138d7e366fc00d2e741e32c78a0fecd16b74f8daeb3f7408b459668005c" + "sha256:8daa7c15ce2100fdccfde212337e0cd5cf085869f54dc2634b6c30d61461ecda" ], - "version": "==1.4" + "version": "==1.5" }, "intervals": { "hashes": [ - "sha256:37921da1407a5e9384e8e1350cfb8500f8d0d69fc43d03d01a4fdc6e7a7c7166" + "sha256:7c963abf7b4be2be40322b84e036af5d4ebec0945b5d29df7da1a638b3fea768", + "sha256:c7ee568c583ca857c0d91af6d90ee5e0e8adef3f5646d0076bfb87305ae43090" ], - "version": "==0.8.1" + "version": "==0.9.2" }, "invenio": { "extras": [ - "elasticsearch6", + "elasticsearch7", "postgresql" ], "hashes": [ - "sha256:adff48d55747a109c6b2c279c0d9b957779a65b5e2dd2e71c484840481510c76", - "sha256:b093fd5b684eb0d4ae2c9d080d332c9ee955e0d3ee3ec494bcb525ca2e1dcbf9" + "sha256:d480e1847c681220624563c28f44a0bcc24eb7457e80b9594ff1c285c86bd69b", + "sha256:eddc4d9e8f0f8a1e2efada5a582c9b45d9fe3e49740051e2fe0fe8ec999f94f0" ], "index": "pypi", - "version": "==3.1.1" + "version": "==3.4.1" }, "invenio-accounts": { "hashes": [ - "sha256:82f75c33e66fb57ec7811da22cc2225601b43c600ef303ca45ce20d40f2422cf", - "sha256:b928535e4f3ffe53fcf07b2056f1f1b27b4ff8b83f57583c489f05db6dec5587" + "sha256:8799b251f3d38b8825d95cd6145e2593c09a6f31bfe2b2369c1cfde02e5aef19", + "sha256:cb690e35f9ced8f5971ad08e2fb9a4b33459d11f486878abbb2222e5f06d2b93" ], "index": "pypi", - "version": "==1.1.1" + "version": "==1.4.8" }, "invenio-app": { "hashes": [ - "sha256:a77aee57118d06909d2187a3e25f3d0a299189e06bb43b4d7404a689119ae75a", - "sha256:df15a9ef65758f82f75f8b392456793c2fc36e9984d15113c852a7d8fd2c52dd" + "sha256:0d53a94ba70cee9b1873d3cad812e5ccf370f42f76af045fa3453b1acb467daf", + "sha256:af2df5647307a3fb58f997466667e8ddfe575d58c651fdc6ccca2e9ddb91bbe5" ], - "version": "==1.1.1" + "index": "pypi", + "version": "==1.3.2" + }, + "invenio-assets": { + "hashes": [ + "sha256:1ba8d88ad740375996086bb0096def3cff86bdaf3567368c8d86f45e1d4cd218", + "sha256:2d1f49136a5705e7521686b642e03ba7d44703288d496ec93312fe887a5daeeb" + ], + "version": "==1.2.7" }, "invenio-base": { "hashes": [ - "sha256:6e532854a43e4f54fc7d9b1cbda720ce4ce6383b00cee6ba5f7e86ef78f12fe2", - "sha256:f972e10b69a68a80c342f0bcf6b3b02a6a67af4fb6e8e347ce8b482fcb47e973" + "sha256:375b84ab32ebef15f766b8be58005e89b6ec13ba0567a9a21da9001a23562977", + "sha256:d22a8dee25def2d5e7f10566a12b63e643d6c1267de0baa335dbdfd7382707d6" ], - "version": "==1.0.2" + "version": "==1.2.5" }, "invenio-cache": { "hashes": [ - "sha256:8431d8b68dbb737cd7035f6467fec18dd29ad9ac35e20405d52af6c2d294557a", - "sha256:f3620bb842f9084ddd5dc81f0fe234f58228c33f59e6771483fd09cb127201cc" + "sha256:1212a83f98fbe29a936587f7c5b2f838f7f934b0b2a9d9a993e377e5a8ab0cf5", + "sha256:a4562639f2f63cbc9de1302e159ecd9363f17d53d912a8d0773ffe76e2f153fc" ], - "version": "==1.0.0" + "version": "==1.1.0" }, "invenio-celery": { "hashes": [ - "sha256:22cda704fa8abaa885a327539899887a939832beda7de0d1f1d5d84b4ac153b1", - "sha256:d102dcf3e94cfa11b0973626852f5fd6cac8fa3ba364c42fcec8ecc0b533d838" + "sha256:b8219039ac6e17cedb684e1ce99c369c77ca4b0207eedc2b147070db8a87d452", + "sha256:ce599456581db9d57f1167db5dd315db441a4cbfbf1223c3d0b079a1b3e5c147" ], - "version": "==1.0.1" + "version": "==1.2.3" }, "invenio-config": { "hashes": [ - "sha256:84f67b7fc45095800aacbad4bf23f7498d03eab9f2f2fad3a367f2c56bf1b9e4", - "sha256:885e092f98aaf50a0bb6ecfd667e239346bb1eb6fc6762d52493842f497664d0" + "sha256:238ab074991e7f0d6ee7ebc6eb2f5e41658749dd977ab6e86476e862c0efaf28", + "sha256:9d10492b49a46703f0ac028ce8ab78b5ff1c72b180ecb4ffcee5bf49682d1e6c" ], - "version": "==1.0.2" + "version": "==1.0.3" }, "invenio-db": { "extras": [ @@ -476,109 +744,105 @@ "versioning" ], "hashes": [ - "sha256:610e9a812527469403806a112ae98bd3579a65b93f8a0ed0842c6db07398edf6", - "sha256:6c61e40ec7487eba01e1e29b43946c996a44855dd3083d7e7bec8426c0e195b4" + "sha256:bc65e82c350a908c4802399d39ae01cde051195ef42e0bc396c6a63e0a75bf50", + "sha256:c8861a665af5cbb3645d4fde5cc0e04354a108a3d5b4cf2c3eee5d252da5d534" ], - "version": "==1.0.4" + "version": "==1.0.9" }, "invenio-i18n": { "hashes": [ - "sha256:69513d531ccffdfa47cec1e7cd701c72966573d2e9c4e24c96607cb7324dce48", - "sha256:b591d753cd79a98bbef98a0ac5d9abf105f5cb8af94614dbf92688782a7b77b0" + "sha256:02534002f3bf63706a4c3d3b15c32ce4cce0c341217d4204c7c29486fabece22", + "sha256:67b22098900f4fa79a4db47cd189d3fb993223c26e560fd1c87f69b7cc2c5bc8" ], - "version": "==1.1.1" + "version": "==1.3.1" }, "invenio-indexer": { "hashes": [ - "sha256:ca8c705813eb1256625f3c6d1550a0610be693676d4929f2f63e0fcf17879973" + "sha256:7dc350c5dd607984082a80553407516ba817e3c3dd26a864507d23a83f3fcf94", + "sha256:a7b9d3de1269d81f2d8be4b5d1f19748e9f560f6489800dcf2999eaa00d413dc" ], "index": "pypi", - "version": "==1.0.2" + "version": "==1.2.1" }, "invenio-logging": { "hashes": [ - "sha256:8c2f6633905d100867814e5894564e79682bca7e45ea2870a6c03a69c4860dec", - "sha256:f3a87ab70993e6c7eb5990e70dda3ab0729b1bfa6c90ecf1f9890018accb926f" + "sha256:3b98778ade4b1a4887f827dbaa095473b5d43d6e39aa4da2ae311b7201a6ef9f", + "sha256:fc2ccf7a3da8533cec4a87353a9c48d05dcc1fc9467c4314f6779bf088cb3cbc" ], "index": "pypi", - "version": "==1.1.1" + "version": "==1.3.0" }, "invenio-oauth2server": { "hashes": [ - "sha256:303b642e24ca8942d1c5f888ea648625ee4f27ce83bda31adb6a047bac6aca1b", - "sha256:d5f5f12df1a76d65f17b3dafdc40cec91667f4cb41694e4ab134b7d31018a0b7" + "sha256:98fcebc98180746533968a6e4fe3ec72568eb442cde904d11d07067825b52759", + "sha256:a460bb66a0a41520761488142dd0ddd7f3760fd84d6d16be4f8847b9d0926643" ], "index": "pypi", - "version": "==1.0.3" + "version": "==1.3.4" }, "invenio-pidstore": { "hashes": [ - "sha256:582b28e7e2bdf4df93e5398a0e147b2eb08690ede339249dd3a8c92b713e6f00", - "sha256:77f59075dfa34564b913e5d58f37d55b2c78d7b4fa1eeaa5f8c42576848bb06d" + "sha256:625c313da90fb9a322b0cf0e331fb8b7bd121f6f96694905a64227f4d3aac917", + "sha256:960fd76702ebe159392e254ae9222503452383fa1ef0b94673ed0305552917f2" ], - "version": "==1.0.0" + "version": "==1.2.2" }, "invenio-queues": { "hashes": [ - "sha256:aa61905d2ca567c12289230c945992f28223ffdb6e5fb9226f552cf8a19f7f75", - "sha256:e30cf63f1dbd5d0125c2f65083df1b719e39f4c849cfcee72c4588dff99c3d5c" + "sha256:15cf3ea8487a387c07c6cce7f955aa9d64570884f2a6907dbabe8660d186e9e4", + "sha256:bbca40a03fb6427e1193557a7a1841e2a0a29ae9400c4198b6f7a839a771337c" ], "index": "pypi", - "version": "==1.0.0a1" + "version": "==1.0.0a3" }, "invenio-records": { "hashes": [ - "sha256:8b7571e27d7a08da2fc3cf48c01dd80cac2bf1702ba63e24127b36f15e0dd9df", - "sha256:8d8d24211b101c601b81d76eb2f0d67d402f7fa755739adf83c173e2530e8d92" + "sha256:a56e2d2268289c7d78b47ee51d8981ed168e03a339c19ac6c017e37da3e7d871", + "sha256:c66f45ee92dd6be64ea222c2fef99bf78f4e2e1d683a7ebe694c83641d8b5758" ], - "version": "==1.3.0" + "version": "==1.6.0" }, "invenio-records-rest": { "hashes": [ - "sha256:ea5bb3e05d331bd38dfcf154d8fc123558dbeaaad0eb990dab852f946ee8f5b9", - "sha256:f89124c7e1e8fcc16b8652597d3c529a66cfc9f1bbba7e4d40bf880038b29691" + "sha256:67fb753131e00bd20aef9d1011d51bcb407d1a30ef2e4af8647bf3b92f2b999e", + "sha256:70ba741f19f8c9a1ae14a700d82c632175e881fd786ffdc4692f2718482e8dd1" ], "index": "pypi", - "version": "==1.4.2" + "version": "==1.8.0" }, "invenio-rest": { "hashes": [ - "sha256:665cdc6d7f47b532e4823dc1a0a62de32e31caf387efc93aff7593a34124ee1d", - "sha256:e5a73fcfc15c052840608950c0524447f1e86d24cc58a8fbf12a48a82f7e582a" + "sha256:c49f62999011b3bd9408f30342a4afbb49ca8a7dda4c35b1df0bed6119d35db8", + "sha256:d198fdea9c38b13139745bfd7ef06dae4300c2fb237a56430e5ee1f91d304821" ], "index": "pypi", - "version": "==1.0.0" + "version": "==1.2.4" }, "invenio-search": { "extras": [ - "elasticsearch6" + "elasticsearch7" ], "hashes": [ - "sha256:3db927a9a447bcfb8f84f4798a3bf656ab8ff6f093d8de83224bdde4518bf830", - "sha256:b51d0af749fb08a6d8e46e8d7d2232e75462d87bb11a78aade33497ed1079773" + "sha256:1d6f09424b731a335a6f8e05c8e5c55c29b3277486c9ac7534d2c15648e1d7ab", + "sha256:50bfbd4f7bc56f05504084305de205e5b93498ccee83741ca0dd4a0fdcc5334a" ], - "version": "==1.1.1" + "index": "pypi", + "version": "==1.4.2" }, - "ipaddress": { + "invenio-theme": { "hashes": [ - "sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794", - "sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c" + "sha256:0ba75a7e2c5a653954449d2400727a2293ddccaba2ef81b4c4f25050c6f66d4b", + "sha256:6df55cad6cbad02af2d4b162a775748e8d725cdfac5b64c74a4a9e7f3535f8ac" ], - "version": "==1.0.22" + "version": "==1.3.9" }, "ipython": { "hashes": [ - "sha256:c4ab005921641e40a68e405e286e7a1fcc464497e14d81b6914b4fd95e5dee9b", - "sha256:dd76831f065f17bddd7eaa5c781f5ea32de5ef217592cf019e34043b56895aa1" + "sha256:4f69d7423a5a1972f6347ff233e38bbf4df6a150ef20fbb00c635442ac3060aa", + "sha256:a658beaf856ce46bc453366d5dc6b2ddc6c481efd3540cb28aa3943819caac9f" ], - "version": "==7.8.0" - }, - "ipython-genutils": { - "hashes": [ - "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8", - "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8" - ], - "version": "==0.2.0" + "index": "pypi", + "version": "==7.29.0" }, "isbnid-fork": { "hashes": [ @@ -588,45 +852,49 @@ }, "itsdangerous": { "hashes": [ - "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", - "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749" + "sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c", + "sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0" ], - "version": "==1.1.0" + "markers": "python_version >= '3.6'", + "version": "==2.0.1" }, "jedi": { "hashes": [ - "sha256:786b6c3d80e2f06fd77162a07fed81b8baa22dde5d62896a790a331d6ac21a27", - "sha256:ba859c74fa3c966a22f2aeebe1b74ee27e2a462f56d3f5f7ca4a59af61bfe42e" + "sha256:18456d83f65f400ab0c2d3319e48520420ef43b23a086fdc05dff34132f0fb93", + "sha256:92550a404bad8afed881a137ec9a461fed49eca661414be45059329614ed0707" ], - "version": "==0.15.1" + "markers": "python_version >= '3.6'", + "version": "==0.18.0" }, "jinja2": { "hashes": [ - "sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", - "sha256:14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b" + "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8", + "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7" ], - "version": "==2.10.1" + "markers": "python_version >= '3.6'", + "version": "==3.0.3" }, - "jinja2-time": { + "jsmin": { "hashes": [ - "sha256:d14eaa4d315e7688daa4969f616f226614350c48730bfa1692d2caebd8c90d40", - "sha256:d3eab6605e3ec8b7a0863df09cc1d23714908fa61aa6986a845c20ba488b4efa" + "sha256:88fc1bd6033a47c5911dbcada7d279c7a8b7ad0841909590f6a742c20c4d2e08" ], - "version": "==0.2.0" + "version": "==3.0.0" }, "jsonpatch": { "hashes": [ - "sha256:83f29a2978c13da29bfdf89da9d65542d62576479caf215df19632d7dc04c6e6", - "sha256:cbb72f8bf35260628aea6b508a107245f757d1ec839a19c34349985e2c05645a" + "sha256:26ac385719ac9f54df8a2f0827bb8253aa3ea8ab7b3368457bcdb8c14595a397", + "sha256:b6ddfe6c3db30d81a96aaeceb6baf916094ffa23d7dd5fa2c13e13f8b6e600c2" ], - "version": "==1.24" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==1.32" }, "jsonpointer": { "hashes": [ - "sha256:c192ba86648e05fdae4f08a17ec25180a9aef5008d973407b581798a83975362", - "sha256:ff379fa021d1b81ab539f5ec467c7745beb1a5671463f9dcc2b2d458bd361c1e" + "sha256:26d9a47a72d4dc3e3ae72c4c6cd432afd73c680164cd2540772eab53cb3823b6", + "sha256:f09f8deecaaa5aea65b5eb4f67ca4e54e1a61f7a11c75085e360fe6feb6a48bf" ], - "version": "==2.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.2" }, "jsonref": { "hashes": [ @@ -637,85 +905,139 @@ }, "jsonresolver": { "hashes": [ - "sha256:bd4268b07143cc6a5895783185266e72be1546c9332febbd09f29ad80daa0f7e", - "sha256:cf1e37f4c8db7415a53f8118cde988ba746f486d890732bd83f6f1ff6083c11b" + "sha256:2d8090f6a1fe92e70f2903f05515415bde7ce46402e528279f865bce4ee689ca", + "sha256:f17a526988456d9895023ae3580714d6ce6af5656869d11d9860dc4a799cf6d4" ], - "version": "==0.2.1" + "version": "==0.3.1" }, "jsonschema": { "hashes": [ - "sha256:5f9c0a719ca2ce14c5de2fd350a64fd2d13e8539db29836a86adc990bb1a068f", - "sha256:8d4a2b7b6c2237e0199c8ea1a6d3e05bf118e289ae2b9d7ba444182a2959560d" + "sha256:2a0f162822a64d95287990481b45d82f096e99721c86534f48201b64ebca6e8c", + "sha256:390713469ae64b8a58698bb3cbc3859abe6925b565a973f87323ef21b09a27a8" ], "index": "pypi", - "version": "==3.0.2" + "version": "==4.2.1" }, "kombu": { "hashes": [ - "sha256:529df9e0ecc0bad9fc2b376c3ce4796c41b482cf697b78b71aea6ebe7ca353c8", - "sha256:7a2cbed551103db9a4e2efafe9b63222e012a61a18a881160ad797b9d4e1d0a1" + "sha256:31bd287191bf56b1addba54a28eced8d6b6b5ba57ad184f48b065578f73c8e33", + "sha256:f262a2adc71b53e5b7dad4933bbdee65d8766ca4df6a9043b13edaad2144aaec" ], - "version": "==4.3.0" + "markers": "python_version >= '3.7'", + "version": "==5.2.1" }, "limits": { "hashes": [ - "sha256:9df578f4161017d79f5188609f1d65f6b639f8aad2914c3960c9252e56a0ff95", - "sha256:a017b8d9e9da6761f4574642149c337f8f540d4edfe573fb91ad2c4001a2bc76" + "sha256:0e5f8b10f18dd809eb2342f5046eb9aa5e4e69a0258567b5f4aa270647d438b3", + "sha256:f0c3319f032c4bfad68438ed1325c0fac86dac64582c7c25cddc87a0b658fa20" ], - "version": "==1.3" + "version": "==1.5.1" }, "mako": { "hashes": [ - "sha256:a36919599a9b7dc5d86a7a8988f23a9a3a3d083070023bab23d64f7f1d1e0a4b" + "sha256:169fa52af22a91900d852e937400e79f535496191c63712e3b9fda5a9bed6fc3", + "sha256:6804ee66a7f6a6416910463b00d76a7b25194cd27f1918500c5bd7be2a088a23" ], - "version": "==1.1.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.1.5" }, "markupsafe": { "hashes": [ - "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", - "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", - "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", - "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", - "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", - "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", - "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", - "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", - "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", - "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", - "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", - "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", - "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", - "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", - "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", - "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", - "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", - "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", - "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", - "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", - "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", - "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", - "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", - "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", - "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", - "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", - "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", - "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7" - ], - "version": "==1.1.1" + "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298", + "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64", + "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b", + "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194", + "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567", + "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff", + "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724", + "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74", + "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646", + "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35", + "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6", + "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a", + "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6", + "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad", + "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26", + "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38", + "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac", + "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7", + "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6", + "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047", + "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75", + "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f", + "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b", + "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135", + "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8", + "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a", + "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a", + "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1", + "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9", + "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864", + "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914", + "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee", + "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f", + "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18", + "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8", + "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2", + "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d", + "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b", + "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b", + "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86", + "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6", + "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f", + "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb", + "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833", + "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28", + "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e", + "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415", + "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902", + "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f", + "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d", + "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9", + "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d", + "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145", + "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066", + "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c", + "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1", + "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a", + "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207", + "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f", + "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53", + "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd", + "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134", + "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85", + "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9", + "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5", + "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94", + "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509", + "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", + "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" + ], + "markers": "python_version >= '3.6'", + "version": "==2.0.1" }, "marshmallow": { "hashes": [ - "sha256:ee20892f41b2ac51f9f1927f30696a2fb91b99fe9e12bf54624e78654612cba7", - "sha256:f88fdf8b9cad487bf74cc03382e0e3792dd740144d4ef3395d74b03f31dcd9cf" + "sha256:04438610bc6dadbdddb22a4a55bcc7f6f8099e69580b2e67f5a681933a1f4400", + "sha256:4c05c1684e0e97fe779c62b91878f173b937fe097b356cd82f793464f5bc6138" ], "index": "pypi", - "version": "==2.20.5" + "version": "==3.14.1" + }, + "matplotlib-inline": { + "hashes": [ + "sha256:a04bfba22e0d1395479f866853ec1ee28eea1485c1d69a6faf00dc3e24ff34ee", + "sha256:aed605ba3b72462d64d475a21a9296f400a19c4f74a31b59103d2a99ffd5aa5c" + ], + "markers": "python_version >= '3.5'", + "version": "==0.1.3" }, "maxminddb": { "hashes": [ - "sha256:df1451bcd848199905ac0de4631b3d02d6a655ad28ba5e5a4ca29a23358db712" + "sha256:e37707ec4fab115804670e0fb7aedb4b57075a8b6f80052bdc648d3c005184e5" ], - "version": "==1.4.1" + "markers": "python_version >= '3.6'", + "version": "==2.2.0" }, "maxminddb-geolite2": { "hashes": [ @@ -723,25 +1045,122 @@ ], "version": "==2018.703" }, - "more-itertools": { - "hashes": [ - "sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", - "sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4" + "msgpack": { + "hashes": [ + "sha256:0cb94ee48675a45d3b86e61d13c1e6f1696f0183f0715544976356ff86f741d9", + "sha256:1026dcc10537d27dd2d26c327e552f05ce148977e9d7b9f1718748281b38c841", + "sha256:26a1759f1a88df5f1d0b393eb582ec022326994e311ba9c5818adc5374736439", + "sha256:2a5866bdc88d77f6e1370f82f2371c9bc6fc92fe898fa2dec0c5d4f5435a2694", + "sha256:31c17bbf2ae5e29e48d794c693b7ca7a0c73bd4280976d408c53df421e838d2a", + "sha256:497d2c12426adcd27ab83144057a705efb6acc7e85957a51d43cdcf7f258900f", + "sha256:5a9ee2540c78659a1dd0b110f73773533ee3108d4e1219b5a15a8d635b7aca0e", + "sha256:8521e5be9e3b93d4d5e07cb80b7e32353264d143c1f072309e1863174c6aadb1", + "sha256:87869ba567fe371c4555d2e11e4948778ab6b59d6cc9d8460d543e4cfbbddd1c", + "sha256:8ffb24a3b7518e843cd83538cf859e026d24ec41ac5721c18ed0c55101f9775b", + "sha256:92be4b12de4806d3c36810b0fe2aeedd8d493db39e2eb90742b9c09299eb5759", + "sha256:9ea52fff0473f9f3000987f313310208c879493491ef3ccf66268eff8d5a0326", + "sha256:a4355d2193106c7aa77c98fc955252a737d8550320ecdb2e9ac701e15e2943bc", + "sha256:a99b144475230982aee16b3d249170f1cccebf27fb0a08e9f603b69637a62192", + "sha256:ac25f3e0513f6673e8b405c3a80500eb7be1cf8f57584be524c4fa78fe8e0c83", + "sha256:b28c0876cce1466d7c2195d7658cf50e4730667196e2f1355c4209444717ee06", + "sha256:b55f7db883530b74c857e50e149126b91bb75d35c08b28db12dcb0346f15e46e", + "sha256:b6d9e2dae081aa35c44af9c4298de4ee72991305503442a5c74656d82b581fe9", + "sha256:c747c0cc08bd6d72a586310bda6ea72eeb28e7505990f342552315b229a19b33", + "sha256:d6c64601af8f3893d17ec233237030e3110f11b8a962cb66720bf70c0141aa54", + "sha256:d8167b84af26654c1124857d71650404336f4eb5cc06900667a493fc619ddd9f", + "sha256:de6bd7990a2c2dabe926b7e62a92886ccbf809425c347ae7de277067f97c2887", + "sha256:e36a812ef4705a291cdb4a2fd352f013134f26c6ff63477f20235138d1d21009", + "sha256:e89ec55871ed5473a041c0495b7b4e6099f6263438e0bd04ccd8418f92d5d7f2", + "sha256:f3e6aaf217ac1c7ce1563cf52a2f4f5d5b1f64e8729d794165db71da57257f0c", + "sha256:f484cd2dca68502de3704f056fa9b318c94b1539ed17a4c784266df5d6978c87", + "sha256:fae04496f5bc150eefad4e9571d1a76c55d021325dcd484ce45065ebbdd00984", + "sha256:fe07bc6735d08e492a327f496b7850e98cb4d112c56df69b0c844dbebcbb47f6" ], - "version": "==7.2.0" + "version": "==1.0.2" }, - "msgpack-python": { - "hashes": [ - "sha256:378cc8a6d3545b532dfd149da715abae4fda2a3adb6d74e525d0d5e51f46909b" - ], - "version": "==0.5.6" + "multidict": { + "hashes": [ + "sha256:06560fbdcf22c9387100979e65b26fba0816c162b888cb65b845d3def7a54c9b", + "sha256:067150fad08e6f2dd91a650c7a49ba65085303fcc3decbd64a57dc13a2733031", + "sha256:0a2cbcfbea6dc776782a444db819c8b78afe4db597211298dd8b2222f73e9cd0", + "sha256:0dd1c93edb444b33ba2274b66f63def8a327d607c6c790772f448a53b6ea59ce", + "sha256:0fed465af2e0eb6357ba95795d003ac0bdb546305cc2366b1fc8f0ad67cc3fda", + "sha256:116347c63ba049c1ea56e157fa8aa6edaf5e92925c9b64f3da7769bdfa012858", + "sha256:1b4ac3ba7a97b35a5ccf34f41b5a8642a01d1e55454b699e5e8e7a99b5a3acf5", + "sha256:1c7976cd1c157fa7ba5456ae5d31ccdf1479680dc9b8d8aa28afabc370df42b8", + "sha256:246145bff76cc4b19310f0ad28bd0769b940c2a49fc601b86bfd150cbd72bb22", + "sha256:25cbd39a9029b409167aa0a20d8a17f502d43f2efebfe9e3ac019fe6796c59ac", + "sha256:28e6d883acd8674887d7edc896b91751dc2d8e87fbdca8359591a13872799e4e", + "sha256:2d1d55cdf706ddc62822d394d1df53573d32a7a07d4f099470d3cb9323b721b6", + "sha256:2e77282fd1d677c313ffcaddfec236bf23f273c4fba7cdf198108f5940ae10f5", + "sha256:32fdba7333eb2351fee2596b756d730d62b5827d5e1ab2f84e6cbb287cc67fe0", + "sha256:35591729668a303a02b06e8dba0eb8140c4a1bfd4c4b3209a436a02a5ac1de11", + "sha256:380b868f55f63d048a25931a1632818f90e4be71d2081c2338fcf656d299949a", + "sha256:3822c5894c72e3b35aae9909bef66ec83e44522faf767c0ad39e0e2de11d3b55", + "sha256:38ba256ee9b310da6a1a0f013ef4e422fca30a685bcbec86a969bd520504e341", + "sha256:3bc3b1621b979621cee9f7b09f024ec76ec03cc365e638126a056317470bde1b", + "sha256:3d2d7d1fff8e09d99354c04c3fd5b560fb04639fd45926b34e27cfdec678a704", + "sha256:517d75522b7b18a3385726b54a081afd425d4f41144a5399e5abd97ccafdf36b", + "sha256:5f79c19c6420962eb17c7e48878a03053b7ccd7b69f389d5831c0a4a7f1ac0a1", + "sha256:5f841c4f14331fd1e36cbf3336ed7be2cb2a8f110ce40ea253e5573387db7621", + "sha256:637c1896497ff19e1ee27c1c2c2ddaa9f2d134bbb5e0c52254361ea20486418d", + "sha256:6ee908c070020d682e9b42c8f621e8bb10c767d04416e2ebe44e37d0f44d9ad5", + "sha256:77f0fb7200cc7dedda7a60912f2059086e29ff67cefbc58d2506638c1a9132d7", + "sha256:7878b61c867fb2df7a95e44b316f88d5a3742390c99dfba6c557a21b30180cac", + "sha256:78c106b2b506b4d895ddc801ff509f941119394b89c9115580014127414e6c2d", + "sha256:8b911d74acdc1fe2941e59b4f1a278a330e9c34c6c8ca1ee21264c51ec9b67ef", + "sha256:93de39267c4c676c9ebb2057e98a8138bade0d806aad4d864322eee0803140a0", + "sha256:9416cf11bcd73c861267e88aea71e9fcc35302b3943e45e1dbb4317f91a4b34f", + "sha256:94b117e27efd8e08b4046c57461d5a114d26b40824995a2eb58372b94f9fca02", + "sha256:9815765f9dcda04921ba467957be543423e5ec6a1136135d84f2ae092c50d87b", + "sha256:98ec9aea6223adf46999f22e2c0ab6cf33f5914be604a404f658386a8f1fba37", + "sha256:a37e9a68349f6abe24130846e2f1d2e38f7ddab30b81b754e5a1fde32f782b23", + "sha256:a43616aec0f0d53c411582c451f5d3e1123a68cc7b3475d6f7d97a626f8ff90d", + "sha256:a4771d0d0ac9d9fe9e24e33bed482a13dfc1256d008d101485fe460359476065", + "sha256:a5635bcf1b75f0f6ef3c8a1ad07b500104a971e38d3683167b9454cb6465ac86", + "sha256:a9acb76d5f3dd9421874923da2ed1e76041cb51b9337fd7f507edde1d86535d6", + "sha256:ac42181292099d91217a82e3fa3ce0e0ddf3a74fd891b7c2b347a7f5aa0edded", + "sha256:b227345e4186809d31f22087d0265655114af7cda442ecaf72246275865bebe4", + "sha256:b61f85101ef08cbbc37846ac0e43f027f7844f3fade9b7f6dd087178caedeee7", + "sha256:b70913cbf2e14275013be98a06ef4b412329fe7b4f83d64eb70dce8269ed1e1a", + "sha256:b9aad49466b8d828b96b9e3630006234879c8d3e2b0a9d99219b3121bc5cdb17", + "sha256:baf1856fab8212bf35230c019cde7c641887e3fc08cadd39d32a421a30151ea3", + "sha256:bd6c9c50bf2ad3f0448edaa1a3b55b2e6866ef8feca5d8dbec10ec7c94371d21", + "sha256:c1ff762e2ee126e6f1258650ac641e2b8e1f3d927a925aafcfde943b77a36d24", + "sha256:c30ac9f562106cd9e8071c23949a067b10211917fdcb75b4718cf5775356a940", + "sha256:c9631c642e08b9fff1c6255487e62971d8b8e821808ddd013d8ac058087591ac", + "sha256:cdd68778f96216596218b4e8882944d24a634d984ee1a5a049b300377878fa7c", + "sha256:ce8cacda0b679ebc25624d5de66c705bc53dcc7c6f02a7fb0f3ca5e227d80422", + "sha256:cfde464ca4af42a629648c0b0d79b8f295cf5b695412451716531d6916461628", + "sha256:d3def943bfd5f1c47d51fd324df1e806d8da1f8e105cc7f1c76a1daf0f7e17b0", + "sha256:d9b668c065968c5979fe6b6fa6760bb6ab9aeb94b75b73c0a9c1acf6393ac3bf", + "sha256:da7d57ea65744d249427793c042094c4016789eb2562576fb831870f9c878d9e", + "sha256:dc3a866cf6c13d59a01878cd806f219340f3e82eed514485e094321f24900677", + "sha256:df23c83398715b26ab09574217ca21e14694917a0c857e356fd39e1c64f8283f", + "sha256:dfc924a7e946dd3c6360e50e8f750d51e3ef5395c95dc054bc9eab0f70df4f9c", + "sha256:e4a67f1080123de76e4e97a18d10350df6a7182e243312426d508712e99988d4", + "sha256:e5283c0a00f48e8cafcecadebfa0ed1dac8b39e295c7248c44c665c16dc1138b", + "sha256:e58a9b5cc96e014ddf93c2227cbdeca94b56a7eb77300205d6e4001805391747", + "sha256:e6453f3cbeb78440747096f239d282cc57a2997a16b5197c9bc839099e1633d0", + "sha256:e6c4fa1ec16e01e292315ba76eb1d012c025b99d22896bd14a66628b245e3e01", + "sha256:e7d81ce5744757d2f05fc41896e3b2ae0458464b14b5a2c1e87a6a9d69aefaa8", + "sha256:ea21d4d5104b4f840b91d9dc8cbc832aba9612121eaba503e54eaab1ad140eb9", + "sha256:ecc99bce8ee42dcad15848c7885197d26841cb24fa2ee6e89d23b8993c871c64", + "sha256:f0bb0973f42ffcb5e3537548e0767079420aefd94ba990b61cf7bb8d47f4916d", + "sha256:f19001e790013ed580abfde2a4465388950728861b52f0da73e8e8a9418533c0", + "sha256:f76440e480c3b2ca7f843ff8a48dc82446b86ed4930552d736c0bac507498a52", + "sha256:f9bef5cff994ca3026fcc90680e326d1a19df9841c5e3d224076407cc21471a1", + "sha256:fc66d4016f6e50ed36fb39cd287a3878ffcebfa90008535c62e0e90a7ab713ae", + "sha256:fd77c8f3cba815aa69cb97ee2b2ef385c7c12ada9c734b0f3b32e26bb88bbf1d" + ], + "markers": "python_version >= '3.6'", + "version": "==5.2.0" }, "node-semver": { "hashes": [ - "sha256:21b9a02069a71c4936b211eea4c600e78cf9ceb03ecc0272186c4ac5c3b4f1dc", - "sha256:272958646985a4791a3daf8b6fc978ee7de5287121c1c3df62fefb8fb720862e" + "sha256:e29ee4e51efb6d82c55aef5d569b888842e62e6404ce95df18d80c421f8e7dac" ], - "version": "==0.7.0" + "version": "==0.1.1" }, "oauthlib": { "hashes": [ @@ -750,27 +1169,36 @@ ], "version": "==2.1.0" }, + "packaging": { + "hashes": [ + "sha256:096d689d78ca690e4cd8a89568ba06d07ca097e3306a4381635073ca91479966", + "sha256:14317396d1e8cdb122989b916fa2c7e9ca8e2be9e8060a6eff75b6b7b4d8a7e0" + ], + "markers": "python_version >= '3.6'", + "version": "==21.2" + }, "parso": { "hashes": [ - "sha256:63854233e1fadb5da97f2744b6b24346d2750b85965e7e399bec1620232797dc", - "sha256:666b0ee4a7a1220f65d367617f2cd3ffddff3e205f3f16a0284df30e774c2a9c" + "sha256:12b83492c6239ce32ff5eed6d3639d6a536170723c6f3f1506869f1ace413398", + "sha256:a8c4922db71e4fdb90e0d0bc6e50f9b273d3397925e5e60a717e719201778d22" ], - "version": "==0.5.1" + "markers": "python_version >= '3.6'", + "version": "==0.8.2" }, "passlib": { "hashes": [ - "sha256:3d948f64138c25633613f303bcc471126eae67c04d5e3f6b7b8ce6242f8653e0", - "sha256:43526aea08fa32c6b6dbbbe9963c4c767285b78147b7437597f992812f69d280" + "sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1", + "sha256:defd50f72b65c5402ab2c573830a6978e5f202ad0d984793c8dde2c4152ebe04" ], - "version": "==1.7.1" + "version": "==1.7.4" }, "pexpect": { "hashes": [ - "sha256:2094eefdfcf37a1fdbfb9aa090862c1a4878e5c7e0e7e7088bdb511c558e5cd1", - "sha256:9e2c1fd0e6ee3a49b28f95d4b33bc389c89b20af6a1255906e90ff1262ce62eb" + "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937", + "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c" ], "markers": "sys_platform != 'win32'", - "version": "==4.7.0" + "version": "==4.8.0" }, "pickleshare": { "hashes": [ @@ -781,127 +1209,154 @@ }, "pluggy": { "hashes": [ - "sha256:0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6", - "sha256:fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34" + "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", + "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" ], - "version": "==0.13.0" - }, - "poyo": { - "hashes": [ - "sha256:3e2ca8e33fdc3c411cd101ca395668395dd5dc7ac775b8e809e3def9f9fe041a", - "sha256:e26956aa780c45f011ca9886f044590e2d8fd8b61db7b1c1cf4e0869f48ed4dd" - ], - "version": "==0.5.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.13.1" }, "prompt-toolkit": { "hashes": [ - "sha256:11adf3389a996a6d45cc277580d0d53e8a5afd281d0c9ec71b28e6f121463780", - "sha256:2519ad1d8038fd5fc8e770362237ad0364d16a7650fb5724af6997ed5515e3c1", - "sha256:977c6583ae813a37dc1c2e1b715892461fcbdaa57f6fc62f33a528c4886c8f55" + "sha256:449f333dd120bd01f5d296a8ce1452114ba3a71fae7288d2f0ae2c918764fa72", + "sha256:48d85cdca8b6c4f16480c7ce03fd193666b62b0a21667ca56b4bb5ad679d1170" ], - "version": "==2.0.9" + "markers": "python_full_version >= '3.6.2'", + "version": "==3.0.22" }, "psycopg2-binary": { "hashes": [ - "sha256:080c72714784989474f97be9ab0ddf7b2ad2984527e77f2909fcd04d4df53809", - "sha256:110457be80b63ff4915febb06faa7be002b93a76e5ba19bf3f27636a2ef58598", - "sha256:171352a03b22fc099f15103959b52ee77d9a27e028895d7e5fde127aa8e3bac5", - "sha256:19d013e7b0817087517a4b3cab39c084d78898369e5c46258aab7be4f233d6a1", - "sha256:249b6b21ae4eb0f7b8423b330aa80fab5f821b9ffc3f7561a5e2fd6bb142cf5d", - "sha256:2ac0731d2d84b05c7bb39e85b7e123c3a0acd4cda631d8d542802c88deb9e87e", - "sha256:2b6d561193f0dc3f50acfb22dd52ea8c8dfbc64bcafe3938b5f209cc17cb6f00", - "sha256:2bd23e242e954214944481124755cbefe7c2cf563b1a54cd8d196d502f2578bf", - "sha256:3e1239242ca60b3725e65ab2f13765fc199b03af9eaf1b5572f0e97bdcee5b43", - "sha256:3eb70bb697abbe86b1d2b1316370c02ba320bfd1e9e35cf3b9566a855ea8e4e5", - "sha256:51a2fc7e94b98bd1bb5d4570936f24fc2b0541b63eccadf8fdea266db8ad2f70", - "sha256:52f1bdafdc764b7447e393ed39bb263eccb12bfda25a4ac06d82e3a9056251f6", - "sha256:5b3581319a3951f1e866f4f6c5e42023db0fae0284273b82e97dfd32c51985cd", - "sha256:63c1b66e3b2a3a336288e4bcec499e0dc310cd1dceaed1c46fa7419764c68877", - "sha256:8123a99f24ecee469e5c1339427bcdb2a33920a18bb5c0d58b7c13f3b0298ba3", - "sha256:85e699fcabe7f817c0f0a412d4e7c6627e00c412b418da7666ff353f38e30f67", - "sha256:8dbff4557bbef963697583366400822387cccf794ccb001f1f2307ed21854c68", - "sha256:908d21d08d6b81f1b7e056bbf40b2f77f8c499ab29e64ec5113052819ef1c89b", - "sha256:af39d0237b17d0a5a5f638e9dffb34013ce2b1d41441fd30283e42b22d16858a", - "sha256:af51bb9f055a3f4af0187149a8f60c9d516cf7d5565b3dac53358796a8fb2a5b", - "sha256:b2ecac57eb49e461e86c092761e6b8e1fd9654dbaaddf71a076dcc869f7014e2", - "sha256:cd37cc170678a4609becb26b53a2bc1edea65177be70c48dd7b39a1149cabd6e", - "sha256:d17e3054b17e1a6cb8c1140f76310f6ede811e75b7a9d461922d2c72973f583e", - "sha256:d305313c5a9695f40c46294d4315ed3a07c7d2b55e48a9010dad7db7a66c8b7f", - "sha256:dd0ef0eb1f7dd18a3f4187226e226a7284bda6af5671937a221766e6ef1ee88f", - "sha256:e1adff53b56db9905db48a972fb89370ad5736e0450b96f91bcf99cadd96cfd7", - "sha256:f0d43828003c82dbc9269de87aa449e9896077a71954fbbb10a614c017e65737", - "sha256:f78e8b487de4d92640105c1389e5b90be3496b1d75c90a666edd8737cc2dbab7" - ], - "version": "==2.8.3" + "sha256:029e09a892b9ebc3c77851f69ce0720e1b72a9c6850460cee49b14dfbf9ccdd2", + "sha256:108b0380969ddab7c8ef2a813a57f87b308b2f88ec15f1a1e7b653964a3cfb25", + "sha256:14427437117f38e65f71db65d8eafd0e86837be456567798712b8da89db2b2dd", + "sha256:234b1f48488b2f86aac04fb00cb04e5e9bcb960f34fa8a8e41b73149d581a93b", + "sha256:2e4bbcfb403221ea1953f3e0a85cef00ed15c1683a66cf35c956a7e37c33a4c4", + "sha256:2eecbdc5fa5886f2dd6cc673ce4291cc0fb8900965315268960ad9c2477f8276", + "sha256:37c8f00f7a2860bac9f7a54f03c243fc1dd9b367e5b2b52f5a02e5f4e9d8c49b", + "sha256:3865d0cd919349c45603bd7e80249a382c5ecf8106304cfd153282adf9684b6a", + "sha256:3a320e7a804f3886a599fea507364aaafbb8387027fffcdfbd34d96316c806c7", + "sha256:3ac83656ff4fbe7f2a956ab085e3eb1d678df54759965d509bdd6a06ce520d49", + "sha256:497372cc76e6cbce2f51b37be141f360a321423c03eb9be45524b1d123f4cd11", + "sha256:4c2dea4deac3dd3687e32daeb0712ee96c535970dfdded37a11de6a21145ab0e", + "sha256:53912199abb626a7249c662e72b70b4f57bf37f840599cec68625171435790dd", + "sha256:5671699aff57d22a245b7f4bba89e3de97dc841c5e98bd7f685429b2b20eca47", + "sha256:578c279cd1ce04f05ae0912530ece00bab92854911808e5aec27588aba87e361", + "sha256:717525cdc97b23182ff6f470fb5bf6f0bc796b5a7000c6f6699d6679991e4a5e", + "sha256:7585ca73dcfe326f31fafa8f96e6bb98ea9e9e46c7a1924ec8101d797914ae27", + "sha256:7e6bd4f532c2cd297b81114526176b240109a1c52020adca69c3f3226c65dc18", + "sha256:8d2aafe46eb87742425ece38130510fbb035787ee89a329af299029c4d9ae318", + "sha256:9c0aaad07941419926b9bd00171e49fe6b06e42e5527fb91671e137fe6c93d77", + "sha256:a04cfa231e7d9b63639e62166a4051cb47ca599fa341463fa3e1c48585fcee64", + "sha256:a1852c5bef7e5f52bd43fde5eda610d4df0fb2efc31028150933e84b4140d47a", + "sha256:a507db7758953b1b170c4310691a1a89877029b1e11b08ba5fc8ae3ddb35596b", + "sha256:a77e98c68b0e6c51d4d6a994d22b30e77276cbd33e4aabdde03b9ad3a2c148aa", + "sha256:aa2847d8073951dbc84c4f8b32c620764db3c2eb0d99a04835fecfab7d04816e", + "sha256:b592f09ff18cfcc9037b9a976fcd62db48cae9dbd5385f2471d4c2ba40c52b4d", + "sha256:b9d45374ba98c1184df9cce93a0b766097544f8bdfcd5de83ff10f939c193125", + "sha256:bf31e6fdb4ec1f6d98a07f48836508ed6edd19b48b13bbf168fbc1bd014b4ca2", + "sha256:c0e1fb7097ded2cc44d9037cfc68ad86a30341261492e7de95d180e534969fb2", + "sha256:c6e16e085fe6dc6c099ee0be56657aa9ad71027465ef9591d302ba230c404c7e", + "sha256:daf6b5c62eb738872d61a1fa740d7768904911ba5a7e055ed72169d379b58beb", + "sha256:db1b03c189f85b8df29030ad32d521dd7dcb862fd5f8892035314f5b886e70ce", + "sha256:eeee7b18c51d02e49bf1984d7af26e8843fe68e31fa1cbab5366ebdfa1c89ade", + "sha256:ef97578fab5115e3af4334dd3376dea3c3a79328a3314b21ec7ced02920b916d", + "sha256:f4dff0f15af6936c6fe6da7067b4216edbbe076ad8625da819cc066591b1133c", + "sha256:f9c37ecb173d76cf49e519133fd70851b8f9c38b6b8c1cb7fcfc71368d4cc6fc" + ], + "version": "==2.9.2" }, "ptyprocess": { "hashes": [ - "sha256:923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0", - "sha256:d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f" + "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", + "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220" ], - "version": "==0.6.0" + "version": "==0.7.0" }, "pycparser": { "hashes": [ - "sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3" + "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", + "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" ], - "version": "==2.19" + "version": "==2.21" }, "pygments": { "hashes": [ - "sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127", - "sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297" + "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380", + "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6" ], - "version": "==2.4.2" + "markers": "python_version >= '3.5'", + "version": "==2.10.0" }, "pyjwt": { "hashes": [ - "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e", - "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96" + "sha256:b888b4d56f06f6dcd777210c334e69c737be74755d3e5e9ee3fe67dc18a0ee41", + "sha256:e0c4bb8d9f0af0c7f5b1ec4c5036309617d03d56932877f2f7a0beeb5318322f" ], - "version": "==1.7.1" + "markers": "python_version >= '3.6'", + "version": "==2.3.0" }, "pynpm": { "hashes": [ - "sha256:b3c2efafc15b0ca4f0a1cc819e55af4179c2b43a2f9bb7b1a1cc1763dc3daa52", - "sha256:e4df0427cd2357ca67d68a322af6873c5ce67e1625a45acfb9603e4448bf3464" + "sha256:3f03fbf667549f8b8b7e0419eef88d1b21833ce288f96de66fbb761b9f4c4061", + "sha256:8a6d3f9423760cf3c142db3bf9bda5a075e8a91837e7d2e2b0a3de5be5e26da2" ], - "version": "==0.1.1" + "version": "==0.1.2" }, - "pyrsistent": { + "pyparsing": { "hashes": [ - "sha256:34b47fa169d6006b32e99d4b3c4031f155e6e68ebcc107d6454852e8e0ee6533" + "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", + "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" ], - "version": "==0.15.4" + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'", + "version": "==2.4.7" }, - "python-dateutil": { + "pyrsistent": { "hashes": [ - "sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", - "sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e" - ], - "version": "==2.8.0" + "sha256:097b96f129dd36a8c9e33594e7ebb151b1515eb52cceb08474c10a5479e799f2", + "sha256:2aaf19dc8ce517a8653746d98e962ef480ff34b6bc563fc067be6401ffb457c7", + "sha256:404e1f1d254d314d55adb8d87f4f465c8693d6f902f67eb6ef5b4526dc58e6ea", + "sha256:48578680353f41dca1ca3dc48629fb77dfc745128b56fc01096b2530c13fd426", + "sha256:4916c10896721e472ee12c95cdc2891ce5890898d2f9907b1b4ae0f53588b710", + "sha256:527be2bfa8dc80f6f8ddd65242ba476a6c4fb4e3aedbf281dfbac1b1ed4165b1", + "sha256:58a70d93fb79dc585b21f9d72487b929a6fe58da0754fa4cb9f279bb92369396", + "sha256:5e4395bbf841693eaebaa5bb5c8f5cdbb1d139e07c975c682ec4e4f8126e03d2", + "sha256:6b5eed00e597b5b5773b4ca30bd48a5774ef1e96f2a45d105db5b4ebb4bca680", + "sha256:73ff61b1411e3fb0ba144b8f08d6749749775fe89688093e1efef9839d2dcc35", + "sha256:772e94c2c6864f2cd2ffbe58bb3bdefbe2a32afa0acb1a77e472aac831f83427", + "sha256:773c781216f8c2900b42a7b638d5b517bb134ae1acbebe4d1e8f1f41ea60eb4b", + "sha256:a0c772d791c38bbc77be659af29bb14c38ced151433592e326361610250c605b", + "sha256:b29b869cf58412ca5738d23691e96d8aff535e17390128a1a52717c9a109da4f", + "sha256:c1a9ff320fa699337e05edcaae79ef8c2880b52720bc031b219e5b5008ebbdef", + "sha256:cd3caef37a415fd0dae6148a1b6957a8c5f275a62cca02e18474608cb263640c", + "sha256:d5ec194c9c573aafaceebf05fc400656722793dac57f254cd4741f3c27ae57b4", + "sha256:da6e5e818d18459fa46fac0a4a4e543507fe1110e808101277c5a2b5bab0cd2d", + "sha256:e79d94ca58fcafef6395f6352383fa1a76922268fa02caa2272fff501c2fdc78", + "sha256:f3ef98d7b76da5eb19c37fda834d50262ff9167c65658d1d8f974d2e4d90676b", + "sha256:f4c8cabb46ff8e5d61f56a037974228e978f26bfefce4f61a4b1ac0ba7a2ab72" + ], + "markers": "python_version >= '3.6'", + "version": "==0.18.0" }, - "python-editor": { + "python-dateutil": { "hashes": [ - "sha256:1bf6e860a8ad52a14c3ee1252d5dc25b2030618ed80c022598f00176adc8367d", - "sha256:51fda6bcc5ddbbb7063b2af7509e43bd84bfc32a4ff71349ec7847713882327b", - "sha256:5f98b069316ea1c2ed3f67e7f5df6c0d8f10b689964a4a811ff64f0106819ec8" + "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", + "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" ], - "version": "==1.0.4" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==2.8.2" }, "pytz": { "hashes": [ - "sha256:26c0b32e437e54a18161324a2fca3c4b9846b74a8dccddd843113109e1116b32", - "sha256:c894d57500a4cd2d5c71114aaab77dbab5eabd9022308ce5ac9bb93a60a6f0c7" + "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c", + "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326" ], - "version": "==2019.2" + "version": "==2021.3" }, "pywebpack": { "hashes": [ - "sha256:2ee79570f56a5a5ec532ffb1ae95c268cd5acceb94d94df63cec47486a7e2e2c", - "sha256:ef115f8f87347f975271523b0dea85d38cf04db0aa017a684c4d8067c71324e4" + "sha256:0aec242f85bc59b0120d7d8e1daf8e22fb124142c4d76753e17d016e8948710b", + "sha256:be882ab55a5d28951d8262936efc717a62935719b0551a4a4bb53bef70d9b022" ], - "version": "==1.0.0" + "version": "==1.2.0" }, "raven": { "extras": [ @@ -916,21 +1371,23 @@ }, "redis": { "hashes": [ - "sha256:98a22fb750c9b9bb46e75e945dc3f61d0ab30d06117cbb21ff9cd1d315fedd3b", - "sha256:c504251769031b0dd7dd5cf786050a6050197c6de0d37778c80c08cb04ae8275" + "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2", + "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24" ], - "version": "==3.3.8" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==3.5.3" }, "requests": { "hashes": [ - "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", - "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" + "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", + "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" ], "index": "pypi", - "version": "==2.22.0" + "version": "==2.26.0" }, "requests-oauthlib": { "hashes": [ + "sha256:490229d14a98e1b69612dcc1a22887ec14f5487dc1b8c6d7ba7f77a42ce7347b", "sha256:be76f2bb72ca5525998e81d47913e09b1ca8b7957ae89b46f787a79e68ad5e61", "sha256:eabd8eb700ebed81ba080c6ead96d39d6bdc39996094bd23000204f6965786b0" ], @@ -938,18 +1395,27 @@ }, "simplekv": { "hashes": [ - "sha256:58bbb99c3d3a55ab69a2dabb064a309fd7089730cb5f9d3eecb47b110e3fc5b0", - "sha256:a2f8cdde73b1f9ae60540f9bc0b49c564226d8a46f6a1bd98d1b6169f98274ed", - "sha256:ae52e8f48618ecf9f81631c152ea8fbed8b88fb7c17870db984a295481483c06" + "sha256:8953a36cb3741ea821c9de1962b5313bf6fe1b927f6ced2a55266eb8ce2cd0f6", + "sha256:af91a50af41a286a8b7b93292b21dd1af37f38e9513fea0eb4fa75ce778c1683", + "sha256:fcee8d972d092de0dc83732084e389c9b95839503537ef85c1a2eeb07182f2f5" ], - "version": "==0.13.0" + "version": "==0.14.1" }, "six": { "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "version": "==1.12.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==1.16.0" + }, + "slackclient": { + "hashes": [ + "sha256:07ec8fa76f6aa64852210ae235ff9e637ba78124e06c0b07a7eeea4abb955965", + "sha256:2d68d668c02f4038299897e5c4723ab85dd40a3548354924b24f333a435856f8" + ], + "index": "pypi", + "version": "==2.9.3" }, "speaklater": { "hashes": [ @@ -959,52 +1425,100 @@ }, "sqlalchemy": { "hashes": [ - "sha256:2f8ff566a4d3a92246d367f2e9cd6ed3edeef670dcd6dda6dfdc9efed88bcd80" - ], - "version": "==1.3.8" + "sha256:014ea143572fee1c18322b7908140ad23b3994036ef4c0d630110faf942652f8", + "sha256:0172423a27fbcae3751ef016663b72e1a516777de324a76e30efa170dbd3dd2d", + "sha256:01aa5f803db724447c1d423ed583e42bf5264c597fd55e4add4301f163b0be48", + "sha256:0352db1befcbed2f9282e72843f1963860bf0e0472a4fa5cf8ee084318e0e6ab", + "sha256:09083c2487ca3c0865dc588e07aeaa25416da3d95f7482c07e92f47e080aa17b", + "sha256:0d5d862b1cfbec5028ce1ecac06a3b42bc7703eb80e4b53fceb2738724311443", + "sha256:14f0eb5db872c231b20c18b1e5806352723a3a89fb4254af3b3e14f22eaaec75", + "sha256:1e2f89d2e5e3c7a88e25a3b0e43626dba8db2aa700253023b82e630d12b37109", + "sha256:26155ea7a243cbf23287f390dba13d7927ffa1586d3208e0e8d615d0c506f996", + "sha256:2ed6343b625b16bcb63c5b10523fd15ed8934e1ed0f772c534985e9f5e73d894", + "sha256:34fcec18f6e4b24b4a5f6185205a04f1eab1e56f8f1d028a2a03694ebcc2ddd4", + "sha256:4d0e3515ef98aa4f0dc289ff2eebb0ece6260bbf37c2ea2022aad63797eacf60", + "sha256:5de2464c254380d8a6c20a2746614d5a436260be1507491442cf1088e59430d2", + "sha256:6607ae6cd3a07f8a4c3198ffbf256c261661965742e2b5265a77cd5c679c9bba", + "sha256:8110e6c414d3efc574543109ee618fe2c1f96fa31833a1ff36cc34e968c4f233", + "sha256:816de75418ea0953b5eb7b8a74933ee5a46719491cd2b16f718afc4b291a9658", + "sha256:861e459b0e97673af6cc5e7f597035c2e3acdfb2608132665406cded25ba64c7", + "sha256:87a2725ad7d41cd7376373c15fd8bf674e9c33ca56d0b8036add2d634dba372e", + "sha256:a006d05d9aa052657ee3e4dc92544faae5fcbaafc6128217310945610d862d39", + "sha256:bce28277f308db43a6b4965734366f533b3ff009571ec7ffa583cb77539b84d6", + "sha256:c10ff6112d119f82b1618b6dc28126798481b9355d8748b64b9b55051eb4f01b", + "sha256:d375d8ccd3cebae8d90270f7aa8532fe05908f79e78ae489068f3b4eee5994e8", + "sha256:d37843fb8df90376e9e91336724d78a32b988d3d20ab6656da4eb8ee3a45b63c", + "sha256:e47e257ba5934550d7235665eee6c911dc7178419b614ba9e1fbb1ce6325b14f", + "sha256:e98d09f487267f1e8d1179bf3b9d7709b30a916491997137dd24d6ae44d18d79", + "sha256:ebbb777cbf9312359b897bf81ba00dae0f5cb69fba2a18265dcc18a6f5ef7519", + "sha256:ee5f5188edb20a29c1cc4a039b074fdc5575337c9a68f3063449ab47757bb064", + "sha256:f03bd97650d2e42710fbe4cf8a59fae657f191df851fc9fc683ecef10746a375", + "sha256:f1149d6e5c49d069163e58a3196865e4321bad1803d7886e07d8710de392c548", + "sha256:f3c5c52f7cb8b84bfaaf22d82cb9e6e9a8297f7c2ed14d806a0f5e4d22e83fb7", + "sha256:f597a243b8550a3a0b15122b14e49d8a7e622ba1c9d29776af741f1845478d79", + "sha256:fc1f2a5a5963e2e73bac4926bdaf7790c4d7d77e8fc0590817880e22dd9d0b8b", + "sha256:fc4cddb0b474b12ed7bdce6be1b9edc65352e8ce66bc10ff8cbbfb3d4047dbf4", + "sha256:fcb251305fa24a490b6a9ee2180e5f8252915fb778d3dafc70f9cc3f863827b9" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.3.24" }, "sqlalchemy-continuum": { "hashes": [ - "sha256:4f4e378938baf3ca7321ee6f5c310c50868b66fef2507fb84ff5e0e27106f82c" + "sha256:bc13b0a96110129fd2c2b4c9e5b2f40f320bb26854b09c867e383394746a3eb1" ], - "version": "==1.3.9" + "version": "==1.3.11" }, "sqlalchemy-utils": { - "extras": [ - "encrypted" - ], "hashes": [ - "sha256:6689b29d7951c5c7c4d79fa6b8c95f9ff9ec708b07aa53f82060599bd14dcc88" + "sha256:01f0f0ebed696386bc7bf9231cd6894087baba374dd60f40eb1b07512d6b1a5e" ], - "version": "==0.34.2" + "version": "==0.35.0" }, "traitlets": { "hashes": [ - "sha256:9c4bd2d267b7153df9152698efb1050a5d84982d3384a37b2c1f7723ba3e7835", - "sha256:c6cb5e6f57c5a9bdaa40fa71ce7b4af30298fbab9ece9815b5d995ab6217c7d9" + "sha256:059f456c5a7c1c82b98c2e8c799f39c9b8128f6d0d46941ee118daace9eb70c7", + "sha256:2d313cc50a42cd6c277e7d7dc8d4d7fedd06a2c215f78766ae7b1a66277e0033" ], - "version": "==4.3.2" + "markers": "python_version >= '3.7'", + "version": "==5.1.1" + }, + "typing-extensions": { + "hashes": [ + "sha256:829704698b22e13ec9eaf959122315eabb370b0884400e9818334d8b677023d9" + ], + "markers": "python_version >= '3.6'", + "version": "==4.0.0" }, "ua-parser": { "hashes": [ - "sha256:3908c19ea0abdcdfe7245366dc03e5b4a8901ec17105bd66ba2ccbe3948dce8a", - "sha256:97bbcfc9321a3151d96bb5d62e54270247b0e3be0590a6f2ff12329851718dcb" + "sha256:46ab2e383c01dbd2ab284991b87d624a26a08f72da4d7d413f5bfab8b9036f8a", + "sha256:47b1782ed130d890018d983fac37c2a80799d9e0b9c532e734c67cf70f185033" ], - "version": "==0.8.0" + "version": "==0.10.0" + }, + "uritools": { + "hashes": [ + "sha256:28ffef82ce3b2793237d36e45aa7cde28dae6502f6a93fdbd05ede401520e279", + "sha256:576737664f51f82d5c2a98e25f6c5da73a57cc88326dbb686fd6c5d06ebd6c29" + ], + "markers": "python_version ~= '3.5'", + "version": "==3.0.2" }, "urllib3": { "hashes": [ - "sha256:2393a695cd12afedd0dcb26fe5d50d0cf248e5a66f75dbd89a3d4eb333a61af4", - "sha256:a637e5fae88995b256e3409dc4d52c2e2e0ba32c42a6365fee8bbd2238de3cfb" + "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece", + "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844" ], - "version": "==1.24.3" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_full_version < '4.0.0'", + "version": "==1.26.7" }, "uwsgi": { "hashes": [ - "sha256:4972ac538800fb2d421027f49b4a1869b66048839507ccf0aa2fda792d99f583" + "sha256:88ab9867d8973d8ae84719cf233b7dafc54326fcaec89683c3f9f77c002cdff9" ], "index": "pypi", - "version": "==2.0.18" + "version": "==2.0.20" }, "uwsgi-tools": { "hashes": [ @@ -1023,31 +1537,34 @@ }, "validators": { "hashes": [ - "sha256:f0ac832212e3ee2e9b10e156f19b106888cf1429c291fbc5297aae87685014ae" + "sha256:0143dcca8a386498edaf5780cbd5960da1a4c85e0719f3ee5c9b41249c4fefbd", + "sha256:37cd9a9213278538ad09b5b9f9134266e7c226ab1fede1d500e29e0a8fbb9ea6" ], - "version": "==0.14.0" + "markers": "python_version >= '3.4'", + "version": "==0.18.2" }, "vine": { "hashes": [ - "sha256:133ee6d7a9016f177ddeaf191c1f58421a1dcc6ee9a42c58b34bed40e1d2cd87", - "sha256:ea4947cc56d1fd6f2095c8d543ee25dad966f78692528e68b4fada11ba3f98af" + "sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30", + "sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e" ], - "version": "==1.3.0" + "markers": "python_version >= '3.6'", + "version": "==5.0.0" }, "wcwidth": { "hashes": [ - "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", - "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c" + "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784", + "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83" ], - "version": "==0.1.7" + "version": "==0.2.5" }, "webargs": { "hashes": [ - "sha256:97b94d375196422a7037971a0a7e0b405a15b06099635dddcb3ecad48872f073", - "sha256:d23e57ebcaf44722349d7d3b235479d329fcc91b7db2f1df7fab950d7ade54f8", - "sha256:e0ece4ce48e880b16dc764e613972314acb4fb99f9043b7cbf5776f3a6a4b531" + "sha256:4f04918864c7602886335d8099f9b8960ee698b6b914f022736ed50be6b71235", + "sha256:871642a2e0c62f21d5b78f357750ac7a87e6bc734c972f633aa5fb6204fbf29a", + "sha256:fc81c9f9d391acfbce406a319217319fd8b2fd862f7fdb5319ad06944f36ed25" ], - "version": "==5.5.1" + "version": "==5.5.3" }, "webencodings": { "hashes": [ @@ -1058,43 +1575,116 @@ }, "werkzeug": { "hashes": [ - "sha256:7280924747b5733b246fe23972186c6b348f9ae29724135a6dfc1e53cea433e7", - "sha256:e5f4a1f98b52b18a93da705a7458e55afb26f32bff83ff5d19189f92462d65c4" + "sha256:63d3dc1cf60e7b7e35e97fa9861f7397283b75d765afcaefd993d6046899de8f", + "sha256:aa2bb6fc8dee8d6c504c0ac1e7f5f7dc5810a9903e793b6f715a9f015bdadb9a" ], - "version": "==0.16.0" - }, - "whichcraft": { - "hashes": [ - "sha256:acdbb91b63d6a15efbd6430d1d7b2d36e44a71697e93e19b7ded477afd9fce87", - "sha256:deda9266fbb22b8c64fd3ee45c050d61139cd87419765f588e37c8d23e236dd9" - ], - "version": "==0.6.1" + "markers": "python_version >= '3.6'", + "version": "==2.0.2" }, "wtforms": { "hashes": [ - "sha256:0cdbac3e7f6878086c334aa25dc5a33869a3954e9d1e015130d65a69309b3b61", - "sha256:e3ee092c827582c50877cdbd49e9ce6d2c5c1f6561f849b3b068c1b8029626f1" + "sha256:7b504fc724d0d1d4d5d5c114e778ec88c37ea53144683e084215eed5155ada4c", + "sha256:81195de0ac94fbc8368abbaf9197b88c4f3ffd6c2719b5bf5fc9da744f3d829c" ], - "version": "==2.2.1" + "version": "==2.3.3" }, "wtforms-alchemy": { "hashes": [ - "sha256:c491755380490c5c016f04e62949b22056f915160f54d0d1103c76b944c1c321" + "sha256:b689314354d7405616402fa2c86f90f027e28ae067e09b5477aac815639053b9" ], - "version": "==0.16.9" + "version": "==0.17.0" }, "wtforms-components": { "hashes": [ - "sha256:4a7751fc12dc4e4b2ef5700973296b5368094dcdf85c2808d2faff2c8e8f4caa" - ], - "version": "==0.10.4" + "sha256:7d0d83dec6d5352c661e522be628f49c2de3aa78cd79c9caf0c1cc3bff4e3872" + ], + "version": "==0.10.5" + }, + "yarl": { + "hashes": [ + "sha256:044daf3012e43d4b3538562da94a88fb12a6490652dbc29fb19adfa02cf72eac", + "sha256:0cba38120db72123db7c58322fa69e3c0efa933040ffb586c3a87c063ec7cae8", + "sha256:167ab7f64e409e9bdd99333fe8c67b5574a1f0495dcfd905bc7454e766729b9e", + "sha256:1be4bbb3d27a4e9aa5f3df2ab61e3701ce8fcbd3e9846dbce7c033a7e8136746", + "sha256:1ca56f002eaf7998b5fcf73b2421790da9d2586331805f38acd9997743114e98", + "sha256:1d3d5ad8ea96bd6d643d80c7b8d5977b4e2fb1bab6c9da7322616fd26203d125", + "sha256:1eb6480ef366d75b54c68164094a6a560c247370a68c02dddb11f20c4c6d3c9d", + "sha256:1edc172dcca3f11b38a9d5c7505c83c1913c0addc99cd28e993efeaafdfaa18d", + "sha256:211fcd65c58bf250fb994b53bc45a442ddc9f441f6fec53e65de8cba48ded986", + "sha256:29e0656d5497733dcddc21797da5a2ab990c0cb9719f1f969e58a4abac66234d", + "sha256:368bcf400247318382cc150aaa632582d0780b28ee6053cd80268c7e72796dec", + "sha256:39d5493c5ecd75c8093fa7700a2fb5c94fe28c839c8e40144b7ab7ccba6938c8", + "sha256:3abddf0b8e41445426d29f955b24aeecc83fa1072be1be4e0d194134a7d9baee", + "sha256:3bf8cfe8856708ede6a73907bf0501f2dc4e104085e070a41f5d88e7faf237f3", + "sha256:3ec1d9a0d7780416e657f1e405ba35ec1ba453a4f1511eb8b9fbab81cb8b3ce1", + "sha256:45399b46d60c253327a460e99856752009fcee5f5d3c80b2f7c0cae1c38d56dd", + "sha256:52690eb521d690ab041c3919666bea13ab9fbff80d615ec16fa81a297131276b", + "sha256:534b047277a9a19d858cde163aba93f3e1677d5acd92f7d10ace419d478540de", + "sha256:580c1f15500e137a8c37053e4cbf6058944d4c114701fa59944607505c2fe3a0", + "sha256:59218fef177296451b23214c91ea3aba7858b4ae3306dde120224cfe0f7a6ee8", + "sha256:5ba63585a89c9885f18331a55d25fe81dc2d82b71311ff8bd378fc8004202ff6", + "sha256:5bb7d54b8f61ba6eee541fba4b83d22b8a046b4ef4d8eb7f15a7e35db2e1e245", + "sha256:6152224d0a1eb254f97df3997d79dadd8bb2c1a02ef283dbb34b97d4f8492d23", + "sha256:67e94028817defe5e705079b10a8438b8cb56e7115fa01640e9c0bb3edf67332", + "sha256:695ba021a9e04418507fa930d5f0704edbce47076bdcfeeaba1c83683e5649d1", + "sha256:6a1a9fe17621af43e9b9fcea8bd088ba682c8192d744b386ee3c47b56eaabb2c", + "sha256:6ab0c3274d0a846840bf6c27d2c60ba771a12e4d7586bf550eefc2df0b56b3b4", + "sha256:6feca8b6bfb9eef6ee057628e71e1734caf520a907b6ec0d62839e8293e945c0", + "sha256:737e401cd0c493f7e3dd4db72aca11cfe069531c9761b8ea474926936b3c57c8", + "sha256:788713c2896f426a4e166b11f4ec538b5736294ebf7d5f654ae445fd44270832", + "sha256:797c2c412b04403d2da075fb93c123df35239cd7b4cc4e0cd9e5839b73f52c58", + "sha256:8300401dc88cad23f5b4e4c1226f44a5aa696436a4026e456fe0e5d2f7f486e6", + "sha256:87f6e082bce21464857ba58b569370e7b547d239ca22248be68ea5d6b51464a1", + "sha256:89ccbf58e6a0ab89d487c92a490cb5660d06c3a47ca08872859672f9c511fc52", + "sha256:8b0915ee85150963a9504c10de4e4729ae700af11df0dc5550e6587ed7891e92", + "sha256:8cce6f9fa3df25f55521fbb5c7e4a736683148bcc0c75b21863789e5185f9185", + "sha256:95a1873b6c0dd1c437fb3bb4a4aaa699a48c218ac7ca1e74b0bee0ab16c7d60d", + "sha256:9b4c77d92d56a4c5027572752aa35082e40c561eec776048330d2907aead891d", + "sha256:9bfcd43c65fbb339dc7086b5315750efa42a34eefad0256ba114cd8ad3896f4b", + "sha256:9c1f083e7e71b2dd01f7cd7434a5f88c15213194df38bc29b388ccdf1492b739", + "sha256:a1d0894f238763717bdcfea74558c94e3bc34aeacd3351d769460c1a586a8b05", + "sha256:a467a431a0817a292121c13cbe637348b546e6ef47ca14a790aa2fa8cc93df63", + "sha256:aa32aaa97d8b2ed4e54dc65d241a0da1c627454950f7d7b1f95b13985afd6c5d", + "sha256:ac10bbac36cd89eac19f4e51c032ba6b412b3892b685076f4acd2de18ca990aa", + "sha256:ac35ccde589ab6a1870a484ed136d49a26bcd06b6a1c6397b1967ca13ceb3913", + "sha256:bab827163113177aee910adb1f48ff7af31ee0289f434f7e22d10baf624a6dfe", + "sha256:baf81561f2972fb895e7844882898bda1eef4b07b5b385bcd308d2098f1a767b", + "sha256:bf19725fec28452474d9887a128e98dd67eee7b7d52e932e6949c532d820dc3b", + "sha256:c01a89a44bb672c38f42b49cdb0ad667b116d731b3f4c896f72302ff77d71656", + "sha256:c0910c6b6c31359d2f6184828888c983d54d09d581a4a23547a35f1d0b9484b1", + "sha256:c10ea1e80a697cf7d80d1ed414b5cb8f1eec07d618f54637067ae3c0334133c4", + "sha256:c1164a2eac148d85bbdd23e07dfcc930f2e633220f3eb3c3e2a25f6148c2819e", + "sha256:c145ab54702334c42237a6c6c4cc08703b6aa9b94e2f227ceb3d477d20c36c63", + "sha256:c17965ff3706beedafd458c452bf15bac693ecd146a60a06a214614dc097a271", + "sha256:c19324a1c5399b602f3b6e7db9478e5b1adf5cf58901996fc973fe4fccd73eed", + "sha256:c2a1ac41a6aa980db03d098a5531f13985edcb451bcd9d00670b03129922cd0d", + "sha256:c6ddcd80d79c96eb19c354d9dca95291589c5954099836b7c8d29278a7ec0bda", + "sha256:c9c6d927e098c2d360695f2e9d38870b2e92e0919be07dbe339aefa32a090265", + "sha256:cc8b7a7254c0fc3187d43d6cb54b5032d2365efd1df0cd1749c0c4df5f0ad45f", + "sha256:cff3ba513db55cc6a35076f32c4cdc27032bd075c9faef31fec749e64b45d26c", + "sha256:d260d4dc495c05d6600264a197d9d6f7fc9347f21d2594926202fd08cf89a8ba", + "sha256:d6f3d62e16c10e88d2168ba2d065aa374e3c538998ed04996cd373ff2036d64c", + "sha256:da6df107b9ccfe52d3a48165e48d72db0eca3e3029b5b8cb4fe6ee3cb870ba8b", + "sha256:dfe4b95b7e00c6635a72e2d00b478e8a28bfb122dc76349a06e20792eb53a523", + "sha256:e39378894ee6ae9f555ae2de332d513a5763276a9265f8e7cbaeb1b1ee74623a", + "sha256:ede3b46cdb719c794427dcce9d8beb4abe8b9aa1e97526cc20de9bd6583ad1ef", + "sha256:f2a8508f7350512434e41065684076f640ecce176d262a7d54f0da41d99c5a95", + "sha256:f44477ae29025d8ea87ec308539f95963ffdc31a82f42ca9deecf2d505242e72", + "sha256:f64394bd7ceef1237cc604b5a89bf748c95982a84bcd3c4bbeb40f685c810794", + "sha256:fc4dd8b01a8112809e6b636b00f487846956402834a7fd59d46d4f4267181c41", + "sha256:fce78593346c014d0d986b7ebc80d782b7f5e19843ca798ed62f8e3ba8728576", + "sha256:fd547ec596d90c8676e369dd8a581a21227fe9b4ad37d0dc7feb4ccf544c2d59" + ], + "markers": "python_version >= '3.6'", + "version": "==1.7.2" }, "zipp": { "hashes": [ - "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", - "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335" + "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832", + "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc" ], - "version": "==0.6.0" + "markers": "python_version < '3.10'", + "version": "==3.6.0" } }, "develop": { @@ -1107,205 +1697,375 @@ }, "astunparse": { "hashes": [ - "sha256:271fb1f3d7a2e3c66eab41000298860f046253d22ec96e4f024cfaf266805a8e", - "sha256:dab3e426715373fd76cd08bb1abe64b550f5aa494cf1e32384f26fd60961eb67" + "sha256:5ad93a8456f0d084c3456d059fd9a92cce667963232cbf763eac3bc5b7940872", + "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8" ], - "version": "==1.6.2" + "version": "==1.6.3" }, - "atomicwrites": { + "async-generator": { "hashes": [ - "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", - "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6" + "sha256:01c7bf666359b4967d2cda0000cc2e4af16a0ae098cbffcb8472fb9e8ad6585b", + "sha256:6ebb3d106c12920aaae42ccb6f787ef5eefdcdd166ea3d628fa8476abe712144" ], - "version": "==1.3.0" + "markers": "python_version >= '3.5'", + "version": "==1.10" }, "attrs": { "hashes": [ - "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", - "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" + "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", + "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" ], - "version": "==19.1.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==21.2.0" }, "babel": { "hashes": [ - "sha256:af92e6106cb7c55286b25b38ad7695f8b4efb36a90ba483d7f7a6628c46158ab", - "sha256:e86135ae101e31e2c8ec20a4e0c5220f4eed12487d5cf3f78be7e98d3a57fc28" + "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9", + "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0" ], - "version": "==2.7.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.9.1" }, - "certifi": { + "build": { "hashes": [ - "sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50", - "sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef" + "sha256:1aaadcd69338252ade4f7ec1265e1a19184bf916d84c9b7df095f423948cb89f", + "sha256:21b7ebbd1b22499c4dac536abc7606696ea4d909fd755e00f09f3c0f2c05e3c8" ], - "version": "==2019.9.11" + "markers": "python_version >= '3.6'", + "version": "==0.7.0" }, - "chardet": { + "certifi": { "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", + "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" ], - "version": "==3.0.4" + "version": "==2021.10.8" + }, + "cffi": { + "hashes": [ + "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3", + "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2", + "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636", + "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20", + "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728", + "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27", + "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66", + "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443", + "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0", + "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7", + "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39", + "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605", + "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a", + "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37", + "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029", + "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139", + "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc", + "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df", + "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14", + "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880", + "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2", + "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a", + "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e", + "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474", + "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024", + "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8", + "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0", + "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e", + "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a", + "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e", + "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032", + "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6", + "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e", + "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b", + "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e", + "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954", + "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962", + "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c", + "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4", + "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55", + "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962", + "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023", + "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c", + "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6", + "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8", + "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382", + "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7", + "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc", + "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997", + "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796" + ], + "version": "==1.15.0" + }, + "charset-normalizer": { + "hashes": [ + "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0", + "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b" + ], + "markers": "python_version >= '3'", + "version": "==2.0.7" }, "check-manifest": { "hashes": [ - "sha256:8754cc8efd7c062a3705b442d1c23ff702d4477b41a269c2e354b25e1f5535a4", - "sha256:a4c555f658a7c135b8a22bd26c2e55cfaf5876e4d5962d8c25652f2addd556bc" + "sha256:365c94d65de4c927d9d8b505371d08ee19f9f369c86b9ac3db97c2754c827c95", + "sha256:56dadd260a9c7d550b159796d2894b6d0bcc176a94cbc426d9bb93e5e48d12ce" ], "index": "pypi", - "version": "==0.39" + "version": "==0.47" }, "click": { "hashes": [ - "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", - "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" + "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", + "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" ], - "version": "==7.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==7.1.2" }, "coverage": { - "hashes": [ - "sha256:08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6", - "sha256:0be0f1ed45fc0c185cfd4ecc19a1d6532d72f86a2bac9de7e24541febad72650", - "sha256:141f08ed3c4b1847015e2cd62ec06d35e67a3ac185c26f7635f4406b90afa9c5", - "sha256:19e4df788a0581238e9390c85a7a09af39c7b539b29f25c89209e6c3e371270d", - "sha256:23cc09ed395b03424d1ae30dcc292615c1372bfba7141eb85e11e50efaa6b351", - "sha256:245388cda02af78276b479f299bbf3783ef0a6a6273037d7c60dc73b8d8d7755", - "sha256:331cb5115673a20fb131dadd22f5bcaf7677ef758741312bee4937d71a14b2ef", - "sha256:386e2e4090f0bc5df274e720105c342263423e77ee8826002dcffe0c9533dbca", - "sha256:3a794ce50daee01c74a494919d5ebdc23d58873747fa0e288318728533a3e1ca", - "sha256:60851187677b24c6085248f0a0b9b98d49cba7ecc7ec60ba6b9d2e5574ac1ee9", - "sha256:63a9a5fc43b58735f65ed63d2cf43508f462dc49857da70b8980ad78d41d52fc", - "sha256:6b62544bb68106e3f00b21c8930e83e584fdca005d4fffd29bb39fb3ffa03cb5", - "sha256:6ba744056423ef8d450cf627289166da65903885272055fb4b5e113137cfa14f", - "sha256:7494b0b0274c5072bddbfd5b4a6c6f18fbbe1ab1d22a41e99cd2d00c8f96ecfe", - "sha256:826f32b9547c8091679ff292a82aca9c7b9650f9fda3e2ca6bf2ac905b7ce888", - "sha256:93715dffbcd0678057f947f496484e906bf9509f5c1c38fc9ba3922893cda5f5", - "sha256:9a334d6c83dfeadae576b4d633a71620d40d1c379129d587faa42ee3e2a85cce", - "sha256:af7ed8a8aa6957aac47b4268631fa1df984643f07ef00acd374e456364b373f5", - "sha256:bf0a7aed7f5521c7ca67febd57db473af4762b9622254291fbcbb8cd0ba5e33e", - "sha256:bf1ef9eb901113a9805287e090452c05547578eaab1b62e4ad456fcc049a9b7e", - "sha256:c0afd27bc0e307a1ffc04ca5ec010a290e49e3afbe841c5cafc5c5a80ecd81c9", - "sha256:dd579709a87092c6dbee09d1b7cfa81831040705ffa12a1b248935274aee0437", - "sha256:df6712284b2e44a065097846488f66840445eb987eb81b3cc6e4149e7b6982e1", - "sha256:e07d9f1a23e9e93ab5c62902833bf3e4b1f65502927379148b6622686223125c", - "sha256:e2ede7c1d45e65e209d6093b762e98e8318ddeff95317d07a27a2140b80cfd24", - "sha256:e4ef9c164eb55123c62411f5936b5c2e521b12356037b6e1c2617cef45523d47", - "sha256:eca2b7343524e7ba246cab8ff00cab47a2d6d54ada3b02772e908a45675722e2", - "sha256:eee64c616adeff7db37cc37da4180a3a5b6177f5c46b187894e633f088fb5b28", - "sha256:ef824cad1f980d27f26166f86856efe11eff9912c4fed97d3804820d43fa550c", - "sha256:efc89291bd5a08855829a3c522df16d856455297cf35ae827a37edac45f466a7", - "sha256:fa964bae817babece5aa2e8c1af841bebb6d0b9add8e637548809d040443fee0", - "sha256:ff37757e068ae606659c28c3bd0d923f9d29a85de79bf25b2b34b148473b5025" + "extras": [ + "toml" + ], + "hashes": [ + "sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c", + "sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6", + "sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45", + "sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a", + "sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03", + "sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529", + "sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a", + "sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a", + "sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2", + "sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6", + "sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759", + "sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53", + "sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a", + "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4", + "sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff", + "sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502", + "sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793", + "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb", + "sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905", + "sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821", + "sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b", + "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81", + "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0", + "sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b", + "sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3", + "sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184", + "sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701", + "sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a", + "sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82", + "sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638", + "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5", + "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083", + "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6", + "sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90", + "sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465", + "sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a", + "sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3", + "sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e", + "sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066", + "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf", + "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b", + "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae", + "sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669", + "sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873", + "sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b", + "sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6", + "sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb", + "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160", + "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c", + "sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079", + "sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d", + "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6" ], "index": "pypi", - "version": "==4.5.4" + "version": "==5.5" }, - "docutils": { + "cryptography": { "hashes": [ - "sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0", - "sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827", - "sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99" - ], - "version": "==0.15.2" + "sha256:07bb7fbfb5de0980590ddfc7f13081520def06dc9ed214000ad4372fb4e3c7f6", + "sha256:18d90f4711bf63e2fb21e8c8e51ed8189438e6b35a6d996201ebd98a26abbbe6", + "sha256:1ed82abf16df40a60942a8c211251ae72858b25b7421ce2497c2eb7a1cee817c", + "sha256:22a38e96118a4ce3b97509443feace1d1011d0571fae81fc3ad35f25ba3ea999", + "sha256:2d69645f535f4b2c722cfb07a8eab916265545b3475fdb34e0be2f4ee8b0b15e", + "sha256:4a2d0e0acc20ede0f06ef7aa58546eee96d2592c00f450c9acb89c5879b61992", + "sha256:54b2605e5475944e2213258e0ab8696f4f357a31371e538ef21e8d61c843c28d", + "sha256:7075b304cd567694dc692ffc9747f3e9cb393cc4aa4fb7b9f3abd6f5c4e43588", + "sha256:7b7ceeff114c31f285528ba8b390d3e9cfa2da17b56f11d366769a807f17cbaa", + "sha256:7eba2cebca600a7806b893cb1d541a6e910afa87e97acf2021a22b32da1df52d", + "sha256:928185a6d1ccdb816e883f56ebe92e975a262d31cc536429041921f8cb5a62fd", + "sha256:9933f28f70d0517686bd7de36166dda42094eac49415459d9bdf5e7df3e0086d", + "sha256:a688ebcd08250eab5bb5bca318cc05a8c66de5e4171a65ca51db6bd753ff8953", + "sha256:abb5a361d2585bb95012a19ed9b2c8f412c5d723a9836418fab7aaa0243e67d2", + "sha256:c10c797ac89c746e488d2ee92bd4abd593615694ee17b2500578b63cad6b93a8", + "sha256:ced40344e811d6abba00295ced98c01aecf0c2de39481792d87af4fa58b7b4d6", + "sha256:d57e0cdc1b44b6cdf8af1d01807db06886f10177469312fbde8f44ccbb284bc9", + "sha256:d99915d6ab265c22873f1b4d6ea5ef462ef797b4140be4c9d8b179915e0985c6", + "sha256:eb80e8a1f91e4b7ef8b33041591e6d89b2b8e122d787e87eeb2b08da71bb16ad", + "sha256:ebeddd119f526bcf323a89f853afb12e225902a24d29b55fe18dd6fcb2838a76" + ], + "markers": "python_version >= '3.6'", + "version": "==35.0.0" + }, + "docker-services-cli": { + "hashes": [ + "sha256:36bf23eaa58cfa797daca723e2e8cb58c83d350ac2002f3991423356014b04da", + "sha256:89acc17cbd4e937b6b40c8308322e84436482a5cb3689706e4398344da80d22f" + ], + "version": "==0.3.1" }, - "entrypoints": { + "docutils": { "hashes": [ - "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", - "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451" + "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125", + "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61" ], - "version": "==0.3" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==0.17.1" }, "flake8": { "hashes": [ - "sha256:19241c1cbc971b9962473e4438a2ca19749a7dd002dd1a946eaba171b4114548", - "sha256:8e9dfa3cecb2400b3738a42c54c3043e821682b9c840b0448c0503f781130696" + "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d", + "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d" ], "index": "pypi", - "version": "==3.7.8" + "version": "==4.0.1" }, "flask": { "hashes": [ - "sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52", - "sha256:45eb5a6fd193d6cf7e0cf5d8a5b31f83d5faae0293695626f539a823e93b13f6" + "sha256:7b2fb8e934ddd50731893bdcdb00fc8c0315916f9fcd50d22c7cc1a95ab634e2", + "sha256:cb90f62f1d8e4dc4621f52106613488b5ba826b2e1e10a33eac92f723093ab6a" ], - "version": "==1.1.1" + "version": "==2.0.2" + }, + "h11": { + "hashes": [ + "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6", + "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042" + ], + "markers": "python_version >= '3.6'", + "version": "==0.12.0" }, "idna": { "hashes": [ - "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e", - "sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16" + "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", + "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" ], - "version": "==2.7" + "markers": "python_version >= '3'", + "version": "==3.3" }, "imagesize": { "hashes": [ - "sha256:3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8", - "sha256:f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5" + "sha256:1db2f82529e53c3e929e8926a1fa9235aa82d0bd0c580359c67ec31b2fddaa8c", + "sha256:cd1750d452385ca327479d45b64d9c7729ecf0b3969a58148298c77092261f9d" ], - "version": "==1.1.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.3.0" }, - "importlib-metadata": { + "iniconfig": { "hashes": [ - "sha256:aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26", - "sha256:d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af" + "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", + "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" ], - "markers": "python_version < '3.8'", - "version": "==0.23" + "version": "==1.1.1" }, "isort": { "hashes": [ - "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", - "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd" + "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7", + "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951" ], "index": "pypi", - "version": "==4.3.21" + "version": "==5.10.1" }, "itsdangerous": { "hashes": [ - "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", - "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749" + "sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c", + "sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0" ], - "version": "==1.1.0" + "markers": "python_version >= '3.6'", + "version": "==2.0.1" }, "jinja2": { "hashes": [ - "sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", - "sha256:14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b" + "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8", + "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7" ], - "version": "==2.10.1" + "markers": "python_version >= '3.6'", + "version": "==3.0.3" }, "markupsafe": { "hashes": [ - "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", - "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", - "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", - "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", - "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", - "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", - "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", - "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", - "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", - "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", - "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", - "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", - "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", - "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", - "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", - "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", - "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", - "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", - "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", - "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", - "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", - "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", - "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", - "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", - "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", - "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", - "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", - "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7" - ], - "version": "==1.1.1" + "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298", + "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64", + "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b", + "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194", + "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567", + "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff", + "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724", + "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74", + "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646", + "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35", + "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6", + "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a", + "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6", + "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad", + "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26", + "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38", + "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac", + "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7", + "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6", + "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047", + "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75", + "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f", + "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b", + "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135", + "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8", + "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a", + "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a", + "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1", + "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9", + "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864", + "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914", + "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee", + "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f", + "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18", + "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8", + "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2", + "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d", + "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b", + "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b", + "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86", + "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6", + "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f", + "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb", + "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833", + "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28", + "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e", + "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415", + "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902", + "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f", + "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d", + "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9", + "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d", + "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145", + "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066", + "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c", + "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1", + "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a", + "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207", + "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f", + "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53", + "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd", + "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134", + "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85", + "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9", + "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5", + "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94", + "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509", + "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", + "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" + ], + "markers": "python_version >= '3.6'", + "version": "==2.0.1" }, "mccabe": { "hashes": [ @@ -1316,128 +2076,165 @@ }, "mock": { "hashes": [ - "sha256:83657d894c90d5681d62155c82bda9c1187827525880eda8ff5df4ec813437c3", - "sha256:d157e52d4e5b938c550f39eb2fd15610db062441a9c2747d3dbfa9298211d0f8" + "sha256:122fcb64ee37cfad5b3f48d7a7d51875d7031aaf3d8be7c42e2bee25044eee62", + "sha256:7d3fbbde18228f4ff2f1f119a45cdffa458b4c0dee32eb4d2bb2f82554bac7bc" ], "index": "pypi", - "version": "==3.0.5" + "version": "==4.0.3" }, - "more-itertools": { + "outcome": { "hashes": [ - "sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", - "sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4" + "sha256:c7dd9375cfd3c12db9801d080a3b63d4b0a261aa996c4c13152380587288d958", + "sha256:e862f01d4e626e63e8f92c38d1f8d5546d3f9cce989263c521b2e7990d186967" ], - "version": "==7.2.0" + "markers": "python_version >= '3.6'", + "version": "==1.1.0" }, "packaging": { "hashes": [ - "sha256:28b924174df7a2fa32c1953825ff29c61e2f5e082343165438812f00d3a7fc47", - "sha256:d9551545c6d761f3def1677baf08ab2a3ca17c56879e70fecba2fc4dde4ed108" + "sha256:096d689d78ca690e4cd8a89568ba06d07ca097e3306a4381635073ca91479966", + "sha256:14317396d1e8cdb122989b916fa2c7e9ca8e2be9e8060a6eff75b6b7b4d8a7e0" ], - "version": "==19.2" + "markers": "python_version >= '3.6'", + "version": "==21.2" }, - "pbr": { + "pep517": { "hashes": [ - "sha256:2c8e420cd4ed4cec4e7999ee47409e876af575d4c35a45840d59e8b5f3155ab8", - "sha256:b32c8ccaac7b1a20c0ce00ce317642e6cf231cf038f9875e0280e28af5bf7ac9" + "sha256:931378d93d11b298cf511dd634cf5ea4cb249a28ef84160b3247ee9afb4e8ab0", + "sha256:dd884c326898e2c6e11f9e0b64940606a93eb10ea022a2e067959f3a110cf161" ], - "version": "==5.4.3" + "version": "==0.12.0" }, "pluggy": { "hashes": [ - "sha256:0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6", - "sha256:fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34" + "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", + "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" ], - "version": "==0.13.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.13.1" }, "py": { "hashes": [ - "sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", - "sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53" + "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", + "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" ], - "version": "==1.8.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==1.11.0" }, "pycodestyle": { "hashes": [ - "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", - "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c" + "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20", + "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==2.8.0" + }, + "pycparser": { + "hashes": [ + "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", + "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" ], - "version": "==2.5.0" + "version": "==2.21" }, "pydocstyle": { "hashes": [ - "sha256:04c84e034ebb56eb6396c820442b8c4499ac5eb94a3bda88951ac3dc519b6058", - "sha256:66aff87ffe34b1e49bff2dd03a88ce6843be2f3346b0c9814410d34987fbab59" + "sha256:1d41b7c459ba0ee6c345f2eb9ae827cab14a7533a88c5c6f7e94923f72df92dc", + "sha256:6987826d6775056839940041beef5c08cc7e3d71d63149b48e36727f70144dc4" ], "index": "pypi", - "version": "==4.0.1" + "version": "==6.1.1" }, "pyflakes": { "hashes": [ - "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0", - "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2" + "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c", + "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e" ], - "version": "==2.1.1" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.4.0" }, "pygments": { "hashes": [ - "sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127", - "sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297" + "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380", + "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6" + ], + "markers": "python_version >= '3.5'", + "version": "==2.10.0" + }, + "pyopenssl": { + "hashes": [ + "sha256:5e2d8c5e46d0d865ae933bef5230090bdaf5506281e9eec60fa250ee80600cb3", + "sha256:8935bd4920ab9abfebb07c41a4f58296407ed77f04bd1a92914044b848ba1ed6" ], - "version": "==2.4.2" + "version": "==21.0.0" }, "pyparsing": { "hashes": [ - "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", - "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4" + "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", + "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" ], - "version": "==2.4.2" + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'", + "version": "==2.4.7" }, "pytest": { "hashes": [ - "sha256:813b99704b22c7d377bbd756ebe56c35252bb710937b46f207100e843440b3c2", - "sha256:cc6620b96bc667a0c8d4fa592a8c9c94178a1bd6cc799dbb057dfd9286d31a31" + "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89", + "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134" ], "index": "pypi", - "version": "==5.1.3" + "version": "==6.2.5" }, "pytest-cov": { "hashes": [ - "sha256:2b097cde81a302e1047331b48cadacf23577e431b61e9c6f49a1170bbe3d3da6", - "sha256:e00ea4fdde970725482f1f35630d12f074e121a23801aabf2ae154ec6bdd343a" + "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6", + "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470" ], "index": "pypi", - "version": "==2.7.1" + "version": "==3.0.0" }, "pytest-flask": { "hashes": [ - "sha256:283730b469604ecb94caac28df99a40b7c785b828dd8d3323596718b51dfaeb2", - "sha256:d874781b622210d8c5d8061cdb091cb059fcb12203125110bd8e6f9256ccbf49" + "sha256:46fde652f77777bf02dc91205aec4ce20cdf2acbbbd66a918ab91f5c14693d3d", + "sha256:fe25b39ad0db09c3d1fe728edecf97ced85e774c775db259a6d25f0270a4e7c9" ], - "version": "==0.15.0" + "markers": "python_version >= '3.5'", + "version": "==1.2.0" }, "pytest-invenio": { "hashes": [ - "sha256:7d6593eb374f1697d8de0194543dd66e4591905ab87aae5a8a8970dce091fc44", - "sha256:86d06c518752f586d7c508510dd9e938ecb764cc2310a680c12dd2e6dc25f412" + "sha256:46d4d5e93656513d2c6a96a0f5e707a836338572303de0823afc71e9e3134787", + "sha256:ce9af8e56819ca92cb046aae888dd12ebd51b65e19a7a345a9f7349269dbdb30" ], "index": "pypi", - "version": "==1.2.0" + "version": "==1.4.2" + }, + "pytest-isort": { + "hashes": [ + "sha256:821a8c5c9c4f3a3c52cfa9c541fbe89ac9e28728125125af53724c4c3f129117", + "sha256:ab949c593213dad38ba75db32a0ce361fcddd11d4152be4a2c93b85104cc4376" + ], + "version": "==2.0.0" }, "pytest-mock": { "hashes": [ - "sha256:43ce4e9dd5074993e7c021bb1c22cbb5363e612a2b5a76bc6d956775b10758b7", - "sha256:5bf5771b1db93beac965a7347dc81c675ec4090cb841e49d9d34637a25c30568" + "sha256:30c2f2cc9759e76eee674b81ea28c9f0b94f8f0445a1b87762cadf774f0df7e3", + "sha256:40217a058c52a63f1042f0784f62009e976ba824c418cced42e88d5f40ab0e62" ], "index": "pypi", - "version": "==1.10.4" + "version": "==3.6.1" }, "pytest-pycodestyle": { "hashes": [ - "sha256:d4f1c1d633158c1a27b02a40cf8e27da7264a9cbd6f59b5d692368e82412ac78" + "sha256:e755e4235ed399760257026b8c3c696520848cb0261277c2df1c8e64af979eb2" ], "index": "pypi", - "version": "==1.4.0" + "version": "==2.2.0" + }, + "pytest-pydocstyle": { + "hashes": [ + "sha256:b4e7eee47252fbb7495f4a0126e547a25f5f114f3096c504e738db49a5034333" + ], + "markers": "python_version ~= '3.6'", + "version": "==2.2.0" }, "pytest-random-order": { "hashes": [ @@ -1449,170 +2246,214 @@ }, "pytest-runner": { "hashes": [ - "sha256:25a013c8d84f0ca60bb01bd11913a3bcab420f601f0f236de4423074af656e7a", - "sha256:d04243fbf29a3b574f18f1bcff2a07f505db5daede82f706f2e32728f77d3f4d" + "sha256:0fce5b8dc68760f353979d99fdd6b3ad46330b6b1837e2077a89ebcf204aac91", + "sha256:85f93af814438ee322b4ea08fe3f5c2ad53b253577f3bd84b2ad451fee450ac5" ], "index": "pypi", - "version": "==5.1" + "version": "==5.3.1" }, "pytz": { "hashes": [ - "sha256:26c0b32e437e54a18161324a2fca3c4b9846b74a8dccddd843113109e1116b32", - "sha256:c894d57500a4cd2d5c71114aaab77dbab5eabd9022308ce5ac9bb93a60a6f0c7" + "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c", + "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326" ], - "version": "==2019.2" + "version": "==2021.3" }, "requests": { "hashes": [ - "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", - "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" + "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", + "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" ], "index": "pypi", - "version": "==2.22.0" + "version": "==2.26.0" }, "selenium": { "hashes": [ - "sha256:2d7131d7bc5a5b99a2d9b04aaf2612c411b03b8ca1b1ee8d3de5845a9be2cb3c", - "sha256:deaf32b60ad91a4611b98d8002757f29e6f2c2d5fcaf202e1c9ad06d6772300d" + "sha256:c942b166a21ce9c9065ad249b54059e926d39f9000167b5ca0fa4950d2ef9a82" ], - "version": "==3.141.0" + "markers": "python_version ~= '3.7'", + "version": "==4.0.0" }, "six": { "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "version": "==1.12.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==1.16.0" + }, + "sniffio": { + "hashes": [ + "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663", + "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de" + ], + "markers": "python_version >= '3.5'", + "version": "==1.2.0" }, "snowballstemmer": { "hashes": [ - "sha256:713e53b79cbcf97bc5245a06080a33d54a77e7cce2f789c835a143bcdb5c033e" + "sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2", + "sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914" ], - "version": "==1.9.1" + "version": "==2.1.0" + }, + "sortedcontainers": { + "hashes": [ + "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", + "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0" + ], + "version": "==2.4.0" }, "sphinx": { "hashes": [ - "sha256:22538e1bbe62b407cf5a8aabe1bb15848aa66bb79559f42f5202bbce6b757a69", - "sha256:f9a79e746b87921cabc3baa375199c6076d1270cee53915dbd24fdbeaaacc427" + "sha256:6d051ab6e0d06cba786c4656b0fe67ba259fe058410f49e95bee6e49c4052cbf", + "sha256:7e2b30da5f39170efcd95c6270f07669d623c276521fee27ad6c380f49d2bf5b" ], "index": "pypi", - "version": "==2.1.2" + "version": "==4.3.0" }, "sphinx-autodoc-typehints": { "hashes": [ - "sha256:0d968ec3ee4f7fe7695ab6facf5cd2d74d3cea67584277458ad9b2788ebbcc3b", - "sha256:8edca714fd3de8e43467d7e51dd3812fe999f8874408a639f7c38a9e1a5a4eb3" + "sha256:193617d9dbe0847281b1399d369e74e34cd959c82e02c7efde077fca908a9f52", + "sha256:5e81776ec422dd168d688ab60f034fccfafbcd94329e9537712c93003bddc04a" ], "index": "pypi", - "version": "==1.8.0" + "version": "==1.12.0" }, "sphinx-click": { "hashes": [ - "sha256:7be243c3f621b6a45e5ff8f644408ed1f7fd88004388b36c77a242e8f0386c4d", - "sha256:877d4e080f6ded85d566127c7256de8afae6ab4fdc7ef301f7cc906a8177e3e8" + "sha256:29896dd12bfaacb566a8c7af2e2b675d010d69b0c5aad3b52495d4842358b15b", + "sha256:8529a02bea8cd2cd47daba2f71d7935c727c89d70baabec7fca31af49a0c379f" ], "index": "pypi", - "version": "==2.3.0" + "version": "==3.0.2" }, "sphinxcontrib-applehelp": { "hashes": [ - "sha256:edaa0ab2b2bc74403149cb0209d6775c96de797dfd5b5e2a71981309efab3897", - "sha256:fb8dee85af95e5c30c91f10e7eb3c8967308518e0f7488a2828ef7bc191d0d5d" + "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a", + "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58" ], - "version": "==1.0.1" + "markers": "python_version >= '3.5'", + "version": "==1.0.2" }, "sphinxcontrib-devhelp": { "hashes": [ - "sha256:6c64b077937330a9128a4da74586e8c2130262f014689b4b89e2d08ee7294a34", - "sha256:9512ecb00a2b0821a146736b39f7aeb90759834b07e81e8cc23a9c70bacb9981" + "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e", + "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4" ], - "version": "==1.0.1" + "markers": "python_version >= '3.5'", + "version": "==1.0.2" }, "sphinxcontrib-htmlhelp": { "hashes": [ - "sha256:4670f99f8951bd78cd4ad2ab962f798f5618b17675c35c5ac3b2132a14ea8422", - "sha256:d4fd39a65a625c9df86d7fa8a2d9f3cd8299a3a4b15db63b50aac9e161d8eff7" + "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07", + "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2" ], - "version": "==1.0.2" + "markers": "python_version >= '3.6'", + "version": "==2.0.0" }, "sphinxcontrib-httpdomain": { "hashes": [ - "sha256:1fb5375007d70bf180cdd1c79e741082be7aa2d37ba99efe561e1c2e3f38191e", - "sha256:ac40b4fba58c76b073b03931c7b8ead611066a6aebccafb34dc19694f4eb6335" + "sha256:2059cfabd0cca8fcc3455cc8ffad92f0915a7d3bb03bfddba078a6a0f35beec5", + "sha256:a3396d6350728d574f52458b400f0ac848f8b6913bd41fed95d391d3ffbbade3" ], "index": "pypi", - "version": "==1.7.0" + "version": "==1.8.0" }, "sphinxcontrib-httpexample": { "hashes": [ - "sha256:2e7705aeaece2c3f4de22500e32fa52d25347c3d4f9026e790633c9c2ba35e57", - "sha256:77ed3599a1a8e3eff414548066c8b9b7d4ca43694626c33c16a7a443d0d66512" + "sha256:2b0e24071e97be7a9580af8005a3e6a643df2f4277307c327274f9de669ce854", + "sha256:3012bbae36a9f91ea06055b7c57abce46f0eacb6d631061f5f1fdde293e4c2c7" ], "index": "pypi", - "version": "==0.10.3" + "version": "==1.0" }, "sphinxcontrib-jsmath": { "hashes": [ "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" ], + "markers": "python_version >= '3.5'", "version": "==1.0.1" }, "sphinxcontrib-qthelp": { "hashes": [ - "sha256:513049b93031beb1f57d4daea74068a4feb77aa5630f856fcff2e50de14e9a20", - "sha256:79465ce11ae5694ff165becda529a600c754f4bc459778778c7017374d4d406f" + "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72", + "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6" ], - "version": "==1.0.2" + "markers": "python_version >= '3.5'", + "version": "==1.0.3" }, "sphinxcontrib-serializinghtml": { "hashes": [ - "sha256:c0efb33f8052c04fd7a26c0a07f1678e8512e0faec19f4aa8f2473a8b81d5227", - "sha256:db6615af393650bf1151a6cd39120c29abaf93cc60db8c48eb2dddbfdc3a9768" + "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd", + "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952" ], - "version": "==1.1.3" + "markers": "python_version >= '3.5'", + "version": "==1.1.5" }, "toml": { "hashes": [ - "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", - "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e" + "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", + "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" ], - "version": "==0.10.0" + "version": "==0.10.2" }, - "urllib3": { + "tomli": { "hashes": [ - "sha256:2393a695cd12afedd0dcb26fe5d50d0cf248e5a66f75dbd89a3d4eb333a61af4", - "sha256:a637e5fae88995b256e3409dc4d52c2e2e0ba32c42a6365fee8bbd2238de3cfb" + "sha256:c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee", + "sha256:f04066f68f5554911363063a30b108d2b5a5b1a010aa8b6132af78489fe3aade" ], - "version": "==1.24.3" + "markers": "python_version >= '3.6'", + "version": "==1.2.2" }, - "wcwidth": { + "trio": { "hashes": [ - "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", - "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c" + "sha256:895e318e5ec5e8cea9f60b473b6edb95b215e82d99556a03eb2d20c5e027efe1", + "sha256:c27c231e66336183c484fbfe080fa6cc954149366c15dc21db8b7290081ec7b8" ], - "version": "==0.1.7" + "markers": "python_version >= '3.6'", + "version": "==0.19.0" + }, + "trio-websocket": { + "hashes": [ + "sha256:5b558f6e83cc20a37c3b61202476c5295d1addf57bd65543364e0337e37ed2bc", + "sha256:a3d34de8fac26023eee701ed1e7bf4da9a8326b61a62934ec9e53b64970fd8fe" + ], + "markers": "python_version >= '3.5'", + "version": "==0.9.2" + }, + "urllib3": { + "hashes": [ + "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece", + "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_full_version < '4.0.0'", + "version": "==1.26.7" }, "werkzeug": { "hashes": [ - "sha256:7280924747b5733b246fe23972186c6b348f9ae29724135a6dfc1e53cea433e7", - "sha256:e5f4a1f98b52b18a93da705a7458e55afb26f32bff83ff5d19189f92462d65c4" + "sha256:63d3dc1cf60e7b7e35e97fa9861f7397283b75d765afcaefd993d6046899de8f", + "sha256:aa2bb6fc8dee8d6c504c0ac1e7f5f7dc5810a9903e793b6f715a9f015bdadb9a" ], - "version": "==0.16.0" + "markers": "python_version >= '3.6'", + "version": "==2.0.2" }, "wheel": { "hashes": [ - "sha256:10c9da68765315ed98850f8e048347c3eb06dd81822dc2ab1d4fde9dc9702646", - "sha256:f4da1763d3becf2e2cd92a14a7c920f0f00eca30fdde9ea992c836685b9faf28" + "sha256:21014b2bd93c6d0034b6ba5d35e4eb284340e09d63c59aef6fc14b0f346146fd", + "sha256:e2ef7239991699e3355d54f8e968a21bb940a1dbf34a4d226741e64462516fad" ], - "version": "==0.33.6" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==0.37.0" }, - "zipp": { + "wsproto": { "hashes": [ - "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", - "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335" + "sha256:868776f8456997ad0d9720f7322b746bbe9193751b5b290b7f924659377c8c38", + "sha256:d8345d1808dd599b5ffb352c25a367adb6157e664e140dbecba3f9bc007edb9f" ], - "version": "==0.6.0" + "markers": "python_full_version >= '3.6.1'", + "version": "==1.0.0" } } } diff --git a/asclepias_broker/config.py b/asclepias_broker/config.py index ed9c864..6b5b49f 100644 --- a/asclepias_broker/config.py +++ b/asclepias_broker/config.py @@ -21,9 +21,10 @@ from invenio_records_rest.facets import range_filter, terms_filter from invenio_records_rest.utils import deny_all from invenio_search.api import RecordsSearch +from celery.schedules import crontab from .search.query import enum_term_filter, nested_range_filter, \ - nested_terms_filter + nested_terms_filter, simple_query_string_filter def _parse_env_bool(var_name, default=None): @@ -125,8 +126,20 @@ def _parse_env_bool(var_name, default=None): 'schedule': timedelta(minutes=60), }, 'reindex': { - 'task': 'asclepias_broker.tasks.reindex_all_relationships', - 'schedule': timedelta(hours=24) + 'task': 'asclepias_broker.search.tasks.reindex_all_relationships', + 'schedule': crontab(hour=23, minute=0) + }, + 'notify': { + 'task': 'asclepias_broker.monitoring.tasks.sendMonitoringReport', + 'schedule': crontab(hour=0, minute=0, day_of_week=0) + }, + 'rerun_harvester_errors': { + 'task': 'asclepias_broker.monitoring.tasks.rerun_harvest_errors', + 'schedule': crontab(hour=22, minute=0) + }, + 'rerun_event_errors': { + 'task': 'asclepias_broker.monitoring.tasks.rerun_event_errors', + 'schedule': crontab(hour=21, minute=0) }, } @@ -167,6 +180,36 @@ def _parse_env_bool(var_name, default=None): max_result_window=10000, error_handlers=dict(), ), + meta=dict( + pid_type='meta', + pid_minter='relid', + pid_fetcher='relid', + search_class=RecordsSearch, + indexer_class=None, + search_index='relationships', + search_type=None, + search_factory_imp='asclepias_broker.search.query.meta_search_factory', + # Only the List GET view is available + create_permission_factory_imp=deny_all, + delete_permission_factory_imp=deny_all, + update_permission_factory_imp=deny_all, + read_permission_factory_imp=deny_all, + links_factory_imp=lambda p, **_: None, + record_serializers={ + 'application/json': ('invenio_records_rest.serializers' + ':json_v1_response'), + }, + # TODO: Implement marshmallow serializers + search_serializers={ + 'application/json': ('invenio_records_rest.serializers' + ':json_v1_search'), + }, + list_route='/metadata', + item_route='/metadata/', + default_media_type='application/json', + max_result_window=10000, + error_handlers=dict(), + ), ) RECORDS_REST_FACETS = dict( relationships=dict( @@ -205,12 +248,41 @@ def _parse_env_bool(var_name, default=None): 'isRelatedTo': 'IsRelatedTo' } ), + keyword=simple_query_string_filter('Source.Keywords_all'), + journal=nested_terms_filter('Source.Publisher.Name','Source.Publisher'), ), post_filters=dict( type=terms_filter('Source.Type.Name'), publication_year=range_filter( - 'Source.PublicationDate', format='yyyy', end_date_math='/y'), + 'Source.PublicationDate', format='yyyy', start_date_math='/y', end_date_math='/y'), ) + ), + + # The topHits agg can't be addded here due to limitations in elasticsearch_dsl aggs function so that is added in query.py + metadata=dict( + aggs=dict( + NumberOfTargets=dict( + cardinality=dict(field='Target.ID') + ), + publication_year=dict( + date_histogram=dict( + field='Source.PublicationDate', + interval='year', + format='yyyy', + ), + ), + ), + filters=dict( + group_by=enum_term_filter( + label='group_by', + field='Grouping', + choices={'identity': 'identity', 'version': 'version'} + ), + keyword=simple_query_string_filter('Source.Keywords_all'), + journal=nested_terms_filter('Source.Publisher.Name','Source.Publisher'), + publication_year=range_filter( + 'Source.PublicationDate', format='yyyy', start_date_math='/y', end_date_math='/y'), + ), ) ) # TODO: See if this actually works @@ -228,6 +300,7 @@ def _parse_env_bool(var_name, default=None): } } RATELIMIT_STORAGE_URL = f'{REDIS_BASE_URL}/3' +RATELIMIT_AUTHENTICATED_USER = '20000 per hour;500 per minute' APP_DEFAULT_SECURE_HEADERS['force_https'] = True APP_DEFAULT_SECURE_HEADERS['session_cookie_secure'] = True diff --git a/asclepias_broker/events/api.py b/asclepias_broker/events/api.py index c2a7b6b..2b3c742 100644 --- a/asclepias_broker/events/api.py +++ b/asclepias_broker/events/api.py @@ -48,7 +48,7 @@ def validate_payload(cls, event): for payload in event: errors = RelationshipSchema(check_existing=True).validate(payload) if errors: - raise MarshmallowValidationError(errors) + raise MarshmallowValidationError(str(errors) + "payload" + str(payload)) @classmethod def handle_event(cls, event: dict, no_index: bool = False, @@ -69,3 +69,16 @@ def handle_event(cls, event: dict, no_index: bool = False, else: task.apply_async() return event_obj + + @classmethod + def rerun_event(cls, event: Event, no_index: bool, eager:bool = False): + event_uuid = str(event.id) + idx_enabled = current_app.config['ASCLEPIAS_SEARCH_INDEXING_ENABLED'] \ + and (not no_index) + task = process_event.s( + event_uuid=event_uuid, indexing_enabled=idx_enabled) + if eager: + task.apply(throw=True) + else: + task.apply_async() + return event diff --git a/asclepias_broker/events/cli.py b/asclepias_broker/events/cli.py index bfea8e5..d35b8f5 100644 --- a/asclepias_broker/events/cli.py +++ b/asclepias_broker/events/cli.py @@ -8,14 +8,18 @@ """Events CLI.""" from __future__ import absolute_import, print_function +import datetime import json import click from flask.cli import with_appcontext +from flask import current_app from ..utils import find_ext from .api import EventAPI +from ..graph.tasks import process_event +from .models import Event, EventStatus @click.group() @@ -41,3 +45,47 @@ def load(jsondir_or_file: str, no_index: bool = False, eager: bool = False): EventAPI.handle_event(data, no_index=no_index, eager=eager) except ValueError: pass + +@events.command('rerun') +@click.option('-i','--id', default=None) +@click.option('-a', '--all', default=False, is_flag=True) +@click.option('-e', '--errors', default=False, is_flag=True) +@click.option('-p', '--processing', default=False, is_flag=True) +@click.option('--no-index', default=False, is_flag=True) +@click.option('--eager', default=False, is_flag=True) +@with_appcontext +def rerun(id: str = None, all: bool = False, errors: bool = True, processing: bool = False, no_index: bool = False, eager: bool = False): + """Rerun failed or stuck events.""" + if id: + rerun_id(id, no_index, eager) + return + if all: + errors = True + processing = True + if processing: + rerun_processing(no_index, eager) + rerun_new(no_index, eager) + if errors: + rerun_errors(no_index, eager) + +def rerun_id(id:str, no_index: bool, eager:bool = False): + event = Event.get(id) + if event: + EventAPI.rerun_event(event, no_index=no_index, eager=eager) + +def rerun_processing(no_index: bool, eager:bool = False): + yesterday = datetime.datetime.now() - datetime.timedelta(days = 1) + resp = Event.query.filter(Event.status == EventStatus.Processing, Event.created < str(yesterday)).all() + for event in resp: + EventAPI.rerun_event(event, no_index=no_index, eager=eager) + +def rerun_new(no_index: bool, eager:bool = False): + yesterday = datetime.datetime.now() - datetime.timedelta(days = 1) + resp = Event.query.filter(Event.status == EventStatus.New, Event.created < str(yesterday)).all() + for event in resp: + EventAPI.rerun_event(event, no_index=no_index, eager=eager) + +def rerun_errors(no_index: bool, eager:bool = False): + resp = Event.query.filter(Event.status == EventStatus.Error).all() + for event in resp: + EventAPI.rerun_event(event, no_index=no_index, eager=eager) \ No newline at end of file diff --git a/asclepias_broker/events/models.py b/asclepias_broker/events/models.py index 041119f..1ba1b30 100644 --- a/asclepias_broker/events/models.py +++ b/asclepias_broker/events/models.py @@ -10,12 +10,14 @@ import enum import uuid from typing import Union +import datetime from invenio_accounts.models import User from invenio_db import db from sqlalchemy.schema import PrimaryKeyConstraint from sqlalchemy_utils.models import Timestamp from sqlalchemy_utils.types import JSONType, UUIDType +from sqlalchemy import func from ..core.models import Identifier, Relationship @@ -53,7 +55,14 @@ class Event(db.Model, Timestamp): def get(cls, id: str = None, **kwargs): """Get the event from the database.""" return cls.query.filter_by(id=id).one_or_none() - + + @classmethod + def getStatsFromLastWeek(cls): + """Gets the stats from the last 7 days""" + last_week = datetime.datetime.now() - datetime.timedelta(days = 7) + resp = db.session.query(cls.status, func.count('*')).filter(cls.updated > str(last_week)).group_by(cls.status).all() + return resp + def __repr__(self): """String representation of the event.""" return f"<{self.id}: {self.created}>" diff --git a/asclepias_broker/graph/models.py b/asclepias_broker/graph/models.py index e82be44..9ce0e7c 100644 --- a/asclepias_broker/graph/models.py +++ b/asclepias_broker/graph/models.py @@ -163,6 +163,7 @@ class GroupM2M(db.Model, Timestamp): __tablename__ = 'groupm2m' __table_args__ = ( PrimaryKeyConstraint('group_id', 'subgroup_id', name='pk_groupm2m'), + UniqueConstraint('subgroup_id', name='uq_groupm2m_subgroup_id'), ) group_id = db.Column( UUIDType, diff --git a/asclepias_broker/graph/tasks.py b/asclepias_broker/graph/tasks.py index 712dc42..f0878f8 100644 --- a/asclepias_broker/graph/tasks.py +++ b/asclepias_broker/graph/tasks.py @@ -12,8 +12,6 @@ from celery import shared_task from flask import current_app from invenio_db import db -from marshmallow.exceptions import \ - ValidationError as MarshmallowValidationError from ..core.models import Relationship from ..events.models import Event, EventStatus, ObjectEvent, PayloadType @@ -22,6 +20,7 @@ from ..schemas.loaders import RelationshipSchema from ..search.indexer import update_indices from .api import update_groups +from ..monitoring.models import ErrorMonitoring def get_or_create(model, **kwargs): @@ -107,8 +106,8 @@ def _set_event_status(event_uuid, status): db.session.commit() -@shared_task(ignore_result=True, max_retries=3, default_retry_delay=5 * 60) -def process_event(event_uuid: str, indexing_enabled: bool = True): +@shared_task(bind=True, ignore_result=True, max_retries=1, default_retry_delay=10 * 60) +def process_event(self, event_uuid: str, indexing_enabled: bool = True): """Process the event.""" # TODO: Should we detect and skip duplicated events? _set_event_status(event_uuid, EventStatus.Processing) @@ -119,12 +118,9 @@ def process_event(event_uuid: str, indexing_enabled: bool = True): for payload_idx, payload in enumerate(event.payload): # TODO: marshmallow validation of all payloads # should be done on first event ingestion (check) - relationship, errors = \ - RelationshipSchema(check_existing=True).load(payload) + relationship = RelationshipSchema(check_existing=True).load(payload) # Errors should never happen as the payload is validated # with RelationshipSchema on the event ingestion - if errors: - raise MarshmallowValidationError(errors) # Skip already known relationships # NOTE: This skips any extra metadata! @@ -150,5 +146,15 @@ def process_event(event_uuid: str, indexing_enabled: bool = True): _set_event_status(event_uuid, EventStatus.Done) event_processed.send(current_app._get_current_object(), event=event) except Exception as exc: + db.session.rollback() _set_event_status(event_uuid, EventStatus.Error) - process_event.retry(exc=exc) + payload = Event.get(id=event_uuid).payload + error_obj = ErrorMonitoring.getFromEvent(event_uuid) + if not error_obj: + error_obj = ErrorMonitoring(event_id = event_uuid, origin=self.__class__.__name__, error=repr(exc), n_retries=self.request.retries, payload=payload) + db.session.add(error_obj) + else: + error_obj.n_retries += 1 + + db.session.commit() + self.retry(exc=exc) \ No newline at end of file diff --git a/asclepias_broker/harvester/cli.py b/asclepias_broker/harvester/cli.py index 589b62e..293eeb4 100644 --- a/asclepias_broker/harvester/cli.py +++ b/asclepias_broker/harvester/cli.py @@ -8,10 +8,13 @@ """Harvesting CLI.""" from __future__ import absolute_import, print_function +import datetime from typing import List import click +from ..monitoring.models import HarvestMonitoring, HarvestStatus +from ..harvester.tasks import harvest_metadata_identifier import idutils from flask.cli import with_appcontext @@ -50,3 +53,67 @@ def events_command(harvester_ids: List[str], eager: bool = False): task.apply(throw=True) else: task.apply_async() + +@harvester.command('rerun') +@click.option('-i','--id', default=None) +@click.option('--start-time', default=None) +@click.option('--end-time', default=None) +@click.option('-a', '--all', default=False, is_flag=True) +@click.option('-e', '--errors', default=False, is_flag=True) +@click.option('-p', '--processing', default=False, is_flag=True) +@click.option('--no-index', default=False, is_flag=True) +@click.option('--eager', default=False, is_flag=True) +@with_appcontext +def rerun(id: str = None, all: bool = False, errors: bool = True, processing: bool = False, + start_time: str = None, end_time:str = None, no_index: bool = False, eager: bool = False): + """Rerun failed or stuck events.""" + if id: + rerun_id(id, no_index, eager) + return + if all: + errors = True + processing = True + if processing: + rerun_processing(no_index, eager) + rerun_new(no_index, eager) + if errors: + rerun_errors(no_index, eager, start_time, end_time) + +def rerun_id(id:str, no_index: bool, eager:bool = False): + event = HarvestMonitoring.get(id) + if event: + rerun_event(event, no_index=no_index, eager=eager) + +def rerun_processing(no_index: bool, eager:bool = False): + yesterday = datetime.datetime.now() - datetime.timedelta(days = 1) + resp = HarvestMonitoring.query.filter(HarvestMonitoring.status == HarvestStatus.Processing, HarvestMonitoring.created < str(yesterday)).all() + for event in resp: + rerun_event(event, no_index=no_index, eager=eager) + +def rerun_new(no_index: bool, eager:bool = False): + yesterday = datetime.datetime.now() - datetime.timedelta(days = 1) + resp = HarvestMonitoring.query.filter(HarvestMonitoring.status == HarvestStatus.New, HarvestMonitoring.created < str(yesterday)).all() + for event in resp: + rerun_event(event, no_index=no_index, eager=eager) + +def rerun_errors(no_index: bool, eager:bool = False, start_time: str = None, end_time:str = None): + if start_time and end_time: + resp = HarvestMonitoring.query.filter(HarvestMonitoring.status == HarvestStatus.Error, HarvestMonitoring.created > start_time, HarvestMonitoring.created < end_time).all() + elif start_time: + resp = HarvestMonitoring.query.filter(HarvestMonitoring.status == HarvestStatus.Error, HarvestMonitoring.created > start_time).all() + elif end_time: + resp = HarvestMonitoring.query.filter(HarvestMonitoring.status == HarvestStatus.Error, HarvestMonitoring.created < end_time).all() + else: + resp = HarvestMonitoring.query.filter(HarvestMonitoring.status == HarvestStatus.Error).all() + for event in resp: + rerun_event(event, no_index=no_index, eager=eager) + +def rerun_event(event: HarvestMonitoring, no_index: bool, eager:bool = False): + event_uuid = str(event.id) + task = harvest_metadata_identifier.s(str(event.harvester), event.identifier, event.scheme, + event_uuid, None) + if eager: + task.apply(throw=True) + else: + task.apply_async() + return event \ No newline at end of file diff --git a/asclepias_broker/harvester/config.py b/asclepias_broker/harvester/config.py index 96bd953..493a4c4 100644 --- a/asclepias_broker/harvester/config.py +++ b/asclepias_broker/harvester/config.py @@ -11,6 +11,9 @@ from .metadata import ADSMetadataHarvester, DOIMetadataHarvester from .zenodo import ZenodoVersioningHarvester +from .github import GitHubHarvester +from .crossref import CrossrefHarvester +from .europepmc import EuropePMCHarvester ASCLEPIAS_HARVESTER_HISTORY_PREFIX = 'asclepias-harvester' @@ -22,33 +25,37 @@ .. code-block:: python - ASCLEPIAS_HARVESTER_EVENT_HARVESTERS = { - 'crossref': (CrossrefHarvester, { - 'id': 'zenodo-doi-references', - 'params': { - 'obj-id.prefix': '10.5281', - 'source': 'crossref', - 'relation-type': 'references', - } - }), - 'europepmc': (EuropePMCHarvester, { - 'id': 'zenodo-dois-query', - 'query': 'zenodo', - 'doi_prefix': '10.5281', - }), - } """ +ASCLEPIAS_HARVESTER_EVENT_HARVESTERS = { + 'crossref': (CrossrefHarvester, { + 'id': 'zenodo-doi-references', + 'params': { + 'obj-id.prefix': '10.5281', + 'source': 'crossref', + 'relation-type': 'references', + } + }), + 'europepmc': (EuropePMCHarvester, { + 'id': 'zenodo-dois-query', + 'query': 'zenodo', + 'doi_prefix': '10.5281', + }), +} ASCLEPIAS_HARVESTER_METADATA_HARVESTERS = { - 'doi': (DOIMetadataHarvester, {}), - 'ads': (ADSMetadataHarvester, {}), - 'zenodo': (ZenodoVersioningHarvester, {}), + 'DOIMetadataHarvester': (DOIMetadataHarvester, {}), + 'ADSMetadataHarvester': (ADSMetadataHarvester, {}), + 'ZenodoVersioningHarvester': (ZenodoVersioningHarvester, {}), + 'GitHubHarvester': (GitHubHarvester, {}) } """Metadata harvesters configuration.""" ASCLEPIAS_HARVESTER_ADS_API_TOKEN = None """API token to be used when accessing the ADS REST API.""" +ASCLEPIAS_HARVESTER_GITHUB_API_TOKEN = None +"""API token to be used when accessing the GITHUB REST API.""" + ASCLEPIAS_HARVESTER_CROSSREF_API_EMAIL = None """Email address to be passed when accessing the Crossref REST API.""" diff --git a/asclepias_broker/harvester/github.py b/asclepias_broker/harvester/github.py new file mode 100644 index 0000000..9a9b86c --- /dev/null +++ b/asclepias_broker/harvester/github.py @@ -0,0 +1,246 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Harvester is free software; you can redistribute it and/or modify +# it under the terms of the MIT License; see LICENSE file for more details. + +"""Versioning metadata harvester.""" + +from datetime import datetime +from typing import List + +from ..events.api import EventAPI + +import re +import time +import requests +from flask import current_app +from sqlalchemy.orm import relationship +from ..utils import chunks, GitHubAPIException, GithubUtility +from .base import MetadataHarvester + + +class GitHubClient: + """GitHub client.""" + + base_url = 'https://api.github.com/' + _api_token = None + + # For some reason a different repo name when using id vs name in the Github API + + def get_repo_metadata_from_id(self, id) -> dict: + url = self.base_url + "repositories/" + id + return self.query_api(url) + + def get_repo_metadata_from_name(self, user, repo) -> dict: + url = self.base_url + "repos/" + user + "/" + repo + return self.query_api(url) + + def get_repo_release_from_name(self, user, repo, tag) -> dict: + repo_meta = self.get_repo_metadata_from_name(user, repo) + releases_url = repo_meta['releases_url'].replace('{/id}','') + return self.get_repo_release(releases_url, repo_meta, tag) + + def get_repo_release_from_id(self, id, tag) -> dict: + repo_meta = self.get_repo_metadata_from_id(id) + releases_url = repo_meta['releases_url'].replace('{/id}','') + return self.get_repo_release(releases_url, repo_meta, tag) + + def get_repo_release(self, url, repo_meta, tag) -> dict: + releases = self.query_api(url) + for release in releases: + if release['tag_name'] == tag: + release['repo_id'] = repo_meta['id'] + release['repo_name'] = repo_meta['full_name'] + return release + + def get_api_token(self): + """.""" + if self._api_token is None: + self._api_token = current_app.config.get( + 'ASCLEPIAS_HARVESTER_GITHUB_API_TOKEN') + elif callable(self._api_token): + self._api_token = self._api_token() + return self._api_token + + def query_api(self, url): + try: + headers = {'X-GitHub-Media-Type':'application/vnd.github.v3.raw+json'} + token = self.get_api_token() + if token is not None: + headers['Authorization'] = 'token ' + token + res = requests.get(url, headers=headers) + if res.ok: + return res.json() + else: + res.raise_for_status() + except Exception as exc: + raise GitHubAPIException(exc) + +class GitHubHarvester(MetadataHarvester): + """Metadata harvester for Github""" + + def __init__(self, *, provider_name: str = None): + """.""" + self.provider_name = provider_name or "Github harvester" + + def can_harvest(self, identifier: str, scheme: str, + providers: List[str] = None) -> bool: + """.""" + is_provider = False + if providers: + is_provider = self.provider_name in providers + + return (self._is_valid_github_url(scheme, identifier) or\ + self._is_github_repo_id(scheme, identifier) or\ + self._is_github_repo_id(scheme, identifier) or\ + self._is_github_release_id(scheme, identifier) )\ + and not is_provider + + def harvest(self, identifier: str, scheme: str, + providers: List[str] = None): + """.""" + try: + #Added a sleeper timer to slow down the harvesters since during large ingestions they cause HTTP 403 errors when too many queries are sent + time.sleep(1) + providers = set(providers) if providers else set() + providers.add(self.provider_name) + payloads = [] + if self._is_valid_github_url(scheme, identifier): + parsed_info = GithubUtility.parse_url_info(identifier) + elif self._is_github_repo_id(scheme, identifier): + parsed_info = dict(id=identifier, identifier=identifier, scheme='github') + elif self._is_github_release_id(scheme, identifier): + id, _, release_id = identifier.split('/') + parsed_info = dict(id=id, sub_type='release_id', release_id=release_id, identifier=identifier, scheme='github') + + child = None + if 'sub_type' in parsed_info.keys(): + for payload in add_version_identifiers(parsed_info, providers): + payloads.append(payload) + child = { + "ID": parsed_info['identifier'], + "IDScheme": parsed_info['scheme'] + } + + for payload in add_parent_identifiers(parsed_info, providers, child): + payloads.append(payload) + + for event_chunk in chunks(payloads, 100): + try: + EventAPI.handle_event(list(event_chunk), no_index=True, eager=True) + except ValueError: + current_app.logger.exception( + 'Error while processing github harvesting event.') + except Exception as exc: + raise GitHubAPIException(exc) + + def _is_github_repo_id(self, scheme: str, identifier: str) -> bool: + if scheme.lower() == 'github' and re.match('^\d+$',identifier): + return True + return False + + def _is_github_release_id(self, scheme: str, identifier: str) -> bool: + if scheme.lower() == 'github' and re.match('^\d+/releases/\d+$',identifier): + return True + return False + + def _is_valid_github_url(self, scheme: str, identifier: str) -> bool: + if scheme.lower() == 'url' and 'github.com' in identifier.lower(): + try: + GithubUtility.parse_url_info(identifier) + except: + return False + return True + else: + return False + +def add_parent_identifiers(parsed_info, providers, child = None) -> List[dict]: + client = GitHubClient() + add_old_name = False + if 'user' in parsed_info.keys(): + parent_meta = client.get_repo_metadata_from_name(user=parsed_info['user'], repo=parsed_info['repo']) + if parent_meta['full_name'] != parsed_info['user'] + '/' + parsed_info['repo']: + add_old_name = True + else: + parent_meta = client.get_repo_metadata_from_id(id=parsed_info['id']) + id = parent_meta['id'] + full_name = parent_meta['full_name'] + + id_identifier = { + "ID": str(id), + "IDScheme": 'github' + } + name_identifier = { + "ID": 'https://github.com/' + full_name, + "IDScheme": 'url' + } + payloads = [] + payloads.append(create_relationship_event(src=id_identifier, target=name_identifier, relationship='IsIdenticalTo', providers=providers)) + if child != None: + payloads.append(create_relationship_event(src=id_identifier, target=child, relationship='HasVersion', providers=providers)) + if add_old_name: + old_name_identifier = { + "ID": 'github.com/' + parsed_info['user'] + '/' + parsed_info['repo'], + "IDScheme": 'url' + } + payloads.append(create_relationship_event(src=name_identifier, target=old_name_identifier, relationship='IsIdenticalTo', providers=providers)) + + return payloads + +def add_version_identifiers(parsed_info, providers) -> List[dict]: + client = GitHubClient() + add_old_name = False + if 'user' in parsed_info.keys(): + version_meta = client.get_repo_release_from_name(user=parsed_info['user'], repo=parsed_info['repo'], tag=parsed_info['tag']) + if version_meta is not None and version_meta['html_url'] != parsed_info['identifier']: + add_old_name = True + else: + version_meta = client.get_repo_release_from_id(id=parsed_info['id'], tag = parsed_info['release_id']) + + payloads = [] + + if version_meta is not None: + id_identifier = { + "ID": str(version_meta['repo_id']) + '/releases/' + str(version_meta['id']), + "IDScheme": 'github' + } + name_identifier = { + "ID": version_meta['html_url'], + "IDScheme": 'url' + } + + payloads.append(create_relationship_event(src=id_identifier, target=name_identifier, relationship='IsIdenticalTo', providers=providers)) + if add_old_name: + old_name_identifier = { + "ID": parsed_info['identifier'], + "IDScheme": 'url' + } + payloads.append(create_relationship_event(src=name_identifier, target=old_name_identifier, relationship='IsIdenticalTo', providers=providers)) + + return payloads + +def create_relationship_event(src, target, relationship, providers) -> dict: + link_publication_date = datetime.now().isoformat() + link_providers = providers or ['unknown'] + link_providers = [{'Name': provider} for provider in link_providers] + payload = { + 'RelationshipType': { + 'Name': 'IsRelatedTo', + 'SubTypeSchema': 'DataCite', + 'SubType': relationship + }, + 'Target': { + 'Identifier': target, + 'Type': {'Name': 'unknown'} + }, + 'LinkProvider': link_providers, + 'Source': { + 'Identifier': src, + 'Type': {'Name': 'unknown'} + }, + 'LinkPublicationDate': link_publication_date, + } + + return payload \ No newline at end of file diff --git a/asclepias_broker/harvester/metadata.py b/asclepias_broker/harvester/metadata.py index 68fa1e7..b94abd7 100644 --- a/asclepias_broker/harvester/metadata.py +++ b/asclepias_broker/harvester/metadata.py @@ -10,7 +10,7 @@ from copy import deepcopy from datetime import datetime from typing import Callable, List, Union - +import time import idutils import requests from flask import current_app @@ -44,99 +44,110 @@ def _date_from_parts(parts): def crossref_metadata(doi: str) -> dict: """.""" - params = {} - email = current_app.config.get('ASCLEPIAS_HARVESTER_CROSSREF_API_EMAIL') - if email: - params['mailto'] = email - resp = requests.get(f'https://api.crossref.org/works/{doi}', params=params) - if resp.ok: - metadata = resp.json()['message'] - result = {} - result['Identifier'] = [{'IDScheme': 'doi', 'ID': doi}] - res_type = metadata['type'] - result['Type'] = { - 'Name': res_type if res_type == 'dataset' else 'literature', - } - if metadata.get('title'): - result['Title'] = metadata['title'][0] - creators = [] - for author_field in ('author', 'editor'): - authors = metadata.get(author_field, []) - for author in authors: - if author.get('family') and author.get('given'): - creators.append( - '{}, {}'.format(author['family'], author['given'])) - if creators: - result['Creator'] = [{'Name': c} for c in creators] - - if metadata.get('publisher'): - result['Publisher'] = [{'Name': metadata['publisher']}] - - for date_field in ('issued', 'published-online', 'published-print'): - if metadata.get(date_field): - result['PublicationDate'] = _date_from_parts( - metadata[date_field]['date-parts'][0]) - break - return result - else: - raise CrossrefAPIException() + try: + params = {} + email = current_app.config.get('ASCLEPIAS_HARVESTER_CROSSREF_API_EMAIL') + if email: + params['mailto'] = email + resp = requests.get(f'https://api.crossref.org/works/{doi}', params=params) + if resp.ok: + metadata = resp.json()['message'] + result = {} + result['Identifier'] = [{'IDScheme': 'doi', 'ID': doi}] + res_type = metadata['type'] + result['Type'] = { + 'Name': res_type if res_type == 'dataset' else 'literature', + } + if metadata.get('title'): + result['Title'] = metadata['title'][0] + creators = [] + for author_field in ('author', 'editor'): + authors = metadata.get(author_field, []) + for author in authors: + if author.get('family') and author.get('given'): + creators.append( + '{}, {}'.format(author['family'], author['given'])) + if creators: + result['Creator'] = [{'Name': c} for c in creators] + + if metadata.get('container-title'): + result['Publisher'] = [] + for pub in metadata['container-title']: + result['Publisher'].append({'Name': pub}) + if metadata.get('short-container-title'): + for pub in metadata['short-container-title']: + result['Publisher'].append({'Name': pub}) + + for date_field in ('issued', 'published-online', 'published-print'): + if metadata.get(date_field): + result['PublicationDate'] = _date_from_parts( + metadata[date_field]['date-parts'][0]) + break + return result + else: + resp.raise_for_status() + except Exception as exc: + raise CrossrefAPIException(exc) def datacite_metadata(doi: str) -> dict: """.""" # TODO: Consider using marshmallow for parsing these responses... - mimetype = 'application/vnd.datacite.datacite+json' - resp = requests.get(f'https://data.datacite.org/{mimetype}/{doi}') - if resp.ok: - metadata = resp.json() - result = {} - - # Identifiers - result['Identifier'] = [] - identifiers = metadata.get('identifiers') or [] - if not isinstance(identifiers, list): - identifiers = [identifiers] - for i in identifiers: - result['Identifier'].append( - {'IDScheme': i['identifierType'].lower(), - 'ID': i['identifier']}) - - # Type - res_type = metadata.get( - 'types', {}).get('resourceTypeGeneral', '').lower() - result['Type'] = { - 'Name': (res_type if res_type in ('dataset', 'software') - else 'literature') - } - - # Title - if metadata.get('titles'): - result['Title'] = metadata['titles'][0]['title'] - - # Creators - creators = [] - if metadata.get('creators'): - for author in metadata['creators']: - if isinstance(author, str): - creators.append(author) - elif author.get('name'): - creators.append(author['name']) - elif author.get('familyName') and author.get('givenName'): - creators.append( - '{}, {}'.format(author['familyName'], - author['givenName'])) - if creators: - result['Creator'] = [{'Name': c} for c in creators] - - # Publication date - dates = [d['date'] for d in metadata.get('dates', []) - if d.get('dateType') == 'Issued' and d.get('date')] - if dates: - result['PublicationDate'] = dates[0] - - return result - else: - raise DataCiteAPIException() + try: + mimetype = 'application/vnd.datacite.datacite+json' + resp = requests.get(f'https://data.datacite.org/{mimetype}/{doi}') + if resp.ok: + metadata = resp.json() + result = {} + + # Identifiers + result['Identifier'] = [] + identifiers = metadata.get('identifiers') or [] + if not isinstance(identifiers, list): + identifiers = [identifiers] + for i in identifiers: + result['Identifier'].append( + {'IDScheme': i['identifierType'].lower(), + 'ID': i['identifier']}) + + # Type + res_type = metadata.get( + 'types', {}).get('resourceTypeGeneral', '').lower() + result['Type'] = { + 'Name': (res_type if res_type in ('dataset', 'software') + else 'literature') + } + + # Title + if metadata.get('titles'): + result['Title'] = metadata['titles'][0]['title'] + + # Creators + creators = [] + if metadata.get('creators'): + for author in metadata['creators']: + if isinstance(author, str): + creators.append(author) + elif author.get('name'): + creators.append(author['name']) + elif author.get('familyName') and author.get('givenName'): + creators.append( + '{}, {}'.format(author['familyName'], + author['givenName'])) + if creators: + result['Creator'] = [{'Name': c} for c in creators] + + # Publication date + dates = [d['date'] for d in metadata.get('dates', []) + if d.get('dateType') == 'Issued' and d.get('date')] + if dates: + result['PublicationDate'] = dates[0] + + return result + else: + resp.raise_for_status() + except Exception as exc: + raise DataCiteAPIException(exc) class DOIMetadataHarvester(MetadataHarvester): @@ -165,13 +176,18 @@ def can_harvest(self, identifier: str, scheme: str, def harvest(self, identifier: str, scheme: str, providers: List[str] = None): """.""" - data = self.get_metadata(identifier) - if data: - providers = set(providers) if providers else set() - providers.add(self.provider_name) - update_metadata( - identifier, scheme, data, - providers=list(providers)) + try: + #Added a sleeper timer to slow down the harvesters since during large ingestions they cause HTTP 403 errors when too many queries are sent + time.sleep(1) + data = self.get_metadata(identifier) + if data: + providers = set(providers) if providers else set() + providers.add(self.provider_name) + update_metadata( + identifier, scheme, data, + providers=list(providers)) + except Exception as exc: + raise MetadataAPIException(exc) def get_metadata(self, doi: str) -> dict: """.""" @@ -192,7 +208,7 @@ def _agency_by_prefix(self, doi_prefix): if res.ok: return res.json()[0].get('RA').lower() else: - raise MetadataAPIException() + res.raise_for_status() class ADSMetadataHarvester(MetadataHarvester): @@ -200,7 +216,7 @@ class ADSMetadataHarvester(MetadataHarvester): ADS_API_URL = 'https://api.adsabs.harvard.edu/v1/search/query' ADS_API_PARAMS = { - 'fl': 'title,author,doi,bibcode,identifier,doctype,pub,year,pubdate', + 'fl': 'title,author,doi,bibcode,identifier,doctype,pub,year,pubdate,keyword, bibstem', } ADS_TYPE_MAPPING = { @@ -248,6 +264,8 @@ def can_harvest(self, identifier: str, scheme: str, def harvest(self, identifier: str, scheme: str, providers: List[str] = None): """.""" + #Added a sleeper timer to slow down the harvesters since during large ingestions they cause HTTP 403 errors when too many queries are sent + time.sleep(1) data = self.get_metadata(identifier) if data: providers = set(providers) if providers else set() @@ -258,26 +276,31 @@ def harvest(self, identifier: str, scheme: str, def get_metadata(self, bibcode: str) -> dict: """.""" - params = deepcopy(self.api_params) - params['q'] = f'identifier:{bibcode}' - res = requests.get( - self.api_url, params=params, headers=self._req_headers) - if res.ok: - data = res.json() - if data['response']['numFound'] == 1: - doc = data['response']['docs'][0] - return { - 'Identifier': self._extract_identifiers(doc), - 'Publisher': ([{'Name': doc['pub']}] - if doc.get('pub') else None), - 'Creator': [{'Name': n} for n in doc.get('author', []) - if n], - 'Title': doc.get('title', [None])[0], - 'PublicationDate': self._extract_date(doc), - 'Type': {'Name': self._extract_type(doc)}, - } - else: - raise AdsAPIException() + try: + params = deepcopy(self.api_params) + params['q'] = f'identifier:{bibcode}' + res = requests.get( + self.api_url, params=params, headers=self._req_headers) + if res.ok: + data = res.json() + if data['response']['numFound'] == 1: + doc = data['response']['docs'][0] + return { + 'Identifier': self._extract_identifiers(doc), + 'Publisher': ([{'Name': doc['pub']}] + if doc.get('pub') else None), + 'Creator': [{'Name': n} for n in doc.get('author', []) + if n], + 'Title': doc.get('title', [None])[0], + 'PublicationDate': self._extract_date(doc), + 'Type': {'Name': self._extract_type(doc)}, + 'Keywords': [{'Keyword': n} for n in doc.get('keyword', []) + if n], + } + else: + res.raise_for_status() + except Exception as exc: + raise AdsAPIException(exc) @cached_property def api_token(self): diff --git a/asclepias_broker/harvester/receivers.py b/asclepias_broker/harvester/receivers.py index 6d6215b..60b74d2 100644 --- a/asclepias_broker/harvester/receivers.py +++ b/asclepias_broker/harvester/receivers.py @@ -8,7 +8,7 @@ from ..events.models import Event, PayloadType from .proxies import current_harvester - +from .tasks import harvest_metadata def harvest_metadata_after_event_process(app, event: Event = None): """.""" @@ -30,3 +30,6 @@ def harvest_metadata_after_event_process(app, event: Event = None): for identifier, scheme, providers in identifiers ] current_harvester.publish_metadata_harvest(payloads) + + task = harvest_metadata.s([], eager=False) + task.apply_async() diff --git a/asclepias_broker/harvester/tasks.py b/asclepias_broker/harvester/tasks.py index 11b9c19..5e319aa 100644 --- a/asclepias_broker/harvester/tasks.py +++ b/asclepias_broker/harvester/tasks.py @@ -8,22 +8,35 @@ """Harvester tasks.""" from typing import List, Optional +from uuid import uuid4 from celery import shared_task from invenio_db import db from .proxies import current_harvester +from ..monitoring.models import ErrorMonitoring, HarvestMonitoring, HarvestStatus - -@shared_task(ignore_result=True, max_retries=3, default_retry_delay=10 * 60) -def harvest_metadata_identifier(harvester: str, identifier: str, scheme: str, - providers: List[str] = None): +@shared_task(bind=True, ignore_result=True, max_retries=1, default_retry_delay=10 * 60) +def harvest_metadata_identifier(self, harvester: str, identifier: str, scheme: str, + event_uuid: str, providers: List[str] = None): """.""" try: + _set_event_status(event_uuid, HarvestStatus.Processing) h = current_harvester.metadata_harvesters[harvester] h.harvest(identifier, scheme, providers) + _set_event_status(event_uuid, HarvestStatus.Done) except Exception as exc: - harvest_metadata_identifier.retry(exc=exc) + db.session.rollback() + _set_event_status(event_uuid, HarvestStatus.Error) + payload = {'identifier':identifier, 'scheme': scheme, 'providers': providers} + error_obj = ErrorMonitoring.getFromEvent(event_uuid) + if not error_obj: + error_obj = ErrorMonitoring(event_id = event_uuid, origin=self.__class__.__name__, error=repr(exc), n_retries=self.request.retries, payload=payload) + db.session.add(error_obj) + else: + error_obj.n_retries += 1 + db.session.commit() + self.retry(exc=exc) @shared_task(ignore_result=True) @@ -41,12 +54,16 @@ def harvest_metadata(identifiers: Optional[List[dict]] = None, providers = payload['providers'] for h_id, harvester in current_harvester.metadata_harvesters.items(): if harvester.can_harvest(value, scheme, providers): - task = harvest_metadata_identifier.s(h_id, value, scheme, - providers) - if eager: - task.apply(throw=True) - else: - task.apply_async() + if not HarvestMonitoring.isRecentlyAdded(identifier=value, scheme=scheme, harvester=harvester.__class__.__name__): + harvest_event_obj = HarvestMonitoring(identifier=value, scheme=scheme,harvester=harvester.__class__.__name__, status=HarvestStatus.New) + db.session.add(harvest_event_obj) + db.session.commit() + task = harvest_metadata_identifier.s(h_id, value, scheme, + str(harvest_event_obj.id), providers) + if eager: + task.apply(throw=True) + else: + task.apply_async() @shared_task(ignore_result=True) @@ -60,3 +77,9 @@ def harvest_events(harvester_ids: List[str], eager: bool = False): with db.session.begin_nested(): harvester.harvest(eager=eager) db.session.commit() + +def _set_event_status(event_uuid, status): + """Set the status of the Event.""" + event = HarvestMonitoring.get(event_uuid) + event.status = status + db.session.commit() \ No newline at end of file diff --git a/asclepias_broker/harvester/utils.py b/asclepias_broker/harvester/utils.py index 43c6c88..10cda5f 100644 --- a/asclepias_broker/harvester/utils.py +++ b/asclepias_broker/harvester/utils.py @@ -26,4 +26,4 @@ def get(self, key: str) -> datetime: def set(self, key: str, value: datetime = None): """.""" return current_cache.set( - f'{self.prefix}:{key}', value or datetime.now(), timeout=-1) + f'{self.prefix}:{key}', value or datetime.now(), timeout=-1) \ No newline at end of file diff --git a/asclepias_broker/harvester/zenodo.py b/asclepias_broker/harvester/zenodo.py index 575aa73..a027d0a 100644 --- a/asclepias_broker/harvester/zenodo.py +++ b/asclepias_broker/harvester/zenodo.py @@ -9,11 +9,13 @@ from copy import deepcopy from datetime import datetime -from typing import List +from typing import Any, List import requests from flask import current_app +from ..harvester.github import GitHubHarvester + from ..utils import chunks from .base import MetadataHarvester @@ -25,7 +27,7 @@ class ZenodoAPIException(Exception): class ZenodoClient: """Zenodo client.""" - url = 'https://zenodo.org/api/records/' + url = 'https://zenodo.org/api/records' params = { 'page': 1, 'size': 100, @@ -47,7 +49,10 @@ def get_concept_doi(self, doi: str) -> str: else: conceptdoi = doi # it's already a conceptdoi else: - raise ZenodoAPIException() + try: + res.raise_for_status() + except Exception as exc: + raise ZenodoAPIException(exc) return conceptdoi def get_versions(self, conceptdoi) -> List[str]: @@ -59,11 +64,11 @@ def get_versions(self, conceptdoi) -> List[str]: while True: res = requests.get(url, params=params) if not res.ok: - raise ZenodoAPIException() + res.raise_for_status() data = res.json() for r in data['hits']['hits']: - yield r['doi'] + yield r if data['links'].get('next'): url = data['links'].get('next') params = { @@ -92,12 +97,15 @@ def can_harvest(self, identifier: str, scheme: str, def harvest(self, identifier: str, scheme: str, providers: List[str] = None): """.""" - conceptdoi, versions = self.get_versioning_metadata(identifier) - if conceptdoi: - providers = set(providers) if providers else set() - providers.add(self.provider_name) - update_versioning(conceptdoi, versions, 'doi', - providers=list(providers)) + try: + conceptdoi, versions = self.get_versioning_metadata(identifier) + if conceptdoi: + providers = set(providers) if providers else set() + providers.add(self.provider_name) + update_versioning(conceptdoi, versions, 'doi', + providers=list(providers)) + except Exception as exc: + raise ZenodoAPIException(exc) def _is_zenodo_doi(self, scheme: str, identifier: str) -> bool: if scheme.lower() == 'doi' and identifier.lower()\ @@ -115,8 +123,47 @@ def get_versioning_metadata(self, doi: str): versions = client.get_versions(conceptdoi) return conceptdoi, versions +def check_for_github_relations(child: dict, child_scheme: str, providers: List[str], link_publication_date: str): -def update_versioning(parent_identifier: str, child_identifiers: List[str], + if 'related_identifiers' in child['metadata'].keys(): + for relation in child['metadata']['related_identifiers']: + + rel_identifier = relation['identifier'] + rel_scheme = relation['scheme'] + relation = relation['relation'] + gitHubHarvester = GitHubHarvester() + if gitHubHarvester.can_harvest(identifier=rel_identifier, scheme=rel_scheme): + target_identifier = { + "ID": rel_identifier, + "IDScheme": rel_scheme + } + source_identifier = { + "ID": child['doi'], + "IDScheme": child_scheme + } + + payload = { + 'RelationshipType': { + 'Name': 'IsRelatedTo', + 'SubTypeSchema': 'DataCite', + 'SubType': 'IsIdenticalTo' + }, + 'Target': { + 'Identifier': target_identifier, + 'Type': {'Name': 'unknown'} + }, + 'LinkProvider': providers, + 'Source': { + 'Identifier': source_identifier, + 'Type': {'Name': 'unknown'} + }, + 'LinkPublicationDate': link_publication_date, + } + yield payload + return None + + +def update_versioning(parent_identifier: str, children: List[Any], scheme: str, providers: List[str] = None, link_publication_date: str = None): """.""" @@ -132,7 +179,8 @@ def update_versioning(parent_identifier: str, child_identifiers: List[str], } event = [] - for identifier in child_identifiers: + for child in children: + identifier = child['doi'] target_identifier = { "ID": identifier, "IDScheme": scheme @@ -156,6 +204,12 @@ def update_versioning(parent_identifier: str, child_identifiers: List[str], } event.append(payload) + github_payloads = check_for_github_relations(child, scheme, providers, link_publication_date) + if github_payloads is not None: + for p in github_payloads: + event.append(p) + + for event_chunk in chunks(event, 100): try: EventAPI.handle_event(list(event_chunk), no_index=True, eager=True) diff --git a/asclepias_broker/jsonschemas/scholix-v3.json b/asclepias_broker/jsonschemas/scholix-v3.json index e348d74..6d853e1 100644 --- a/asclepias_broker/jsonschemas/scholix-v3.json +++ b/asclepias_broker/jsonschemas/scholix-v3.json @@ -157,6 +157,17 @@ "items": { "$ref": "#/definitions/PersonOrOrgType" } + }, + "Keywords": { + "type": "array", + "items": { + "keyword": { + "type": "string", + "title": "Objects article keyord", + "description": "An article keyword", + "default": "" + } + } } }, "required": [ @@ -221,7 +232,7 @@ ] }, "LicenseURL": { - "type": "string", + "type": ["string", "null"], "title": "License URL schema", "description": "URL to the license of this Link Information Package.", "default": "", diff --git a/asclepias_broker/mappings/v6/relationships/v1.0.0.json b/asclepias_broker/mappings/v6/relationships/v1.0.0.json index 4eef38e..0c57d85 100644 --- a/asclepias_broker/mappings/v6/relationships/v1.0.0.json +++ b/asclepias_broker/mappings/v6/relationships/v1.0.0.json @@ -1,4 +1,15 @@ { + "settings": { + "analysis": { + "normalizer": { + "lowercase_normalizer": { + "type": "custom", + "char_filter": [], + "filter": ["lowercase", "asciifolding"] + } + } + } + }, "mappings": { "doc": { "properties": { @@ -123,11 +134,23 @@ }, "type": "nested" }, + "Keywords": { + "properties": { + "Keyword": { + "type": "text", + "copy_to": "Source.Keywords_all" + } + }, + "type": "nested" + }, + "Keywords_all": { + "type": "text" + }, "Publisher": { "properties": { "Name": { - "type": "text", - "copy_to": "_search_all" + "type": "keyword", + "normalizer": "lowercase_normalizer" }, "Identifier": { "properties": { diff --git a/asclepias_broker/mappings/v7/__init__.py b/asclepias_broker/mappings/v7/__init__.py new file mode 100644 index 0000000..969cda1 --- /dev/null +++ b/asclepias_broker/mappings/v7/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. +"""Elasticsearch v6 mappings.""" diff --git a/asclepias_broker/mappings/v7/relationships/v1.0.0.json b/asclepias_broker/mappings/v7/relationships/v1.0.0.json new file mode 100644 index 0000000..4baa0a4 --- /dev/null +++ b/asclepias_broker/mappings/v7/relationships/v1.0.0.json @@ -0,0 +1,278 @@ +{ + "settings": { + "analysis": { + "normalizer": { + "lowercase_normalizer": { + "type": "custom", + "char_filter": [], + "filter": ["lowercase", "asciifolding"] + } + } + } + }, + "mappings": { + "properties": { + "_search_all": { + "type": "text" + }, + "ID": { + "type": "keyword" + }, + "Grouping": { + "type": "keyword" + }, + "RelationshipType": { + "type": "keyword" + }, + "History": { + "properties": { + "LinkPublicationDate": { + "type": "date" + }, + "LinkProvider": { + "properties": { + "Name": { + "type": "text", + "copy_to": "_search_all" + }, + "Identifier": { + "properties": { + "IDURL": { + "type": "keyword" + }, + "ID": { + "type": "keyword" + }, + "IDScheme": { + "type": "keyword" + } + }, + "type": "nested" + } + }, + "type": "nested" + }, + "LicenseURL": { + "type": "keyword" + } + }, + "type": "nested" + }, + "Source": { + "properties": { + "ID": { + "type": "keyword" + }, + "Type": { + "properties": { + "Name": { + "type": "keyword" + }, + "SubType": { + "type": "keyword" + }, + "SubTypeSchema": { + "type": "keyword" + } + }, + "type": "object" + }, + "Title": { + "type": "text", + "copy_to": "_search_all" + }, + "SearchIdentifier": { + "properties": { + "IDURL": { + "type": "keyword" + }, + "ID": { + "type": "keyword", + "copy_to": "_search_all" + }, + "IDScheme": { + "type": "keyword" + } + }, + "type": "nested" + }, + "Identifier": { + "properties": { + "IDURL": { + "type": "keyword" + }, + "ID": { + "type": "keyword" + }, + "IDScheme": { + "type": "keyword" + } + }, + "type": "nested" + }, + "Creator": { + "properties": { + "Name": { + "type": "text", + "copy_to": "_search_all" + }, + "Identifier": { + "properties": { + "IDURL": { + "type": "keyword" + }, + "ID": { + "type": "keyword" + }, + "IDScheme": { + "type": "keyword" + } + }, + "type": "nested" + } + }, + "type": "nested" + }, + "Keywords": { + "properties": { + "Keyword": { + "type": "text", + "copy_to": "Source.Keywords_all" + } + }, + "type": "nested" + }, + "Keywords_all": { + "type": "text" + }, + "Publisher": { + "properties": { + "Name": { + "type": "keyword", + "normalizer": "lowercase_normalizer" + }, + "Identifier": { + "properties": { + "IDURL": { + "type": "keyword" + }, + "ID": { + "type": "keyword" + }, + "IDScheme": { + "type": "keyword" + } + }, + "type": "nested" + } + }, + "type": "nested" + }, + "PublicationDate": { + "type": "date" + } + } + }, + "Target": { + "properties": { + "ID": { + "type": "keyword" + }, + "Type": { + "properties": { + "Name": { + "type": "keyword" + }, + "SubType": { + "type": "keyword" + }, + "SubTypeSchema": { + "type": "keyword" + } + }, + "type": "object" + }, + "Title": { + "type": "text" + }, + "SearchIdentifier": { + "properties": { + "IDURL": { + "type": "keyword" + }, + "ID": { + "type": "keyword" + }, + "IDScheme": { + "type": "keyword" + } + }, + "type": "nested" + }, + "Identifier": { + "properties": { + "IDURL": { + "type": "keyword" + }, + "ID": { + "type": "keyword" + }, + "IDScheme": { + "type": "keyword" + } + }, + "type": "nested" + }, + "Creator": { + "properties": { + "Name": { + "type": "text" + }, + "Identifier": { + "properties": { + "IDURL": { + "type": "keyword" + }, + "ID": { + "type": "keyword" + }, + "IDScheme": { + "type": "keyword" + } + }, + "type": "nested" + } + }, + "type": "nested" + }, + "Publisher": { + "properties": { + "Name": { + "type": "text" + }, + "Identifier": { + "properties": { + "IDURL": { + "type": "keyword" + }, + "ID": { + "type": "keyword" + }, + "IDScheme": { + "type": "keyword" + } + }, + "type": "nested" + } + }, + "type": "nested" + }, + "PublicationDate": { + "type": "date" + } + } + } + }, + "dynamic": false + } +} diff --git a/asclepias_broker/metadata/api.py b/asclepias_broker/metadata/api.py index 3f9285d..f74233e 100644 --- a/asclepias_broker/metadata/api.py +++ b/asclepias_broker/metadata/api.py @@ -19,7 +19,7 @@ from ..graph.models import GroupRelationship, GroupType from ..utils import chunks from .models import GroupMetadata, GroupRelationshipMetadata - +from ..monitoring.models import ErrorMonitoring # TODO: When merging/splitting groups there is some merging/duplicating of # metadata as well @@ -62,9 +62,9 @@ def update_metadata(id_value: str, scheme: str, data: dict, target_identifiers = set() for i in data.get('Identifier', []): - value, scheme = i['ID'], i['IDScheme'].lower() - value = idutils.normalize_pid(value, scheme) - target_identifiers.add((value, scheme)) + value, target_scheme = i['ID'], i['IDScheme'].lower() + value = idutils.normalize_pid(value, target_scheme) + target_identifiers.add((value, target_scheme)) # Check if there are identity links that can be created: if create_identity_events and len(target_identifiers) > 0: @@ -99,18 +99,19 @@ def update_metadata(id_value: str, scheme: str, data: dict, try: EventAPI.handle_event( list(event_chunk), no_index=True, eager=True) - except ValueError: + except ValueError as exc: + error_obj = ErrorMonitoring(origin="update_metadata", error=repr(exc), n_retries = 99, payload=event_chunk) + db.session.add(error_obj) + db.session.commit() current_app.logger.exception( 'Error while processing identity event') - try: - id_group = get_group_from_id(id_value, scheme) - if not id_group and create_missing_groups: - identifier = Identifier( - value=id_value, scheme=scheme).fetch_or_create_id() - db.session.commit() - id_group, _ = get_or_create_groups(identifier) - db.session.commit() - id_group.data.update(data) + + id_group = get_group_from_id(id_value, scheme) + if not id_group and create_missing_groups: + identifier = Identifier( + value=id_value, scheme=scheme).fetch_or_create_id() + db.session.commit() + id_group, _ = get_or_create_groups(identifier) db.session.commit() - except Exception: - current_app.logger.exception('Error while updating group metadata') + id_group.data.update(data) + db.session.commit() diff --git a/asclepias_broker/metadata/cli.py b/asclepias_broker/metadata/cli.py index 4666a63..9ecb410 100644 --- a/asclepias_broker/metadata/cli.py +++ b/asclepias_broker/metadata/cli.py @@ -16,7 +16,9 @@ from ..utils import find_ext from .api import update_metadata - +from ..monitoring.models import ErrorMonitoring +from flask import current_app +from invenio_db import db @click.group() def metadata(): @@ -32,11 +34,17 @@ def load_metadata(jsondir): files = find_ext(jsondir, 'json') with click.progressbar(files) as bar_files: for fn in bar_files: - with open(fn, 'r') as fp: - data = json.load(fp) - - identifier = data['Object']['Identifier'][0]['ID'] - scheme = data['Object']['Identifier'][0]['IDScheme'] - provider = data.get('Provider') - update_metadata( - identifier, scheme, data['Object'], provider=provider) + try: + with open(fn, 'r') as fp: + data = json.load(fp) + identifier = data['Object']['Identifier'][0]['ID'] + scheme = data['Object']['Identifier'][0]['IDScheme'] + provider = data.get('Provider') + update_metadata( + identifier, scheme, data['Object'], provider=provider) + except Exception as exc: + payload = {'identifier':identifier, 'scheme': scheme, 'providers': provider, 'fileName':fn} + error_obj = ErrorMonitoring(origin="cli_load_metadata", error=repr(exc), n_retries = 99, payload=payload) + db.session.add(error_obj) + db.session.commit() + current_app.logger.exception('Error in cli load metadata using file:' + fn) \ No newline at end of file diff --git a/asclepias_broker/metadata/models.py b/asclepias_broker/metadata/models.py index f3eb0ee..1c25bbd 100644 --- a/asclepias_broker/metadata/models.py +++ b/asclepias_broker/metadata/models.py @@ -21,7 +21,8 @@ COMMON_SCHEMA_DEFINITIONS = SCHOLIX_SCHEMA['definitions'] OBJECT_TYPE_SCHEMA = COMMON_SCHEMA_DEFINITIONS['ObjectType'] -OVERRIDABLE_KEYS = {'Type', 'Title', 'Creator', 'PublicationDate', 'Publisher'} +OVERRIDABLE_KEYS = {'Type', 'Title', 'Creator', 'PublicationDate'} +MERGEABLE_KEYS = {'Publisher', 'Keywords'} class GroupMetadata(db.Model, Timestamp): @@ -53,7 +54,7 @@ class GroupMetadata(db.Model, Timestamp): 'additionalProperties': False, 'properties': { k: v for k, v in OBJECT_TYPE_SCHEMA['properties'].items() - if k in OVERRIDABLE_KEYS + if k in OVERRIDABLE_KEYS or k in MERGEABLE_KEYS }, } @@ -67,6 +68,8 @@ def update(self, payload: dict, validate: bool = True): if type_val == 'unknown': continue new_json[key] = payload[key] + for key in MERGEABLE_KEYS: + mergeKey(new_json, payload, key) # Set "Type" to "unknown" if not provided if not new_json.get('Type', {}).get('Name'): new_json['Type'] = {'Name': 'unknown'} @@ -76,6 +79,18 @@ def update(self, payload: dict, validate: bool = True): flag_modified(self, 'json') return self +def mergeKey(new_json: dict, payload: dict, key: str): + + if payload.get(key): + if not key in new_json.keys(): + new_json[key] = [] + for item in payload.get(key): + #Should only be one item per dictionary here + val = list(item.values())[0] + current_values = [list(s.values())[0].lower() for s in new_json[key]] + if val.lower() not in current_values: + item_key = list(item.keys())[0] + new_json[key].append({item_key : val}) class GroupRelationshipMetadata(db.Model, Timestamp): """Metadata for a group relationship.""" diff --git a/asclepias_broker/monitoring/__init__.py b/asclepias_broker/monitoring/__init__.py new file mode 100644 index 0000000..4486618 --- /dev/null +++ b/asclepias_broker/monitoring/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. +"""Monitoring module.""" diff --git a/asclepias_broker/monitoring/cli.py b/asclepias_broker/monitoring/cli.py new file mode 100644 index 0000000..9ee95df --- /dev/null +++ b/asclepias_broker/monitoring/cli.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. + +"""Monitoring CLI.""" + +from __future__ import absolute_import, print_function + +from typing import List + +import click +from flask.cli import with_appcontext + +from .tasks import sendMonitoringReport + +@click.group() +def monitor(): + """Monitoring CLI commands.""" + + +@monitor.command('report') +@click.option('-e', '--eager', default=False, is_flag=True) +@with_appcontext +def report(eager: bool = False): + """Send monitoring report""" + # Detect identifier schemes + task = sendMonitoringReport.s() + if eager: + task.apply(throw=True) + else: + task.apply_async() \ No newline at end of file diff --git a/asclepias_broker/monitoring/models.py b/asclepias_broker/monitoring/models.py new file mode 100644 index 0000000..8111a6f --- /dev/null +++ b/asclepias_broker/monitoring/models.py @@ -0,0 +1,98 @@ + +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. +"""Monitoring database models.""" + +import uuid +import enum +import datetime + +from sqlalchemy.sql.sqltypes import Boolean +from sqlalchemy import func +from invenio_db import db +from sqlalchemy.dialects import postgresql +from sqlalchemy_utils.models import Timestamp +from sqlalchemy_utils.types import JSONType, UUIDType + +class HarvestStatus(enum.Enum): + """Event status.""" + New = 1 + Processing = 2 + Error = 3 + Done = 4 + +class ErrorMonitoring(db.Model, Timestamp): + """Error monitoring model.""" + + __tablename__ = 'error_monitoring' + + id = db.Column(UUIDType, default=uuid.uuid4, primary_key=True) + event_id = db.Column(UUIDType) + origin = db.Column(db.String, nullable=False) + error = db.Column(db.String) + n_retries = db.Column(db.Integer) + payload = db.Column( + db.JSON() + .with_variant(postgresql.JSONB(none_as_null=True), 'postgresql') + .with_variant(JSONType(), 'sqlite'), + default=dict, + ) + + @classmethod + def getLastWeeksErrors(cls, **kwargs): + """Gets all the errors from last week where it has been rerun for at least 2 times all ready""" + last_week = datetime.datetime.now() - datetime.timedelta(days = 8) + resp = cls.query.filter(cls.created > str(last_week), cls.n_retries > 2).all() + return resp + + @classmethod + def getFromEvent(cls, event_id): + """Dictionary representation of the error.""" + return cls.query.filter_by(event_id=event_id).one_or_none() + + def to_dict(self): + """Dictionary representation of the error.""" + return dict(created=self.created, updated = self.updated, id = self.id, origin = self.origin, error = self.error, payload = self.payload) + + def __repr__(self): + """String representation of the error.""" + return str(self.to_dict()) + + +class HarvestMonitoring(db.Model, Timestamp): + """Harvesting monitoring model.""" + + __tablename__ = 'harvest_monitoring' + + id = db.Column(UUIDType, default=uuid.uuid4, primary_key=True) + identifier = db.Column(db.String, nullable=False) + scheme = db.Column(db.String) + harvester = db.Column(db.String) + status = db.Column(db.Enum(HarvestStatus), nullable=False) + + @classmethod + def get(cls, id: str = None, **kwargs): + """Get the event from the database.""" + return cls.query.filter_by(id=id).one_or_none() + + @classmethod + def isRecentlyAdded(cls, identifier: str, scheme: str, harvester: str, **kwargs) -> Boolean: + """Check if the same identifier has been queried for during the last week to avoid duplicates""" + last_week = datetime.datetime.now() - datetime.timedelta(days = 7) + resp = cls.query.filter(cls.identifier==identifier, cls.scheme==scheme, cls.harvester==harvester, cls.updated > str(last_week)).first() + return resp is not None + + @classmethod + def getStatsFromLastWeek(cls): + """Gets the stats from the last 7 days""" + last_week = datetime.datetime.now() - datetime.timedelta(days = 7) + resp = db.session.query(cls.status, func.count('*')).filter(cls.updated > str(last_week)).group_by(cls.status).all() + return resp + + def __repr__(self): + """String representation of the event.""" + return f"<{self.id}: {self.created} : {self.identifier}>" \ No newline at end of file diff --git a/asclepias_broker/monitoring/tasks.py b/asclepias_broker/monitoring/tasks.py new file mode 100644 index 0000000..1a2c106 --- /dev/null +++ b/asclepias_broker/monitoring/tasks.py @@ -0,0 +1,177 @@ + +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. +"""Monitoring tasks""" + +import datetime + +from sqlalchemy.orm.util import join +from celery import shared_task +from sqlalchemy import and_ +from invenio_db import db +import slack +import os + +from ..monitoring.models import ErrorMonitoring, HarvestMonitoring, HarvestStatus +from ..events.models import Event, EventStatus +from ..events.api import EventAPI +from ..harvester.cli import rerun_event + +@shared_task(ignore_result=True) +def rerun_harvest_errors(): + two_days_ago = datetime.datetime.now() - datetime.timedelta(days = 2) + resp = HarvestMonitoring.query.filter(HarvestMonitoring.status == HarvestStatus.Error, HarvestMonitoring.created > str(two_days_ago)).all() + for event in resp: + rerun_event(event, no_index=True, eager=False) + +@shared_task(ignore_result=True) +def rerun_event_errors(): + two_days_ago = datetime.datetime.now() - datetime.timedelta(days = 2) + resp = Event.query.filter(Event.status == EventStatus.Error, Event.created > str(two_days_ago)).all() + for event in resp: + EventAPI.rerun_event(event, no_index=True, eager=False) + +@shared_task(ignore_result=True) +def sendMonitoringReport(): + """Sends monitor report to the Slack bot defined with SLACK_API_TOKEN in the enviroment + + Sends a report of the number of events and harvester that have been done during the last 7 days + and also adds a list of all errors that have taken place during the ingestions""" + + slack_token = os.environ.get("SLACK_API_TOKEN") + if slack_token is not None and slack_token != "CHANGE_ME": + client = slack.WebClient(token=slack_token) + channel = 'broker-alerts' + sendHarvestErrors(client, channel) + sendEventErrors(client, channel) + sendHarvestReport(client, channel) + sendEventReport(client, channel) + +def sendHarvestErrors(client, channel): + errors = (db.session.query(ErrorMonitoring) + .join(HarvestMonitoring, ErrorMonitoring.event_id == HarvestMonitoring.id) + .filter(HarvestMonitoring.status == HarvestStatus.Error)) + sendErrorReport(errors, client, channel) + +def sendEventErrors(client, channel): + errors = (db.session.query(ErrorMonitoring) + .join(Event, ErrorMonitoring.event_id == Event.id) + .filter(Event.status == EventStatus.Error)) + sendErrorReport(errors, client, channel) + +def sendErrorReport(errors, client, channel:str): + blocks = [] + blocks.append({"type": "section", + "text": { + "text": "*Errors during the last 7 days*", + "type": "mrkdwn" + }, + }) + for i, error in enumerate(errors): + err_dict = error.to_dict() + fields = [{ + "type": "plain_text", + "text": 'origin' + }, + { + "type": "plain_text", + "text": str(err_dict['origin']) + }, + { + "type": "plain_text", + "text": 'created' + },{ + "type": "plain_text", + "text": str(err_dict['created']) + },{ + "type": "plain_text", + "text": 'error' + },{ + "type": "plain_text", + "text": str(err_dict['error']).replace('\\n', '\n') + },{ + "type": "plain_text", + "text": 'payload' + },{ + "type": "plain_text", + "text": str(err_dict['payload']).replace('\\n', '\n')[:1000] + }] + blocks.append({"type": "section", + "text": { + "text": "Error #" + str(i), + "type": "mrkdwn" + }, + "fields":fields + }) + + if i % 40 == 0: + client.chat_postMessage(channel=channel, blocks=blocks) + blocks = [] + if len(blocks) > 0: + client.chat_postMessage(channel=channel, blocks=blocks) + + +def sendHarvestReport(client, channel:str): + list = HarvestMonitoring.getStatsFromLastWeek() + fields = [] + for obj in list: + fields.append({ + "type": "plain_text", + "text": obj[0].name + }) + fields.append({ + "type": "plain_text", + "text": str(obj[1]) + }) + if len(fields) == 0: + fields.append({ + "type": "plain_text", + "text": "Done" + }) + fields.append({ + "type": "plain_text", + "text": str(0) + }) + blocks = [{"type": "section", + "text": { + "text": "*Number of harvests done during the last 7 days*", + "type": "mrkdwn" + }, + "fields":fields + }] + client.chat_postMessage(channel=channel, blocks=blocks) + + +def sendEventReport(client, channel:str): + list = Event.getStatsFromLastWeek() + fields = [] + for obj in list: + fields.append({ + "type": "plain_text", + "text": obj[0].name + }) + fields.append({ + "type": "plain_text", + "text": str(obj[1]) + }) + if len(fields) == 0: + fields.append({ + "type": "plain_text", + "text": "Done" + }) + fields.append({ + "type": "plain_text", + "text": str(0) + }) + blocks = [{"type": "section", + "text": { + "text": "*Number of events done during the last 7 days*", + "type": "mrkdwn" + }, + "fields":fields + }] + client.chat_postMessage(channel=channel, blocks=blocks) \ No newline at end of file diff --git a/asclepias_broker/schemas/loaders.py b/asclepias_broker/schemas/loaders.py index adfc074..6507261 100644 --- a/asclepias_broker/schemas/loaders.py +++ b/asclepias_broker/schemas/loaders.py @@ -15,6 +15,7 @@ from marshmallow import Schema, fields, post_load, pre_load, validates_schema from marshmallow.exceptions import ValidationError +from ..utils import GithubUtility from ..core.models import Identifier, Relation, Relationship DATACITE_RELATION_MAP = { @@ -60,7 +61,13 @@ def __init__(self, *args, check_existing=False, **kwargs): super().__init__(*args, **kwargs) @post_load - def to_model(self, data): + def to_model(self, data, **kwargs): + """Remove the link date and provider metadata""" + + data.pop('link_publication_date', None) + data.pop('link_provider', None) + data.pop('id_url', None) + data.pop('license_url', None) if self.context.get('check_existing'): return model_cls.get(**data) or model_cls(**data) return model_cls(**data) @@ -85,25 +92,31 @@ def from_scholix_relation(rel_obj: dict) -> Tuple[Relation, bool]: return from_datacite_relation(relation) +class LinkProviderSchema(Schema): + """LinkProvider loader schema.""" + name = fields.String(required=True, data_key='Name') + @to_model(Identifier) class IdentifierSchema(Schema): """Identifier loader schema.""" - value = fields.Str(required=True, load_from='ID') + value = fields.String(required=True, data_key='ID') + id_url = fields.String(data_key='IDURL') scheme = fields.Function( - deserialize=lambda s: s.lower(), required=True, load_from='IDScheme') + deserialize=lambda s: s.lower(), required=True, data_key='IDScheme') @pre_load - def normalize_value(self, data): + def normalize_value(self, data, **kwargs): """Normalize identifier value.""" try: data['ID'] = idutils.normalize_pid(data['ID'], data['IDScheme']) + return data except Exception: current_app.logger.warning( 'Failed to normalize PID value.', extra={'data': data}) @validates_schema - def check_scheme(self, data): + def check_scheme(self, data, **kwargs): """Validate the provided identifier scheme.""" value = data['value'] scheme = data['scheme'].lower() @@ -112,6 +125,13 @@ def check_scheme(self, data): # if schemes and scheme not in schemes: # raise ValidationError("Invalid scheme '{}'".format( # data['scheme']), 'IDScheme') + + #Check for valid github url + if scheme == 'url' and 'github' in value: + try: + GithubUtility.parse_url_info(value) + except: + raise ValidationError("Invalid github repo or release '{}'".format(value)) @to_model(Relationship) @@ -119,25 +139,28 @@ class RelationshipSchema(Schema): """Relationship loader schema.""" relation = fields.Method( - deserialize='load_relation', load_from='RelationshipType') - source = fields.Nested(IdentifierSchema, load_from='Source') - target = fields.Nested(IdentifierSchema, load_from='Target') + deserialize='load_relation', data_key='RelationshipType') + source = fields.Nested(IdentifierSchema, data_key='Source') + target = fields.Nested(IdentifierSchema, data_key='Target') + link_publication_date = fields.String(data_key='LinkPublicationDate') + link_provider = fields.List(fields.Nested(LinkProviderSchema), data_key='LinkProvider') + license_url = fields.String(data_key='LicenseURL') @pre_load - def remove_object_envelope(self, obj): + def remove_object_envelope(self, obj, **kwargs): """Remove the envelope for the Source and Target identifier fields.""" obj2 = deepcopy(obj) for k in ('Source', 'Target'): obj2[k] = obj[k]['Identifier'] return obj2 - def load_relation(self, data): + def load_relation(self, data, **kwargs): """Load the relation type value.""" rel_name, self._inversed = from_scholix_relation(data) return rel_name @post_load - def inverse(self, data): + def inverse(self, data, **kwargs): """Normalize the relationship direction based on its type.""" if data['source'].value == data['target'].value \ and data['source'].scheme == data['target'].scheme: diff --git a/asclepias_broker/search/indexer.py b/asclepias_broker/search/indexer.py index 2d4d957..b0639d0 100644 --- a/asclepias_broker/search/indexer.py +++ b/asclepias_broker/search/indexer.py @@ -97,7 +97,7 @@ def index_documents(docs: Iterable[dict], bulk: bool = False): client=current_search_client, actions=docs, index=index_name, - doc_type='doc', + doc_type='_doc', raise_on_error=False, chunk_size=300, # TODO: Make configurable max_chunk_bytes=(30 * 1024 * 1024), # TODO: Make configurable diff --git a/asclepias_broker/search/query.py b/asclepias_broker/search/query.py index db87841..cf7a747 100644 --- a/asclepias_broker/search/query.py +++ b/asclepias_broker/search/query.py @@ -6,14 +6,14 @@ # under the terms of the MIT License; see LICENSE file for more details. """Search utilities.""" -from typing import Dict +from typing import Dict, Sized from elasticsearch_dsl import Q from elasticsearch_dsl.query import Range from flask import request from invenio_records_rest.errors import InvalidQueryRESTError from invenio_rest.errors import FieldError, RESTValidationError - +import json def search_factory(self, search, query_parser=None): """Parse query using elasticsearch DSL query. @@ -55,6 +55,56 @@ def search_factory(self, search, query_parser=None): search = search.source(exclude=['*.SearchIdentifier']) return search, urlkwargs +def meta_search_factory(self, search, query_parser=None): + """Parse query using elasticsearch DSL query. + + :param self: REST view. + :param search: Elastic search DSL search instance. + :returns: Tuple with search instance and URL arguments. + """ + from invenio_records_rest.facets import default_facets_factory + from invenio_records_rest.sorter import default_sorter_factory + + # for field in (['keyword']): + # if field not in request.values: + # raise RESTValidationError( + # errors=[FieldError(field, 'Required field.')]) + + search, urlkwargs = default_facets_factory(search, "metadata") + search, sortkwargs = default_sorter_factory(search, "metadata") + for key, value in sortkwargs.items(): + urlkwargs.add(key, value) + + search = search.extra(size=0) + + # Apply 'identity' grouping by default + search = search.filter(Q('term', RelationshipType='Cites')) + if 'group_by' not in request.values: + search = search.filter(Q('term', Grouping='identity')) + urlkwargs['group_by'] = 'identity' + + try: + query_string = request.values.get('q') + if query_string: + search = search.query(Q('query_string', query=query_string, + default_field='_search_all')) + urlkwargs['q'] = query_string + except SyntaxError: + raise InvalidQueryRESTError() + size = 10 + if 'size' in request.values: + size = request.values.get('size') + + start = 0 + if 'page' in request.values: + start = int(int(request.values.get('page')) - 1) * int(size) + + search.aggs.bucket('Target', 'terms', field='Target.ID', size=1000)\ + .metric("first", "top_hits", _source=dict(include=["Target.Identifier.*", "Target.Creator.Name", "Target.Title"]), size=1) + kwargs = {'from':start, 'size':size, 'sort':[{'_count':{'order':'desc'}}]} + search.aggs['Target'].bucket('pagination', 'bucket_sort', **kwargs) + return search, urlkwargs + def enum_term_filter(label: str, field: str, choices: Dict[str, str]): """Term filter with controlled vocabulary.""" @@ -71,15 +121,26 @@ def inner(values): return inner +def nested_match_filter(field: str, path: str = None): + """Nested match filter.""" + path = path or field.rsplit('.', 1)[0] + def inner(values): + return Q('nested', path=path, query=dict(match={field: values})) + return inner + +def simple_query_string_filter(field: str): + """Simple query string filter.""" + def inner(values): + return Q('simple_query_string',query=values[0], fields=[field], default_operator='AND') + return inner + def nested_terms_filter(field: str, path: str = None): """Nested terms filter.""" path = path or field.rsplit('.', 1)[0] - def inner(values): return Q('nested', path=path, query=dict(terms={field: values})) return inner - def nested_range_filter( label: str, field: str, path: str = None, op: str = None): """Nested range filter.""" diff --git a/asclepias_broker/utils.py b/asclepias_broker/utils.py index 09d6575..1450ee1 100644 --- a/asclepias_broker/utils.py +++ b/asclepias_broker/utils.py @@ -79,3 +79,37 @@ def decorated(*args, **kwargs): return res return decorated return decorator + +class GitHubAPIException(Exception): + """Github exception.""" + +class GithubUtility: + @classmethod + def parse_url_info(cls, url): + parts = url.split('/') + github_index = next(i for i,p in enumerate(parts) if 'github.com' in p) + + if len(parts) - github_index < 3: + raise GitHubAPIException('Not a valid github repo url: ' + url, ) + + resp = dict() + resp['identifier'] = url + resp['scheme'] = 'url' + resp['user'] = parts[github_index + 1] + resp['repo'] = parts[github_index + 2] + + # Specific version urls shoudl be either on the form + # github.com/user/repo/tree/tag_we_want + # or + # github.com/user/repo/releases/tag/tag_we_want + # or + # github.com/user/repo/commit/tag_we_want + if len(parts) - github_index > 3: + resp['sub_type'] = parts[github_index + 3] + if resp['sub_type'] == 'tree' or resp['sub_type'] == 'commit': + resp['tag'] = parts[github_index + 4] + elif resp['sub_type'] == 'releases': + resp['tag'] = parts[github_index + 5] + else: + raise GitHubAPIException('Not a valid github repo url: ' + url, ) + return resp \ No newline at end of file diff --git a/docker-compose.aasdeployment.yml b/docker-compose.aasdeployment.yml new file mode 100644 index 0000000..2a114ef --- /dev/null +++ b/docker-compose.aasdeployment.yml @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. + +version: '2.3' +services: + # Load balancer + lb: + extends: + file: docker-services.yml + service: lb + build: ./docker/haproxy-production/ + image: asclepias-broker-lb-production + networks: + - main + volumes: + - /etc/letsencrypt/:/etc/letsencrypt + # Frontend + frontend: + extends: + file: docker-services.yml + service: frontend + build: ./docker/nginx-production/ + image: asclepias-broker-frontend-production + volumes: + - static_data:/opt/invenio/var/instance/static + - /etc/letsencrypt/:/etc/certbot/conf + networks: + - main + # Web application + web: + extends: + file: docker-services.yml + service: app + command: pipenv run uwsgi /app/docker/uwsgi/uwsgi.ini + image: asclepias-broker-web + ports: + - "5000" + volumes: + - static_data:/opt/invenio/var/instance/static + networks: + - main + # Worker + worker: + extends: + file: docker-services.yml + service: app + restart: "always" + command: "pipenv run celery -A invenio_app.celery worker --beat --loglevel=INFO" + image: asclepias-broker-worker + networks: + - main + # Monitoring + # Turning off Flower and Kibana in production + # kibana: + # extends: + # file: docker-services.yml + # service: kibana + # networks: + # - main + # flower: + # extends: + # file: docker-services.yml + # service: flower + # networks: + # - main + # Base services + cache: + extends: + file: docker-services.yml + service: cache + networks: + - main + db: + extends: + file: docker-services.yml + service: db + volumes: + - pg_data:/var/lib/postgresql/data + networks: + - main + mq: + extends: + file: docker-services.yml + service: mq + mem_limit: 500M + networks: + - main + # Three Node Elasticsearch Cluster + es: + image: docker.elastic.co/elasticsearch/elasticsearch:7.14.1 + restart: "always" + container_name: es + environment: + - node.name=es + - cluster.name=es-docker-cluster + - discovery.seed_hosts=es02,es03 + - cluster.initial_master_nodes=es,es02,es03 + - bootstrap.memory_lock=true + - "ES_JAVA_OPTS=-Xms1g -Xmx1g" + ulimits: + memlock: + soft: -1 + hard: -1 + mem_limit: 2g + volumes: + - es_data:/usr/share/elasticsearch/data + ports: + - "9200:9200" + - "9300:9300" + networks: + - main + es02: + image: docker.elastic.co/elasticsearch/elasticsearch:7.14.1 + restart: "always" + container_name: es02 + environment: + - node.name=es02 + - cluster.name=es-docker-cluster + - discovery.seed_hosts=es,es03 + - cluster.initial_master_nodes=es,es02,es03 + - bootstrap.memory_lock=true + - "ES_JAVA_OPTS=-Xms1g -Xmx1g" + ulimits: + memlock: + soft: -1 + hard: -1 + mem_limit: 2g + volumes: + - es02_data:/usr/share/elasticsearch/data + networks: + - main + es03: + image: docker.elastic.co/elasticsearch/elasticsearch:7.14.1 + restart: "always" + container_name: es03 + environment: + - node.name=es03 + - cluster.name=es-docker-cluster + - discovery.seed_hosts=es,es02 + - cluster.initial_master_nodes=es,es02,es03 + - bootstrap.memory_lock=true + - "ES_JAVA_OPTS=-Xms1g -Xmx1g" + ulimits: + memlock: + soft: -1 + hard: -1 + mem_limit: 2g + volumes: + - es03_data:/usr/share/elasticsearch/data + networks: + - main +volumes: + static_data: + pg_data: + es_data: + driver: local + es02_data: + driver: local + es03_data: + driver: local +networks: + main: + diff --git a/docker-compose.azure-dev.yml b/docker-compose.azure-dev.yml new file mode 100644 index 0000000..39f2d63 --- /dev/null +++ b/docker-compose.azure-dev.yml @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. + +version: '2.3' +services: + # Load balancer + lb: + extends: + file: docker-services.yml + service: lb + build: ./docker/haproxy-dev-ssl/ + image: asclepias-broker-lb-ssl + links: + - frontend + volumes: + - /etc/letsencrypt/:/etc/certbot/conf + # Frontend + frontend: + extends: + file: docker-services.yml + service: frontend + build: ./docker/nginx-dev-ssl/ + image: asclepias-broker-frontend-ssl + volumes: + - static_data:/opt/invenio/var/instance/static + - /etc/letsencrypt/:/etc/certbot/conf + links: + - web + # Web application + web: + extends: + file: docker-services.yml + service: app + command: pipenv run uwsgi /app/docker/uwsgi/uwsgi.ini + image: asclepias-broker-web + ports: + - "5000" + volumes: + - static_data:/opt/invenio/var/instance/static + links: + - cache + - es + - mq + - db + # Worker + worker: + extends: + file: docker-services.yml + service: app + restart: "always" + command: "pipenv run celery -A invenio_app.celery worker --beat --loglevel=INFO" + image: asclepias-broker-worker + links: + - cache + - es + - mq + - db + # Monitoring + kibana: + extends: + file: docker-services.yml + service: kibana + flower: + extends: + file: docker-services.yml + service: flower + links: + - mq + # Base services + cache: + extends: + file: docker-services.yml + service: cache + db: + extends: + file: docker-services.yml + service: db + mq: + extends: + file: docker-services.yml + service: mq + es: + extends: + file: docker-services.yml + service: es +volumes: + static_data: diff --git a/docker-compose.full.yml b/docker-compose.full.yml index 16e21e5..e72cc85 100644 --- a/docker-compose.full.yml +++ b/docker-compose.full.yml @@ -28,7 +28,7 @@ services: extends: file: docker-services.yml service: app - command: pipenv run uwsgi /opt/invenio/var/instance/uwsgi.ini + command: pipenv run uwsgi /app/docker/uwsgi/uwsgi.ini image: asclepias-broker-web ports: - "5000" @@ -45,7 +45,7 @@ services: file: docker-services.yml service: app restart: "always" - command: "pipenv run celery worker -A invenio_app.celery --loglevel=INFO" + command: "pipenv run celery -A invenio_app.celery worker --beat --loglevel=INFO" image: asclepias-broker-worker links: - cache diff --git a/docker-compose.yml b/docker-compose.yml index b0df84f..ecb56e0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,10 +7,17 @@ version: '2.3' services: + app: + extends: + file: docker-services.yml + service: app cache: extends: file: docker-services.yml service: cache + extends: + file: docker-services.yml + service: cache db: extends: file: docker-services.yml diff --git a/docker-services.yml b/docker-services.yml index 6dd186c..92c8129 100644 --- a/docker-services.yml +++ b/docker-services.yml @@ -26,6 +26,7 @@ services: - "INVENIO_SQLALCHEMY_DATABASE_URI=postgresql+psycopg2://asclepias:asclepias@db/asclepias" - "INVENIO_WSGI_PROXIES=2" - "INVENIO_INSTANCE_PATH=/opt/invenio/var/instance/" + - "SLACK_API_TOKEN=CHANGE_ME" lb: build: ./docker/haproxy/ image: asclepias-broker-lb @@ -57,13 +58,15 @@ services: ports: - "5432:5432" mq: - image: rabbitmq:3-management + image: rabbitmq:3.9.12-management + volumes: + - "./docker/rabbitmq/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf" restart: "always" ports: - "15672:15672" - "5672:5672" es: - image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.2.4 + image: docker.elastic.co/elasticsearch/elasticsearch:7.14.1 restart: "always" environment: - bootstrap.memory_lock=true @@ -79,13 +82,13 @@ services: - "9200:9200" - "9300:9300" kibana: - image: docker.elastic.co/kibana/kibana-oss:6.2.4 + image: docker.elastic.co/kibana/kibana:7.14.1 environment: - - ELASTICSEARCH_URL=http://es:9200 + - ELASTICSEARCH_HOSTS=http://es:9200 - ES_JAVA_OPTS=-Xms512m -Xmx512m ports: ['5601:5601'] flower: image: mher/flower - command: --broker=amqp://guest:guest@mq:5672/ --broker_api=http://guest:guest@mq:15672/api/ + command: celery flower --broker=amqp://guest:guest@mq:5672/ --broker_api=http://guest:guest@mq:15672/api/ ports: - "5555:5555" diff --git a/docker/haproxy-dev-ssl/Dockerfile b/docker/haproxy-dev-ssl/Dockerfile new file mode 100644 index 0000000..3f832e9 --- /dev/null +++ b/docker/haproxy-dev-ssl/Dockerfile @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. + +FROM haproxy:1.8 +RUN mkdir -p /usr/local/var/lib/haproxy/ +COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg \ No newline at end of file diff --git a/docker/haproxy-dev-ssl/haproxy.cfg b/docker/haproxy-dev-ssl/haproxy.cfg new file mode 100644 index 0000000..03a6683 --- /dev/null +++ b/docker/haproxy-dev-ssl/haproxy.cfg @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. + +global + chroot /usr/local/var/lib/haproxy/ + maxconn 4000 + stats socket /usr/local/var/lib/haproxy/stats level admin + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256 + ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets + ssl-default-server-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256 + ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets + +defaults + log global + maxconn 3000 + mode http + option dontlognull + retries 2 + timeout http-request 10s + timeout queue 2m + timeout connect 10s + timeout client 2m + timeout server 2m + timeout http-keep-alive 10s + timeout check 10s + +frontend in-http + bind *:80 + redirect scheme https code 301 if !{ ssl_fc } + +frontend in-https + bind *:443 ssl crt /etc/certbot/conf/live/asclepias-broker-node.eastus.cloudapp.azure.com/asclepias-broker-node.eastus.cloudapp.azure.com.pem + acl is_static path_beg -i /static + default_backend ssl_app + use_backend ssl_static if is_static + +frontend in-stats + bind *:8080 + stats enable + stats uri / + stats hide-version + +backend ssl_app + balance leastconn + http-check disable-on-404 + option http-server-close + option forwardfor except 127.0.0.0/8 + option httpchk HEAD /ping HTTP/1.0 + server web1 frontend:443 check check-ssl fall 2 inter 20000 maxconn 30 rise 1 ssl verify none weight 2 + +backend ssl_static + balance leastconn + http-check disable-on-404 + option http-server-close + option forwardfor except 127.0.0.0/8 + option httpchk HEAD /ping HTTP/1.0 + server web1 frontend:443 check check-ssl fall 2 inter 5000 maxconn 255 rise 1 ssl verify none weight 2 diff --git a/docker/haproxy-production/Dockerfile b/docker/haproxy-production/Dockerfile new file mode 100644 index 0000000..3f832e9 --- /dev/null +++ b/docker/haproxy-production/Dockerfile @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. + +FROM haproxy:1.8 +RUN mkdir -p /usr/local/var/lib/haproxy/ +COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg \ No newline at end of file diff --git a/docker/haproxy-production/haproxy.cfg b/docker/haproxy-production/haproxy.cfg new file mode 100644 index 0000000..976b41f --- /dev/null +++ b/docker/haproxy-production/haproxy.cfg @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. + +global + chroot /usr/local/var/lib/haproxy/ + maxconn 4000 + stats socket /usr/local/var/lib/haproxy/stats level admin + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256 + ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets + ssl-default-server-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256 + ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets + +defaults + log global + maxconn 3000 + mode http + option dontlognull + retries 2 + timeout http-request 10s + timeout queue 2m + timeout connect 10s + timeout client 2m + timeout server 2m + timeout http-keep-alive 10s + timeout check 10s + +frontend in-http + bind *:80 + redirect scheme https code 301 if !{ ssl_fc } + +frontend in-https + bind *:443 ssl crt /etc/letsencrypt/live/asclepias-broker.aas.org/asclepias-broker.aas.org.pem + acl is_static path_beg -i /static + default_backend ssl_app + use_backend ssl_static if is_static + +frontend in-stats + bind *:8080 + stats enable + stats uri / + stats hide-version + +backend ssl_app + balance leastconn + http-check disable-on-404 + option http-server-close + option forwardfor except 127.0.0.0/8 + option httpchk HEAD /ping HTTP/1.0 + server web1 frontend:443 check check-ssl fall 2 inter 20000 maxconn 30 rise 1 ssl verify none weight 2 + +backend ssl_static + balance leastconn + http-check disable-on-404 + option http-server-close + option forwardfor except 127.0.0.0/8 + option httpchk HEAD /ping HTTP/1.0 + server web1 frontend:443 check check-ssl fall 2 inter 5000 maxconn 255 rise 1 ssl verify none weight 2 diff --git a/docker/nginx-dev-ssl/Dockerfile b/docker/nginx-dev-ssl/Dockerfile new file mode 100644 index 0000000..318f973 --- /dev/null +++ b/docker/nginx-dev-ssl/Dockerfile @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. + +FROM nginx +COPY nginx.conf /etc/nginx/nginx.conf +COPY conf.d/* /etc/nginx/conf.d/ +COPY fullchain.pem /etc/certbot/conf/live/asclepias-broker-node.eastus.cloudapp.azure.com/fullchain.pem +COPY privkey.pem /etc/certbot/conf/live/asclepias-broker-node.eastus.cloudapp.azure.com/privkey.pem \ No newline at end of file diff --git a/docker/nginx-dev-ssl/conf.d/default.conf b/docker/nginx-dev-ssl/conf.d/default.conf new file mode 100644 index 0000000..e0f0641 --- /dev/null +++ b/docker/nginx-dev-ssl/conf.d/default.conf @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. + +# This nginx configuration defines two servers, one on port 80 and one on port +# 443. All traffix on port 80 is redirect to port 443 on SSL. +# +# Nginx proxies all requests on port 443 to upstream the application server +# which is expected to be running on port 5000. + +upstream web_server { + server web:5000 fail_timeout=0; +} + +# HTTP server +server { + # Redirects all requests to https. - this is in addition to HAProxy which + # already redirects http to https. This redirect is needed in case you access + # the server directly (e.g. useful for debugging). + listen 80; # IPv4 + listen [::]:80; # IPv6 + server_name _; + return 301 https://$host$request_uri; +} + +# HTTPS server +server { + listen 443; # IPv4 + listen [::]:443; # IPv6 + server_name _; + charset utf-8; + keepalive_timeout 5; + + # SSL configuration according to best practices from + # https://mozilla.github.io/server-side-tls/ssl-config-generator/ + ssl on; + # The provided certificate (test.crt) and private key (test.key) is only for + # testing and must never be used in production environment. + ssl_certificate /etc/certbot/conf/live/asclepias-broker-node.eastus.cloudapp.azure.com/fullchain.pem; + ssl_certificate_key /etc/certbot/conf/live/asclepias-broker-node.eastus.cloudapp.azure.com/privkey.pem; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + + # Accepted protocols and ciphers + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; + ssl_prefer_server_ciphers on; + + add_header Strict-Transport-Security "max-age=15768000"; # 6 months + + # The request body is sent to the proxied server immediately as it is + # received + proxy_request_buffering off; + # Sets the HTTP protocol v1.1 for proxying in order to not use the buffer + # in case of chunked transfer encoding + proxy_http_version 1.1; + + # Proxying to the application server + location / { + uwsgi_pass web_server; + include uwsgi_params; + uwsgi_buffering off; + uwsgi_request_buffering off; + uwsgi_param Host $host; + uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for; + uwsgi_param X-Forwarded-Proto $scheme; + # Max upload size is set to 100mb as default. + client_max_body_size 100m; + } + + # Static content is served directly by nginx and not the application server. + location /static { + alias /opt/invenio/var/instance/static; + autoindex off; + } + + location /.well-known { + alias /var/www/.well-known; + } + +} diff --git a/docker/nginx-dev-ssl/fullchain.pem b/docker/nginx-dev-ssl/fullchain.pem new file mode 100644 index 0000000..28138e9 --- /dev/null +++ b/docker/nginx-dev-ssl/fullchain.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIUVOBMpW2x4CFApWIK7XS1VpTLyFcwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMTExMTEwMzEzNTdaFw0yMTEx +MTMwMzEzNTdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDO84tBfpqT7B4uC//WDteJfp8XqGqmR639REZZP72a +fHtduhxka7gWzMnOAgbAa5qKjDQIpkBYEVfE9+FG2EgIiOaYTUSGFH3Su2EYE8sz +8ihobMH278g2TR8jsFvTEE4T6xKXzGyghjxS4vEghPca6JqrVpPeVUuJSXbb5hH3 +3xdgQ32GaDK2YYZNYoQwEAiOA6kyGjcfGRM6Y3gzn2+1GOiFxrIh7x6VFjb8K3nG +evcxkey858KdV+koaNUFvgXhammTPNgwH7ddQs0R5uO1Pfff5KhHCe4HE/ynvFdQ +XqKl2NpJgmw/IfRtxhuFpQR37ljP965KXOWmBYhqhDBiSQg/eh3Gr8rQJnAmuBoL +2uKbXOSB04AAE+Hxk7FMQh4Su/JsVFw2iZTKB5SrQnkgwghIDje0hhlEcRlJxAIN +3jUBImhIOzWhp7DPzWjwS9LS48r5cDm6J/yzhfR+F5UaZFamvIAr8L9UpyzHMy9p +1a2FVyOz1lMGYQV0Yf1CvQIEGn439aMcKcuOC6f+BpcVdF5qHtIOxAKwVJKdxbMF +GJKv1VfocS5qvUTswP6FBNn2x0J4tvGSTijJ1t1VODUY7oULd4OZACC+50BnM8J1 +0vZeb2N+rFjpP1+jpH62WgbGBMHhSFqle91FX1A0YfiLtx3K+Mx7cCGChhwS7GT8 +EwIDAQABo1MwUTAdBgNVHQ4EFgQUNVPrnbT0Ukcu1e3mBfoO1Osx0J0wHwYDVR0j +BBgwFoAUNVPrnbT0Ukcu1e3mBfoO1Osx0J0wDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCAgEAsnyecZdlq6Uz+V1q+mTfvQp8lMP7nKlbpfSBawLNTIj3 +16P4Ugg4fFlbOaMO/uIiV8oTDuAC88XSkVfcRFuW4934MV8GWpbEwhiP4UMUTNmH +zMW8WEzA1hc/Pk98tmGIcHo7ixH2wEJiaAJSwb16CqkX2RFeH0dKxxGImREMTaqT +dLwuEI8VnMz3bHbLODPmG5aSiQdjajoC5yMzZ6IQOxbcisbapGnqvdrKKoiH01UK +zbGU61Bc/5S5tFASK3BzZRRPr1KHYJI/r4WzHKxSWkJtdC4IBchNyDWqPeo207xM +INqjP0Wd7KptL1+ztLve8YnyLJK6qaEfTVg6Ogxbsf5/tYQFZS8W3y8T/Qw18TRs +ZnHQ3O+ExWSu0bzHoG5O/kUrXB4Fy5t6UbbCCsYyueDAH6uw3jb69vxPTRUyk2ll +qhm3VzI0QqVNHnI+8NLDMnkoY4Zxfqo1b64sBAKYxO+qMdGgLicGaQ0BXRS3DRPq +huuUXtFWDFLOvijveCbPBU0SBrBqbn/Iu1hMel9enznRlNzs98Ubpd+ZoK8v7TKf +CCuX+zWtM8D/Y5/RmvbB/GkprM8dtfhBwvr5K7vlKiqyZ/PQYwTvLnOf7zflb45g +0E2VSQxM0wRezBCN6A5Wr0rvEdKAkGzyCT+nwf4hdShSqHEGUTB2y/7+jI+8vik= +-----END CERTIFICATE----- diff --git a/docker/nginx-dev-ssl/nginx.conf b/docker/nginx-dev-ssl/nginx.conf new file mode 100644 index 0000000..909b880 --- /dev/null +++ b/docker/nginx-dev-ssl/nginx.conf @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. + +user nginx; +worker_processes 1; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + + keepalive_timeout 65; + + gzip on; + gzip_disable "msie6"; + gzip_http_version 1.1; + gzip_comp_level 5; # or anything between 4-6 + gzip_min_length 100; + gzip_proxied any; + # We may need more mime-types here (eg. 'application/x-bibtex') + gzip_types + application/atom+xml + application/javascript + application/json + application/ld+json + application/manifest+json + application/octet-stream + application/rss+xml + application/vnd.geo+json + application/vnd.ms-fontobject + application/x-font-ttf + application/x-javascript + application/x-web-app-manifest+json + application/xhtml+xml + application/xml + application/xml+rss + font/opentype + image/bmp + image/svg+xml + image/x-icon + text/cache-manifest + text/css + text/html + text/javascript + text/plain + text/vcard + text/vnd.rim.location.xloc + text/vtt + text/x-component + text/x-cross-domain-policy + text/xml; + gzip_vary on; + + include /etc/nginx/conf.d/*.conf; +} diff --git a/docker/nginx-dev-ssl/privkey.pem b/docker/nginx-dev-ssl/privkey.pem new file mode 100644 index 0000000..1dba2a5 --- /dev/null +++ b/docker/nginx-dev-ssl/privkey.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDO84tBfpqT7B4u +C//WDteJfp8XqGqmR639REZZP72afHtduhxka7gWzMnOAgbAa5qKjDQIpkBYEVfE +9+FG2EgIiOaYTUSGFH3Su2EYE8sz8ihobMH278g2TR8jsFvTEE4T6xKXzGyghjxS +4vEghPca6JqrVpPeVUuJSXbb5hH33xdgQ32GaDK2YYZNYoQwEAiOA6kyGjcfGRM6 +Y3gzn2+1GOiFxrIh7x6VFjb8K3nGevcxkey858KdV+koaNUFvgXhammTPNgwH7dd +Qs0R5uO1Pfff5KhHCe4HE/ynvFdQXqKl2NpJgmw/IfRtxhuFpQR37ljP965KXOWm +BYhqhDBiSQg/eh3Gr8rQJnAmuBoL2uKbXOSB04AAE+Hxk7FMQh4Su/JsVFw2iZTK +B5SrQnkgwghIDje0hhlEcRlJxAIN3jUBImhIOzWhp7DPzWjwS9LS48r5cDm6J/yz +hfR+F5UaZFamvIAr8L9UpyzHMy9p1a2FVyOz1lMGYQV0Yf1CvQIEGn439aMcKcuO +C6f+BpcVdF5qHtIOxAKwVJKdxbMFGJKv1VfocS5qvUTswP6FBNn2x0J4tvGSTijJ +1t1VODUY7oULd4OZACC+50BnM8J10vZeb2N+rFjpP1+jpH62WgbGBMHhSFqle91F +X1A0YfiLtx3K+Mx7cCGChhwS7GT8EwIDAQABAoICADLwKS+WvO9557fHxlHm11CF +dR06m/2PmRjErFgdY0raJvdb7s8c4HPkNivZvdWw5poBhnE2kpHauvLFXJK2e4x2 +PePw6NPjyVCMRIrLnHGNwjppwphITsxm0SpUp1VdJwqqCqqIa5hbUg/IwjcR40yh +Qii4J69K6UvCZFod2ABdzgAovIXPsePIP2levVCjMafa6NNnNngWEPCHOTfjn3hA +yELdNE078RgbHq+U9+VNsPhnhZC9rt5RnBcRLpW6PvJL4e6WxFOcCuMOpTEp1pRu +y0s1meHaZNcjKUYUCp3CnWAa7ye2zXQApIw8fdu4UVA/v2Z4/VJaaUAjDn/BR7MH +5JMdG44c3BQwtvcHgb5ZYh1IoW/ZSdo/cwl6iYYgPwtLOpW3C18MqpXme47ehHCA +LhdHKXTy8/ZwTVlWhd62y7z2GdcheoIY2GTv3rMQw/G2KH3S6HFhJxI+iO3mVcAP +yN8oGppjgaD7VYy/PINf6DxXr1jXmKSGy8bekAlpCt1kccFj/z4ScinBMneCOikw +hjy0eRqQlSFA5PHS4oSS/e4qFd8AE8Y0Woe1tv+gn+S8XrpNE85aOuUAZXWGYKxk +++a5GDYDS7A2HB51cS8GutaaXko6EBhbftkP1vlQqYOYsGe3QTE9F5Y4qZKlfkxQ +SoxYi8Hq7hUGaeqqpXm5AoIBAQD1E3aka8spPDL2FkwDfZi+S/ocOGUIpMaDcJst +4FgoA0+FxlCiwQGGStC6YoHrUnjYdU/qKEpAQJMLHjys+jgIvXR6FxTAx7gQza39 +zZle/+lqWPmjYPEDzGW/Y6y0hJJGK5T0n+5BE6Y9NNVJYuPPGHyzwnD1qNALxOn+ +6m/GHHr0QJ1b4nK721M7AZGfkgz7bhAE20j4nVHdKZMOR6B1RQYZby84RsxWBAKv +MnMzfXu+au6seRHE79fGE6pv1qX6uCPihD2O/299DV1tD1djpw8+6POVz4+RWBI4 +1FBcDsEdxAMpOts6jNm/KsxYZC4iWiGIaGFOGvZnhrNFFonfAoIBAQDYLQs1WXCf +zaYssstR5yb/MI8V4AwuSXtHAeYnz9UEIz6UxpKI4d//DrS95dpGSsagg8pN2a1l +jmYjaLwfeF28CTVwLAuryn1BNnwv0R/NDUZH6V/GpzwcS0rgr2BzjyMEXVS0iL3R +wl4kzGFfQ9dCBZB8ubJdnjp32BLAyancFnTMjnr5uYTq2RJ3tfL0JDoedPVlBDrX +WdmWBUFgLSS4l840A141Uls5K85fU7iykKfY8FFO+uZLV1VDxV4Z4+t9rMGrIyR5 +0NdIGvA7ei9/Gkg8KSb1TKwhm6SMiC4afXNWv6aMzbvncdqJmRghbuIumFOUmtiw +kgvBKEgT2vxNAoIBAQCF8vlprLEB/LEt58nsLn2JpSUyv3AZZVZLCQUH8hK86/JO +/7GbAzq+F6418RlpcU4zoQroxNSwgZrc/M3VDX4K6OH8yRjCtWZZaNGsYu9tCRqe +0brAHYAdv13tWaFPmRYJ3FAx1Cf40bCOy4236qDw1EV0StZKrtXnWN08Qw6MjYx2 +a8qWKhLjsmCvY5AgU0ddNS70OJaNrA7Ofqatq2B8OBm5VRfN/oQ4j0CYWU612eQE +k5WYFyQrK5wX2y/QqNVXT8XtTLIIsnxRMTjbHwN4qBqhG9nnC+dAXY64GPNDHZ1X +k4bWxiCEw+9PmSjPNxIwHGsvjz1/3yTGOM1K+aKpAoIBAQCpHnwhTYp9in5Rg8Lq +nWL1y8B1BaWh5JzMDWFIjiCBLy17aOokqkj6GkAuPA8KZN+FnfT7+Krdw4yGcR6T +pC/4tl+XFO5AhJZ/GSgIpJszaQotohbqq9Sr8f9vTeSwIy/q7zUgU8XkvyG1uisH +Q2S44u+JlCFFek8ViPYK2vnHE85mZaUxjwC8VfxLqQ2cEGdjgm6ki62Y4lMGObBO +lKKgwypvqJ7gKkDxtiKqky3wjJizcDa8Ci92i6lJ7rNSn+uQk0GkKEcWAdsaLvD4 +JvvXfPE8F5nB2Czl0gTmaHdhA/niyOZ8S0uQopKsiRfGuB+9AjCJFqclY+xMPb49 +wlkVAoIBAQCaXZvQGwtnutxWNSutmfe3qHKT/r4gwppPJHN7+duPyWJVkg5lDs/i +QZPoi63kfA5MkAZM5R6N5RuzVIfg/138l1ldTHWZoRxqga3c9ED9zbRJEkdbFfuI +d6IiWXDAVHt5Gh7rYxu5OL1ZzL1+2RO3KrMLmLXy7h7ZX46tU2Z8+PkJXNJT9fPR +07ohZ9xtkqnb7MeIPK6YONK5krjafBqimxGlWDDG159XMEaX7iA26NR70VKloWoS +X2MUdC82TYBzRzMSUcsnZ2nCms2WreLZHH5e2gXRMG5M9W8ducomZh8VRsD71vXa +BV6Zf8L5DX0gCGFOzJ30IaenkQt+gcQ8 +-----END PRIVATE KEY----- diff --git a/docker/nginx-production/Dockerfile b/docker/nginx-production/Dockerfile new file mode 100644 index 0000000..c6f1cee --- /dev/null +++ b/docker/nginx-production/Dockerfile @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. + +FROM nginx +COPY nginx.conf /etc/nginx/nginx.conf +COPY conf.d/* /etc/nginx/conf.d/ +COPY fullchain.pem /etc/letsencrypt/live/asclepias-broker.aas.org/fullchain.pem +COPY privkey.pem /etc/letsencrypt/live/asclepias-broker.aas.org/privkey.pem \ No newline at end of file diff --git a/docker/nginx-production/conf.d/default.conf b/docker/nginx-production/conf.d/default.conf new file mode 100644 index 0000000..936e847 --- /dev/null +++ b/docker/nginx-production/conf.d/default.conf @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. + +# This nginx configuration defines two servers, one on port 80 and one on port +# 443. All traffix on port 80 is redirect to port 443 on SSL. +# +# Nginx proxies all requests on port 443 to upstream the application server +# which is expected to be running on port 5000. + +upstream web_server { + server web:5000 fail_timeout=0; +} + +# HTTP server +server { + # Redirects all requests to https. - this is in addition to HAProxy which + # already redirects http to https. This redirect is needed in case you access + # the server directly (e.g. useful for debugging). + listen 80; # IPv4 + listen [::]:80; # IPv6 + server_name _; + return 301 https://$host$request_uri; +} + +# HTTPS server +server { + listen 443; # IPv4 + listen [::]:443; # IPv6 + server_name _; + charset utf-8; + keepalive_timeout 5; + + # SSL configuration according to best practices from + # https://mozilla.github.io/server-side-tls/ssl-config-generator/ + ssl on; + # The provided certificate (test.crt) and private key (test.key) is only for + # testing and must never be used in production environment. + ssl_certificate /etc/letsencrypt/live/asclepias-broker.aas.org/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/asclepias-broker.aas.org/privkey.pem; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + + # Accepted protocols and ciphers + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; + ssl_prefer_server_ciphers on; + + add_header Strict-Transport-Security "max-age=15768000"; # 6 months + + # The request body is sent to the proxied server immediately as it is + # received + proxy_request_buffering off; + # Sets the HTTP protocol v1.1 for proxying in order to not use the buffer + # in case of chunked transfer encoding + proxy_http_version 1.1; + + # Proxying to the application server + location / { + uwsgi_pass web_server; + include uwsgi_params; + uwsgi_buffering off; + uwsgi_request_buffering off; + uwsgi_param Host $host; + uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for; + uwsgi_param X-Forwarded-Proto $scheme; + # Max upload size is set to 100mb as default. + client_max_body_size 100m; + } + + # Static content is served directly by nginx and not the application server. + location /static { + alias /opt/invenio/var/instance/static; + autoindex off; + } + + location /.well-known { + alias /var/www/.well-known; + } + +} diff --git a/docker/nginx-production/fullchain.pem b/docker/nginx-production/fullchain.pem new file mode 100644 index 0000000..28138e9 --- /dev/null +++ b/docker/nginx-production/fullchain.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIUVOBMpW2x4CFApWIK7XS1VpTLyFcwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMTExMTEwMzEzNTdaFw0yMTEx +MTMwMzEzNTdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDO84tBfpqT7B4uC//WDteJfp8XqGqmR639REZZP72a +fHtduhxka7gWzMnOAgbAa5qKjDQIpkBYEVfE9+FG2EgIiOaYTUSGFH3Su2EYE8sz +8ihobMH278g2TR8jsFvTEE4T6xKXzGyghjxS4vEghPca6JqrVpPeVUuJSXbb5hH3 +3xdgQ32GaDK2YYZNYoQwEAiOA6kyGjcfGRM6Y3gzn2+1GOiFxrIh7x6VFjb8K3nG +evcxkey858KdV+koaNUFvgXhammTPNgwH7ddQs0R5uO1Pfff5KhHCe4HE/ynvFdQ +XqKl2NpJgmw/IfRtxhuFpQR37ljP965KXOWmBYhqhDBiSQg/eh3Gr8rQJnAmuBoL +2uKbXOSB04AAE+Hxk7FMQh4Su/JsVFw2iZTKB5SrQnkgwghIDje0hhlEcRlJxAIN +3jUBImhIOzWhp7DPzWjwS9LS48r5cDm6J/yzhfR+F5UaZFamvIAr8L9UpyzHMy9p +1a2FVyOz1lMGYQV0Yf1CvQIEGn439aMcKcuOC6f+BpcVdF5qHtIOxAKwVJKdxbMF +GJKv1VfocS5qvUTswP6FBNn2x0J4tvGSTijJ1t1VODUY7oULd4OZACC+50BnM8J1 +0vZeb2N+rFjpP1+jpH62WgbGBMHhSFqle91FX1A0YfiLtx3K+Mx7cCGChhwS7GT8 +EwIDAQABo1MwUTAdBgNVHQ4EFgQUNVPrnbT0Ukcu1e3mBfoO1Osx0J0wHwYDVR0j +BBgwFoAUNVPrnbT0Ukcu1e3mBfoO1Osx0J0wDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCAgEAsnyecZdlq6Uz+V1q+mTfvQp8lMP7nKlbpfSBawLNTIj3 +16P4Ugg4fFlbOaMO/uIiV8oTDuAC88XSkVfcRFuW4934MV8GWpbEwhiP4UMUTNmH +zMW8WEzA1hc/Pk98tmGIcHo7ixH2wEJiaAJSwb16CqkX2RFeH0dKxxGImREMTaqT +dLwuEI8VnMz3bHbLODPmG5aSiQdjajoC5yMzZ6IQOxbcisbapGnqvdrKKoiH01UK +zbGU61Bc/5S5tFASK3BzZRRPr1KHYJI/r4WzHKxSWkJtdC4IBchNyDWqPeo207xM +INqjP0Wd7KptL1+ztLve8YnyLJK6qaEfTVg6Ogxbsf5/tYQFZS8W3y8T/Qw18TRs +ZnHQ3O+ExWSu0bzHoG5O/kUrXB4Fy5t6UbbCCsYyueDAH6uw3jb69vxPTRUyk2ll +qhm3VzI0QqVNHnI+8NLDMnkoY4Zxfqo1b64sBAKYxO+qMdGgLicGaQ0BXRS3DRPq +huuUXtFWDFLOvijveCbPBU0SBrBqbn/Iu1hMel9enznRlNzs98Ubpd+ZoK8v7TKf +CCuX+zWtM8D/Y5/RmvbB/GkprM8dtfhBwvr5K7vlKiqyZ/PQYwTvLnOf7zflb45g +0E2VSQxM0wRezBCN6A5Wr0rvEdKAkGzyCT+nwf4hdShSqHEGUTB2y/7+jI+8vik= +-----END CERTIFICATE----- diff --git a/docker/nginx-production/nginx.conf b/docker/nginx-production/nginx.conf new file mode 100644 index 0000000..909b880 --- /dev/null +++ b/docker/nginx-production/nginx.conf @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2018 CERN. +# +# Asclepias Broker is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. + +user nginx; +worker_processes 1; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + + keepalive_timeout 65; + + gzip on; + gzip_disable "msie6"; + gzip_http_version 1.1; + gzip_comp_level 5; # or anything between 4-6 + gzip_min_length 100; + gzip_proxied any; + # We may need more mime-types here (eg. 'application/x-bibtex') + gzip_types + application/atom+xml + application/javascript + application/json + application/ld+json + application/manifest+json + application/octet-stream + application/rss+xml + application/vnd.geo+json + application/vnd.ms-fontobject + application/x-font-ttf + application/x-javascript + application/x-web-app-manifest+json + application/xhtml+xml + application/xml + application/xml+rss + font/opentype + image/bmp + image/svg+xml + image/x-icon + text/cache-manifest + text/css + text/html + text/javascript + text/plain + text/vcard + text/vnd.rim.location.xloc + text/vtt + text/x-component + text/x-cross-domain-policy + text/xml; + gzip_vary on; + + include /etc/nginx/conf.d/*.conf; +} diff --git a/docker/nginx-production/privkey.pem b/docker/nginx-production/privkey.pem new file mode 100644 index 0000000..1dba2a5 --- /dev/null +++ b/docker/nginx-production/privkey.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDO84tBfpqT7B4u +C//WDteJfp8XqGqmR639REZZP72afHtduhxka7gWzMnOAgbAa5qKjDQIpkBYEVfE +9+FG2EgIiOaYTUSGFH3Su2EYE8sz8ihobMH278g2TR8jsFvTEE4T6xKXzGyghjxS +4vEghPca6JqrVpPeVUuJSXbb5hH33xdgQ32GaDK2YYZNYoQwEAiOA6kyGjcfGRM6 +Y3gzn2+1GOiFxrIh7x6VFjb8K3nGevcxkey858KdV+koaNUFvgXhammTPNgwH7dd +Qs0R5uO1Pfff5KhHCe4HE/ynvFdQXqKl2NpJgmw/IfRtxhuFpQR37ljP965KXOWm +BYhqhDBiSQg/eh3Gr8rQJnAmuBoL2uKbXOSB04AAE+Hxk7FMQh4Su/JsVFw2iZTK +B5SrQnkgwghIDje0hhlEcRlJxAIN3jUBImhIOzWhp7DPzWjwS9LS48r5cDm6J/yz +hfR+F5UaZFamvIAr8L9UpyzHMy9p1a2FVyOz1lMGYQV0Yf1CvQIEGn439aMcKcuO +C6f+BpcVdF5qHtIOxAKwVJKdxbMFGJKv1VfocS5qvUTswP6FBNn2x0J4tvGSTijJ +1t1VODUY7oULd4OZACC+50BnM8J10vZeb2N+rFjpP1+jpH62WgbGBMHhSFqle91F +X1A0YfiLtx3K+Mx7cCGChhwS7GT8EwIDAQABAoICADLwKS+WvO9557fHxlHm11CF +dR06m/2PmRjErFgdY0raJvdb7s8c4HPkNivZvdWw5poBhnE2kpHauvLFXJK2e4x2 +PePw6NPjyVCMRIrLnHGNwjppwphITsxm0SpUp1VdJwqqCqqIa5hbUg/IwjcR40yh +Qii4J69K6UvCZFod2ABdzgAovIXPsePIP2levVCjMafa6NNnNngWEPCHOTfjn3hA +yELdNE078RgbHq+U9+VNsPhnhZC9rt5RnBcRLpW6PvJL4e6WxFOcCuMOpTEp1pRu +y0s1meHaZNcjKUYUCp3CnWAa7ye2zXQApIw8fdu4UVA/v2Z4/VJaaUAjDn/BR7MH +5JMdG44c3BQwtvcHgb5ZYh1IoW/ZSdo/cwl6iYYgPwtLOpW3C18MqpXme47ehHCA +LhdHKXTy8/ZwTVlWhd62y7z2GdcheoIY2GTv3rMQw/G2KH3S6HFhJxI+iO3mVcAP +yN8oGppjgaD7VYy/PINf6DxXr1jXmKSGy8bekAlpCt1kccFj/z4ScinBMneCOikw +hjy0eRqQlSFA5PHS4oSS/e4qFd8AE8Y0Woe1tv+gn+S8XrpNE85aOuUAZXWGYKxk +++a5GDYDS7A2HB51cS8GutaaXko6EBhbftkP1vlQqYOYsGe3QTE9F5Y4qZKlfkxQ +SoxYi8Hq7hUGaeqqpXm5AoIBAQD1E3aka8spPDL2FkwDfZi+S/ocOGUIpMaDcJst +4FgoA0+FxlCiwQGGStC6YoHrUnjYdU/qKEpAQJMLHjys+jgIvXR6FxTAx7gQza39 +zZle/+lqWPmjYPEDzGW/Y6y0hJJGK5T0n+5BE6Y9NNVJYuPPGHyzwnD1qNALxOn+ +6m/GHHr0QJ1b4nK721M7AZGfkgz7bhAE20j4nVHdKZMOR6B1RQYZby84RsxWBAKv +MnMzfXu+au6seRHE79fGE6pv1qX6uCPihD2O/299DV1tD1djpw8+6POVz4+RWBI4 +1FBcDsEdxAMpOts6jNm/KsxYZC4iWiGIaGFOGvZnhrNFFonfAoIBAQDYLQs1WXCf +zaYssstR5yb/MI8V4AwuSXtHAeYnz9UEIz6UxpKI4d//DrS95dpGSsagg8pN2a1l +jmYjaLwfeF28CTVwLAuryn1BNnwv0R/NDUZH6V/GpzwcS0rgr2BzjyMEXVS0iL3R +wl4kzGFfQ9dCBZB8ubJdnjp32BLAyancFnTMjnr5uYTq2RJ3tfL0JDoedPVlBDrX +WdmWBUFgLSS4l840A141Uls5K85fU7iykKfY8FFO+uZLV1VDxV4Z4+t9rMGrIyR5 +0NdIGvA7ei9/Gkg8KSb1TKwhm6SMiC4afXNWv6aMzbvncdqJmRghbuIumFOUmtiw +kgvBKEgT2vxNAoIBAQCF8vlprLEB/LEt58nsLn2JpSUyv3AZZVZLCQUH8hK86/JO +/7GbAzq+F6418RlpcU4zoQroxNSwgZrc/M3VDX4K6OH8yRjCtWZZaNGsYu9tCRqe +0brAHYAdv13tWaFPmRYJ3FAx1Cf40bCOy4236qDw1EV0StZKrtXnWN08Qw6MjYx2 +a8qWKhLjsmCvY5AgU0ddNS70OJaNrA7Ofqatq2B8OBm5VRfN/oQ4j0CYWU612eQE +k5WYFyQrK5wX2y/QqNVXT8XtTLIIsnxRMTjbHwN4qBqhG9nnC+dAXY64GPNDHZ1X +k4bWxiCEw+9PmSjPNxIwHGsvjz1/3yTGOM1K+aKpAoIBAQCpHnwhTYp9in5Rg8Lq +nWL1y8B1BaWh5JzMDWFIjiCBLy17aOokqkj6GkAuPA8KZN+FnfT7+Krdw4yGcR6T +pC/4tl+XFO5AhJZ/GSgIpJszaQotohbqq9Sr8f9vTeSwIy/q7zUgU8XkvyG1uisH +Q2S44u+JlCFFek8ViPYK2vnHE85mZaUxjwC8VfxLqQ2cEGdjgm6ki62Y4lMGObBO +lKKgwypvqJ7gKkDxtiKqky3wjJizcDa8Ci92i6lJ7rNSn+uQk0GkKEcWAdsaLvD4 +JvvXfPE8F5nB2Czl0gTmaHdhA/niyOZ8S0uQopKsiRfGuB+9AjCJFqclY+xMPb49 +wlkVAoIBAQCaXZvQGwtnutxWNSutmfe3qHKT/r4gwppPJHN7+duPyWJVkg5lDs/i +QZPoi63kfA5MkAZM5R6N5RuzVIfg/138l1ldTHWZoRxqga3c9ED9zbRJEkdbFfuI +d6IiWXDAVHt5Gh7rYxu5OL1ZzL1+2RO3KrMLmLXy7h7ZX46tU2Z8+PkJXNJT9fPR +07ohZ9xtkqnb7MeIPK6YONK5krjafBqimxGlWDDG159XMEaX7iA26NR70VKloWoS +X2MUdC82TYBzRzMSUcsnZ2nCms2WreLZHH5e2gXRMG5M9W8ducomZh8VRsD71vXa +BV6Zf8L5DX0gCGFOzJ30IaenkQt+gcQ8 +-----END PRIVATE KEY----- diff --git a/docker/rabbitmq/rabbitmq.conf b/docker/rabbitmq/rabbitmq.conf new file mode 100644 index 0000000..72d720a --- /dev/null +++ b/docker/rabbitmq/rabbitmq.conf @@ -0,0 +1,2 @@ +consumer_timeout = 1800000 +vm_memory_high_watermark.absolute = 400MiB \ No newline at end of file diff --git a/docs/api/graph.rst b/docs/api/graph.rst index 1d60e98..39c38d3 100644 --- a/docs/api/graph.rst +++ b/docs/api/graph.rst @@ -28,4 +28,3 @@ Tasks .. automodule:: asclepias_broker.graph.tasks :members: -.. autotask:: asclepias_broker.graph.tasks.process_event diff --git a/docs/api/harvester.rst b/docs/api/harvester.rst new file mode 100644 index 0000000..b6d9193 --- /dev/null +++ b/docs/api/harvester.rst @@ -0,0 +1,18 @@ +.. + Copyright (C) 2018 CERN. + + Asclepias Broker is free software; you can redistribute it and/or modify it + under the terms of the MIT License; see LICENSE file for more details. + +Harvester +--------- + +CLI +~~~ + +.. automodule:: asclepias_broker.harvester.cli + :members: + +.. click:: asclepias_broker.harvester.cli:harvester + :prog: asclepias-broker harvester + :show-nested: diff --git a/docs/api/monitoring.rst b/docs/api/monitoring.rst new file mode 100644 index 0000000..3e3fa04 --- /dev/null +++ b/docs/api/monitoring.rst @@ -0,0 +1,34 @@ +.. + Copyright (C) 2018 CERN. + + Asclepias Broker is free software; you can redistribute it and/or modify it + under the terms of the MIT License; see LICENSE file for more details. + +Monitoring +------------ + +.. automodule:: asclepias_broker.monitoring + :members: + +Models +~~~~~~ + +.. automodule:: asclepias_broker.monitoring.models + :members: + +CLI +~~~ + +.. automodule:: asclepias_broker.monitoring.cli + :members: + +.. click:: asclepias_broker.monitoring.cli:monitor + :prog: asclepias-broker monitor + :show-nested: + +Tasks +~~~~~ + +.. automodule:: asclepias_broker.monitoring.tasks + :members: + diff --git a/docs/api/search.rst b/docs/api/search.rst index 08c5727..5000026 100644 --- a/docs/api/search.rst +++ b/docs/api/search.rst @@ -46,8 +46,6 @@ Tasks .. automodule:: asclepias_broker.search.tasks :members: -.. autotask:: asclepias_broker.search.tasks.reindex_all_relationships - Views ~~~~~ diff --git a/docs/index.rst b/docs/index.rst index de5a043..23dc67c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -56,6 +56,8 @@ this part of the documentation is for you. api/graph api/metadata api/search + api/monitoring + api/harvester Additional Notes ---------------- diff --git a/docs/usage.rst b/docs/usage.rst index 0a7eead..114b5a3 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -129,8 +129,7 @@ reindex everything you can run: .. code-block:: shell - # We pass the "--destroy" flag to clean the index state - $ pipenv run asclepias-broker search reindex --destroy + $ pipenv run asclepias-broker search reindex Querying -------- diff --git a/setup.py b/setup.py index 94769dd..8d86cc8 100644 --- a/setup.py +++ b/setup.py @@ -45,6 +45,7 @@ 'events = asclepias_broker.events.cli:events', 'search = asclepias_broker.search.cli:search', 'harvester = asclepias_broker.harvester.cli:harvester', + 'monitor = asclepias_broker.monitoring.cli:monitor', ], 'invenio_config.module': [ 'asclepias_broker = asclepias_broker.config', @@ -72,6 +73,7 @@ 'asclepias_broker_graph_tasks = asclepias_broker.graph.tasks', 'asclepias_broker_search_tasks = asclepias_broker.search.tasks', 'asclepias_harvester_tasks = asclepias_broker.harvester.tasks', + 'asclepias_monitoring_tasks = asclepias_broker.monitoring.tasks' ], 'invenio_db.models': [ 'asclepias_broker_core = asclepias_broker.core.models', @@ -81,9 +83,11 @@ ], 'invenio_pidstore.fetchers': [ 'relid = asclepias_broker.pidstore:relid_fetcher', + 'meta = asclepias_broker.pidstore:relid_fetcher', ], 'invenio_pidstore.minters': [ 'relid = asclepias_broker.pidstore:relid_minter', + 'meta = asclepias_broker.pidstore:relid_minter', ], 'invenio_search.mappings': [ 'relationships = asclepias_broker.mappings',