diff --git a/build.sh b/build.sh index 1f2bad32efcc0c6ee7d126b76938d287615e0fc7..522c0b8d6810d5a92f8a1ad6e9f32818bfc4ca3d 100755 --- a/build.sh +++ b/build.sh @@ -39,12 +39,17 @@ function build_wheel() { pip check } +function npm_install() { + npm install +} + function main() { # setup_venv pip_compile pip_install pip_install_via_setup_py - #build_wheel + build_wheel + npm_install } main diff --git a/data b/data index 108957a7adba824d962b29902b1cce92ee02f79e..7e26515893ac523c9bf94cb9556f3763c5048cb5 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 108957a7adba824d962b29902b1cce92ee02f79e +Subproject commit 7e26515893ac523c9bf94cb9556f3763c5048cb5 diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 137e369d6c6ef6e787643e7235f2f9ad7840de4c..ba48f3ee5e6628a08402cb1ec8f66f70cb5062ad 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -289,7 +289,7 @@ * Fixed #213 WHO-template: change URL to for_url() * ------------------------------------- * Issue #195 RkiVaccinationImport.get_daterep_missing_in_vaccination_data(): native SQL to SQLalechemy Query -* Issue #83 WhoImport.get_new_dates_as_array() SQLalchemy instead of SQL +* Fixed #83 WhoImport.get_new_dates_as_array() SQLalchemy instead of SQL * Fixed #219 WhoImport.countries() SQLalchemy instead of SQL * ------------------------------------- * Issue #207 remove deprecated: database.port @@ -297,8 +297,8 @@ * Issue #209 remove deprecated: database.ITEMS_PER_PAGE * ------------------------------------- * Issue #210 database.py: logging for Celery on Windows -*------------------------------------- -* Issue #196 OwidImport.get_new_dates_reported_as_array() needs implementation +* ------------------------------------- +* Fixed #196 OwidImport.get_new_dates_reported_as_array() needs implementation * ------------------------------------- * Issue #212 implement OwidService.task_database_drop_create() * ------------------------------------- diff --git a/requirements/build.txt b/requirements/build.txt index ca6be47cefc5372cc8ca8fe8690a844fded257a6..5790071eb4f2cfb68d042b31e70de523cfd7dd1d 100644 --- a/requirements/build.txt +++ b/requirements/build.txt @@ -2,39 +2,43 @@ # This file is autogenerated by pip-compile # To update, run: # -# pip-compile 'requirements\build.in' +# pip-compile requirements/build.in # alembic==1.5.5 - # via -r requirements\build.in + # via -r requirements/build.in appdirs==1.4.4 # via virtualenv argparse==1.4.0 # via pytoolbox attrs==20.3.0 - # via -r requirements\build.in + # via -r requirements/build.in bleach==3.3.0 # via readme-renderer build==0.3.1.post1 - # via -r requirements\build.in + # via -r requirements/build.in certifi==2020.12.5 # via # pipenv # requests +cffi==1.14.5 + # via cryptography cfgv==3.2.0 # via pre-commit chardet==3.0.4 # via - # -r requirements\build.in + # -r requirements/build.in # requests click==7.1.2 # via pip-tools colorama==0.4.4 # via twine +cryptography==3.4.7 + # via secretstorage distlib==0.3.1 # via virtualenv docutils==0.17 # via - # -r requirements\build.in + # -r requirements/build.in # readme-renderer filelock==3.0.12 # via virtualenv @@ -42,7 +46,7 @@ greenlet==1.0.0 # via sqlalchemy identify==2.2.2 # via - # -r requirements\build.in + # -r requirements/build.in # pre-commit idna==2.10 # via requests @@ -50,6 +54,10 @@ importlib-metadata==3.10.0 # via # keyring # twine +jeepney==0.6.0 + # via + # keyring + # secretstorage keyring==23.0.1 # via twine mako==1.1.4 @@ -60,55 +68,55 @@ nodeenv==1.5.0 # via pre-commit packaging==20.9 # via - # -r requirements\build.in + # -r requirements/build.in # bleach # build pbr==3.1.1 - # via -r requirements\build.in + # via -r requirements/build.in pep517==0.10.0 # via - # -r requirements\build.in + # -r requirements/build.in # build pip-licenses==3.3.0 - # via -r requirements\build.in + # via -r requirements/build.in pip-tools==5.5.0 - # via -r requirements\build.in + # via -r requirements/build.in pipenv==2020.11.15 - # via -r requirements\build.in + # via -r requirements/build.in pkginfo==1.7.0 # via twine pre-commit==2.10.1 - # via -r requirements\build.in + # via -r requirements/build.in ptable==0.9.2 # via pip-licenses py==1.10.0 - # via -r requirements\build.in + # via -r requirements/build.in pyaml==20.4.0 # via pytoolbox +pycparser==2.20 + # via cffi pygments==2.8.1 # via - # -r requirements\build.in + # -r requirements/build.in # readme-renderer pyparsing==2.4.7 # via - # -r requirements\build.in + # -r requirements/build.in # packaging python-dateutil==2.8.1 # via alembic python-dotenv==0.15.0 - # via -r requirements\build.in + # via -r requirements/build.in python-editor==1.0.4 # via alembic python-magic==0.4.22 # via pytoolbox pytoolbox==14.0.0 - # via -r requirements\build.in + # via -r requirements/build.in pytz==2020.5 # via - # -r requirements\build.in + # -r requirements/build.in # pytoolbox -pywin32-ctypes==0.2.0 - # via keyring pyyaml==5.4.1 # via # pre-commit @@ -124,9 +132,11 @@ requests==2.25.1 # twine rfc3986==1.4.0 # via twine +secretstorage==3.3.1 + # via keyring six==1.15.0 # via - # -r requirements\build.in + # -r requirements/build.in # bleach # python-dateutil # readme-renderer @@ -135,31 +145,31 @@ sqlalchemy==1.4.6 # via alembic toml==0.10.2 # via - # -r requirements\build.in + # -r requirements/build.in # build # pep517 # pre-commit tqdm==4.59.0 # via twine twine==3.4.1 - # via -r requirements\build.in + # via -r requirements/build.in urllib3==1.26.4 # via - # -r requirements\build.in + # -r requirements/build.in # requests venv-run==0.1.0 - # via -r requirements\build.in + # via -r requirements/build.in virtualenv-clone==0.5.4 # via pipenv virtualenv==20.4.3 # via - # -r requirements\build.in + # -r requirements/build.in # pipenv # pre-commit webencodings==0.5.1 # via bleach wheel==0.36.2 - # via -r requirements\build.in + # via -r requirements/build.in zipp==3.4.1 # via importlib-metadata diff --git a/requirements/dev.txt b/requirements/dev.txt index 0bdb917973aa157687c2a8752050dfe9868e8d3b..5ca97ef7008deeb673005051f1eaf2f135a02505 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -2,13 +2,13 @@ # This file is autogenerated by pip-compile # To update, run: # -# pip-compile 'requirements\dev.in' +# pip-compile requirements/dev.in # alabaster==0.7.12 # via sphinx alembic==1.5.5 # via - # -r requirements\build.in + # -r requirements/build.in # flask-db amqp==5.0.5 # via kombu @@ -16,11 +16,9 @@ appdirs==1.4.4 # via virtualenv argparse==1.4.0 # via pytoolbox -atomicwrites==1.4.0 - # via pytest attrs==20.3.0 # via - # -r requirements\build.in + # -r requirements/build.in # pytest babel==2.9.0 # via sphinx @@ -29,9 +27,9 @@ billiard==3.6.3.0 bleach==3.3.0 # via readme-renderer build==0.3.1.post1 - # via -r requirements\build.in + # via -r requirements/build.in celery[redis]==5.0.5 - # via -r requirements\dev.in + # via -r requirements/dev.in certifi==2020.12.5 # via # pipenv @@ -42,7 +40,7 @@ cfgv==3.2.0 # via pre-commit chardet==3.0.4 # via - # -r requirements\build.in + # -r requirements/build.in # requests click-didyoumean==0.0.3 # via celery @@ -59,56 +57,55 @@ click==7.1.2 # flask # pip-tools colorama==0.4.4 - # via - # pytest - # sphinx - # twine + # via twine cryptography==3.4.7 - # via jwcrypto + # via + # jwcrypto + # secretstorage cycler==0.10.0 # via matplotlib distlib==0.3.1 # via virtualenv dnspython==2.1.0 # via - # -r requirements\dev.in + # -r requirements/dev.in # email-validator docutils==0.17 # via - # -r requirements\build.in + # -r requirements/build.in # readme-renderer # sphinx dominate==2.6.0 # via flask-bs4 email-validator==1.1.2 - # via -r requirements\dev.in + # via -r requirements/dev.in filelock==3.0.12 # via virtualenv flask-admin==1.5.7 - # via -r requirements\dev.in + # via -r requirements/dev.in flask-bs4==4.5.3.0 - # via -r requirements\dev.in + # via -r requirements/dev.in flask-cors==3.0.10 - # via -r requirements\dev.in + # via -r requirements/dev.in flask-db==0.3.1 - # via -r requirements\tests.in + # via -r requirements/tests.in flask-fixtures==0.3.8 - # via -r requirements\tests.in + # via -r requirements/tests.in flask-login==0.5.0 - # via -r requirements\dev.in + # via -r requirements/dev.in flask-sqlalchemy==2.5.1 # via - # -r requirements\dev.in + # -r requirements/dev.in # flask-db # flask-fixtures # pytest-flask-sqlalchemy flask-wtf==0.14.3 # via - # -r requirements\dev.in + # -r requirements/dev.in # flask-bs4 flask==1.1.2 # via - # -r requirements\dev.in + # -r requirements/dev.in # flask-admin # flask-bs4 # flask-cors @@ -126,7 +123,7 @@ httplib2==0.19.0 # via plantuml identify==2.2.2 # via - # -r requirements\build.in + # -r requirements/build.in # pre-commit idna==2.10 # via @@ -148,6 +145,10 @@ jaraco.context==4.0.0 # via pytest-enabler jaraco.functools==3.2.1 # via pytest-enabler +jeepney==0.6.0 + # via + # keyring + # secretstorage jinja2==2.11.3 # via # flask @@ -196,7 +197,7 @@ numba==0.52.0 # via pynndescent numpy==1.20.2 # via - # -r requirements\dev.in + # -r requirements/dev.in # matplotlib # numba # pandas @@ -207,41 +208,41 @@ numpy==1.20.2 # visdom packaging==20.9 # via - # -r requirements\build.in + # -r requirements/build.in # bleach # build # pytest # pytest-flask-sqlalchemy # sphinx pandas==1.2.3 - # via -r requirements\dev.in + # via -r requirements/dev.in pbr==3.1.1 # via - # -r requirements\build.in + # -r requirements/build.in # sphinxcontrib-gravizo pep517==0.10.0 # via - # -r requirements\build.in + # -r requirements/build.in # build pillow==8.2.0 # via - # -r requirements\dev.in + # -r requirements/dev.in # matplotlib # visdom pip-licenses==3.3.0 - # via -r requirements\build.in + # via -r requirements/build.in pip-tools==5.5.0 - # via -r requirements\build.in + # via -r requirements/build.in pipenv==2020.11.15 - # via -r requirements\build.in + # via -r requirements/build.in pkginfo==1.7.0 # via twine plantuml-gentools==0.1.2 - # via -r requirements\docs.in + # via -r requirements/docs.in plantuml-markdown==3.4.2 - # via -r requirements\docs.in + # via -r requirements/docs.in plantuml-wrapper==0.1.0 - # via -r requirements\docs.in + # via -r requirements/docs.in plantuml==0.3.0 # via plantuml-markdown pluggy==0.13.1 @@ -249,7 +250,7 @@ pluggy==0.13.1 port-for==0.4 # via pytest-postgresql pre-commit==2.10.1 - # via -r requirements\build.in + # via -r requirements/build.in prettytable==2.0.0 # via pyecharts prompt-toolkit==3.0.16 @@ -257,55 +258,55 @@ prompt-toolkit==3.0.16 psutil==5.8.0 # via mirakuru psycopg2-binary==2.8.6 - # via -r requirements\dev.in + # via -r requirements/dev.in ptable==0.9.2 # via pip-licenses py2puml==0.4.0 - # via -r requirements\docs.in + # via -r requirements/docs.in py==1.10.0 # via - # -r requirements\build.in + # -r requirements/build.in # pytest pyaml==20.4.0 # via pytoolbox pycparser==2.20 # via cffi pyecharts-extras==0.0.5 - # via -r requirements\dev.in + # via -r requirements/dev.in pyecharts==1.9.0 # via - # -r requirements\dev.in + # -r requirements/dev.in # pyecharts-extras pygments==2.8.1 # via - # -r requirements\build.in + # -r requirements/build.in # readme-renderer # sphinx pynndescent==0.5.2 - # via -r requirements\dev.in + # via -r requirements/dev.in pyparsing==2.4.7 # via - # -r requirements\build.in + # -r requirements/build.in # httplib2 # matplotlib # packaging pytest-enabler==1.2.0 - # via -r requirements\tests.in + # via -r requirements/tests.in pytest-flask-sqlalchemy==1.0.2 - # via -r requirements\tests.in + # via -r requirements/tests.in pytest-flask==1.2.0 - # via -r requirements\tests.in + # via -r requirements/tests.in pytest-mock==3.5.1 # via pytest-flask-sqlalchemy pytest-postgresql==2.6.1 - # via -r requirements\tests.in + # via -r requirements/tests.in pytest-runner==5.3.0 - # via -r requirements\tests.in + # via -r requirements/tests.in pytest-venv==0.2.1 - # via -r requirements\tests.in + # via -r requirements/tests.in pytest==6.2.3 # via - # -r requirements\tests.in + # -r requirements/tests.in # pytest-flask # pytest-flask-sqlalchemy # pytest-mock @@ -318,22 +319,20 @@ python-dateutil==2.8.1 # matplotlib # pandas python-dotenv==0.15.0 - # via -r requirements\build.in + # via -r requirements/build.in python-editor==1.0.4 # via alembic python-magic==0.4.22 # via pytoolbox pytoolbox==14.0.0 - # via -r requirements\build.in + # via -r requirements/build.in pytz==2020.5 # via - # -r requirements\build.in + # -r requirements/build.in # babel # celery # pandas # pytoolbox -pywin32-ctypes==0.2.0 - # via keyring pyyaml==5.4.1 # via # pre-commit @@ -360,16 +359,18 @@ scikit-learn==0.24.1 # via pynndescent scipy==1.6.2 # via - # -r requirements\dev.in + # -r requirements/dev.in # pynndescent # scikit-learn # statisticaldiagrams # visdom +secretstorage==3.3.1 + # via keyring simplejson==3.17.2 # via pyecharts six==1.15.0 # via - # -r requirements\build.in + # -r requirements/build.in # bleach # click-repl # cycler @@ -384,10 +385,10 @@ six==1.15.0 snowballstemmer==2.1.0 # via sphinx speaklater==1.3 - # via -r requirements\docs.in + # via -r requirements/docs.in sphinx==3.4.3 # via - # -r requirements\docs.in + # -r requirements/docs.in # sphinxcontrib-github # sphinxcontrib-log-cabinet # sphinxcontrib-plantuml @@ -396,17 +397,17 @@ sphinxcontrib-applehelp==1.0.2 sphinxcontrib-devhelp==1.0.2 # via sphinx sphinxcontrib-github==0.1.3 - # via -r requirements\docs.in + # via -r requirements/docs.in sphinxcontrib-gravizo==0.0.4 - # via -r requirements\docs.in + # via -r requirements/docs.in sphinxcontrib-htmlhelp==1.0.3 # via sphinx sphinxcontrib-jsmath==1.0.1 # via sphinx sphinxcontrib-log-cabinet==1.0.1 - # via -r requirements\docs.in + # via -r requirements/docs.in sphinxcontrib-plantuml==0.20.1 - # via -r requirements\docs.in + # via -r requirements/docs.in sphinxcontrib-qthelp==1.0.3 # via sphinx sphinxcontrib-serializinghtml==1.1.4 @@ -415,28 +416,28 @@ sqlalchemy-utils==0.36.8 # via flask-db sqlalchemy==1.4.5 # via - # -r requirements\dev.in + # -r requirements/dev.in # alembic # flask-db # flask-sqlalchemy # pytest-flask-sqlalchemy # sqlalchemy-utils statisticaldiagrams==20.5 - # via -r requirements\dev.in + # via -r requirements/dev.in threadpoolctl==2.1.0 # via scikit-learn tokenize-rt==4.1.0 - # via -r requirements\docs.in + # via -r requirements/docs.in toml==0.10.2 # via - # -r requirements\build.in + # -r requirements/build.in # build # pep517 # pre-commit # pytest # pytest-enabler torch==1.8.1 - # via -r requirements\dev.in + # via -r requirements/dev.in torchfile==0.1.0 # via visdom tornado==6.1 @@ -444,17 +445,17 @@ tornado==6.1 tqdm==4.59.0 # via twine twine==3.4.1 - # via -r requirements\build.in + # via -r requirements/build.in typing-extensions==3.7.4.3 # via torch uritemplate==3.0.1 # via github3.py urllib3==1.26.4 # via - # -r requirements\build.in + # -r requirements/build.in # requests venv-run==0.1.0 - # via -r requirements\build.in + # via -r requirements/build.in vine==5.0.0 # via # amqp @@ -463,12 +464,12 @@ virtualenv-clone==0.5.4 # via pipenv virtualenv==20.4.3 # via - # -r requirements\build.in + # -r requirements/build.in # pipenv # pre-commit # pytest-venv visdom==0.1.8.9 - # via -r requirements\dev.in + # via -r requirements/dev.in visitor==0.1.3 # via flask-bs4 wcwidth==0.1.8 @@ -484,9 +485,9 @@ werkzeug==1.0.1 # flask # pytest-flask wget==3.2 - # via -r requirements\dev.in + # via -r requirements/dev.in wheel==0.36.2 - # via -r requirements\build.in + # via -r requirements/build.in wtforms==2.3.3 # via # flask-admin diff --git a/requirements/docs.txt b/requirements/docs.txt index e8b9624db42ddb59a1251f3eb07fb5b9d54369c2..c5dd3ae78f5654ce920efd0becff3850c80541d4 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -2,24 +2,24 @@ # This file is autogenerated by pip-compile # To update, run: # -# pip-compile 'requirements\docs.in' +# pip-compile requirements/docs.in # alabaster==0.7.12 # via sphinx alembic==1.5.5 - # via -r requirements\build.in + # via -r requirements/build.in appdirs==1.4.4 # via virtualenv argparse==1.4.0 # via pytoolbox attrs==20.3.0 - # via -r requirements\build.in + # via -r requirements/build.in babel==2.9.0 # via sphinx bleach==3.3.0 # via readme-renderer build==0.3.1.post1 - # via -r requirements\build.in + # via -r requirements/build.in certifi==2020.12.5 # via # pipenv @@ -30,21 +30,21 @@ cfgv==3.2.0 # via pre-commit chardet==3.0.4 # via - # -r requirements\build.in + # -r requirements/build.in # requests click==7.1.2 # via pip-tools colorama==0.4.4 - # via - # sphinx - # twine + # via twine cryptography==3.4.7 - # via jwcrypto + # via + # jwcrypto + # secretstorage distlib==0.3.1 # via virtualenv docutils==0.17 # via - # -r requirements\build.in + # -r requirements/build.in # readme-renderer # sphinx filelock==3.0.12 @@ -57,7 +57,7 @@ httplib2==0.19.0 # via plantuml identify==2.2.2 # via - # -r requirements\build.in + # -r requirements/build.in # pre-commit idna==2.10 # via requests @@ -67,6 +67,10 @@ importlib-metadata==3.10.0 # via # keyring # twine +jeepney==0.6.0 + # via + # keyring + # secretstorage jinja2==2.11.3 # via sphinx jwcrypto==0.8 @@ -85,54 +89,54 @@ nodeenv==1.5.0 # via pre-commit packaging==20.9 # via - # -r requirements\build.in + # -r requirements/build.in # bleach # build # sphinx pbr==3.1.1 # via - # -r requirements\build.in + # -r requirements/build.in # sphinxcontrib-gravizo pep517==0.10.0 # via - # -r requirements\build.in + # -r requirements/build.in # build pip-licenses==3.3.0 - # via -r requirements\build.in + # via -r requirements/build.in pip-tools==5.5.0 - # via -r requirements\build.in + # via -r requirements/build.in pipenv==2020.11.15 - # via -r requirements\build.in + # via -r requirements/build.in pkginfo==1.7.0 # via twine plantuml-gentools==0.1.2 - # via -r requirements\docs.in + # via -r requirements/docs.in plantuml-markdown==3.4.2 - # via -r requirements\docs.in + # via -r requirements/docs.in plantuml-wrapper==0.1.0 - # via -r requirements\docs.in + # via -r requirements/docs.in plantuml==0.3.0 # via plantuml-markdown pre-commit==2.10.1 - # via -r requirements\build.in + # via -r requirements/build.in ptable==0.9.2 # via pip-licenses py2puml==0.4.0 - # via -r requirements\docs.in + # via -r requirements/docs.in py==1.10.0 - # via -r requirements\build.in + # via -r requirements/build.in pyaml==20.4.0 # via pytoolbox pycparser==2.20 # via cffi pygments==2.8.1 # via - # -r requirements\build.in + # -r requirements/build.in # readme-renderer # sphinx pyparsing==2.4.7 # via - # -r requirements\build.in + # -r requirements/build.in # httplib2 # packaging python-dateutil==2.8.1 @@ -140,20 +144,18 @@ python-dateutil==2.8.1 # alembic # github3.py python-dotenv==0.17.0 - # via -r requirements\build.in + # via -r requirements/build.in python-editor==1.0.4 # via alembic python-magic==0.4.22 # via pytoolbox pytoolbox==14.0.0 - # via -r requirements\build.in + # via -r requirements/build.in pytz==2020.5 # via - # -r requirements\build.in + # -r requirements/build.in # babel # pytoolbox -pywin32-ctypes==0.2.0 - # via keyring pyyaml==5.4.1 # via # pre-commit @@ -171,9 +173,11 @@ requests==2.25.1 # twine rfc3986==1.4.0 # via twine +secretstorage==3.3.1 + # via keyring six==1.15.0 # via - # -r requirements\build.in + # -r requirements/build.in # bleach # python-dateutil # readme-renderer @@ -181,10 +185,10 @@ six==1.15.0 snowballstemmer==2.1.0 # via sphinx speaklater==1.3 - # via -r requirements\docs.in + # via -r requirements/docs.in sphinx==3.4.3 # via - # -r requirements\docs.in + # -r requirements/docs.in # sphinxcontrib-github # sphinxcontrib-log-cabinet # sphinxcontrib-plantuml @@ -193,17 +197,17 @@ sphinxcontrib-applehelp==1.0.2 sphinxcontrib-devhelp==1.0.2 # via sphinx sphinxcontrib-github==0.1.3 - # via -r requirements\docs.in + # via -r requirements/docs.in sphinxcontrib-gravizo==0.0.4 - # via -r requirements\docs.in + # via -r requirements/docs.in sphinxcontrib-htmlhelp==1.0.3 # via sphinx sphinxcontrib-jsmath==1.0.1 # via sphinx sphinxcontrib-log-cabinet==1.0.1 - # via -r requirements\docs.in + # via -r requirements/docs.in sphinxcontrib-plantuml==0.20.1 - # via -r requirements\docs.in + # via -r requirements/docs.in sphinxcontrib-qthelp==1.0.3 # via sphinx sphinxcontrib-serializinghtml==1.1.4 @@ -211,36 +215,36 @@ sphinxcontrib-serializinghtml==1.1.4 sqlalchemy==1.4.6 # via alembic tokenize-rt==4.1.0 - # via -r requirements\docs.in + # via -r requirements/docs.in toml==0.10.2 # via - # -r requirements\build.in + # -r requirements/build.in # build # pep517 # pre-commit tqdm==4.60.0 # via twine twine==3.4.1 - # via -r requirements\build.in + # via -r requirements/build.in uritemplate==3.0.1 # via github3.py urllib3==1.26.4 # via - # -r requirements\build.in + # -r requirements/build.in # requests venv-run==0.1.0 - # via -r requirements\build.in + # via -r requirements/build.in virtualenv-clone==0.5.4 # via pipenv virtualenv==20.4.3 # via - # -r requirements\build.in + # -r requirements/build.in # pipenv # pre-commit webencodings==0.5.1 # via bleach wheel==0.36.2 - # via -r requirements\build.in + # via -r requirements/build.in zipp==3.4.1 # via importlib-metadata diff --git a/requirements/tests.txt b/requirements/tests.txt index 0186fbf2ff65ac41757b9fc49c11660ecd7d935a..a10be830e2d99b322594f9248a9c9d049a68e885 100644 --- a/requirements/tests.txt +++ b/requirements/tests.txt @@ -2,56 +2,56 @@ # This file is autogenerated by pip-compile # To update, run: # -# pip-compile 'requirements\tests.in' +# pip-compile requirements/tests.in # alembic==1.5.5 # via - # -r requirements\build.in + # -r requirements/build.in # flask-db appdirs==1.4.4 # via virtualenv argparse==1.4.0 # via pytoolbox -atomicwrites==1.4.0 - # via pytest attrs==20.3.0 # via - # -r requirements\build.in + # -r requirements/build.in # pytest bleach==3.3.0 # via readme-renderer build==0.3.1.post1 - # via -r requirements\build.in + # via -r requirements/build.in certifi==2020.12.5 # via # pipenv # requests +cffi==1.14.5 + # via cryptography cfgv==3.2.0 # via pre-commit chardet==3.0.4 # via - # -r requirements\build.in + # -r requirements/build.in # requests click==7.1.2 # via # flask # pip-tools colorama==0.4.4 - # via - # pytest - # twine + # via twine +cryptography==3.4.7 + # via secretstorage distlib==0.3.1 # via virtualenv docutils==0.17 # via - # -r requirements\build.in + # -r requirements/build.in # readme-renderer filelock==3.0.12 # via virtualenv flask-db==0.3.1 - # via -r requirements\tests.in + # via -r requirements/tests.in flask-fixtures==0.3.8 - # via -r requirements\tests.in + # via -r requirements/tests.in flask-sqlalchemy==2.4.4 # via # flask-db @@ -65,7 +65,7 @@ flask==1.1.2 # pytest-flask identify==2.2.2 # via - # -r requirements\build.in + # -r requirements/build.in # pre-commit idna==2.10 # via requests @@ -81,6 +81,10 @@ jaraco.context==4.0.0 # via pytest-enabler jaraco.functools==3.2.1 # via pytest-enabler +jeepney==0.6.0 + # via + # keyring + # secretstorage jinja2==2.11.3 # via flask keyring==23.0.1 @@ -101,23 +105,23 @@ nodeenv==1.5.0 # via pre-commit packaging==20.9 # via - # -r requirements\build.in + # -r requirements/build.in # bleach # build # pytest # pytest-flask-sqlalchemy pbr==3.1.1 - # via -r requirements\build.in + # via -r requirements/build.in pep517==0.10.0 # via - # -r requirements\build.in + # -r requirements/build.in # build pip-licenses==3.3.0 - # via -r requirements\build.in + # via -r requirements/build.in pip-tools==5.5.0 - # via -r requirements\build.in + # via -r requirements/build.in pipenv==2020.11.15 - # via -r requirements\build.in + # via -r requirements/build.in pkginfo==1.7.0 # via twine pluggy==0.13.1 @@ -125,42 +129,44 @@ pluggy==0.13.1 port-for==0.4 # via pytest-postgresql pre-commit==2.10.1 - # via -r requirements\build.in + # via -r requirements/build.in psutil==5.8.0 # via mirakuru ptable==0.9.2 # via pip-licenses py==1.10.0 # via - # -r requirements\build.in + # -r requirements/build.in # pytest pyaml==20.4.0 # via pytoolbox +pycparser==2.20 + # via cffi pygments==2.8.1 # via - # -r requirements\build.in + # -r requirements/build.in # readme-renderer pyparsing==2.4.7 # via - # -r requirements\build.in + # -r requirements/build.in # packaging pytest-enabler==1.2.0 - # via -r requirements\tests.in + # via -r requirements/tests.in pytest-flask-sqlalchemy==1.0.2 - # via -r requirements\tests.in + # via -r requirements/tests.in pytest-flask==1.2.0 - # via -r requirements\tests.in + # via -r requirements/tests.in pytest-mock==3.5.1 # via pytest-flask-sqlalchemy pytest-postgresql==2.6.1 - # via -r requirements\tests.in + # via -r requirements/tests.in pytest-runner==5.3.0 - # via -r requirements\tests.in + # via -r requirements/tests.in pytest-venv==0.2.1 - # via -r requirements\tests.in + # via -r requirements/tests.in pytest==6.2.3 # via - # -r requirements\tests.in + # -r requirements/tests.in # pytest-flask # pytest-flask-sqlalchemy # pytest-mock @@ -169,19 +175,17 @@ pytest==6.2.3 python-dateutil==2.8.1 # via alembic python-dotenv==0.17.0 - # via -r requirements\build.in + # via -r requirements/build.in python-editor==1.0.4 # via alembic python-magic==0.4.22 # via pytoolbox pytoolbox==14.0.0 - # via -r requirements\build.in + # via -r requirements/build.in pytz==2020.5 # via - # -r requirements\build.in + # -r requirements/build.in # pytoolbox -pywin32-ctypes==0.2.0 - # via keyring pyyaml==5.4.1 # via # pre-commit @@ -197,9 +201,11 @@ requests==2.25.1 # twine rfc3986==1.4.0 # via twine +secretstorage==3.3.1 + # via keyring six==1.15.0 # via - # -r requirements\build.in + # -r requirements/build.in # bleach # flask-fixtures # python-dateutil @@ -217,7 +223,7 @@ sqlalchemy==1.3.23 # sqlalchemy-utils toml==0.10.2 # via - # -r requirements\build.in + # -r requirements/build.in # build # pep517 # pre-commit @@ -226,18 +232,18 @@ toml==0.10.2 tqdm==4.60.0 # via twine twine==3.4.1 - # via -r requirements\build.in + # via -r requirements/build.in urllib3==1.26.4 # via - # -r requirements\build.in + # -r requirements/build.in # requests venv-run==0.1.0 - # via -r requirements\build.in + # via -r requirements/build.in virtualenv-clone==0.5.4 # via pipenv virtualenv==20.4.3 # via - # -r requirements\build.in + # -r requirements/build.in # pipenv # pre-commit # pytest-venv @@ -248,7 +254,7 @@ werkzeug==1.0.1 # flask # pytest-flask wheel==0.36.2 - # via -r requirements\build.in + # via -r requirements/build.in zipp==3.4.1 # via importlib-metadata diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/config.py b/src/config.py index 02a4c965fbcfaf579014a57bf7149960ea5209a6..9fc4dff014590e4e93978a1aefbefed0a829544f 100644 --- a/src/config.py +++ b/src/config.py @@ -14,3 +14,6 @@ SQLALCHEMY_TRACK_MODIFICATIONS = True FLASK_ADMIN_SWATCH = 'superhero' FLASK_APP_DEBUGGER_ACTIVE = True PORT = 9090 +USER_ADMIN_LOGIN = 'admin@admin.de' +USER_ADMIN_USERNAME = 'admin' +USER_ADMIN_PASSWORD = 'pbkdf2:sha256:150000$O4SZaWF5$85ad348809215aa7fe0a16f79dc61228e7d0fb214c24df68b0745f1570ffc148' diff --git a/src/covid19/Gruntfile.js b/src/covid19/Gruntfile.js new file mode 100644 index 0000000000000000000000000000000000000000..a3cec32e26f7bfe65b5b893adc7cce546a82acd7 --- /dev/null +++ b/src/covid19/Gruntfile.js @@ -0,0 +1,60 @@ +module.exports = function(grunt) { + + // Project configuration. + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + uglify: { + options: { + banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n' + }, + build: { + src: 'src/<%= pkg.name %>.js', + dest: 'build/<%= pkg.name %>.min.js' + } + }, + versioning: { + doc: 'index.html', + files: { + css: [], + js: [], + hastype : 'date' + } + }, + sass: { + dist: { + files: { + 'node_modules/jquery-fancybox/source/css/jquery.fancybox.css': 'node_modules/jquery-fancybox/source/scss/jquery.fancybox.scss' + } + } + }, + copy: { + main: { + files: [ + {expand: true, cwd: 'node_modules/jquery/dist/', src: ['**'], dest: 'static/vendor/jquery'}, + {expand: true, cwd: 'node_modules/popper.js/dist/', src: ['**'], dest: 'static/vendor/popper.js'}, + {expand: true, cwd: 'node_modules/bootstrap/dist/', src: ['**'], dest: 'static/vendor/bootstrap'}, + {expand: true, cwd: 'node_modules/@fortawesome/fontawesome-free/', src: ['**'], dest: 'static/vendor/fontawesome-free'}, + {expand: true, cwd: 'node_modules/bootswatch/dist/', src: ['**'], dest: 'static/vendor/bootswatch'}, + ], + }, + }, + }); + + // Load the plugin that provides the "uglify" task. + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-contrib-sass'); + grunt.loadNpmTasks('grunt-contrib-less'); + grunt.loadNpmTasks('grunt-contrib-cssmin'); + grunt.loadNpmTasks('grunt-run-grunt'); + grunt.loadNpmTasks('grunt-contrib-versioning2'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-contrib-copy'); + + // Default task(s). + grunt.registerTask('default', ['copy']); + + // https://www.npmjs.com/package/grunt-contrib-copy + // https://www.npmjs.com/package/grunt-contrib-jshint + // https://www.npmjs.com/package/grunt-contrib-clean + // https://www.npmjs.com/package/grunt-contrib-sass +}; \ No newline at end of file diff --git a/src/covid19/__init__.py b/src/covid19/__init__.py index a2b7f3149d3a1a43b0a3df461f39665979c4c16c..5549a515b79e4aede461987f09bd7e18f59e47ac 100644 --- a/src/covid19/__init__.py +++ b/src/covid19/__init__.py @@ -1,13 +1,11 @@ -from database import app, run_run_with_debug, port +from database import app, run_run_with_debug, port, db import covid19.blueprints.application.application_views - +from covid19.blueprints.application.application_services import user_service +from covid19.blueprints.application.application_service import ApplicationService def run_web(): - app.logger.info(" ") - app.logger.info("#############################################################") - app.logger.info("# Covid19 Data - WEB #") - app.logger.info("#############################################################") - app.logger.info(" ") + application_service = ApplicationService(db, user_service) + application_service.prepare_run_web() app.run(debug=run_run_with_debug, port=port) diff --git a/src/covid19/blueprints/admin/admin_service.py b/src/covid19/blueprints/admin/admin_service.py index f35a29ce222e386cef671222f261bfe9412aa7cb..e5e6ab9e08cfd6ab51db88122765252ebca6632e 100644 --- a/src/covid19/blueprints/admin/admin_service.py +++ b/src/covid19/blueprints/admin/admin_service.py @@ -16,7 +16,9 @@ class AdminService: app.logger.info(" Admin Service [ready]") def task_database_drop_create(self): + app.logger.info(" AdminService.task_database_drop_create() [begin]") self.run_admin_database_dump() + app.logger.info(" AdminService.task_database_drop_create() [begin]") return self def run_admin_database_dump(self): @@ -53,6 +55,7 @@ class AdminService: return returncode def run_admin_database_dump_reimport(self): + flash(" run database dump reimport [begin]") app.logger.info(" run database dump reimport [begin]") app.logger.info("------------------------------------------------------------") user = app.config['SQLALCHEMY_POSTGRES_USER'] @@ -67,9 +70,10 @@ class AdminService: app.logger.info(msg) app.logger.info(" run database dump reimport [done]") app.logger.info("------------------------------------------------------------") + flash(" run database dump reimport [done]") return self - def run_admin_database_drop(self): + def run_admin_database_drop_and_create(self): app.logger.info(" run database drop and create [begin]") app.logger.info("------------------------------------------------------------") self.__database.drop_all() diff --git a/src/covid19/blueprints/admin/admin_views.py b/src/covid19/blueprints/admin/admin_views.py index 88f94557620ea16b2451bb6eea6661fe051ab384..53bbd704452c2cd5214bbf291ef4fbed4b2724b2 100644 --- a/src/covid19/blueprints/admin/admin_views.py +++ b/src/covid19/blueprints/admin/admin_views.py @@ -241,15 +241,17 @@ def url_admin_database_dump_reimport(): def url_admin_database_dropcreate_only(): app.logger.info("url_admin_database_drop [start]") flash("admin_service.run_admin_database_drop started") - admin_service.run_admin_database_drop() + admin_service.run_admin_database_drop_and_create() app.logger.info("url_admin_database_drop [done]") return redirect(url_for('app_admin.url_admin_tasks')) @app_admin.route('/database/drop') def url_admin_database_drop(): - app.logger.info("url_admin_database_drop [start]") - admin_service.run_admin_database_drop() + flash("url_admin_database_drop [start]") + app.logger.info("admin_service.run_admin_database_drop_and_create [start]") + admin_service.run_admin_database_drop_and_create() + app.logger.info("admin_service.run_admin_database_drop_and_create [done]") if drop_and_create_data_again: who_service.pretask_database_drop_create() ecdc_service.pretask_database_drop_create() diff --git a/src/covid19/blueprints/admin/templates/admin/admin_tasks.html b/src/covid19/blueprints/admin/templates/admin/admin_tasks.html index fccabeef4aa9af5637b613130193c5b1fdfd7fea..f4c149fea59f24e5b2b3c3b602a82b11e8dbf37a 100644 --- a/src/covid19/blueprints/admin/templates/admin/admin_tasks.html +++ b/src/covid19/blueprints/admin/templates/admin/admin_tasks.html @@ -33,6 +33,12 @@ href="{{ url_for( 'app_admin.url_admin_index') }}" role="button">Admin :: database :: Flask Admin</a> </div> + <p></p> + <div class="btn-group-vertical" role="group" aria-label="Views"> + <a class="btn btn-primary btn-lg btn-block text-left" + href="{{ url_for( 'who.url_who_mytest') }}" + role="button">WHO :: url_who_mytest</a> + </div> </div> <div class="col"> <div class="btn-group-vertical" role="group" aria-label="Views"> diff --git a/src/covid19/blueprints/application/application_model.py b/src/covid19/blueprints/application/application_model.py index 36b4451cd77f28c09cb7640fd7769cbd10ad871a..7af9a69eb40f267c29a863971f134d42eb1f2bdd 100644 --- a/src/covid19/blueprints/application/application_model.py +++ b/src/covid19/blueprints/application/application_model.py @@ -7,11 +7,11 @@ from sqlalchemy.orm import joinedload class ApplicationDateReported(db.Model): __tablename__ = 'application_datereported' __table_args__ = ( - db.UniqueConstraint('date_reported', 'datum', name="uix_application_datereported"), + db.UniqueConstraint('date_reported_import_str', 'datum', name="uix_application_datereported"), ) # id = db.Column(db.Integer, primary_key=True) - date_reported = db.Column(db.String(255), nullable=False, unique=True) + date_reported_import_str = db.Column(db.String(255), nullable=False, unique=True) year_week = db.Column(db.String(255), nullable=False) datum = db.Column(db.Date, nullable=False, unique=True) year = db.Column(db.Integer, nullable=False) @@ -83,12 +83,12 @@ class ApplicationDateReported(db.Model): @classmethod def create_new_object_factory(cls, my_date_rep: str): (my_year, my_month, my_day) = cls.get_datum_parts(my_date_rep) - date_reported = cls.get_datum_as_str(my_year, my_month, my_day) + date_reported_import_str = cls.get_datum_as_str(my_year, my_month, my_day) my_datum = cls.get_datum(my_year, my_month, my_day) (my_iso_year, week_number, weekday) = my_datum.isocalendar() my_year_week = cls.my_year_week(my_iso_year, week_number) return ApplicationDateReported( - date_reported=date_reported, + date_reported_import_str=date_reported_import_str, datum=my_datum, year=my_datum.year, month=my_datum.month, @@ -108,7 +108,7 @@ class ApplicationDateReported(db.Model): @classmethod def get_all_as_page(cls, page: int): return db.session.query(cls)\ - .order_by(cls.date_reported.desc())\ + .order_by(cls.date_reported_import_str.desc())\ .paginate(page, per_page=ITEMS_PER_PAGE) @classmethod @@ -119,7 +119,7 @@ class ApplicationDateReported(db.Model): def get_all_as_dict(cls): dates_reported = {} for my_date_reported in cls.get_all(): - dates_reported[my_date_reported.date_reported] = my_date_reported + dates_reported[my_date_reported.date_reported_import_str] = my_date_reported return dates_reported @classmethod @@ -137,13 +137,13 @@ class ApplicationDateReported(db.Model): @classmethod def get_by_date_reported(cls, p_date_reported: str): return db.session.query(cls)\ - .filter(cls.date_reported == p_date_reported)\ + .filter(cls.date_reported_import_str == p_date_reported)\ .one() @classmethod def find_by_date_reported(cls, p_date_reported: str): return db.session.query(cls)\ - .filter(cls.date_reported == p_date_reported)\ + .filter(cls.date_reported_import_str == p_date_reported)\ .one_or_none() @classmethod @@ -158,6 +158,11 @@ class ApplicationDateReported(db.Model): .filter(cls.year_week == year_week)\ .one_or_none() + @classmethod + def get_joungest_datum(cls): + return db.session.query(cls)\ + .order_by(cls.date_reported_import_str.desc())\ + .first() class ApplicationRegion(db.Model): __tablename__ = 'application_region' diff --git a/src/covid19/blueprints/application/application_service.py b/src/covid19/blueprints/application/application_service.py index 8ea7186e68593138affb649f1b87c849de6554ec..b5b4557719c1f59855a8db7c49f527514edf0c2d 100644 --- a/src/covid19/blueprints/application/application_service.py +++ b/src/covid19/blueprints/application/application_service.py @@ -1,11 +1,36 @@ from database import app - class ApplicationService: - def __init__(self, database): + def __init__(self, database, user_service): app.logger.debug("------------------------------------------------------------") - app.logger.debug(" Common Service [init]") + app.logger.debug(" Application Service [init]") app.logger.debug("------------------------------------------------------------") self.__database = database + self.__user_service = user_service app.logger.debug("------------------------------------------------------------") - app.logger.info(" Common Service [ready]") + app.logger.info(" Application Service [ready]") + + def prepare_run_web(self): + app.logger.info(" ") + app.logger.info("#############################################################") + app.logger.info("# Covid19 Data - WEB #") + app.logger.info("#############################################################") + app.logger.info(" ") + self.__user_service.prepare_default_user_login() + app.logger.info(" ") + + def prepare_run_mq(self): + app.logger.info(" ") + app.logger.info("#############################################################") + app.logger.info("# Covid19 Data - MQ (Celery WORKER) #") + app.logger.info("#############################################################") + app.logger.info(" ") + self.__user_service.prepare_default_user_login() + app.logger.info(" ") + + def prepare_start_redis(selfs): + my_app.logger.info("-------------------------------------------------------------") + my_app.logger.info("# start REDIS-Server #") + my_app.logger.info("-------------------------------------------------------------") + + diff --git a/src/covid19/blueprints/application/application_services.py b/src/covid19/blueprints/application/application_services.py index 276c3581b647def8474903d39ae774134a10998b..4c13000b2a3e9da2057c49ff8ceecdc308515582 100644 --- a/src/covid19/blueprints/application/application_services.py +++ b/src/covid19/blueprints/application/application_services.py @@ -1,7 +1,6 @@ from database import db from covid19.blueprints.admin.admin_service import AdminService -from covid19.blueprints.application.application_service import ApplicationService from covid19.blueprints.ecdc.ecdc_service import EcdcService from covid19.blueprints.owid.owid_service import OwidService from covid19.blueprints.rki.rki_bundeslaender.rki_bundeslaender_service import RkiBundeslaenderService @@ -16,7 +15,6 @@ from covid19.blueprints.user.user_service import UserService # Services # admin_service = AdminService(db) -application_service = ApplicationService(db) ecdc_service = EcdcService(db) owid_service = OwidService(db) rki_service_bundeslaender = RkiBundeslaenderService(db) diff --git a/src/covid19/blueprints/application/application_views.py b/src/covid19/blueprints/application/application_views.py index c6c0cd78a51d1a6d070ba45e91219a22b40944f2..a3e7886cd7014e505e6f58b2abe10ecaa7dc10da 100644 --- a/src/covid19/blueprints/application/application_views.py +++ b/src/covid19/blueprints/application/application_views.py @@ -1,17 +1,8 @@ from flask import render_template, redirect, url_for, Blueprint -from flask_admin.contrib.sqla import ModelView -from database import app, admin, db +from database import app from covid19.blueprints.application.application_model_transient import ApplicationPage -import covid19.blueprints.admin.admin_views -import covid19.blueprints.ecdc.ecdc_views -import covid19.blueprints.rki.rki_bundeslaender.rki_bundeslaender_views -import covid19.blueprints.rki.rki_landkreise.rki_landkreise_views -import covid19.blueprints.rki.rki_vaccination.rki_vaccination_views -import covid19.blueprints.who.who_views - - from covid19.blueprints.admin.admin_views import app_admin from covid19.blueprints.ecdc.ecdc_views import app_ecdc from covid19.blueprints.rki.rki_bundeslaender.rki_bundeslaender_views import app_rki_bundeslaender @@ -21,6 +12,10 @@ from covid19.blueprints.who.who_views import app_who from covid19.blueprints.owid.owid_views import app_owid from covid19.blueprints.user.user_views import app_user + +from covid19.blueprints.owid_test.owid_test_views import app_owid_test +from covid19.blueprints.who_test.who_test_views import app_who_test + app_application = Blueprint('application', __name__, template_folder='templates', url_prefix='/') app.register_blueprint(app_admin, url_prefix='/admin') @@ -33,6 +28,8 @@ app.register_blueprint(app_who, url_prefix='/who') app.register_blueprint(app_owid, url_prefix='/owid') app.register_blueprint(app_user, url_prefix='/usr') +app.register_blueprint(app_owid_test, url_prefix='/owid/test') +app.register_blueprint(app_who_test, url_prefix='/who/test') ############################################################################################ # diff --git a/src/covid19/blueprints/application/application_workers.py b/src/covid19/blueprints/application/application_workers.py index 8cc054ce26228f807efae76764c523513147dc56..f6809d65d8715e1919cca9294a93811ffa38cd4f 100644 --- a/src/covid19/blueprints/application/application_workers.py +++ b/src/covid19/blueprints/application/application_workers.py @@ -1,21 +1,17 @@ import sys import subprocess from covid19 import app -from database import create_celery, run_run_with_debug, port - +from database import create_celery, run_run_with_debug, port, db +from covid19.blueprints.application.application_services import user_service +from covid19.blueprints.application.application_service import ApplicationService def run_mq(my_app, my_celery): + application_service = ApplicationService(db, user_service) if sys.platform != 'linux': - my_app.logger.info("-------------------------------------------------------------") - #my_app.logger.info("# start REDIS-Server #") - #my_app.logger.info("-------------------------------------------------------------") - #redis_cmd = ['redis-server'] - #subprocess.Popen(redis_cmd, shell=True) - my_app.logger.info(" ") - my_app.logger.info("#############################################################") - my_app.logger.info("# Covid19 Data - WORKER #") - my_app.logger.info("#############################################################") - my_app.logger.info(" ") + application_service.prepare_start_redis() + redis_cmd = ['redis-server'] + # subprocess.Popen(redis_cmd, shell=True) + application_service.prepare_run_mq() args = ['worker', '-l', 'INFO'] my_celery.start(args) diff --git a/src/covid19/blueprints/ecdc/ecdc_model.py b/src/covid19/blueprints/ecdc/ecdc_model.py index 97b2912e2737635b711e2158c77ba79273b4895b..055aac10dff6b609fd8759f6efa140fd8484e49b 100644 --- a/src/covid19/blueprints/ecdc/ecdc_model.py +++ b/src/covid19/blueprints/ecdc/ecdc_model.py @@ -8,11 +8,11 @@ class EcdcDateReported(ApplicationDateReported): __tablename__ = 'ecdc_datereported' __mapper_args__ = {'concrete': True} __table_args__ = ( - db.UniqueConstraint('date_reported', 'datum', name="uix_ecdc_datereported"), + db.UniqueConstraint('date_reported_import_str', 'datum', name="uix_ecdc_datereported"), ) id = db.Column(db.Integer, primary_key=True) - date_reported = db.Column(db.String(255), nullable=False, unique=True) + date_reported_import_str = db.Column(db.String(255), nullable=False, unique=True) year_week = db.Column(db.String(255), nullable=False) datum = db.Column(db.Date, nullable=False, unique=True) year = db.Column(db.Integer, nullable=False) @@ -22,10 +22,10 @@ class EcdcDateReported(ApplicationDateReported): week_of_year = db.Column(db.Integer, nullable=False) def get_name_for_datum(self): - return self.date_reported + return self.date_reported_import_str def get_date_import_format_from_date_reported(self): - my_date_parts = self.date_reported.split("-") + my_date_parts = self.date_reported_import_str.split("-") my_year = my_date_parts[0] my_month = my_date_parts[1] my_day = my_date_parts[2] @@ -59,12 +59,12 @@ class EcdcDateReported(ApplicationDateReported): @classmethod def create_new_object_factory(cls, my_date_rep: str): (my_year, my_month, my_day) = cls.get_datum_parts(my_date_rep) - date_reported = super().get_datum_as_str(my_year, my_month, my_day) + date_reported_import_str = super().get_datum_as_str(my_year, my_month, my_day) my_datum = super().get_datum(my_year, my_month, my_day) (my_iso_year, week_number, weekday) = my_datum.isocalendar() my_year_week = super().my_year_week(my_iso_year, week_number) return EcdcDateReported( - date_reported=date_reported, + date_reported_import_str=date_reported_import_str, datum=my_datum, year=my_datum.year, month=my_datum.month, @@ -195,15 +195,17 @@ class EcdcData(db.Model): ecdc_country_id = db.Column(db.Integer, db.ForeignKey('ecdc_country.id'), nullable=False) ecdc_country = db.relationship( 'EcdcCountry', - lazy='subquery', cascade="all, delete", + lazy='subquery', + cascade='save-update', order_by='asc(EcdcCountry.countries_and_territories)' ) ecdc_datereported_id = db.Column(db.Integer, db.ForeignKey('ecdc_datereported.id'), nullable=False) ecdc_datereported = db.relationship( 'EcdcDateReported', - lazy='joined', cascade='all, delete', - order_by='desc(EcdcDateReported.date_reported)' + lazy='joined', + cascade='save-update', + order_by='desc(EcdcDateReported.date_reported_import_str)' ) @classmethod diff --git a/src/covid19/blueprints/ecdc/ecdc_service.py b/src/covid19/blueprints/ecdc/ecdc_service.py index 1cd1b35c4bf231b1a7e47e3c35f5570a63d0e250..ead68848378b39a1165fb374309cb7712fd70fb2 100644 --- a/src/covid19/blueprints/ecdc/ecdc_service.py +++ b/src/covid19/blueprints/ecdc/ecdc_service.py @@ -22,12 +22,17 @@ class EcdcService: def pretask_database_drop_create(self): flash("ecdc_service.download started") + app.logger.info("ecdc_service.download started") self.service_download.download_file() + app.logger.info("ecdc_service.download done") + flash("ecdc_service.download done") return self def task_database_drop_create(self): + app.logger.info("ecdc_service.task_database_drop_create started") self.service_import.import_file() self.service_update.update_star_schema_initial() + app.logger.info("ecdc_service.task_database_drop_create done") return self def run_download_only(self): diff --git a/src/covid19/blueprints/ecdc/ecdc_service_import.py b/src/covid19/blueprints/ecdc/ecdc_service_import.py index 875e0bf97e484bb605c3eb4cadcbac82ef63a3ae..a56b1a666004845b33d2f5cc6d1162abe4587450 100644 --- a/src/covid19/blueprints/ecdc/ecdc_service_import.py +++ b/src/covid19/blueprints/ecdc/ecdc_service_import.py @@ -44,7 +44,7 @@ class EcdcServiceImport: ) db.session.add(o) k = k + 1 - if (k % 500) == 0: + if (k % 1000) == 0: db.session.commit() app.logger.info(" import ECDC ... " + str(k) + " rows") db.session.commit() diff --git a/src/covid19/blueprints/ecdc/ecdc_service_update.py b/src/covid19/blueprints/ecdc/ecdc_service_update.py index 63fa8a2126e7c4cf50e6a1dba39da0a424a19cf9..363462c94037e6cd5baed351aedb2621a291a300 100644 --- a/src/covid19/blueprints/ecdc/ecdc_service_update.py +++ b/src/covid19/blueprints/ecdc/ecdc_service_update.py @@ -167,7 +167,7 @@ class EcdcServiceUpdate: ) db.session.add(o) i += 1 - if i % 500 == 0: + if i % 1000 == 0: app.logger.info(" update EDCD initial ... " + str(i) + " rows") db.session.commit() db.session.commit() diff --git a/src/covid19/blueprints/owid/owid_model.py b/src/covid19/blueprints/owid/owid_model.py index 0c57f6a68558d9aed82967cce1b038917a1cf419..e9b03ad3d34a2d67bd2563ce7d74ec765f6ef3dd 100644 --- a/src/covid19/blueprints/owid/owid_model.py +++ b/src/covid19/blueprints/owid/owid_model.py @@ -1,7 +1,9 @@ from sqlalchemy import and_, func from datetime import date +from sqlalchemy.orm import joinedload, load_only, defaultload, defer, undefer, query_expression, subqueryload +from sqlalchemy.sql import select + from database import db, ITEMS_PER_PAGE -from sqlalchemy.orm import joinedload from covid19.blueprints.application.application_model import ApplicationDateReported, ApplicationRegion @@ -9,11 +11,11 @@ class OwidDateReported(ApplicationDateReported): __tablename__ = 'owid_datereported' __mapper_args__ = {'concrete': True} __table_args__ = ( - db.UniqueConstraint('date_reported', 'datum', name="uix_owid_datereported"), + db.UniqueConstraint('date_reported_import_str', 'datum', name="uix_owid_datereported"), ) id = db.Column(db.Integer, primary_key=True) - date_reported = db.Column(db.String(255), nullable=False, unique=True) + date_reported_import_str = db.Column(db.String(255), nullable=False, unique=True) year_week = db.Column(db.String(255), nullable=False) datum = db.Column(db.Date, nullable=False, unique=True) year = db.Column(db.Integer, nullable=False) @@ -33,7 +35,7 @@ class OwidDateReported(ApplicationDateReported): my_year_week += "-" my_year_week += str(week_number) return OwidDateReported( - date_reported=my_date_rep, + date_reported_import_str=my_date_rep, datum=my_datum, year=my_datum.year, month=my_datum.month, @@ -64,7 +66,7 @@ class OwidCountry(db.Model): continent = db.relationship( 'OwidContinent', lazy='joined', - cascade='all, delete', + cascade='save-update', order_by='desc(OwidContinent.region)') iso_code = db.Column(db.String(255), nullable=False) location = db.Column(db.String(255), nullable=False) @@ -137,14 +139,14 @@ class OwidData(db.Model): date_reported = db.relationship( 'OwidDateReported', lazy='joined', - cascade='all, delete', - order_by='desc(OwidDateReported.date_reported)') + cascade='save-update', + order_by='desc(OwidDateReported.date_reported_import_str)') country_id = db.Column(db.Integer, db.ForeignKey('owid_country.id'), nullable=False) country = db.relationship( 'OwidCountry', lazy='joined', - cascade='all, delete', + cascade='save-update', order_by='desc(OwidCountry.location)') total_cases = db.Column(db.String(255), nullable=False) new_cases = db.Column(db.String(255), nullable=False) @@ -231,16 +233,54 @@ class OwidData(db.Model): @classmethod def get_data_for_day_order_by_deaths_new(cls, date_reported, page): + # TODO pass @classmethod def get_data_for_day_order_by_deaths_cumulative(cls, date_reported, page): + # TODO pass @classmethod def get_data_for_day_order_by_cases_cumulative(cls, date_reported, page): + # TODO pass @classmethod def get_data_for_day_order_by_cases_new(cls, date_reported, page): + # TODO pass + + @classmethod + def get_data_for_one_day(cls, date_reported): + return db.session.query(cls).filter( + cls.date_reported_id == date_reported.id + ).populate_existing().options( + joinedload(cls.country).joinedload(OwidCountry.continent), + joinedload(cls.date_reported) + ).order_by( + cls.new_deaths.desc(), + cls.new_cases.desc(), + cls.new_deaths_per_million.desc(), + cls.new_cases_per_million.desc() + ).all() + + @classmethod + def get_datum_of_all_data(cls): + datum_of_all_who_data = [] + for data in db.session.query(cls).options(subqueryload("date_reported").load_only("date_reported_import_str")): + datum = data.date_reported.date_reported_import_str + if not datum in datum_of_all_who_data: + datum_of_all_who_data.append(datum) + datum_of_all_who_data.sort() + return datum_of_all_who_data + + @classmethod + def get_joungest_datum(cls): + return cls.get_datum_of_all_data().pop() + + @classmethod + def delete_data_for_one_day(cls, date_reported): + for data in cls.get_data_for_one_day(date_reported): + db.session.delete(data) + db.session.commit() diff --git a/src/covid19/blueprints/owid/owid_model_import.py b/src/covid19/blueprints/owid/owid_model_import.py index 332aef1d66eef1bb2fda2ec92032ad0a50863a04..d3b47020e7b3d2fdaabea376cad0f6b4e26f0ba7 100644 --- a/src/covid19/blueprints/owid/owid_model_import.py +++ b/src/covid19/blueprints/owid/owid_model_import.py @@ -1,3 +1,7 @@ +from sqlalchemy.orm import Load +from sqlalchemy import func +from sqlalchemy.orm import Bundle +from sqlalchemy.orm.strategy_options import load_only from database import db, ITEMS_PER_PAGE @@ -124,6 +128,10 @@ class OwidImport(db.Model): def get_new_dates_reported_as_array(cls): return cls.get_dates_reported_as_array() + @classmethod + def get_datum_of_all_import(cls): + return cls.get_dates_reported_as_array() + @classmethod def get_continents(cls, page): return db.session.query(cls.continent)\ @@ -131,3 +139,8 @@ class OwidImport(db.Model): .distinct()\ .order_by(cls.continent.asc())\ .paginate(page, per_page=ITEMS_PER_PAGE) + + @classmethod + def countries(cls): + bu = Bundle('countries', cls.iso_code, cls.location, cls.continent) + return db.session.query(bu).distinct() diff --git a/src/covid19/blueprints/owid/owid_service.py b/src/covid19/blueprints/owid/owid_service.py index 9e0d20b193e290c6e1a8a01029812c952ae88cef..524c5ef007dae9417ad84f1a501585973266e008 100644 --- a/src/covid19/blueprints/owid/owid_service.py +++ b/src/covid19/blueprints/owid/owid_service.py @@ -23,14 +23,19 @@ class OwidService: def pretask_database_drop_create(self): flash("OwidService.pretask_database_drop_create started") + app.logger.info("OwidService.pretask_database_drop_create started") self.service_download.download_file() + app.logger.info("OwidService.pretask_database_drop_create done") + flash("OwidService.pretask_database_drop_create done") return self def task_database_drop_create(self): + app.logger.info("OwidService.task_database_drop_create started") self.service_import.import_file() # TODO #212 implement OwidService.task_database_drop_create() self.service_update.update_dimension_tables_only() self.service_update.update_fact_table_incremental_only() + app.logger.info("OwidService.task_database_drop_create done") return self #def run_download_only(self): diff --git a/src/covid19/blueprints/owid/owid_service_update.py b/src/covid19/blueprints/owid/owid_service_update.py index 88915cbf5623fed719fb66d36e401e2ec1a8bfb3..7b36061410ce3636c3e7cd4060e533511dc816a4 100644 --- a/src/covid19/blueprints/owid/owid_service_update.py +++ b/src/covid19/blueprints/owid/owid_service_update.py @@ -14,9 +14,19 @@ class OwidServiceUpdate: app.logger.debug("------------------------------------------------------------") app.logger.debug(" OWID Service Update [ready]") + def who_import_get_new_dates_as_array(self): + new_dates_reported_from_import = [] + list_datum_of_all_data = OwidData.get_datum_of_all_data() + for item in OwidImport.get_datum_of_all_import(): + if not item in list_datum_of_all_data: + new_dates_reported_from_import.append(item) + return new_dates_reported_from_import + def __update_date_reported(self): app.logger.info(" __update_date_reported [begin]") app.logger.info("------------------------------------------------------------") + OwidData.remove_all() + OwidDateReported.remove_all() i = 0 for i_date_reported, in OwidImport.get_dates(): i += 1 @@ -38,7 +48,8 @@ class OwidServiceUpdate: def __update_fact_table_incremental(self): app.logger.info(" __update_fact_tables_incremental [begin]") app.logger.info("------------------------------------------------------------") - new_dates_reported_from_import = OwidImport.get_new_dates_reported_as_array() + #new_dates_reported_from_import = OwidImport.get_new_dates_reported_as_array() + new_dates_reported_from_import = self.who_import_get_new_dates_as_array() i = 0 for my_date_reported in new_dates_reported_from_import: my_OwidDateReported = OwidDateReported.find_by_date_reported(my_date_reported) diff --git a/src/covid19/blueprints/owid/templates/owid/navigation/owid_navtabs.html b/src/covid19/blueprints/owid/templates/owid/navigation/owid_navtabs.html index 00cf32bbcb7b07b4407009f0f3b10cde11b1c89d..f63c40cad8c29f9e9e83bf99f9bf2e60132739bd 100644 --- a/src/covid19/blueprints/owid/templates/owid/navigation/owid_navtabs.html +++ b/src/covid19/blueprints/owid/templates/owid/navigation/owid_navtabs.html @@ -14,6 +14,12 @@ href="{{ url_for( 'owid.url_owid_tasks') }}">OWID tasks</a> </li> {% endif %} + {% if current_user.is_authenticated %} + <li class="nav-item"> + <a class="nav-link" + href="{{ url_for( 'owid_test.url_owid_test_tests') }}">OWID Tests</a> + </li> + {% endif %} <li class="nav-item"> <a class="nav-link" href="{{ url_for( 'owid.url_owid_date_reported_all') }}">OWID Date Reported</a> diff --git a/src/covid19/blueprints/owid/templates/owid/owid_tasks.html b/src/covid19/blueprints/owid/templates/owid/owid_tasks.html index 8f20a561db11dd023e897c8f50c7bb47d2f02747..239be8c387edff3c5c39c25563d461f429f35b80 100644 --- a/src/covid19/blueprints/owid/templates/owid/owid_tasks.html +++ b/src/covid19/blueprints/owid/templates/owid/owid_tasks.html @@ -18,16 +18,16 @@ </div> <div class="col"> <div class="btn-group-vertical" role="group" aria-label="Views"> - <a class="btn btn-secondary btn-lg btn-block text-left" + <a class="btn btn-success btn-lg btn-block text-left" href="{{ url_for( 'owid.url_task_owid_download_only') }}" role="button">OWID :: Task :: download :: only</a> - <a class="btn btn-secondary btn-lg btn-block text-left" + <a class="btn btn-info btn-lg btn-block text-left" href="{{ url_for( 'owid.url_task_owid_import_only') }}" role="button">OWID :: Task :: import :: only</a> - <a class="btn btn-secondary btn-lg btn-block text-left" + <a class="btn btn-warning btn-lg btn-block text-left" href="{{ url_for( 'owid.url_task_owid_update_dimension_tables_only') }}" role="button">OWID :: Task :: update :: dimension-tables : only</a> - <a class="btn btn-secondary btn-lg btn-block text-left" + <a class="btn btn-danger btn-lg btn-block text-left" href="{{ url_for( 'owid.url_task_owid_update_fact_table_incremental_only') }}" role="button">OWID :: Task :: update :: fact-table :: only :: incremental</a> <a class="btn btn-secondary btn-lg btn-block text-left" diff --git a/src/covid19/blueprints/owid_test/__init__.py b/src/covid19/blueprints/owid_test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/covid19/blueprints/owid_test/owid_test_service.py b/src/covid19/blueprints/owid_test/owid_test_service.py new file mode 100644 index 0000000000000000000000000000000000000000..9640cb2c712deda87607b60798a8a9cbeebaaa2f --- /dev/null +++ b/src/covid19/blueprints/owid_test/owid_test_service.py @@ -0,0 +1,50 @@ +from flask import flash + +from database import app + +from covid19.blueprints.application.application_service_config import ApplicationServiceConfig +from covid19.blueprints.application.application_service_download import ApplicationServiceDownload +from covid19.blueprints.owid.owid_service_import import OwidServiceImport +from covid19.blueprints.owid.owid_service_update import OwidServiceUpdate +from covid19.blueprints.owid.owid_model import OwidDateReported, OwidContinent, OwidCountry, OwidData + + +class OwidTestService: + def __init__(self, database, owid_service): + app.logger.debug("------------------------------------------------------------") + app.logger.debug(" OwidTestService [init]") + app.logger.debug("------------------------------------------------------------") + self.__database = database + self.__owid_service = owid_service + self.cfg = ApplicationServiceConfig.create_config_for_owid() + app.logger.debug("------------------------------------------------------------") + app.logger.info(" OwidTestService [ready]") + + def delete_last_day(self): + app.logger.debug("------------------------------------------------------------") + app.logger.debug(" OwidTestService.delete_last_day() [START]") + app.logger.debug("------------------------------------------------------------") + joungest_datum_str = OwidData.get_joungest_datum() + joungest_datum = OwidDateReported.find_by_date_reported(joungest_datum_str) + app.logger.info("joungest_datum:") + app.logger.info(joungest_datum) + app.logger.info("WhoData.get_data_for_one_day(joungest_datum):") + i = 0 + for data in OwidData.get_data_for_one_day(joungest_datum): + i += 1 + line = " | " + str(i) + " | " + str(data.date_reported) + " | " + data.country.location + " | to be deleted" + app.logger.info(line) + app.logger.info("WhoData.delete_data_for_one_day(joungest_datum)") + OwidData.delete_data_for_one_day(joungest_datum) + app.logger.debug("------------------------------------------------------------") + app.logger.debug(" OwidTestService.delete_last_day() [DONE]") + app.logger.debug("------------------------------------------------------------") + + def run_update_star_schema_incremental(self): + app.logger.debug("------------------------------------------------------------") + app.logger.debug(" OwidTestService.run_update_star_schema_incremental() [START]") + app.logger.debug("------------------------------------------------------------") + self.__owid_service.run_update_star_schema_incremental() + app.logger.debug("------------------------------------------------------------") + app.logger.debug(" OwidTestService.run_update_star_schema_incremental() [DONE]") + app.logger.debug("------------------------------------------------------------") diff --git a/src/covid19/blueprints/owid_test/owid_test_views.py b/src/covid19/blueprints/owid_test/owid_test_views.py new file mode 100644 index 0000000000000000000000000000000000000000..00837ed80fe8378ede9a14e1729c61cd60165533 --- /dev/null +++ b/src/covid19/blueprints/owid_test/owid_test_views.py @@ -0,0 +1,182 @@ +from flask import render_template, redirect, url_for, flash, Blueprint +from sqlalchemy.exc import OperationalError +from celery import states +from celery.utils.log import get_task_logger +from flask_admin.contrib.sqla import ModelView +from flask_login import login_required + +from database import app, admin, db +from covid19.blueprints.application.application_services import owid_service +from covid19.blueprints.application.application_workers import celery +from covid19.blueprints.owid.owid_model import OwidDateReported, OwidData, OwidContinent, OwidCountry +from covid19.blueprints.owid.owid_model_import import OwidImport +from covid19.blueprints.application.application_model_transient import ApplicationPage + +from covid19.blueprints.owid_test.owid_test_service import OwidTestService + +owid_test_service = OwidTestService(db, owid_service) + +app_owid_test = Blueprint('owid_test', __name__, template_folder='templates', url_prefix='/owid/test') + +# --------------------------------------------------------------------------------------------------------------- +# Url Routes Frontend +# --------------------------------------------------------------------------------------------------------------- + +@app_owid_test.route('/tests') +@login_required +def url_owid_test_tests(): + page_info = ApplicationPage('OWID', "Tests") + return render_template( + 'owid_test/owid_tests.html', + page_info=page_info) + +@app_owid_test.route('/update_dimension_tables_only') +@login_required +def url_owid_test_update_dimension_tables_only(): + app.logger.info("test_update_dimension_tables_only - START") + flash("test_update_dimension_tables_only - START") + return redirect(url_for('owid_test.url_owid_test_tests')) + +@app_owid_test.route('/update_fact_table_incremental_only') +@login_required +def url_owid_test_update_fact_table_incremental_only(): + app.logger.info("update_fact_table_incremental_only - START") + flash("update_fact_table_incremental_only - START") + return redirect(url_for('owid_test.url_owid_test_tests')) + +@app_owid_test.route('/update_fact_table_initial_only') +@login_required +def url_owid_test_update_fact_table_initial_only(): + app.logger.info("update_fact_table_initial_only - START") + flash("update_fact_table_initial_only - START") + return redirect(url_for('owid_test.url_owid_test_tests')) + +@app_owid_test.route('/update_star_schema/incremental') +@login_required +def url_owid_test_update_star_schema_incremental(): + app.logger.info("update_star_schema_incremental - START") + flash("update_star_schema_incremental - START") + return redirect(url_for('owid_test.url_owid_test_tests')) + +@app_owid_test.route('/update_star_schema/initial') +@login_required +def url_owid_test_update_star_schema_initial(): + app.logger.info("update_star_schema_initial - START") + flash("update_star_schema_initial - START") + return redirect(url_for('owid_test.url_owid_test_tests')) + + +@app_owid_test.route('/owid_import/countries') +@login_required +def url_owid_test_owid_import_countries(): + app.logger.info("url_owid_test_owid_import_countries - START") + flash("url_owid_test_owid_import_countries - START") + i = 0 + for c in OwidImport.countries(): + i += 1 + line = " | " + str(i) + " | " + c.countries.iso_code + " | " + c.countries.location + " | " + c.countries.continent + " | " + app.logger.info(line) + app.logger.info("url_owid_test_owid_import_countries - DONE") + flash("url_owid_test_owid_import_countries - DONE") + return redirect(url_for('owid_test.url_owid_test_tests')) + + +@app_owid_test.route('/owid_import/get_new_dates_as_array') +@login_required +def url_owid_test_owid_import_get_new_dates_as_array(): + app.logger.info("url_owid_test_owid_import_get_new_dates_as_array - START") + flash("url_owid_test_owid_import_get_new_dates_as_array - START") + i = 0 + for date_reported in OwidImport.get_new_dates_reported_as_array(): + i += 1 + line = " | " + str(i) + " | " + date_reported + " | " + app.logger.info(line) + app.logger.info("url_owid_test_owid_import_get_new_dates_as_array - DONE") + flash("url_owid_test_owid_import_get_new_dates_as_array - DONE") + return redirect(url_for('owid_test.url_owid_test_tests')) + + +@app_owid_test.route('/owid_data/get_datum_of_all_owid_data') +@login_required +def url_owid_test_owid_data_get_datum_of_all_owid_data(): + app.logger.info("url_owid_test_owid_data_get_datum_of_all_owid_data - START") + flash("url_owid_test_owid_data_get_datum_of_all_owid_data - START") + for datum in OwidData.get_datum_of_all_data(): + app.logger.info(str(datum)) + app.logger.info("url_owid_test_owid_data_get_datum_of_all_owid_data - DONE") + flash("url_owid_test_owid_data_get_datum_of_all_owid_data - DONE") + return redirect(url_for('owid_test.url_owid_test_tests')) + + +@app_owid_test.route('/owid_data/update_star_schema_initial') +@login_required +def url_owid_test_owid_data_get_datum_of_all_owid_import(): + app.logger.info("url_owid_test_owid_data_get_datum_of_all_owid_import - START") + flash("url_owid_test_owid_data_get_datum_of_all_owid_import - START") + for datum in OwidImport.get_datum_of_all_import(): + app.logger.info(str(datum)) + app.logger.info("url_owid_test_owid_data_get_datum_of_all_owid_import - DONE") + flash("url_owid_test_owid_data_get_datum_of_all_owid_import - DONE") + return redirect(url_for('owid_test.url_owid_test_tests')) + + +@app_owid_test.route('/owid_service/owid_import/get_new_dates_as_array') +@login_required +def url_owid_test_owid_service_owid_import_get_new_dates_as_array(): + app.logger.info("url_owid_test_owid_service_owid_import_get_new_dates_as_array - START") + flash("url_owid_test_owid_service_owid_import_get_new_dates_as_array - START") + for datum in owid_service.service_update.who_import_get_new_dates_as_array(): + app.logger.info(str(datum)) + app.logger.info("url_owid_test_owid_service_owid_import_get_new_dates_as_array - DONE") + flash("url_owid_test_owid_service_owid_import_get_new_dates_as_array - DONE") + return redirect(url_for('owid_test.url_owid_test_tests')) + + +@app_owid_test.route('/owid_test_service/delete_last_days_data') +@login_required +def url_owid_test_owid_test_service_delete_last_days_data(): + app.logger.info("url_owid_test_owid_test_service_delete_last_days_data - START") + flash("url_owid_test_owid_test_service_delete_last_days_data - START") + owid_test_service.delete_last_day() + app.logger.info("url_owid_test_owid_test_service_delete_last_days_data - DONE") + flash("url_owid_test_owid_test_service_delete_last_days_data - DONE") + return redirect(url_for('owid_test.url_owid_test_tests')) + + + +# ---------------------------------------------------------------------------------------------------------------- +# Celery TASKS +# ---------------------------------------------------------------------------------------------------------------- + + +@celery.task(bind=True) +def task_owid_test_update_star_schema_incremental(self): + logger = get_task_logger(__name__) + self.update_state(state=states.STARTED) + logger.info("------------------------------------------------------------") + logger.info(" Received: task_owid_test_update_star_schema_incremental [OK] ") + logger.info("------------------------------------------------------------") + owid_test_service.run_update_star_schema_incremental() + self.update_state(state=states.SUCCESS) + result = "OK (task_owid_test_update_star_schema_incremental)" + return result + +# ---------------------------------------------------------------------------------------------------------------- +# URL Routes for Celery TASKS +# ---------------------------------------------------------------------------------------------------------------- + +@app_owid_test.route('/task/owid_test/update_star_schema_incremental') +@login_required +def url_task_owid_test_update_star_schema_incremental(): + app.logger.info("url_task_owid_test_update_star_schema_incremental - START: task_owid_test_update_star_schema_incremental()") + flash("url_task_owid_test_update_star_schema_incremental - START: task_owid_test_update_star_schema_incremental()") + task_owid_test_update_star_schema_incremental.apply_async() + flash("url_task_owid_test_update_star_schema_incremental - DONE: task_owid_test_update_star_schema_incremental()") + app.logger.info("url_task_owid_test_update_star_schema_incremental - DONE: task_owid_test_update_star_schema_incremental()") + return redirect(url_for('owid_test.url_owid_test_tests')) + + + + + + diff --git a/src/covid19/blueprints/owid_test/templates/__init__.py b/src/covid19/blueprints/owid_test/templates/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/covid19/blueprints/owid_test/templates/owid_test/owid_tests.html b/src/covid19/blueprints/owid_test/templates/owid_test/owid_tests.html new file mode 100644 index 0000000000000000000000000000000000000000..a4416ef59a1811415c69486cb64863a7cf62fb35 --- /dev/null +++ b/src/covid19/blueprints/owid_test/templates/owid_test/owid_tests.html @@ -0,0 +1,85 @@ +{% extends 'application/page_layout.html' %} + +{% block content %} + {{super()}} + {% include 'owid/navigation/owid_navtabs.html' %} + + <div class="container"> + <div class="row"> + <div class="col"> + <div class="btn-group-vertical" role="group" aria-label="Views"> + <a class="btn btn-primary btn-lg btn-block text-left" + href="{{ url_for( 'owid.url_owid_tasks') }}" + role="button">OWID :: Tasks</a> + </div> + </div> + <div class="col"> + <div class="btn-group-vertical" role="group" aria-label="Views"> + <a class="btn btn-primary btn-lg btn-block text-left" + href="{{ url_for( 'owid_test.url_task_owid_test_update_star_schema_incremental') }}" + role="button">url_task_owid_test_update_star_schema_incremental</a> + </div> + </div> + </div> + <p></p> + <div class="row"> + <div class="col"> + <div class="btn-group-vertical" role="group" aria-label="Views"> + <a class="btn btn-danger btn-lg btn-block text-left" + href="{{ url_for( 'owid_test.url_owid_test_owid_import_countries') }}" + role="button">url_owid_test_owid_import_countries</a> + <a class="btn btn-primary btn-lg btn-block text-left" + href="{{ url_for( 'owid_test.url_owid_test_owid_import_get_new_dates_as_array') }}" + role="button">url_owid_test_owid_import_get_new_dates_as_array</a> + <a class="btn btn-danger btn-lg btn-block text-left" + href="{{ url_for( 'owid_test.url_owid_test_owid_data_get_datum_of_all_owid_data') }}" + role="button">url_owid_test_owid_data_get_datum_of_all_owid_data</a> + <a class="btn btn-primary btn-lg btn-block text-left" + href="{{ url_for( 'owid_test.url_owid_test_owid_data_get_datum_of_all_owid_import') }}" + role="button">url_owid_test_owid_data_get_datum_of_all_owid_import</a> + <a class="btn btn-danger btn-lg btn-block text-left" + href="{{ url_for( 'owid_test.url_owid_test_owid_service_owid_import_get_new_dates_as_array') }}" + role="button">url_owid_test_owid_service_owid_import_get_new_dates_as_array</a> + <a class="btn btn-primary btn-lg btn-block text-left" + href="{{ url_for( 'owid_test.url_owid_test_owid_test_service_delete_last_days_data') }}" + role="button">url_owid_test_owid_test_service_delete_last_days_data</a> + </div> + </div> + <div class="col"> + </div> + </div> + <p></p> + <div class="row"> + <div class="col"> + </div> + <div class="col"> + <div class="btn-group-vertical" role="group" aria-label="Views"> + <a class="btn btn-danger btn-lg btn-block text-left" + href="{{ url_for( 'owid_test.url_owid_test_update_dimension_tables_only') }}" + role="button">test_update_dimension_tables_only</a> + <a class="btn btn-secondary btn-lg btn-block text-left" + href="{{ url_for( 'owid_test.url_owid_test_update_fact_table_incremental_only') }}" + role="button">test_update_fact_table_incremental_only</a> + <a class="btn btn-danger btn-lg btn-block text-left" + href="{{ url_for( 'owid_test.url_owid_test_update_fact_table_initial_only') }}" + role="button">test_update_fact_table_initial_only</a> + <a class="btn btn-secondary btn-lg btn-block text-left" + href="{{ url_for( 'owid_test.url_owid_test_update_star_schema_incremental') }}" + role="button">test_update_star_schema_incremental</a> + <a class="btn btn-danger btn-lg btn-block text-left" + href="{{ url_for( 'owid_test.url_owid_test_update_star_schema_initial') }}" + role="button">test_update_star_schema_initial</a> + </div> + </div> + </div> + </div> +{% endblock %} + + + +{% block footer_container %} + +{% endblock %} + + + diff --git a/src/covid19/blueprints/rki/rki_bundeslaender/rki_bundeslaender_service.py b/src/covid19/blueprints/rki/rki_bundeslaender/rki_bundeslaender_service.py index 021f75888f5855567f558982e5c2e2e52d9a600d..ac24c73ed5d8b29f105d199fa1c27dfbc140efcd 100644 --- a/src/covid19/blueprints/rki/rki_bundeslaender/rki_bundeslaender_service.py +++ b/src/covid19/blueprints/rki/rki_bundeslaender/rki_bundeslaender_service.py @@ -22,12 +22,17 @@ class RkiBundeslaenderService: def pretask_database_drop_create(self): flash("RkiBundeslaenderService.pretask_database_drop_create started") + app.logger.info("RkiBundeslaenderService.pretask_database_drop_create started") self.service_download.download_file() + app.logger.info("RkiBundeslaenderService.pretask_database_drop_create done") + flash("RkiBundeslaenderService.pretask_database_drop_create done") return self def task_database_drop_create(self): + app.logger.info("RkiBundeslaenderService.task_database_drop_create started") self.service_import.import_file() self.service_update.update_star_schema_initial() + app.logger.info("RkiBundeslaenderService.task_database_drop_create done") return self def run_download_only(self): diff --git a/src/covid19/blueprints/rki/rki_vaccination/rki_vaccination_model.py b/src/covid19/blueprints/rki/rki_vaccination/rki_vaccination_model.py index 64bf7b1803bc673acc71e71cee3ddc07212e9fe9..b68f57bcb414616b6aa17e3b87d965bcb640c48b 100644 --- a/src/covid19/blueprints/rki/rki_vaccination/rki_vaccination_model.py +++ b/src/covid19/blueprints/rki/rki_vaccination/rki_vaccination_model.py @@ -10,11 +10,11 @@ class RkiVaccinationDateReported(ApplicationDateReported): 'concrete': True } __table_args__ = ( - db.UniqueConstraint('date_reported', 'datum', name="uix_rki_vaccination_datereported"), + db.UniqueConstraint('date_reported_import_str', 'datum', name="uix_rki_vaccination_datereported"), ) id = db.Column(db.Integer, primary_key=True) - date_reported = db.Column(db.String(255), nullable=False, unique=True) + date_reported_import_str = db.Column(db.String(255), nullable=False, unique=True) year_week = db.Column(db.String(255), nullable=False) datum = db.Column(db.Date, nullable=False, unique=True) year = db.Column(db.Integer, nullable=False) @@ -34,7 +34,7 @@ class RkiVaccinationDateReported(ApplicationDateReported): my_year_week += "-" my_year_week += str(week_number) return RkiVaccinationDateReported( - date_reported=my_date_rep, + date_reported_import_str=my_date_rep, datum=my_datum, year=my_datum.year, month=my_datum.month, @@ -53,8 +53,8 @@ class RkiVaccinationData(db.Model): date_reported = db.relationship( 'RkiVaccinationDateReported', lazy='joined', - cascade='all, delete', - order_by='desc(RkiVaccinationDateReported.date_reported)') + cascade='save-update', + order_by='desc(RkiVaccinationDateReported.date_reported_import_str)') dosen_kumulativ = db.Column(db.Integer, nullable=False) dosen_differenz_zum_vortag = db.Column(db.Integer, nullable=False) dosen_biontech_kumulativ = db.Column(db.Integer, nullable=False) diff --git a/src/covid19/blueprints/rki/rki_vaccination/rki_vaccination_service.py b/src/covid19/blueprints/rki/rki_vaccination/rki_vaccination_service.py index e300f9ffb9f1af62624116f2792613446388e9d3..72dd2f67d381390dfaa8f4b2534e4285427899d3 100644 --- a/src/covid19/blueprints/rki/rki_vaccination/rki_vaccination_service.py +++ b/src/covid19/blueprints/rki/rki_vaccination/rki_vaccination_service.py @@ -22,12 +22,17 @@ class RkiVaccinationService: def pretask_database_drop_create(self): flash("vaccination_service.run_download started") + app.logger.info("vaccination_service.run_download started") self.service_download.download_file() + app.logger.info("vaccination_service.run_download done") + flash("vaccination_service.run_download done") return self def task_database_drop_create(self): + app.logger.info("vaccination_service.task_database_drop_create started") self.service_import.import_file() self.service_update.update_star_schema_initial() + app.logger.info("vaccination_service.task_database_drop_create done") return self def run_download_only(self): diff --git a/src/covid19/blueprints/rki/rki_vaccination/rki_vaccination_service_update.py b/src/covid19/blueprints/rki/rki_vaccination/rki_vaccination_service_update.py index 7bcf0bec0ca22d0e3a21e1b86a232d5b667d9a50..d1d382cdf46138255f3c3cabbfe7769269d6b304 100644 --- a/src/covid19/blueprints/rki/rki_vaccination/rki_vaccination_service_update.py +++ b/src/covid19/blueprints/rki/rki_vaccination/rki_vaccination_service_update.py @@ -46,7 +46,7 @@ class RkiVaccinationServiceUpdate: if date_reported is None: o = RkiVaccinationDateReported.create_new_object_factory(my_date_rep=item_date_rep) date_reported = o - result_data_import = RkiVaccinationImport.find_by_datum(date_reported.date_reported) + result_data_import = RkiVaccinationImport.find_by_datum(date_reported.date_reported_import_str) for item_import in result_data_import: o = RkiVaccinationData( date_reported=date_reported, diff --git a/src/covid19/blueprints/user/templates/usr/user_info.html b/src/covid19/blueprints/user/templates/usr/user_info.html index 911c629e0168893b478cfec2fa480ec795637a67..66af388f4d8a1701e59594d7915efdef1d187a72 100644 --- a/src/covid19/blueprints/user/templates/usr/user_info.html +++ b/src/covid19/blueprints/user/templates/usr/user_info.html @@ -7,38 +7,9 @@ <div class="container"> <div class="row"> <div class="col"> - <div class="card"> - <div class="card-body"> - <div class="card-title"> - User - </div> - <div class="card-text"> - Coronavirus Pandemic (COVID-19) - </div> - <div class="card-text"> - <a class="btn btn-primary" href="https://ourworldindata.org/coronavirus"> - https://ourworldindata.org/coronavirus - </a> - </div> - </div> - </div> - </div> - <div class="col"> - <div class="card"> - <div class="card-body"> - <div class="card-title"> - n.n - </div> - <div class="card-text"> - n.n - </div> - <div class="card-text"> - <a class="btn btn-primary" href="https://ourworldindata.org/coronavirus"> - n.n - </a> - </div> - </div> - </div> + {% if current_user.is_authenticated %} + {% include 'usr/usr_table.html' %} + {% endif %} </div> </div> </div> diff --git a/src/covid19/blueprints/user/templates/usr/usr_table.html b/src/covid19/blueprints/user/templates/usr/usr_table.html new file mode 100644 index 0000000000000000000000000000000000000000..d926a5ae2fe1023db828790d569447e29b216c33 --- /dev/null +++ b/src/covid19/blueprints/user/templates/usr/usr_table.html @@ -0,0 +1,26 @@ + <table class="table table-hover table-striped table-dark"> + <thead class="table-secondary"> + <tr> + <th scope="col" class="text-right">Email</th> + <th scope="col" class="text-left">Name</th> + </tr> + </thead> + <tbody> + {% for usr in page_data.items %} + <tr> + <td class="text-right"> + {{ usr.email }} + </td> + <td class="text-left"> + {{ usr.name }} + </td> + </tr> + {% endfor %} + </tbody> + <tfoot class="table-secondary"> + <tr> + <th scope="col" class="text-right">Email</th> + <th scope="col" class="text-left">Name</th> + </tr> + </tfoot> + </table> \ No newline at end of file diff --git a/src/covid19/blueprints/user/user_model.py b/src/covid19/blueprints/user/user_model.py index 050fe148872d2cd86c39f89849ded01848085915..9fbf6eb71d68872dd299ef20c6ed0847ce7b2735 100644 --- a/src/covid19/blueprints/user/user_model.py +++ b/src/covid19/blueprints/user/user_model.py @@ -25,6 +25,10 @@ class User(UserMixin, db.Model): def check_password(self, password): return check_password_hash(self.password_hash, password) + @classmethod + def count(cls): + return db.session.query(cls).count() + @classmethod def remove_all(cls): for one in cls.get_all(): @@ -43,7 +47,7 @@ class User(UserMixin, db.Model): @classmethod def get_by_id(cls, other_id): my_other_id = int(other_id) - return db.session.query(cls).filter(cls.id == my_other_id).one() + return db.session.query(cls).filter(cls.id == my_other_id).one_or_none() class AnonymousUserValueObject(AnonymousUserMixin): diff --git a/src/covid19/blueprints/user/user_service.py b/src/covid19/blueprints/user/user_service.py index 72e33fe305b19c37592da7af42041996d7db79d4..61ce87194d99ff6635769579f1ea8e882db7c4b9 100644 --- a/src/covid19/blueprints/user/user_service.py +++ b/src/covid19/blueprints/user/user_service.py @@ -21,3 +21,17 @@ class UserService: user.password = form.password return user + def prepare_default_user_login(self): + app.logger.info(" UserService.prepare_default_user_login()") + if User.count() == 0: + app.logger.info("User.count() == 0") + login = app.config['USER_ADMIN_LOGIN'] + name = app.config['USER_ADMIN_USERNAME'] + pw = app.config['USER_ADMIN_PASSWORD'] + user = User(email=login, name=name, password_hash=pw) + self.__database.session.add(user) + self.__database.session.commit() + else: + app.logger.info("User.count() > 0") + + diff --git a/src/covid19/blueprints/user/user_views.py b/src/covid19/blueprints/user/user_views.py index fceb5e679943e5166e75ae56508bc63f1c52bfa5..76eafe67de49456e0a8c024ffcccc767c647f22f 100644 --- a/src/covid19/blueprints/user/user_views.py +++ b/src/covid19/blueprints/user/user_views.py @@ -79,12 +79,18 @@ def unauthorized(): # Url Routes Frontend # --------------------------------------------------------------------------------------------------------------- - +@app_user.route('/info/page/<int:page>') @app_user.route('/info') -def url_user_info(): +def url_user_info(page=1): page_info = ApplicationPage('usr', "Info") + try: + page_data = User.get_all_as_page(page) + except OperationalError: + flash("No data in the database.") + page_data = None return render_template( 'usr/user_info.html', + page_data=page_data, page_info=page_info) diff --git a/src/covid19/blueprints/who/templates/who/navigation/who_navtabs.html b/src/covid19/blueprints/who/templates/who/navigation/who_navtabs.html index d0392ab5a98f3c1f1c4c1429c5a04f756dd0e19d..032b51dc9f878a8676f2532346bc6777e51662e3 100644 --- a/src/covid19/blueprints/who/templates/who/navigation/who_navtabs.html +++ b/src/covid19/blueprints/who/templates/who/navigation/who_navtabs.html @@ -14,6 +14,12 @@ href="{{ url_for( 'who.url_who_tasks') }}">WHO tasks</a> </li> {% endif %} + {% if current_user.is_authenticated %} + <li class="nav-item"> + <a class="nav-link" + href="{{ url_for( 'who_test.url_who_test_tests') }}">WHO Tests</a> + </li> + {% endif %} <li class="nav-item"> <a class="nav-link" href="{{ url_for( 'who.url_who_date_reported_all') }}">WHO Date Reported</a> diff --git a/src/covid19/blueprints/who/templates/who/who_tasks.html b/src/covid19/blueprints/who/templates/who/who_tasks.html index 580850ced48f35d29a674462886e3a24e8801fa6..51281f271f0c5ec2be13e31e5afc593922e060ff 100644 --- a/src/covid19/blueprints/who/templates/who/who_tasks.html +++ b/src/covid19/blueprints/who/templates/who/who_tasks.html @@ -15,24 +15,19 @@ href="{{ url_for( 'who.url_task_who_update_star_schema_incremental') }}" role="button">WHO :: Task :: update :: star_schema :: incremental</a> </div> - <div class="btn-group-vertical" role="group" aria-label="Views"> - <a class="btn btn-primary btn-lg btn-block text-left" - href="{{ url_for( 'who.url_who_mytest') }}" - role="button">WHO :: url_who_mytest</a> - </div> </div> <div class="col"> <div class="btn-group-vertical" role="group" aria-label="Views"> - <a class="btn btn-secondary btn-lg btn-block text-left" + <a class="btn btn-success btn-lg btn-block text-left" href="{{ url_for( 'who.url_task_who_download_only') }}" role="button">WHO :: Task :: download :: only</a> - <a class="btn btn-secondary btn-lg btn-block text-left" + <a class="btn btn-info btn-lg btn-block text-left" href="{{ url_for( 'who.url_task_who_import_only') }}" role="button">WHO :: Task :: import :: only</a> - <a class="btn btn-secondary btn-lg btn-block text-left" + <a class="btn btn-warning btn-lg btn-block text-left" href="{{ url_for( 'who.url_task_who_update_dimension_tables_only') }}" role="button">WHO :: Task :: update :: dimension-tables : only</a> - <a class="btn btn-secondary btn-lg btn-block text-left" + <a class="btn btn-danger btn-lg btn-block text-left" href="{{ url_for( 'who.url_task_who_update_fact_table_incremental_only') }}" role="button">WHO :: Task :: update :: fact-table :: only :: incremental</a> <a class="btn btn-secondary btn-lg btn-block text-left" diff --git a/src/covid19/blueprints/who/who_model.py b/src/covid19/blueprints/who/who_model.py index 849b0d4c8000de0b764eac24cc0919b55c2573c1..dac88da082ee330e8415f148d23f978f46c36d29 100644 --- a/src/covid19/blueprints/who/who_model.py +++ b/src/covid19/blueprints/who/who_model.py @@ -1,7 +1,8 @@ from sqlalchemy import and_, func from datetime import date +from sqlalchemy.orm import joinedload, load_only, defaultload, defer, undefer, query_expression, subqueryload +from sqlalchemy.sql import select from database import db, ITEMS_PER_PAGE -from sqlalchemy.orm import joinedload from covid19.blueprints.application.application_model import ApplicationDateReported, ApplicationRegion @@ -9,11 +10,11 @@ class WhoDateReported(ApplicationDateReported): __tablename__ = 'who_datereported' __mapper_args__ = {'concrete': True} __table_args__ = ( - db.UniqueConstraint('date_reported', 'datum', name="uix_who_datereported"), + db.UniqueConstraint('date_reported_import_str', 'datum', name="uix_who_datereported"), ) id = db.Column(db.Integer, primary_key=True) - date_reported = db.Column(db.String(255), nullable=False, unique=True) + date_reported_import_str = db.Column(db.String(255), nullable=False, unique=True) year_week = db.Column(db.String(255), nullable=False) datum = db.Column(db.Date, nullable=False, unique=True) year = db.Column(db.Integer, nullable=False) @@ -33,7 +34,7 @@ class WhoDateReported(ApplicationDateReported): my_year_week += "-" my_year_week += str(week_number) return WhoDateReported( - date_reported=my_date_rep, + date_reported_import_str=my_date_rep, datum=my_datum, year=my_datum.year, month=my_datum.month, @@ -43,7 +44,6 @@ class WhoDateReported(ApplicationDateReported): year_week=my_year_week ) - class WhoRegion(ApplicationRegion): __tablename__ = 'who_country_region' __mapper_args__ = {'concrete': True} @@ -68,7 +68,7 @@ class WhoCountry(db.Model): region = db.relationship( 'WhoRegion', lazy='joined', - cascade='all, delete', + cascade='save-update', order_by='WhoRegion.region') def __str__(self): @@ -173,14 +173,14 @@ class WhoData(db.Model): date_reported = db.relationship( 'WhoDateReported', lazy='joined', - cascade='all, delete', - order_by='desc(WhoDateReported.date_reported)') + cascade='save-update', + order_by='desc(WhoDateReported.date_reported_import_str)') country_id = db.Column(db.Integer, db.ForeignKey('who_country.id'), nullable=False) country = db.relationship( 'WhoCountry', lazy='joined', - cascade='all, delete', + cascade='save-update', order_by='asc(WhoCountry.country)') @classmethod @@ -234,6 +234,27 @@ class WhoData(db.Model): cls.cases_cumulative.desc() ).paginate(page, per_page=ITEMS_PER_PAGE) + @classmethod + def get_data_for_one_day(cls, date_reported): + return db.session.query(cls).filter( + cls.date_reported_id == date_reported.id + ).populate_existing().options( + joinedload(cls.country).joinedload(WhoCountry.region), + joinedload(cls.date_reported) + ).order_by( + cls.deaths_new.desc(), + cls.cases_new.desc(), + cls.deaths_cumulative.desc(), + cls.cases_cumulative.desc() + ).all() + + @classmethod + def delete_data_for_one_day(cls, date_reported): + for one_who_date in cls.get_data_for_one_day(date_reported): + db.session.delete(one_who_date) + db.session.commit() + return None + @classmethod def get_data_for_day_order_by_cases_new(cls, date_reported, page): return db.session.query(cls).filter( @@ -321,3 +342,17 @@ class WhoData(db.Model): ).order_by( cls.deaths_cumulative.desc() ).paginate(page, per_page=ITEMS_PER_PAGE) + + @classmethod + def get_datum_of_all_data(cls): + datum_of_all_who_data = [] + for data in db.session.query(cls).options(subqueryload("date_reported").load_only("date_reported_import_str")): + datum = data.date_reported.date_reported_import_str + if not datum in datum_of_all_who_data: + datum_of_all_who_data.append(datum) + datum_of_all_who_data.sort() + return datum_of_all_who_data + + @classmethod + def get_joungest_datum(cls): + return cls.get_datum_of_all_who_data().pop() diff --git a/src/covid19/blueprints/who/who_model_import.py b/src/covid19/blueprints/who/who_model_import.py index cf4f463c73487890894ee48e2040d0e71e4a9c62..fb5e3da53079181ba43f0051aa29ccf4f66e7643 100644 --- a/src/covid19/blueprints/who/who_model_import.py +++ b/src/covid19/blueprints/who/who_model_import.py @@ -89,7 +89,7 @@ class WhoImport(db.Model): not in ( select distinct - who_datereported.date_reported + who_datereported.date_reported_import_str from who left join @@ -97,9 +97,9 @@ class WhoImport(db.Model): on who.date_reported_id=who_datereported.id group by - who_datereported.date_reported + who_datereported.date_reported_import_str order by - who_datereported.date_reported desc + who_datereported.date_reported_import_str desc ) group by application__import__who.date_reported @@ -125,7 +125,7 @@ class WhoImport(db.Model): not in ( select distinct - who_datereported.date_reported + who_datereported.date_reported_import_str from who left join @@ -133,9 +133,9 @@ class WhoImport(db.Model): on who.date_reported_id=who_datereported.id group by - who_datereported.date_reported + who_datereported.date_reported_import_str order by - who_datereported.date_reported desc + who_datereported.date_reported_import_str desc ) group by application__import__who.date_reported @@ -149,9 +149,20 @@ class WhoImport(db.Model): @classmethod def get_new_dates_as_array(cls): - return cls.__get_new_dates_as_array_sql() + #return cls.__get_new_dates_as_array_sql() + return cls.__get_new_dates_as_array_orm() @classmethod def countries(cls): bu = Bundle('countries', cls.country_code, cls.country, cls.who_region) return db.session.query(bu).distinct() + + @classmethod + def get_datum_of_all_who_import(cls): + dates_reported = [] + bu = Bundle('dates_reported', cls.date_reported) + for date_reported in db.session.query(bu).distinct().order_by(cls.date_reported): + item = date_reported[0][0] + if not item in dates_reported: + dates_reported.append(item) + return dates_reported diff --git a/src/covid19/blueprints/who/who_service.py b/src/covid19/blueprints/who/who_service.py index 9a9f68827ae69f5026afbde443539359bc4bc82e..371869fd6c77445066feafec413b8024f97c9daf 100644 --- a/src/covid19/blueprints/who/who_service.py +++ b/src/covid19/blueprints/who/who_service.py @@ -22,13 +22,18 @@ class WhoService: def pretask_database_drop_create(self): flash("WhoService.pretask_database_drop_create started") + app.logger.info("WhoService.pretask_database_drop_create started") self.service_download.download_file() + app.logger.info("WhoService.pretask_database_drop_create done") + flash("WhoService.pretask_database_drop_create done") return self def task_database_drop_create(self): + app.logger.info("WhoService.task_database_drop_create started") self.service_import.import_file() self.service_update.update_dimension_tables_only() self.service_update.update_fact_table_incremental_only() + app.logger.info("WhoService.task_database_drop_create done") return self #def run_download_only(self): diff --git a/src/covid19/blueprints/who/who_service_update.py b/src/covid19/blueprints/who/who_service_update.py index 887f9ca36cdc47b266689c08077f4133b42591bf..a984b67bd6ea0c6a58b9b6a6a2b2c9a375fd4ff1 100644 --- a/src/covid19/blueprints/who/who_service_update.py +++ b/src/covid19/blueprints/who/who_service_update.py @@ -89,12 +89,21 @@ class WhoServiceUpdate: app.logger.info("------------------------------------------------------------") return self + def who_import_get_new_dates_as_array(self): + new_dates_reported_from_import = [] + list_datum_of_all_who_data = WhoData.get_datum_of_all_who_data() + for item in WhoImport.get_datum_of_all_who_import(): + if not item in list_datum_of_all_who_data: + new_dates_reported_from_import.append(item) + return new_dates_reported_from_import + def __update_data_incremental(self): app.logger.info(" WhoServiceUpdate.__update_fact_tables_incremental [begin]") app.logger.info("------------------------------------------------------------") - new_dates_reported_from_import = WhoImport.get_new_dates_as_array() + new_dates_reported_from_import = self.who_import_get_new_dates_as_array() i = 0 for my_date_reported in new_dates_reported_from_import: + app.logger.info(my_date_reported) my_date = WhoDateReported.find_by_date_reported(my_date_reported) if my_date is None: myday = WhoDateReported.create_new_object_factory(my_date_reported) @@ -118,7 +127,7 @@ class WhoServiceUpdate: db.session.add(o) i += 1 k += 1 - if i % 500 == 0: + if i % 2000 == 0: app.logger.info(" update WHO incremental ... "+str(i)+" rows") db.session.commit() app.logger.info(" update WHO incremental ... " + str(i) + " rows [" + str(my_date) + "] (" + str(k) + ")") @@ -153,7 +162,7 @@ class WhoServiceUpdate: result_item.row_imported = True db.session.add(result_item) i += 1 - if i % 500 == 0: + if i % 2000 == 0: app.logger.info(" update WHO initial ... "+str(i)+" rows") db.session.commit() db.session.commit() diff --git a/src/covid19/blueprints/who/who_views.py b/src/covid19/blueprints/who/who_views.py index ea1cd87cbe24002e5f6ba964d76c49ad5fd55fe8..5842d14920461fbaad11da3a7c16e4576976f13b 100644 --- a/src/covid19/blueprints/who/who_views.py +++ b/src/covid19/blueprints/who/who_views.py @@ -325,13 +325,31 @@ def url_who_germany(page: int = 1): @app_who.route('/mytest') def url_who_mytest(): - flash("url_who_mytest - Start") + flash("url_who_mytest - START: WhoImport.countries()") + app.logger.info("url_who_mytest - START: WhoImport.countries()") i = 0 for c in WhoImport.countries(): i += 1 line = " | " + str(i) + " | " + c.countries.country_code + " | " + c.countries.country + " | " + c.countries.who_region + " | " app.logger.info(line) - flash("url_who_mytest - Done") + flash("url_who_mytest - DONE: WhoImport.countries()") + app.logger.info("url_who_mytest - DONE: WhoImport.countries()") + flash("url_who_mytest - START: WhoImport.get_new_dates_as_array()") + app.logger.info("url_who_mytest - START: WhoImport.get_new_dates_as_array()") + i = 0 + for date_reported in WhoImport.get_new_dates_as_array(): + i += 1 + line = " | " + str(i) + " | " + date_reported + " | " + app.logger.info(line) + joungest_datum = WhoDateReported.get_joungest_datum() + app.logger.info(joungest_datum) + i = 0 + for who_data in WhoData.get_data_for_one_day(joungest_datum): + i += 1 + line = " | " + str(i) + " | " + str(who_data.date_reported) + " | " + who_data.country.country + " | " + app.logger.info(line) + flash("url_who_mytest - DONE: WhoImport.get_new_dates_as_array()") + app.logger.info("url_who_mytest - DONE: WhoImport.get_new_dates_as_array()") return redirect(url_for('who.url_who_tasks')) # ---------------------------------------------------------------------------------------------------------------- diff --git a/src/covid19/blueprints/who_test/__init__.py b/src/covid19/blueprints/who_test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/covid19/blueprints/who_test/templates/__init__.py b/src/covid19/blueprints/who_test/templates/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/covid19/blueprints/who_test/templates/who_test/who_tests.html b/src/covid19/blueprints/who_test/templates/who_test/who_tests.html new file mode 100644 index 0000000000000000000000000000000000000000..f79ff4b1cf1ea3bce6075f1d7108fefaa131b554 --- /dev/null +++ b/src/covid19/blueprints/who_test/templates/who_test/who_tests.html @@ -0,0 +1,59 @@ +{% extends 'application/page_layout.html' %} + +{% block content %} + {{super()}} + {% include 'who/navigation/who_navtabs.html' %} + + <div class="container"> + <div class="row"> + <div class="col"> + <div class="btn-group-vertical" role="group" aria-label="Views"> + <a class="btn btn-primary btn-lg btn-block text-left" + href="{{ url_for( 'who.url_who_tasks') }}" + role="button">WHO :: Tasks</a> + </div> + </div> + </div> + <p></p> + <div class="row"> + <div class="col"> + <div class="btn-group-vertical" role="group" aria-label="Views"> + <a class="btn btn-danger btn-lg btn-block text-left" + href="{{ url_for( 'who_test.url_who_test_who_import_countries') }}" + role="button">url_who_test_who_import_countries</a> + <a class="btn btn-primary btn-lg btn-block text-left" + href="{{ url_for( 'who_test.url_who_test_who_import_get_new_dates_as_array') }}" + role="button">url_who_test_who_import_get_new_dates_as_array</a> + <a class="btn btn-danger btn-lg btn-block text-left" + href="{{ url_for( 'who_test.url_who_test_who_data_get_datum_of_all_who_data') }}" + role="button">url_who_test_who_data_get_datum_of_all_who_data</a> + <a class="btn btn-primary btn-lg btn-block text-left" + href="{{ url_for( 'who_test.url_who_test_who_data_get_datum_of_all_who_import') }}" + role="button">url_who_test_who_data_get_datum_of_all_who_import</a> + <a class="btn btn-danger btn-lg btn-block text-left" + href="{{ url_for( 'who_test.url_who_test_who_service_who_import_get_new_dates_as_array') }}" + role="button">url_who_test_who_service_who_import_get_new_dates_as_array</a> + <a class="btn btn-primary btn-lg btn-block text-left" + href="{{ url_for( 'who_test.url_who_test_who_test_service_delete_last_days_data') }}" + role="button">url_who_test_who_test_service_delete_last_days_data</a> + </div> + </div> + <div class="col"> + <div class="btn-group-vertical" role="group" aria-label="Views"> + <a class="btn btn-primary btn-lg btn-block text-left" + href="{{ url_for( 'who_test.url_task_who_test_update_star_schema_incremental') }}" + role="button">url_task_who_test_update_star_schema_incremental</a> + </div> + </div> + </div> + </div> +{% endblock %} + + + +{% block footer_container %} + +{% endblock %} + + + diff --git a/src/covid19/blueprints/who_test/who_test_service.py b/src/covid19/blueprints/who_test/who_test_service.py new file mode 100644 index 0000000000000000000000000000000000000000..26a1be175c6b29235316cf9fc59887aacd5c697e --- /dev/null +++ b/src/covid19/blueprints/who_test/who_test_service.py @@ -0,0 +1,45 @@ +from flask import flash + +from database import app +from covid19.blueprints.application.application_service_config import ApplicationServiceConfig +from covid19.blueprints.who.who_model import WhoDateReported, WhoData + +class WhoTestService: + def __init__(self, database, who_service): + app.logger.debug("------------------------------------------------------------") + app.logger.debug(" WHO Test Service [init]") + app.logger.debug("------------------------------------------------------------") + self.__database = database + self.__who_service = who_service + self.cfg = ApplicationServiceConfig.create_config_for_who() + app.logger.debug("------------------------------------------------------------") + app.logger.info(" WHO Test Service [ready]") + + def delete_last_day(self): + app.logger.debug("------------------------------------------------------------") + app.logger.debug(" WhoTestService.delete_last_day() [START]") + app.logger.debug("------------------------------------------------------------") + joungest_datum_str = WhoData.get_joungest_datum() + joungest_datum = WhoDateReported.find_by_date_reported(joungest_datum_str) + app.logger.info("joungest_datum:") + app.logger.info(joungest_datum) + app.logger.info("WhoData.get_data_for_one_day(joungest_datum):") + i = 0 + for data in WhoData.get_data_for_one_day(joungest_datum): + i += 1 + line = " | " + str(i) + " | " + str(data.date_reported) + " | " + data.country.country + " | to be deleted" + app.logger.info(line) + app.logger.info("WhoData.delete_data_for_one_day(joungest_datum)") + WhoData.delete_data_for_one_day(joungest_datum) + app.logger.debug("------------------------------------------------------------") + app.logger.debug(" WhoTestService.delete_last_day() [DONE]") + app.logger.debug("------------------------------------------------------------") + + def run_update_star_schema_incremental(self): + app.logger.debug("------------------------------------------------------------") + app.logger.debug(" WhoTestService.run_update_star_schema_incremental() [START]") + app.logger.debug("------------------------------------------------------------") + self.__who_service.run_update_star_schema_incremental() + app.logger.debug("------------------------------------------------------------") + app.logger.debug(" WhoTestService.run_update_star_schema_incremental() [DONE]") + app.logger.debug("------------------------------------------------------------") diff --git a/src/covid19/blueprints/who_test/who_test_views.py b/src/covid19/blueprints/who_test/who_test_views.py new file mode 100644 index 0000000000000000000000000000000000000000..5445165d693672773f5162795a3e69f17ce4b160 --- /dev/null +++ b/src/covid19/blueprints/who_test/who_test_views.py @@ -0,0 +1,140 @@ +from flask import render_template, redirect, url_for, flash, Blueprint +from sqlalchemy.exc import OperationalError +from celery import states +from celery.utils.log import get_task_logger +from flask_admin.contrib.sqla import ModelView +from flask_login import login_required + +from database import app, admin, db +from covid19.blueprints.application.application_services import who_service +from covid19.blueprints.application.application_workers import celery + +from covid19.blueprints.who.who_model_import import WhoImport +from covid19.blueprints.who.who_model import WhoRegion, WhoCountry, WhoDateReported, WhoData +from covid19.blueprints.application.application_model_transient import ApplicationPage + +from covid19.blueprints.who.who_views import app_who + +from covid19.blueprints.who_test.who_test_service import WhoTestService + +who_test_service = WhoTestService(db, who_service) + +app_who_test = Blueprint('who_test', __name__, template_folder='templates', url_prefix='/who/test') + +# --------------------------------------------------------------------------------------------------------------- +# Url Routes Frontend +# --------------------------------------------------------------------------------------------------------------- + + +@app_who_test.route('/tests') +@login_required +def url_who_test_tests(): + page_info = ApplicationPage('WHO', "Tests") + return render_template( + 'who_test/who_tests.html', + page_info=page_info) + +@app_who_test.route('/who_import/countries') +@login_required +def url_who_test_who_import_countries(): + flash("url_who_mytest - START: WhoImport.countries()") + app.logger.info("url_who_mytest - START: WhoImport.countries()") + i = 0 + for c in WhoImport.countries(): + i += 1 + line = " | " + str(i) + " | " + c.countries.country_code + " | " + c.countries.country + " | " + c.countries.who_region + " | " + app.logger.info(line) + flash("url_who_mytest - DONE: WhoImport.countries()") + return redirect(url_for('who_test.url_who_test_tests')) + + +@app_who_test.route('/who_import/get_new_dates_as_array') +@login_required +def url_who_test_who_import_get_new_dates_as_array(): + app.logger.info("url_who_mytest - DONE: WhoImport.countries()") + flash("url_who_mytest - START: WhoImport.get_new_dates_as_array()") + app.logger.info("url_who_mytest - START: WhoImport.get_new_dates_as_array()") + app.logger.info("WhoImport.get_new_dates_as_array():") + i = 0 + for date_reported in WhoImport.get_new_dates_as_array(): + i += 1 + line = " | " + str(i) + " | " + date_reported + " | " + app.logger.info(line) + flash("url_who_mytest - DONE: WhoImport.get_new_dates_as_array()") + app.logger.info("url_who_mytest - DONE: WhoImport.get_new_dates_as_array()") + return redirect(url_for('who_test.url_who_test_tests')) + +@app_who_test.route('/who_data/get_datum_of_all_who_data') +@login_required +def url_who_test_who_data_get_datum_of_all_who_data(): + app.logger.info("url_who_test_who_data_get_datum_of_all_who_data - DONE: WhoData.get_datum_of_all_who_data()") + flash("url_who_test_who_data_get_datum_of_all_who_data - START: WhoData.get_datum_of_all_who_data()") + for datum in WhoData.get_datum_of_all_data(): + app.logger.info(str(datum)) + flash("url_who_test_who_data_get_datum_of_all_who_data - DONE: WhoData.get_datum_of_all_who_data()") + app.logger.info("url_who_test_who_data_get_datum_of_all_who_data - DONE: WhoData.get_datum_of_all_who_data()") + return redirect(url_for('who_test.url_who_test_tests')) + +@app_who_test.route('/who_data/get_datum_of_all_who_import') +@login_required +def url_who_test_who_data_get_datum_of_all_who_import(): + app.logger.info("url_who_test_who_data_get_datum_of_all_who_import - START: WhoImport.get_datum_of_all_who_import()") + flash("url_who_test_who_data_get_datum_of_all_who_import - START: WhoImport.get_datum_of_all_who_import()") + for datum in WhoImport.get_datum_of_all_who_import(): + app.logger.info(str(datum)) + flash("url_who_test_who_data_get_datum_of_all_who_import - DONE: WhoImport.get_datum_of_all_who_import()") + app.logger.info("url_who_test_who_data_get_datum_of_all_who_import - DONE: WhoImport.get_datum_of_all_who_import()") + return redirect(url_for('who_test.url_who_test_tests')) + +@app_who_test.route('/who_service/service_update/who_import_get_new_dates_as_array') +@login_required +def url_who_test_who_service_who_import_get_new_dates_as_array(): + app.logger.info("url_who_test_who_import_get_new_dates_as_array - START: WhoService.who_import_get_new_dates_as_array()") + flash("url_who_test_who_import_get_new_dates_as_array - START: WhoService.who_import_get_new_dates_as_array()") + for datum in who_service.service_update.who_import_get_new_dates_as_array(): + app.logger.info(str(datum)) + flash("url_who_test_who_import_get_new_dates_as_array - DONE: WhoService.who_import_get_new_dates_as_array()") + app.logger.info("url_who_test_who_import_get_new_dates_as_array - DONE: WhoService.who_import_get_new_dates_as_array()") + return redirect(url_for('who_test.url_who_test_tests')) + +@app_who_test.route('/who_test_service/delete_last_day') +@login_required +def url_who_test_who_test_service_delete_last_days_data(): + app.logger.info("url_who_test_who_test_service_delete_last_days_data - START: WhoService.who_import_get_new_dates_as_array()") + flash("url_who_test_who_test_service_delete_last_days_data - START: WhoService.who_import_get_new_dates_as_array()") + who_test_service.delete_last_day() + flash("url_who_test_who_test_service_delete_last_days_data - DONE: WhoService.who_import_get_new_dates_as_array()") + app.logger.info("url_who_test_who_test_service_delete_last_days_data - DONE: WhoService.who_import_get_new_dates_as_array()") + return redirect(url_for('who_test.url_who_test_tests')) + + +# ---------------------------------------------------------------------------------------------------------------- +# Celery TASKS +# ---------------------------------------------------------------------------------------------------------------- + + +@celery.task(bind=True) +def task_who_test_update_star_schema_incremental(self): + logger = get_task_logger(__name__) + self.update_state(state=states.STARTED) + logger.info("------------------------------------------------------------") + logger.info(" Received: task_who_test_update_star_schema_incremental [OK] ") + logger.info("------------------------------------------------------------") + who_test_service.run_update_star_schema_incremental() + self.update_state(state=states.SUCCESS) + result = "OK (task_who_test_update_star_schema_incremental)" + return result + +# ---------------------------------------------------------------------------------------------------------------- +# URL Routes for Celery TASKS +# ---------------------------------------------------------------------------------------------------------------- + +@app_who_test.route('/task/update_star_schema_incremental') +@login_required +def url_task_who_test_update_star_schema_incremental(): + app.logger.info("url_task_who_update_star_schema_incremental - START: task_who_update_star_schema_incremental()") + flash("url_task_who_update_star_schema_incremental - START: task_who_update_star_schema_incremental()") + task_who_test_update_star_schema_incremental.apply_async() + flash("url_task_who_update_star_schema_incremental - DONE: task_who_update_star_schema_incremental()") + app.logger.info("url_task_who_update_star_schema_incremental - DONE: task_who_update_star_schema_incremental()") + return redirect(url_for('who_test.url_who_test_tests')) diff --git a/src/covid19/gulpfile.js b/src/covid19/gulpfile.js deleted file mode 100644 index 024abf734b3853ee727a78e4150314d81eca37d2..0000000000000000000000000000000000000000 --- a/src/covid19/gulpfile.js +++ /dev/null @@ -1,61 +0,0 @@ -"use strict"; - -// Load plugins -const browsersync = require("browser-sync").create(); -const del = require("del"); -const gulp = require("gulp"); -const merge = require("merge-stream"); - -// BrowserSync -function browserSync(done) { - browsersync.init({ - server: { - baseDir: "./" - }, - port: 3000 - }); - done(); -} - -// BrowserSync reload -function browserSyncReload(done) { - browsersync.reload(); - done(); -} - -// Clean vendor -function clean() { - return del(["./vendor/"]); -} - -// Bring third party dependencies from node_modules into vendor directory -function modules() { - var bootstrap = gulp.src('./node_modules/bootstrap/dist/**/*').pipe(gulp.dest('./static/vendor/bootstrap')); - var jquery = gulp.src(['./node_modules/jquery/dist/*','!./node_modules/jquery/dist/core.js']) - .pipe(gulp.dest('./static/vendor/jquery')); - var popper_js = gulp.src(['./node_modules/popper.js/dist/**/*']).pipe(gulp.dest('./static/vendor/popper.js')); - var fontawesome = gulp.src(['./node_modules/@fortawesome/fontawesome-free/**/*']) - .pipe(gulp.dest('./static/vendor/fontawesome-free')); - var bootswatch = gulp.src(['./node_modules/bootswatch/dist/**/*']).pipe(gulp.dest('./static/vendor/bootswatch')); - return merge( - bootstrap, jquery, popper_js, fontawesome, bootswatch - ); -} - -// Watch files -function watchFiles() { - gulp.watch("./**/*.css", browserSyncReload); - gulp.watch("./**/*.html", browserSyncReload); -} - -// Define complex tasks -const vendor = gulp.series(clean, modules); -const build = gulp.series(vendor); -const watch = gulp.series(build, gulp.parallel(watchFiles, browserSync)); - -// Export tasks -exports.clean = clean; -exports.vendor = vendor; -exports.build = build; -exports.watch = watch; -exports.default = build; diff --git a/src/covid19/package-lock.json b/src/covid19/package-lock.json index 1736612528db156aa63822594855bd7645a34657..328871ec78b1a7b9f6a16d6e111764b1393dd742 100644 --- a/src/covid19/package-lock.json +++ b/src/covid19/package-lock.json @@ -35,6 +35,12 @@ "fastq": "^1.6.0" } }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -122,6 +128,23 @@ "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + }, + "dependencies": { + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + } + } + }, "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", @@ -624,12 +647,39 @@ } } }, + "clean-css": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.1.2.tgz", + "integrity": "sha512-QcaGg9OuMo+0Ds933yLOY+gHPWbxhxqF0HDexmToPf8pczvmvZGYzd+QqWp9/mkucAOKViI+dSFOqoZIvXbeBw==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true }, + "cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", + "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "dev": true, + "requires": { + "exit": "0.1.2", + "glob": "^7.1.1" + } + }, "cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -735,6 +785,12 @@ "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "dev": true }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -806,6 +862,15 @@ "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", "dev": true }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "^0.1.4" + } + }, "convert-source-map": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", @@ -821,6 +886,15 @@ "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", "dev": true }, + "copy-anything": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.3.tgz", + "integrity": "sha512-GK6QUtisv4fNS+XcI7shX0Gx9ORg7QqIznyfho79JTnX1XhLiyZHfftvGiziqzRiEi/Bjhgpi+D2o7HxJFPnDQ==", + "dev": true, + "requires": { + "is-what": "^3.12.0" + } + }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", @@ -843,6 +917,19 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, "d": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", @@ -853,6 +940,24 @@ "type": "^1.0.1" } }, + "dargs": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-6.1.0.tgz", + "integrity": "sha512-5dVBvpBLBnPwSsYXqfybFyehMmC/EenKEcf23AhCTgTf48JFBbmJKqoZBsERDnjL0FyiVTYWdFsRfTLHxLyKdQ==", + "dev": true + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true + }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -1002,6 +1107,61 @@ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "dev": true }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "dev": true + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + } + } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, "duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", @@ -1132,6 +1292,22 @@ "has-binary2": "~1.0.2" } }, + "entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", + "dev": true + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "requires": { + "prr": "~1.0.1" + } + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -1203,18 +1379,36 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "dev": true }, + "eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", + "dev": true + }, "eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": true }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", @@ -1418,6 +1612,21 @@ "reusify": "^1.0.4" } }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-sync-cmp": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz", + "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=", + "dev": true + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1708,6 +1917,12 @@ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", "dev": true }, + "getobject": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-1.0.0.tgz", + "integrity": "sha512-tbUz6AKKKr2YiMB+fLWIgq5ZeBOobop9YMMAU9dC54/ot2ksMXt3DOFyBuhZw6ptcVszEykgByK20j7W9jHFag==", + "dev": true + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -2002,42 +2217,627 @@ "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", "dev": true, "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "globby": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", + "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "glogg": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "dev": true, + "requires": { + "sparkles": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "grunt": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.4.0.tgz", + "integrity": "sha512-yRFc0GVCDu9yxqOFzpuXQ2pEdgtLDnFv5Qz54jfIcNnpJ8Z7B7P7kPkT4VMuRvm+N+QOsI8C4v/Q0DSaoj3LgQ==", + "dev": true, + "requires": { + "dateformat": "~3.0.3", + "eventemitter2": "~0.4.13", + "exit": "~0.1.2", + "findup-sync": "~0.3.0", + "glob": "~7.1.6", + "grunt-cli": "~1.4.2", + "grunt-known-options": "~1.1.1", + "grunt-legacy-log": "~3.0.0", + "grunt-legacy-util": "~2.0.1", + "iconv-lite": "~0.4.13", + "js-yaml": "~3.14.0", + "minimatch": "~3.0.4", + "mkdirp": "~1.0.4", + "nopt": "~3.0.6", + "rimraf": "~3.0.2" + }, + "dependencies": { + "findup-sync": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", + "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", + "dev": true, + "requires": { + "glob": "~5.0.0" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + } + } + }, + "grunt-cli": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.2.tgz", + "integrity": "sha512-wsu6BZh7KCnfeaSkDrKIAvOlqGKxNRTZjc8xfZlvxCByQIqUfZ31kh5uHpPnhQ4NdVgvaWaVxa1LUbVU80nACw==", + "dev": true, + "requires": { + "grunt-known-options": "~1.1.1", + "interpret": "~1.1.0", + "liftup": "~3.0.1", + "nopt": "~4.0.1", + "v8flags": "~3.2.0" + }, + "dependencies": { + "interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "dev": true + }, + "nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dev": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + } + } + }, + "grunt-contrib-clean": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-2.0.0.tgz", + "integrity": "sha512-g5ZD3ORk6gMa5ugZosLDQl3dZO7cI3R14U75hTM+dVLVxdMNJCPVmwf9OUt4v4eWgpKKWWoVK9DZc1amJp4nQw==", + "dev": true, + "requires": { + "async": "^2.6.1", + "rimraf": "^2.6.2" + }, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "grunt-contrib-copy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz", + "integrity": "sha1-cGDGWB6QS4qw0A8HbgqPbj58NXM=", + "dev": true, + "requires": { + "chalk": "^1.1.1", + "file-sync-cmp": "^0.1.0" + } + }, + "grunt-contrib-cssmin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-cssmin/-/grunt-contrib-cssmin-4.0.0.tgz", + "integrity": "sha512-jXU+Zlk8Q8XztOGNGpjYlD/BDQ0n95IHKrQKtFR7Gd8hZrzgqiG1Ra7cGYc8h2DD9vkSFGNlweb9Q00rBxOK2w==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "clean-css": "^5.0.1", + "maxmin": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "grunt-contrib-jshint": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-3.0.0.tgz", + "integrity": "sha512-o0V3HNK54+w2Lss/AP0LsAUCEmPDQIcgsDFvTy0sE8sdPXq/8vHdNdMEitK9Wcfoq7H6v02v6soiiwJ0wavT7A==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "hooker": "^0.2.3", + "jshint": "~2.12.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "grunt-contrib-less": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-less/-/grunt-contrib-less-3.0.0.tgz", + "integrity": "sha512-fBB8MUDCo5EgT7WdOVQnZq4GF+XCeFdnkhaxI7uepp8P973sH1jdodjF87c6d9WSHKgArJAGP5JEtthhdKVovg==", + "dev": true, + "requires": { + "async": "^3.2.0", + "chalk": "^4.1.0", + "less": "^4.1.1", + "lodash": "^4.17.21" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==", + "dev": true + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "grunt-contrib-sass": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-sass/-/grunt-contrib-sass-2.0.0.tgz", + "integrity": "sha512-RxZ3dlZZTX4YBPu2zMu84NPYgJ2AYAlIdEqlBaixNVyLNbgvJBGUr5Gi0ec6IiOQbt/I/z7uZVN9HsRxgznIRw==", + "dev": true, + "requires": { + "async": "^2.6.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "dargs": "^6.0.0", + "which": "^1.3.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "grunt-contrib-uglify": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-5.0.1.tgz", + "integrity": "sha512-T/aXZ4WIpAtoswZqb6HROKg7uq9QbKwl+lUuOwK4eoFj3tFv9/a/oMyd3/qvetV29Pbf8P1YYda1gDwZppr60A==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "maxmin": "^2.1.0", + "uglify-js": "^3.13.3", + "uri-path": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "gzip-size": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz", + "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=", + "dev": true, + "requires": { + "duplexer": "^0.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "maxmin": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-2.1.0.tgz", + "integrity": "sha1-TTsiCQPZXu5+t6x/qGTnLcCaMWY=", + "dev": true, + "requires": { + "chalk": "^1.0.0", + "figures": "^1.0.1", + "gzip-size": "^3.0.0", + "pretty-bytes": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "pretty-bytes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz", + "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "grunt-contrib-versioning2": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/grunt-contrib-versioning2/-/grunt-contrib-versioning2-1.0.7.tgz", + "integrity": "sha1-FOtUe7xrvtXkfjuUoGUvS7+VFpA=", + "dev": true + }, + "grunt-known-options": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.1.tgz", + "integrity": "sha512-cHwsLqoighpu7TuYj5RonnEuxGVFnztcUqTqp5rXFGYL4OuPFofwC4Ycg7n9fYwvK6F5WbYgeVOwph9Crs2fsQ==", + "dev": true + }, + "grunt-legacy-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.0.tgz", + "integrity": "sha512-GHZQzZmhyq0u3hr7aHW4qUH0xDzwp2YXldLPZTCjlOeGscAOWWPftZG3XioW8MasGp+OBRIu39LFx14SLjXRcA==", + "dev": true, + "requires": { + "colors": "~1.1.2", + "grunt-legacy-log-utils": "~2.1.0", + "hooker": "~0.2.3", + "lodash": "~4.17.19" + } + }, + "grunt-legacy-log-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.0.tgz", + "integrity": "sha512-lwquaPXJtKQk0rUM1IQAop5noEpwFqOXasVoedLeNzaibf/OPWjKYvvdqnEHNmU+0T0CaReAXIbGo747ZD+Aaw==", + "dev": true, + "requires": { + "chalk": "~4.1.0", + "lodash": "~4.17.19" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, - "globby": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", - "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", + "grunt-legacy-util": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.1.tgz", + "integrity": "sha512-2bQiD4fzXqX8rhNdXkAywCadeqiPiay0oQny77wA2F3WF4grPJXCvAcyoWUJV+po/b15glGkxuSiQCK299UC2w==", "dev": true, "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" + "async": "~3.2.0", + "exit": "~0.1.2", + "getobject": "~1.0.0", + "hooker": "~0.2.3", + "lodash": "~4.17.21", + "underscore.string": "~3.3.5", + "which": "~2.0.2" + }, + "dependencies": { + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==", + "dev": true + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } } }, - "glogg": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", - "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "grunt-run-grunt": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/grunt-run-grunt/-/grunt-run-grunt-1.0.1.tgz", + "integrity": "sha512-3d2eAfLqbi9wa9NRc0tP7HWtHm/aGjhry52kOudr0iXRyFdgbgiWLEDZCunw5Z+C1DoErJ3RQOTVWoZhz1lXGg==", "dev": true, "requires": { - "sparkles": "^1.0.0" + "async": "^2.6.1", + "grunt-known-options": "^1.1.1", + "lodash": "^4.17.11" + }, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + } } }, - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - }, "gulp": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", @@ -2189,6 +2989,24 @@ "glogg": "^1.0.0" } }, + "gzip-size": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", + "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "pify": "^4.0.1" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -2222,6 +3040,12 @@ "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", "dev": true }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", @@ -2289,12 +3113,57 @@ "parse-passwd": "^1.0.0" } }, + "hooker": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", + "dev": true + }, "hosted-git-info": { "version": "2.8.8", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", "dev": true }, + "htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "dev": true, + "requires": { + "domelementtype": "1", + "domhandler": "2.3", + "domutils": "1.5", + "entities": "1.0", + "readable-stream": "1.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, "http-errors": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", @@ -2342,6 +3211,13 @@ "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", "dev": true }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", + "dev": true, + "optional": true + }, "immutable": { "version": "3.8.2", "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", @@ -2592,6 +3468,12 @@ "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", "dev": true }, + "is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -2627,6 +3509,32 @@ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz", "integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==" }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jshint": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.12.0.tgz", + "integrity": "sha512-TwuuaUDmra0JMkuqvqy+WGo2xGHSNjv1BA1nTIgtH2K5z1jHuAEeAgp7laaR+hLRmajRjcrM71+vByBDanCyYA==", + "dev": true, + "requires": { + "cli": "~1.0.0", + "console-browserify": "1.1.x", + "exit": "0.1.x", + "htmlparser2": "3.8.x", + "lodash": "~4.17.19", + "minimatch": "~3.0.2", + "shelljs": "0.3.x", + "strip-json-comments": "1.0.x" + } + }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -2691,6 +3599,33 @@ "flush-write-stream": "^1.0.2" } }, + "less": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.1.tgz", + "integrity": "sha512-w09o8tZFPThBscl5d0Ggp3RcrKIouBoQscnOMgFH3n5V3kN/CXGHNfCkRPtxJk6nKryDXaV9aHLK55RXuH4sAw==", + "dev": true, + "requires": { + "copy-anything": "^2.0.1", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^2.5.2", + "parse-node-version": "^1.0.1", + "source-map": "~0.6.0", + "tslib": "^1.10.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, "liftoff": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", @@ -2707,6 +3642,45 @@ "resolve": "^1.1.7" } }, + "liftup": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", + "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", + "dev": true, + "requires": { + "extend": "^3.0.2", + "findup-sync": "^4.0.0", + "fined": "^1.2.0", + "flagged-respawn": "^1.0.1", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.1", + "rechoir": "^0.7.0", + "resolve": "^1.19.0" + }, + "dependencies": { + "findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + } + }, + "rechoir": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", + "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", + "dev": true, + "requires": { + "resolve": "^1.9.0" + } + } + } + }, "limiter": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", @@ -2791,6 +3765,26 @@ "integrity": "sha1-+4m2WpqAKBgz8LdHizpRBPiY67M=", "dev": true }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "optional": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "optional": true + } + } + }, "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", @@ -2953,6 +3947,48 @@ } } }, + "maxmin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-3.0.0.tgz", + "integrity": "sha512-wcahMInmGtg/7c6a75fr21Ch/Ks1Tb+Jtoan5Ft4bAI0ZvJqyOw8kkM7e7p8hDSzY805vmxwHT50KcjGwKyJ0g==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "figures": "^3.2.0", + "gzip-size": "^5.1.1", + "pretty-bytes": "^5.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -3032,6 +4068,12 @@ } } }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -3063,6 +4105,37 @@ "to-regex": "^3.0.1" } }, + "needle": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.6.0.tgz", + "integrity": "sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg==", + "dev": true, + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "optional": true + } + } + }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", @@ -3075,6 +4148,21 @@ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -3108,6 +4196,12 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -3249,6 +4343,12 @@ "readable-stream": "^2.0.1" } }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, "os-locale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", @@ -3258,6 +4358,22 @@ "lcid": "^1.0.0" } }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -3365,6 +4481,12 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", @@ -3440,6 +4562,12 @@ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "dev": true }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true + }, "pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", @@ -3452,6 +4580,13 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true, + "optional": true + }, "pump": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", @@ -3805,6 +4940,13 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true, + "optional": true + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -3991,6 +5133,27 @@ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", "dev": true }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "dev": true + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -4269,6 +5432,12 @@ "extend-shallow": "^3.0.0" } }, + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + }, "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -4379,6 +5548,12 @@ "is-utf8": "^0.2.0" } }, + "strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "dev": true + }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", @@ -4509,6 +5684,12 @@ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", "dev": true }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "type": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", @@ -4527,12 +5708,28 @@ "integrity": "sha512-yo+miGzQx5gakzVK3QFfN0/L9uVhosXBBO7qmnk7c2iw1IhL212wfA3zbnI54B0obGwC/5NWub/iT9sReMx+Fw==", "dev": true }, + "uglify-js": { + "version": "3.13.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.4.tgz", + "integrity": "sha512-kv7fCkIXyQIilD5/yQy8O+uagsYIOt5cZvs890W40/e/rvjMSzJw81o9Bg0tkURxzZBROtDQhW2LFjOGoK3RZw==", + "dev": true + }, "unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", "dev": true }, + "underscore.string": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz", + "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==", + "dev": true, + "requires": { + "sprintf-js": "^1.0.3", + "util-deprecate": "^1.0.2" + } + }, "undertaker": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", @@ -4643,6 +5840,12 @@ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", "dev": true }, + "uri-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", + "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=", + "dev": true + }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", diff --git a/src/covid19/package.json b/src/covid19/package.json index aaec60f7544d093d4d02f9a9d458693e0d2ae0e3..1c88617c89162e1ec1316eebc50bc57a6b025fbc 100644 --- a/src/covid19/package.json +++ b/src/covid19/package.json @@ -27,7 +27,7 @@ "build:version": "node scripts/version.js", "docker:build": "node scripts/docker/docker-build.js", "docker:run": "node scripts/docker/docker-run.js", - "postinstall": "./node_modules/.bin/gulp" + "postinstall": "./node_modules/.bin/grunt" }, "private": true, "dependencies": { @@ -42,7 +42,18 @@ "del": "^6.0.0", "gulp": "^4.0.2", "gulp-cli": "^2.3.0", - "merge-stream": "^2.0.0" + "merge-stream": "^2.0.0", + "grunt": "^1.4.0", + "grunt-cli": "^1.4.2", + "grunt-contrib-clean": "^2.0.0", + "grunt-contrib-copy": "^1.0.0", + "grunt-contrib-cssmin": "^4.0.0", + "grunt-contrib-jshint": "^3.0.0", + "grunt-contrib-less": "^3.0.0", + "grunt-contrib-sass": "^2.0.0", + "grunt-contrib-uglify": "^5.0.1", + "grunt-contrib-versioning2": "^1.0.7", + "grunt-run-grunt": "^1.0.1" }, "engines": { "node": ">=v12.18.2" diff --git a/src/database.py b/src/database.py index abb56fb5925b447b9264a8399779ba38b1dd2b71..8deaf8440213051517d80801f6e42f9863751c5b 100644 --- a/src/database.py +++ b/src/database.py @@ -92,14 +92,18 @@ ITEMS_PER_PAGE = app.config['SQLALCHEMY_ITEMS_PER_PAGE'] # TODO: #210 database.py: logging for Celery on Windows my_logging_config = { 'version': 1, - 'formatters': {'default': { - 'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s', - }}, - 'handlers': {'wsgi': { - 'class': 'logging.StreamHandler', - 'stream': 'ext://flask.logging.wsgi_errors_stream', - 'formatter': 'default' - }}, + 'formatters': { + 'default': { + 'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s', + } + }, + 'handlers': { + 'wsgi': { + 'class': 'logging.StreamHandler', + 'stream': 'ext://flask.logging.wsgi_errors_stream', + 'formatter': 'default' + } + }, 'root': { 'level': 'INFO', 'handlers': ['wsgi']