From a633cc7c0984f07be025af950ea6a64c7898f4da Mon Sep 17 00:00:00 2001 From: Aaron Louie Date: Sun, 24 May 2020 18:30:57 -0400 Subject: [PATCH] Reorganizes files for consistency between repos. Completely refactors Dockerfile to install from wheel. --- .gitignore | 2 +- Dockerfile | 60 ++++-- Pipfile | 1 + Pipfile.lock | 257 ++++++++++++++----------- app.py => pb/__init__.py | 10 +- api.yml => pb/api.yml | 8 +- forms.py => pb/forms.py | 9 +- models.py => pb/models.py | 2 +- run.py | 2 +- setup.cfg | 5 + setup.py | 3 + static/app.css | 133 +++++++++++++ tests/__init__.py | 0 test_sanity.py => tests/test_sanity.py | 6 +- 14 files changed, 344 insertions(+), 154 deletions(-) rename app.py => pb/__init__.py (96%) rename api.yml => pb/api.yml (99%) rename forms.py => pb/forms.py (90%) rename models.py => pb/models.py (99%) create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 static/app.css create mode 100644 tests/__init__.py rename test_sanity.py => tests/test_sanity.py (95%) diff --git a/.gitignore b/.gitignore index 1a77a3e..729225f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ __pycache__/ app.db static/.webassets-cache* -static/*.css +pb/static/*.css diff --git a/Dockerfile b/Dockerfile index d708d51..76b9055 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,30 +1,48 @@ -FROM python:3.7 +# +# https://medium.com/@greut/building-a-python-package-a-docker-image-using-pipenv-233d8793b6cc +# https://github.com/greut/pipenv-to-wheel +# +FROM kennethreitz/pipenv as pipenv -ENV PATH=/root/.local/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin +ADD . /app +WORKDIR /app -# install node and yarn -RUN apt-get update -RUN apt-get -y install postgresql-client libpcre3 libpcre3-dev +RUN pipenv install --dev \ + && pipenv lock -r > requirements.txt \ + && pipenv run python setup.py bdist_wheel -# config project dir -RUN mkdir /protocol-builder-mock -WORKDIR /protocol-builder-mock +# ---------------------------------------------------------------------------- +FROM ubuntu:bionic -# install python requirements -RUN pip install pipenv -ADD Pipfile /protocol-builder-mock/ -ADD Pipfile.lock /protocol-builder-mock/ -RUN pipenv install --dev +ARG DEBIAN_FRONTEND=noninteractive -# include rejoiner code (gets overriden by local changes) -COPY . /protocol-builder-mock/ +COPY --from=pipenv /app/dist/*.whl . -ENV FLASK_APP=/protocol-builder-mock/app.py +RUN set -xe \ + && apt-get update -q \ + && apt-get install -y -q \ + python3-minimal \ + python3-wheel \ + python3-pip \ + gunicorn3 \ + postgresql-client \ + && python3 -m pip install *.whl \ + && apt-get remove -y python3-pip python3-wheel \ + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -f *.whl \ + && rm -rf /root/.cache \ + && rm -rf /var/lib/apt/lists/* \ + && mkdir -p /app \ + && useradd _gunicorn --no-create-home --user-group -# run webserver by default -CMD ["pipenv", "run", "python", "/protocol-builder-mock/run.py"] - -# expose ports -EXPOSE 5001 +USER _gunicorn +COPY ./static /app/static +COPY ./docker_run.sh /app/ +COPY ./wait-for-it.sh /app/ +WORKDIR /app +CMD ["gunicorn3", \ + "--bind", "0.0.0.0:8000", \ + "pb:app"] diff --git a/Pipfile b/Pipfile index 2d13f1d..5f4a440 100644 --- a/Pipfile +++ b/Pipfile @@ -4,6 +4,7 @@ url = "https://pypi.org/simple" verify_ssl = true [dev-packages] +pbr = "*" [packages] flask = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 34da46f..c59122e 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "ca92325f9ff90d6263f261dc514de998c618a3e91614f9c1987b2f0db9b72dcf" + "sha256": "6d81da4e1f722cf965aeff5e24c86278b5df745f0eadaa2b401d54e7f836c654" }, "pipfile-spec": 6, "requires": { @@ -38,10 +38,10 @@ }, "certifi": { "hashes": [ - "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", - "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" + "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304", + "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519" ], - "version": "==2019.11.28" + "version": "==2020.4.5.1" }, "chardet": { "hashes": [ @@ -52,10 +52,10 @@ }, "click": { "hashes": [ - "sha256:8a18b4ea89d8820c5d0c7da8a64b2c324b4dabb695804dbfea19b9be9d88c0cc", - "sha256:e345d143d80bf5ee7534056164e5e112ea5e22716bbb1ce727941f4c8b471b9a" + "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", + "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" ], - "version": "==7.1.1" + "version": "==7.1.2" }, "clickclick": { "hashes": [ @@ -69,11 +69,11 @@ "swagger-ui" ], "hashes": [ - "sha256:bf32bfae6af337cfa4a8489c21516adbe5c50e3f8dc0b7ed2394ce8dde218018", - "sha256:c568e579f84be808e387dcb8570bb00a536891be1318718a0dad3ba90f034191" + "sha256:1ccfac57d4bb7adf4295ba6f5e48f5a1f66057df6a0713417766c9b5235182ee", + "sha256:5439e9659a89c4380d93a07acfbf3380d70be4130574de8881e5f0dfec7ad0e2" ], "index": "pypi", - "version": "==2.6.0" + "version": "==2.7.0" }, "decorator": { "hashes": [ @@ -84,11 +84,11 @@ }, "flask": { "hashes": [ - "sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52", - "sha256:45eb5a6fd193d6cf7e0cf5d8a5b31f83d5faae0293695626f539a823e93b13f6" + "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060", + "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557" ], "index": "pypi", - "version": "==1.1.1" + "version": "==1.1.2" }, "flask-assets": { "hashes": [ @@ -107,11 +107,11 @@ }, "flask-marshmallow": { "hashes": [ - "sha256:01520ef1851ccb64d4ffb33196cddff895cc1302ae1585bff1abf58684a8111a", - "sha256:28b969193958d9602ab5d6add6d280e0e360c8e373d3492c2f73b024ecd36374" + "sha256:6e6aec171b8e092e0eafaf035ff5b8637bf3a58ab46f568c4c1bab02f2a3c196", + "sha256:a1685536e7ab5abdc712bbc1ac1a6b0b50951a368502f7985e7d1c27b3c21e59" ], "index": "pypi", - "version": "==0.11.0" + "version": "==0.12.0" }, "flask-migrate": { "hashes": [ @@ -146,32 +146,31 @@ }, "gevent": { "hashes": [ - "sha256:0774babec518a24d9a7231d4e689931f31b332c4517a771e532002614e270a64", - "sha256:0e1e5b73a445fe82d40907322e1e0eec6a6745ca3cea19291c6f9f50117bb7ea", - "sha256:0ff2b70e8e338cf13bedf146b8c29d475e2a544b5d1fe14045aee827c073842c", - "sha256:107f4232db2172f7e8429ed7779c10f2ed16616d75ffbe77e0e0c3fcdeb51a51", - "sha256:14b4d06d19d39a440e72253f77067d27209c67e7611e352f79fe69e0f618f76e", - "sha256:1b7d3a285978b27b469c0ff5fb5a72bcd69f4306dbbf22d7997d83209a8ba917", - "sha256:1eb7fa3b9bd9174dfe9c3b59b7a09b768ecd496debfc4976a9530a3e15c990d1", - "sha256:2711e69788ddb34c059a30186e05c55a6b611cb9e34ac343e69cf3264d42fe1c", - "sha256:28a0c5417b464562ab9842dd1fb0cc1524e60494641d973206ec24d6ec5f6909", - "sha256:3249011d13d0c63bea72d91cec23a9cf18c25f91d1f115121e5c9113d753fa12", - "sha256:44089ed06a962a3a70e96353c981d628b2d4a2f2a75ea5d90f916a62d22af2e8", - "sha256:4bfa291e3c931ff3c99a349d8857605dca029de61d74c6bb82bd46373959c942", - "sha256:50024a1ee2cf04645535c5ebaeaa0a60c5ef32e262da981f4be0546b26791950", - "sha256:53b72385857e04e7faca13c613c07cab411480822ac658d97fd8a4ddbaf715c8", - "sha256:74b7528f901f39c39cdbb50cdf08f1a2351725d9aebaef212a29abfbb06895ee", - "sha256:7d0809e2991c9784eceeadef01c27ee6a33ca09ebba6154317a257353e3af922", - "sha256:896b2b80931d6b13b5d9feba3d4eebc67d5e6ec54f0cf3339d08487d55d93b0e", - "sha256:8d9ec51cc06580f8c21b41fd3f2b3465197ba5b23c00eb7d422b7ae0380510b0", - "sha256:9f7a1e96fec45f70ad364e46de32ccacab4d80de238bd3c2edd036867ccd48ad", - "sha256:ab4dc33ef0e26dc627559786a4fba0c2227f125db85d970abbf85b77506b3f51", - "sha256:d1e6d1f156e999edab069d79d890859806b555ce4e4da5b6418616322f0a3df1", - "sha256:d752bcf1b98174780e2317ada12013d612f05116456133a6acf3e17d43b71f05", - "sha256:e5bcc4270671936349249d26140c267397b7b4b1381f5ec8b13c53c5b53ab6e1" + "sha256:00b03601b8dd1ee2aa07811cb60a4befe36173b15d91c6e207e37f8d77dd6fac", + "sha256:0acc15ba2ac2a555529ad82d5a28fc85dbb6b2ff947657d67bebfd352e2b5c14", + "sha256:15eae3cd450dac7dae7f4ac59e01db1378965c9ef565c39c5ae78c5a888f9ac9", + "sha256:1dc7f1f6bc1f67d625e4272b01e717eba0b4fa024d2ff7934c8d320674d6f7fa", + "sha256:1dd95433be45e1115053878366e3f5332ae99c39cb345be23851327c062b9f4a", + "sha256:28b7d83b4327ceb79668eca2049bf4b9ce66d5ace18a88335e3035b573f889fd", + "sha256:31dc5d4ab8172cc00c4ff17cb18edee633babd961f64bf54214244d769bc3a74", + "sha256:38db524ea88d81d596b2cbb6948fced26654a15fec40ea4529224e239a6f45e8", + "sha256:3ff477b6d275396123faf8ce2d5b82f96d85ba264e0b9d4b56a2bac49d1b9adc", + "sha256:4d2729dd4bf9c4d0f29482f53cdf9fc90a498aebb5cd7ae8b45d35657437d2ac", + "sha256:52e5cd607749ed3b8aa0272cacf2c11deec61fca4c3bec57a9fea8c49316627d", + "sha256:5c604179cebcc57f10505d8db177b92a715907815a464b066e7eba322d1c33ac", + "sha256:88c76df4967c5229f853aa67ad1b394d9e4f985b0359c9bc9879416bba3e7c68", + "sha256:929c33df8e9bcbe31906024fcd21580bd018196dbd3249eb5b2f19d63e11092d", + "sha256:92edc18a357473e01a4e4a82c073ed3c99ceca6e3ce93c23668dd4a2401f07dc", + "sha256:937d36730f2b0dee3387712074b1f15b802e2e074a3d7c6dcaf70521236d607c", + "sha256:9b4e940fc6071afebb86ba5f48dbb5f1fc3cb96ebeb8cf145eb5b499e9c6ee33", + "sha256:a7805934e8ce81610b61f806572c3d504cedd698cc8c9460d78d2893ba598c4a", + "sha256:d07a2afe4215731eb57d5b257a2e7e7e170d8a7ae1f02f6d0682cd3403debea9", + "sha256:e01d5373528e4ebdde66dc47a608d225fa3c4408ccd828d26c49b7ff75d82bd9", + "sha256:efd9546468502a30ddd4699c3124ccb9d3099130f9b5ae1e2a54ad5b46e86120", + "sha256:fcb64f3a28420d1b872b7ef41b12e8a1a4dcadfc8eff3c09993ab0cdf52584a1" ], "index": "pypi", - "version": "==1.4.0" + "version": "==20.5.0" }, "greenlet": { "hashes": [ @@ -210,23 +209,25 @@ }, "importlib-metadata": { "hashes": [ - "sha256:06f5b3a99029c7134207dd882428a66992a9de2bef7c2b699b5641f9886c3302", - "sha256:b97607a1a18a5100839aec1dc26a1ea17ee0d93b20b0f008d80a5a050afb200b" + "sha256:2a688cbaa90e0cc587f1df48bdc97a6eadccdcd9c35fb3f976a09e3b5016d90f", + "sha256:34513a8a0c4962bc66d35b359558fd8a5e10cd472d37aec5f66858addef32c1e" ], "markers": "python_version < '3.8'", - "version": "==1.5.0" + "version": "==1.6.0" }, "infinity": { "hashes": [ + "sha256:91069282767a8695b880feda218948aafc1b89fddddd9b1b156792d9de8f6234", "sha256:dc4aa138d7e366fc00d2e741e32c78a0fecd16b74f8daeb3f7408b459668005c" ], "version": "==1.4" }, "inflection": { "hashes": [ - "sha256:18ea7fb7a7d152853386523def08736aa8c32636b047ade55f7578c4edeb16ca" + "sha256:32a5c3341d9583ec319548b9015b7fbdf8c429cbcb575d326c33ae3a0e90d52c", + "sha256:9a15d3598f01220e93f2207c432cfede50daff53137ce660fb8be838ef1ca6cc" ], - "version": "==0.3.1" + "version": "==0.4.0" }, "intervals": { "hashes": [ @@ -243,10 +244,10 @@ }, "jinja2": { "hashes": [ - "sha256:93187ffbc7808079673ef52771baa950426fd664d3aad1d0fa3e95644360e250", - "sha256:b0eaf100007721b5c16c1fc1eecb87409464edc10469ddc9a22a27a99123be49" + "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0", + "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035" ], - "version": "==2.11.1" + "version": "==2.11.2" }, "jsonschema": { "hashes": [ @@ -315,18 +316,18 @@ }, "marshmallow": { "hashes": [ - "sha256:90854221bbb1498d003a0c3cc9d8390259137551917961c8b5258c64026b2f85", - "sha256:ac2e13b30165501b7d41fc0371b8df35944f5849769d136f20e2c5f6cdc6e665" + "sha256:c2673233aa21dde264b84349dc2fd1dce5f30ed724a0a00e75426734de5b84ab", + "sha256:f88fe96434b1f0f476d54224d59333eba8ca1a203a2695683c1855675c4049a7" ], - "version": "==3.5.1" + "version": "==3.6.0" }, "marshmallow-sqlalchemy": { "hashes": [ - "sha256:9301c6fd197bd97337820ea1417aa1233d0ee3e22748ebd5821799bc841a57e8", - "sha256:dde9e20bcb710e9e59f765a38e3d6d17f1b2d6b4320cbdc2cea0f6b57f70d08c" + "sha256:3247e41e424146340b03a369f2b7c6f0364477ccedc4e2481e84d5f3a8d3c67f", + "sha256:dbbe51d28bb28e7ee2782e51310477f7a2c5a111a301f6dd8e264e11ab820427" ], "index": "pypi", - "version": "==0.22.3" + "version": "==0.23.0" }, "openapi-spec-validator": { "hashes": [ @@ -338,41 +339,39 @@ }, "psycopg2-binary": { "hashes": [ - "sha256:040234f8a4a8dfd692662a8308d78f63f31a97e1c42d2480e5e6810c48966a29", - "sha256:086f7e89ec85a6704db51f68f0dcae432eff9300809723a6e8782c41c2f48e03", - "sha256:18ca813fdb17bc1db73fe61b196b05dd1ca2165b884dd5ec5568877cabf9b039", - "sha256:19dc39616850342a2a6db70559af55b22955f86667b5f652f40c0e99253d9881", - "sha256:2166e770cb98f02ed5ee2b0b569d40db26788e0bf2ec3ae1a0d864ea6f1d8309", - "sha256:3a2522b1d9178575acee4adf8fd9f979f9c0449b00b4164bb63c3475ea6528ed", - "sha256:3aa773580f85a28ffdf6f862e59cb5a3cc7ef6885121f2de3fca8d6ada4dbf3b", - "sha256:3b5deaa3ee7180585a296af33e14c9b18c218d148e735c7accf78130765a47e3", - "sha256:407af6d7e46593415f216c7f56ba087a9a42bd6dc2ecb86028760aa45b802bd7", - "sha256:4c3c09fb674401f630626310bcaf6cd6285daf0d5e4c26d6e55ca26a2734e39b", - "sha256:4c6717962247445b4f9e21c962ea61d2e884fc17df5ddf5e35863b016f8a1f03", - "sha256:50446fae5681fc99f87e505d4e77c9407e683ab60c555ec302f9ac9bffa61103", - "sha256:5057669b6a66aa9ca118a2a860159f0ee3acf837eda937bdd2a64f3431361a2d", - "sha256:5dd90c5438b4f935c9d01fcbad3620253da89d19c1f5fca9158646407ed7df35", - "sha256:659c815b5b8e2a55193ede2795c1e2349b8011497310bb936da7d4745652823b", - "sha256:69b13fdf12878b10dc6003acc8d0abf3ad93e79813fd5f3812497c1c9fb9be49", - "sha256:7a1cb80e35e1ccea3e11a48afe65d38744a0e0bde88795cc56a4d05b6e4f9d70", - "sha256:7e6e3c52e6732c219c07bd97fff6c088f8df4dae3b79752ee3a817e6f32e177e", - "sha256:7f42a8490c4fe854325504ce7a6e4796b207960dabb2cbafe3c3959cb00d1d7e", - "sha256:84156313f258eafff716b2961644a4483a9be44a5d43551d554844d15d4d224e", - "sha256:8578d6b8192e4c805e85f187bc530d0f52ba86c39172e61cd51f68fddd648103", - "sha256:890167d5091279a27e2505ff0e1fb273f8c48c41d35c5b92adbf4af80e6b2ed6", - "sha256:98e10634792ac0e9e7a92a76b4991b44c2325d3e7798270a808407355e7bb0a1", - "sha256:9aadff9032e967865f9778485571e93908d27dab21d0fdfdec0ca779bb6f8ad9", - "sha256:9f24f383a298a0c0f9b3113b982e21751a8ecde6615494a3f1470eb4a9d70e9e", - "sha256:a73021b44813b5c84eda4a3af5826dd72356a900bac9bd9dd1f0f81ee1c22c2f", - "sha256:afd96845e12638d2c44d213d4810a08f4dc4a563f9a98204b7428e567014b1cd", - "sha256:b73ddf033d8cd4cc9dfed6324b1ad2a89ba52c410ef6877998422fcb9c23e3a8", - "sha256:b8f490f5fad1767a1331df1259763b3bad7d7af12a75b950c2843ba319b2415f", - "sha256:dbc5cd56fff1a6152ca59445178652756f4e509f672e49ccdf3d79c1043113a4", - "sha256:eac8a3499754790187bb00574ab980df13e754777d346f85e0ff6df929bcd964", - "sha256:eaed1c65f461a959284649e37b5051224f4db6ebdc84e40b5e65f2986f101a08" + "sha256:008da3ab51adc70a5f1cfbbe5db3a22607ab030eb44bcecf517ad11a0c2b3cac", + "sha256:07cf82c870ec2d2ce94d18e70c13323c89f2f2a2628cbf1feee700630be2519a", + "sha256:08507efbe532029adee21b8d4c999170a83760d38249936038bd0602327029b5", + "sha256:107d9be3b614e52a192719c6bf32e8813030020ea1d1215daa86ded9a24d8b04", + "sha256:17a0ea0b0eabf07035e5e0d520dabc7950aeb15a17c6d36128ba99b2721b25b1", + "sha256:3286541b9d85a340ee4ed42732d15fc1bb441dc500c97243a768154ab8505bb5", + "sha256:3939cf75fc89c5e9ed836e228c4a63604dff95ad19aed2bbf71d5d04c15ed5ce", + "sha256:40abc319f7f26c042a11658bf3dd3b0b3bceccf883ec1c565d5c909a90204434", + "sha256:51f7823f1b087d2020d8e8c9e6687473d3d239ba9afc162d9b2ab6e80b53f9f9", + "sha256:6bb2dd006a46a4a4ce95201f836194eb6a1e863f69ee5bab506673e0ca767057", + "sha256:702f09d8f77dc4794651f650828791af82f7c2efd8c91ae79e3d9fe4bb7d4c98", + "sha256:7036ccf715925251fac969f4da9ad37e4b7e211b1e920860148a10c0de963522", + "sha256:7b832d76cc65c092abd9505cc670c4e3421fd136fb6ea5b94efbe4c146572505", + "sha256:8f74e631b67482d504d7e9cf364071fc5d54c28e79a093ff402d5f8f81e23bfa", + "sha256:930315ac53dc65cbf52ab6b6d27422611f5fb461d763c531db229c7e1af6c0b3", + "sha256:96d3038f5bd061401996614f65d27a4ecb62d843eb4f48e212e6d129171a721f", + "sha256:a20299ee0ea2f9cca494396ac472d6e636745652a64a418b39522c120fd0a0a4", + "sha256:a34826d6465c2e2bbe9d0605f944f19d2480589f89863ed5f091943be27c9de4", + "sha256:a69970ee896e21db4c57e398646af9edc71c003bc52a3cc77fb150240fefd266", + "sha256:b9a8b391c2b0321e0cd7ec6b4cfcc3dd6349347bd1207d48bcb752aa6c553a66", + "sha256:ba13346ff6d3eb2dca0b6fa0d8a9d999eff3dcd9b55f3a890f12b0b6362b2b38", + "sha256:bb0608694a91db1e230b4a314e8ed00ad07ed0c518f9a69b83af2717e31291a3", + "sha256:c8830b7d5f16fd79d39b21e3d94f247219036b29b30c8270314c46bf8b732389", + "sha256:cac918cd7c4c498a60f5d2a61d4f0a6091c2c9490d81bc805c963444032d0dab", + "sha256:cc30cb900f42c8a246e2cb76539d9726f407330bc244ca7729c41a44e8d807fb", + "sha256:ccdc6a87f32b491129ada4b87a43b1895cf2c20fdb7f98ad979647506ffc41b6", + "sha256:d1a8b01f6a964fec702d6b6dac1f91f2b9f9fe41b310cbb16c7ef1fac82df06d", + "sha256:e004db88e5a75e5fdab1620fb9f90c9598c2a195a594225ac4ed2a6f1c23e162", + "sha256:eb2f43ae3037f1ef5e19339c41cf56947021ac892f668765cd65f8ab9814192e", + "sha256:fa466306fcf6b39b8a61d003123d442b23707d635a5cb05ac4e1b62cc79105cd" ], "index": "pypi", - "version": "==2.8.4" + "version": "==2.8.5" }, "pyrsistent": { "hashes": [ @@ -382,10 +381,10 @@ }, "pyscss": { "hashes": [ - "sha256:123c1a9087f1c420bea891ebf19d5222262c7d30ced20bb38586023de28c9d4f" + "sha256:f1df571569021a23941a538eb154405dde80bed35dc1ea7c5f3e18e0144746bf" ], "index": "pypi", - "version": "==1.3.6" + "version": "==1.3.7" }, "python-dateutil": { "hashes": [ @@ -404,10 +403,10 @@ }, "pytz": { "hashes": [ - "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d", - "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be" + "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed", + "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048" ], - "version": "==2019.3" + "version": "==2020.1" }, "pyyaml": { "hashes": [ @@ -434,23 +433,50 @@ }, "six": { "hashes": [ - "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", - "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c" + "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", + "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" ], - "version": "==1.14.0" + "version": "==1.15.0" }, "sqlalchemy": { "hashes": [ - "sha256:c4cca4aed606297afbe90d4306b49ad3a4cd36feb3f87e4bfd655c57fd9ef445" + "sha256:128bc917ed20d78143a45024455ff0aed7d3b96772eba13d5dbaf9cc57e5c41b", + "sha256:156a27548ba4e1fed944ff9fcdc150633e61d350d673ae7baaf6c25c04ac1f71", + "sha256:27e2efc8f77661c9af2681755974205e7462f1ae126f498f4fe12a8b24761d15", + "sha256:2a12f8be25b9ea3d1d5b165202181f2b7da4b3395289000284e5bb86154ce87c", + "sha256:31c043d5211aa0e0773821fcc318eb5cbe2ec916dfbc4c6eea0c5188971988eb", + "sha256:65eb3b03229f684af0cf0ad3bcc771970c1260a82a791a8d07bffb63d8c95bcc", + "sha256:6cd157ce74a911325e164441ff2d9b4e244659a25b3146310518d83202f15f7a", + "sha256:703c002277f0fbc3c04d0ae4989a174753a7554b2963c584ce2ec0cddcf2bc53", + "sha256:869bbb637de58ab0a912b7f20e9192132f9fbc47fc6b5111cd1e0f6cdf5cf9b0", + "sha256:8a0e0cd21da047ea10267c37caf12add400a92f0620c8bc09e4a6531a765d6d7", + "sha256:8d01e949a5d22e5c4800d59b50617c56125fc187fbeb8fa423e99858546de616", + "sha256:925b4fe5e7c03ed76912b75a9a41dfd682d59c0be43bce88d3b27f7f5ba028fb", + "sha256:9cb1819008f0225a7c066cac8bb0cf90847b2c4a6eb9ebb7431dbd00c56c06c5", + "sha256:a87d496884f40c94c85a647c385f4fd5887941d2609f71043e2b73f2436d9c65", + "sha256:a9030cd30caf848a13a192c5e45367e3c6f363726569a56e75dc1151ee26d859", + "sha256:a9e75e49a0f1583eee0ce93270232b8e7bb4b1edc89cc70b07600d525aef4f43", + "sha256:b50f45d0e82b4562f59f0e0ca511f65e412f2a97d790eea5f60e34e5f1aabc9a", + "sha256:b7878e59ec31f12d54b3797689402ee3b5cfcb5598f2ebf26491732758751908", + "sha256:ce1ddaadee913543ff0154021d31b134551f63428065168e756d90bdc4c686f5", + "sha256:ce2646e4c0807f3461be0653502bb48c6e91a5171d6e450367082c79e12868bf", + "sha256:ce6c3d18b2a8ce364013d47b9cad71db815df31d55918403f8db7d890c9d07ae", + "sha256:e4e2664232005bd306f878b0f167a31f944a07c4de0152c444f8c61bbe3cfb38", + "sha256:e8aa395482728de8bdcca9cc0faf3765ab483e81e01923aaa736b42f0294f570", + "sha256:eb4fcf7105bf071c71068c6eee47499ab8d4b8f5a11fc35147c934f0faa60f23", + "sha256:ed375a79f06cad285166e5be74745df1ed6845c5624aafadec4b7a29c25866ef", + "sha256:f35248f7e0d63b234a109dd72fbfb4b5cb6cb6840b221d0df0ecbf54ab087654", + "sha256:f502ef245c492b391e0e23e94cba030ab91722dcc56963c85bfd7f3441ea2bbe", + "sha256:fe01bac7226499aedf472c62fa3b85b2c619365f3f14dd222ffe4f3aa91e5f98" ], "index": "pypi", - "version": "==1.3.15" + "version": "==1.3.17" }, "sqlalchemy-utils": { "hashes": [ - "sha256:f268af5bc03597fe7690d60df3e5f1193254a83e07e4686f720f61587ec4493a" + "sha256:7a7fab14bed80df065412bbf71a0a9b0bfeb4b7c111c2d9bffe57283082f3a6b" ], - "version": "==0.36.3" + "version": "==0.36.6" }, "swagger-ui-bundle": { "hashes": [ @@ -462,16 +488,16 @@ }, "urllib3": { "hashes": [ - "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc", - "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc" + "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527", + "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115" ], - "version": "==1.25.8" + "version": "==1.25.9" }, "validators": { "hashes": [ - "sha256:b192e6bde7d617811d59f50584ed240b580375648cd032d106edeb3164099508" + "sha256:31e8bb01b48b48940a021b8a9576b840f98fa06b91762ef921d02cb96d38727a" ], - "version": "==0.14.2" + "version": "==0.15.0" }, "webassets": { "hashes": [ @@ -482,17 +508,17 @@ }, "werkzeug": { "hashes": [ - "sha256:169ba8a33788476292d04186ab33b01d6add475033dfc07215e6d219cc077096", - "sha256:6dc65cf9091cf750012f56f2cad759fa9e879f511b5ff8685e456b4e3bf90d16" + "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43", + "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c" ], - "version": "==1.0.0" + "version": "==1.0.1" }, "wtforms": { "hashes": [ - "sha256:0cdbac3e7f6878086c334aa25dc5a33869a3954e9d1e015130d65a69309b3b61", - "sha256:e3ee092c827582c50877cdbd49e9ce6d2c5c1f6561f849b3b068c1b8029626f1" + "sha256:6ff8635f4caeed9f38641d48cfe019d0d3896f41910ab04494143fc027866e1b", + "sha256:861a13b3ae521d6700dac3b2771970bd354a63ba7043ecc3a82b5288596a1972" ], - "version": "==2.2.1" + "version": "==2.3.1" }, "wtforms-alchemy": { "hashes": [ @@ -515,5 +541,14 @@ "version": "==3.1.0" } }, - "develop": {} + "develop": { + "pbr": { + "hashes": [ + "sha256:07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c", + "sha256:579170e23f8e0c2f24b0de612f71f648eccb79fb1322c814ae6b3c07b5ba23e8" + ], + "index": "pypi", + "version": "==5.4.5" + } + } } diff --git a/app.py b/pb/__init__.py similarity index 96% rename from app.py rename to pb/__init__.py index 1f0023c..8056a2c 100644 --- a/app.py +++ b/pb/__init__.py @@ -11,7 +11,6 @@ from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow from flask_migrate import Migrate from sqlalchemy import func - from wtforms.ext.appengine.db import model_form PROTOCOLS = {} @@ -40,8 +39,7 @@ def get_study_details(studyid): def get_form(id, requirement_code): return - -conn = connexion.App('Protocol Builder', specification_dir='./') +conn = connexion.App('Protocol Builder', specification_dir='pb') app = conn.app @@ -66,7 +64,7 @@ assets.register('app_scss', scss) # Loads all the descriptions from the API so we can display them in the editor. description_map = {} -with open(r'api.yml') as file: +with open(r'pb/api.yml') as file: api_config = yaml.load(file, Loader=yaml.FullLoader) study_detail_properties = api_config['components']['schemas']['StudyDetail']['properties'] for schema in api_config['components']['schemas']: @@ -98,8 +96,8 @@ def site_map(): # ************************** # WEB FORMS # ************************** -from forms import StudyForm, StudyTable, InvestigatorForm, StudyDetailsForm -from models import Study, RequiredDocument, Investigator, StudySchema, RequiredDocumentSchema, InvestigatorSchema, \ +from pb.forms import StudyForm, StudyTable, InvestigatorForm, StudyDetailsForm +from pb.models import Study, RequiredDocument, Investigator, StudySchema, RequiredDocumentSchema, InvestigatorSchema, \ StudyDetails, StudyDetailsSchema diff --git a/api.yml b/pb/api.yml similarity index 99% rename from api.yml rename to pb/api.yml index ac59e64..6893ea9 100644 --- a/api.yml +++ b/pb/api.yml @@ -20,7 +20,7 @@ paths: tags: - CR-Connect summary: A list of all studies related to a given UVA ID - operationId: app.get_user_studies + operationId: pb.get_user_studies description: "By passing in a valid UVA Id (ex: dhf8r) it will return a list of all studies that exist for that user in Protocol Builder" parameters: - in: query @@ -49,7 +49,7 @@ paths: tags: - CR-Connect summary: Required documents - operationId: app.required_docs + operationId: pb.required_docs description: A list of all documents Protocol Builder considers required, given input from the PI parameters: - in: query @@ -72,7 +72,7 @@ paths: tags: - CR-Connect summary: Personnel associated with this study. - operationId: app.investigators + operationId: pb.investigators description: A list of everyone that is associated with the study, including the PI, Study Coordinator, etc... This is currently returned on the "study" endpoint with other information. parameters: - in: query @@ -101,7 +101,7 @@ paths: get: tags: - CR-Connect - operationId: app.get_study_details + operationId: pb.get_study_details summary: Details about a specific protocol. responses: 200: diff --git a/forms.py b/pb/forms.py similarity index 90% rename from forms.py rename to pb/forms.py index 0b8e7f6..ceae06d 100644 --- a/forms.py +++ b/pb/forms.py @@ -1,12 +1,9 @@ -import sys - -from flask_table import Table, Col, DateCol, LinkCol, BoolCol, DatetimeCol, NestedTableCol +from flask_table import Table, Col, LinkCol, BoolCol, DatetimeCol, NestedTableCol from flask_wtf import FlaskForm -from wtforms import SelectMultipleField, SubmitField, StringField, IntegerField, BooleanField, DateField, widgets, \ - SelectField, validators, HiddenField +from wtforms import SelectMultipleField, StringField, BooleanField, SelectField, validators, HiddenField from wtforms_alchemy import ModelForm -from models import RequiredDocument, Investigator, StudyDetails +from pb.models import RequiredDocument, Investigator, StudyDetails class StudyForm(FlaskForm): diff --git a/models.py b/pb/models.py similarity index 99% rename from models.py rename to pb/models.py index 023ea0c..42c2b96 100644 --- a/models.py +++ b/pb/models.py @@ -1,5 +1,5 @@ from sqlalchemy import func -from app import db, ma +from pb import db, ma class Study(db.Model): diff --git a/run.py b/run.py index 6058c0e..9eb95ca 100644 --- a/run.py +++ b/run.py @@ -1,4 +1,4 @@ -from app import app +from pb import app if __name__ == "__main__": flask_port = app.config['FLASK_PORT'] app.run(host='0.0.0.0', port=flask_port) diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..9e50b6b --- /dev/null +++ b/setup.cfg @@ -0,0 +1,5 @@ +[metadata] +name = pb + +[files] +packages = pb diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..159a3d3 --- /dev/null +++ b/setup.py @@ -0,0 +1,3 @@ +from setuptools import setup + +setup(setup_requires=["pbr"], pbr=True) diff --git a/static/app.css b/static/app.css new file mode 100644 index 0000000..aaa9fcd --- /dev/null +++ b/static/app.css @@ -0,0 +1,133 @@ +.mat-icon { + font-family: 'Material Icons', sans-serif; + font-size: 24px; } + + .text-center { + text-align: center; } + + html, body { + padding: 1em; + margin: 0; + font-family: Arial, sans-serif; + font-size: 16px; } + + table { + border: 1px solid #cacaca; + background-color: white; + width: 100%; + text-align: left; + border-collapse: collapse; } + table th, table td { + padding: 0.5em; } + table td, table.blueTable th { + border: 1px solid #cacaca; } + table tbody td { + font-size: 14px; } + table tr:nth-child(even) { + background: #ededed; } + table thead { + background-color: #495e9d; } + table thead th { + font-size: 16px; + font-weight: bold; + color: white; + border-left: 1px solid #cacaca; } + table thead th:first-child { + border-left: none; } + table tfoot { + font-size: 16px; + font-weight: bold; + color: white; + background-color: #cacaca; } + table tfoot td { + font-size: 16px; } + table tfoot .links { + text-align: right; } + table tfoot .links a { + display: inline-block; + background: #495e9d; + color: white; + padding: 2px 8px; + border-radius: 5px; } + +.btn { + font-size: 16px; + padding: 0.5em 1em; + border-radius: 5px; + text-decoration: none; + color: white; + white-space: nowrap; + border: none; } + .btn:hover { + text-decoration: none; } + .btn.btn-icon { + font-family: 'Material Icons', sans-serif; + font-size: 24px; + border: none; } + .btn.btn-icon.btn-default { + color: #4e4e4e; + background-color: transparent; + border: none; } + .btn.btn-icon.btn-default:hover { + color: #373737; + background-color: transparent; } + .btn.btn-icon.btn-primary { + color: #232D4B; + background-color: transparent; } + .btn.btn-icon.btn-primary:hover { + color: #191f34; + background-color: transparent; } + .btn.btn-icon.btn-accent { + color: #E57200; + background-color: transparent; } + .btn.btn-icon.btn-accent:hover { + color: #a05000; + background-color: transparent; } + .btn.btn-icon.btn-warn { + color: #DF1E43; + background-color: transparent; } + .btn.btn-icon.btn-warn:hover { + color: #9c152f; + background-color: transparent; } + .btn.btn-default { + color: #373737; + background-color: white; + border: 1px solid #cacaca; } + .btn.btn-default:hover { + background-color: #ededed; } + .btn.btn-primary { + background-color: #232D4B; } + .btn.btn-primary:hover { + background-color: #191f34; } + .btn.btn-warn { + background-color: #DF1E43; } + .btn.btn-warn:hover { + background-color: #9c152f; } + .btn.btn-accent { + background-color: #E57200; } + .btn.btn-accent:hover { + background-color: #a05000; } + +select.multi { + height: 600px; } + + .form-field { + display: flex; + width: 100%; + margin-bottom: 40px; + padding: 2em; } + .form-field:nth-child(even) { + background-color: #ededed; } + .form-field .form-field-label, .form-field .form-field-help, + .form-field .form-field-input { + width: 30%; + text-align: left; + margin-right: 40px; } + .form-field .form-field-label { + font-weight: bold; } + .form-field .form-field-input input { + width: 100%; } + .form-field .form-field-help { + font-style: italic; } + .form-field .form-field-error { + color: #DF1E43; } diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test_sanity.py b/tests/test_sanity.py similarity index 95% rename from test_sanity.py rename to tests/test_sanity.py index 2be2710..29e32d0 100644 --- a/test_sanity.py +++ b/tests/test_sanity.py @@ -3,9 +3,9 @@ import os os.environ["TESTING"] = "true" import unittest -from app import app, db -from forms import StudyForm -from models import Study, RequiredDocument +from pb import app, db +from pb.forms import StudyForm +from pb.models import Study, RequiredDocument class Sanity_Check_Test(unittest.TestCase):