Fixes all the paths and routing errors
This commit is contained in:
parent
d54160600e
commit
07d0c43e8e
|
@ -1,5 +1,7 @@
|
|||
.idea
|
||||
__pycache__/
|
||||
app.db
|
||||
pb/static/.webassets-cache*
|
||||
pb/static/*.css
|
||||
static/.webassets-cache*
|
||||
static/*.css
|
||||
|
|
|
@ -23,8 +23,8 @@ WORKDIR /app
|
|||
ENV FLASK_APP=/app/pb/__init__.py
|
||||
|
||||
# Don't run gunicorn until the DC/OS container actually starts.
|
||||
# Otherwise, environment variables will not be availabele.
|
||||
# Otherwise, environment variables will not be available.
|
||||
#CMD ["pipenv", "run", "gunicorn", \
|
||||
# "--bind", "0.0.0.0:8000", \
|
||||
# "-e", "SCRIPT_NAME=/api", \
|
||||
# "crc:app"]
|
||||
# "wsgi:app"]
|
||||
|
|
1
Pipfile
1
Pipfile
|
@ -23,6 +23,7 @@ wtforms-alchemy = "*"
|
|||
psycopg2-binary = "*"
|
||||
pyscss = "*"
|
||||
gunicorn = "*"
|
||||
werkzeug = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.7"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "22303ab4362e0b95f21f7c949b2d43a4ec58b42add20699c159d2a7cc3eaf0be"
|
||||
"sha256": "42147b649c5838de2eba97ebf9360b65d4bdbb8b3ae94ba23c813660a9490ed3"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
|
@ -518,6 +518,7 @@
|
|||
"sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43",
|
||||
"sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.0.1"
|
||||
},
|
||||
"wtforms": {
|
||||
|
|
|
@ -18,4 +18,4 @@ if [ "$RESET_DB" = "true" ]; then
|
|||
pipenv run flask load-example-data
|
||||
fi
|
||||
|
||||
pipenv run gunicorn -e SCRIPT_NAME="$APPLICATION_ROOT" --bind 0.0.0.0:$PORT0 run:app
|
||||
pipenv run gunicorn -e SCRIPT_NAME="$APPLICATION_ROOT" --bind 0.0.0.0:$PORT0 wsgi:app
|
||||
|
|
119
pb/__init__.py
119
pb/__init__.py
|
@ -39,8 +39,7 @@ def get_study_details(studyid):
|
|||
def get_form(id, requirement_code):
|
||||
return
|
||||
|
||||
conn = connexion.App('Protocol Builder', specification_dir='pb')
|
||||
|
||||
conn = connexion.FlaskApp('Protocol Builder', specification_dir='pb')
|
||||
app = conn.app
|
||||
|
||||
app.config.from_object('config.default')
|
||||
|
@ -53,13 +52,43 @@ else:
|
|||
app.config.root_path = app.instance_path
|
||||
app.config.from_pyfile('config.py', silent=True)
|
||||
|
||||
conn.add_api('api.yml', base_path='/pb')
|
||||
conn.add_api('api.yml', base_path='/v2.0')
|
||||
db = SQLAlchemy(app)
|
||||
migrate = Migrate(app, db)
|
||||
ma = Marshmallow(app)
|
||||
|
||||
# Set the path of the static directory
|
||||
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
|
||||
APP_STATIC = os.path.join(APP_ROOT, 'static')
|
||||
BASE_HREF = app.config['APPLICATION_ROOT'].strip('/')
|
||||
app.static_folder = APP_STATIC
|
||||
app.static_url_path = app.config['APPLICATION_ROOT'] + 'static'
|
||||
|
||||
print('app.static_folder', app.static_folder)
|
||||
print('app.static_url_path', app.static_url_path)
|
||||
|
||||
# remove old static map
|
||||
url_map = app.url_map
|
||||
try:
|
||||
for rule in url_map.iter_rules('static'):
|
||||
url_map._rules.remove(rule)
|
||||
except ValueError:
|
||||
# no static view was created yet
|
||||
pass
|
||||
|
||||
# register new; the same view function is used
|
||||
app.add_url_rule(
|
||||
app.static_url_path + '/<path:filename>',
|
||||
endpoint='static', view_func=app.send_static_file)
|
||||
|
||||
assets = Environment(app)
|
||||
assets.init_app(app)
|
||||
assets.url = app.static_url_path
|
||||
scss = Bundle('scss/app.scss', filters='pyscss', output='app.css')
|
||||
scss = Bundle(
|
||||
'scss/app.scss',
|
||||
filters='pyscss',
|
||||
output='app.css'
|
||||
)
|
||||
assets.register('app_scss', scss)
|
||||
|
||||
# Loads all the descriptions from the API so we can display them in the editor.
|
||||
|
@ -88,7 +117,7 @@ def site_map():
|
|||
# Filter out rules we can't navigate to in a browser
|
||||
# and rules that require parameters
|
||||
if "GET" in rule.methods and has_no_empty_params(rule):
|
||||
url = url_for(rule.endpoint, **(rule.defaults or {}))
|
||||
url = app.confg['APPLICATION_ROOT'].strip('/') + url_for(rule.endpoint, **(rule.defaults or {}))
|
||||
links.append((url, rule.endpoint))
|
||||
return json.dumps({"links": links})
|
||||
|
||||
|
@ -106,25 +135,33 @@ def index():
|
|||
# display results
|
||||
studies = db.session.query(Study).order_by(Study.DATE_MODIFIED.desc()).all()
|
||||
table = StudyTable(studies)
|
||||
return render_template('index.html', table=table, APPLICATION_ROOT=app.config['APPLICATION_ROOT'])
|
||||
return render_template(
|
||||
'index.html',
|
||||
table=table,
|
||||
base_href=BASE_HREF
|
||||
)
|
||||
|
||||
|
||||
@app.route('/new_study', methods=['GET', 'POST'])
|
||||
def new_study():
|
||||
form = StudyForm(request.form)
|
||||
action = "/new_study"
|
||||
action = BASE_HREF + "/new_study"
|
||||
title = "New Study"
|
||||
if request.method == 'POST':
|
||||
study = Study()
|
||||
study.study_details = StudyDetails()
|
||||
_update_study(study, form)
|
||||
flash('Study created successfully!')
|
||||
return redirect('/')
|
||||
return redirect_home()
|
||||
|
||||
return render_template('form.html', form=form,
|
||||
action=action,
|
||||
title=title,
|
||||
description_map=description_map)
|
||||
return render_template(
|
||||
'form.html',
|
||||
form=form,
|
||||
action=action,
|
||||
title=title,
|
||||
description_map=description_map,
|
||||
base_href=BASE_HREF
|
||||
)
|
||||
|
||||
|
||||
@app.route('/study/<study_id>', methods=['GET', 'POST'])
|
||||
|
@ -132,7 +169,7 @@ def edit_study(study_id):
|
|||
study = db.session.query(Study).filter(Study.STUDYID == study_id).first()
|
||||
form = StudyForm(request.form, obj=study)
|
||||
if request.method == 'GET':
|
||||
action = "/study/" + study_id
|
||||
action = BASE_HREF + "/study/" + study_id
|
||||
title = "Edit Study #" + study_id
|
||||
if study.requirements:
|
||||
form.requirements.data = list(map(lambda r: r.AUXDOCID, list(study.requirements)))
|
||||
|
@ -141,17 +178,21 @@ def edit_study(study_id):
|
|||
if request.method == 'POST':
|
||||
_update_study(study, form)
|
||||
flash('Study updated successfully!')
|
||||
return redirect('/')
|
||||
return render_template('form.html', form=form,
|
||||
action=action,
|
||||
title=title,
|
||||
description_map={})
|
||||
return redirect_home()
|
||||
return render_template(
|
||||
'form.html',
|
||||
form=form,
|
||||
action=action,
|
||||
title=title,
|
||||
description_map={},
|
||||
base_href=BASE_HREF
|
||||
)
|
||||
|
||||
|
||||
@app.route('/investigator/<study_id>', methods=['GET', 'POST'])
|
||||
def new_investigator(study_id):
|
||||
form = InvestigatorForm(request.form)
|
||||
action = "/investigator/" + study_id
|
||||
action = BASE_HREF + "/investigator/" + study_id
|
||||
title = "Add Investigator to Study " + study_id
|
||||
if request.method == 'POST':
|
||||
investigator = Investigator(STUDYID=study_id)
|
||||
|
@ -160,19 +201,23 @@ def new_investigator(study_id):
|
|||
db.session.add(investigator)
|
||||
db.session.commit()
|
||||
flash('Investigator created successfully!')
|
||||
return redirect('/')
|
||||
return redirect_home()
|
||||
|
||||
return render_template('form.html', form=form,
|
||||
action=action,
|
||||
title=title,
|
||||
description_map={})
|
||||
return render_template(
|
||||
'form.html',
|
||||
form=form,
|
||||
action=action,
|
||||
title=title,
|
||||
description_map={},
|
||||
base_href=BASE_HREF
|
||||
)
|
||||
|
||||
|
||||
@app.route('/del_investigator/<inv_id>', methods=['GET'])
|
||||
def del_investigator(inv_id):
|
||||
db.session.query(Investigator).filter(Investigator.id == inv_id).delete()
|
||||
db.session.commit()
|
||||
return redirect('/')
|
||||
return redirect_home()
|
||||
|
||||
|
||||
@app.route('/del_study/<study_id>', methods=['GET'])
|
||||
|
@ -182,7 +227,7 @@ def del_study(study_id):
|
|||
db.session.query(StudyDetails).filter(StudyDetails.STUDYID == study_id).delete()
|
||||
db.session.query(Study).filter(Study.STUDYID == study_id).delete()
|
||||
db.session.commit()
|
||||
return redirect('/')
|
||||
return redirect_home()
|
||||
|
||||
|
||||
def _update_study(study, form):
|
||||
|
@ -217,7 +262,7 @@ def study_details(study_id):
|
|||
study_details = StudyDetails(STUDYID=study_id)
|
||||
form = StudyDetailsForm(request.form, obj=study_details)
|
||||
if request.method == 'GET':
|
||||
action = "/study_details/" + study_id
|
||||
action = BASE_HREF + "/study_details/" + study_id
|
||||
title = "Edit Study Details for Study #" + study_id
|
||||
details = "Numeric fields can be 1 for true, 0 or false, or Null if not applicable."
|
||||
if request.method == 'POST':
|
||||
|
@ -225,12 +270,20 @@ def study_details(study_id):
|
|||
db.session.add(study_details)
|
||||
db.session.commit()
|
||||
flash('Study updated successfully!')
|
||||
return redirect('/')
|
||||
return render_template('form.html', form=form,
|
||||
action=action,
|
||||
title=title,
|
||||
details=details,
|
||||
description_map=description_map)
|
||||
return redirect_home()
|
||||
return render_template(
|
||||
'form.html',
|
||||
form=form,
|
||||
action=action,
|
||||
title=title,
|
||||
details=details,
|
||||
description_map=description_map,
|
||||
base_href=BASE_HREF
|
||||
)
|
||||
|
||||
|
||||
def redirect_home():
|
||||
return redirect('/' + BASE_HREF)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
133
static/app.css
133
static/app.css
|
@ -1,133 +0,0 @@
|
|||
.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; }
|
|
@ -3,11 +3,13 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Protocol Builder Mock Configuration</title>
|
||||
<base href="/">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://use.typekit.net/kwp6dli.css">
|
||||
{% assets 'app_scss' %}
|
||||
<link href="{{ ASSET_URL }}" rel="stylesheet" type="text/css">
|
||||
<link href="{{ base_href + ASSET_URL }}" rel="stylesheet" type="text/css">
|
||||
{% endassets %}
|
||||
<link rel="shortcut icon" href="{{ base_href + url_for('static', filename='favicon.ico') }}">
|
||||
</head>
|
||||
<body>
|
||||
<h2>{{ title }}</h2>
|
||||
|
@ -27,7 +29,7 @@
|
|||
</div>
|
||||
{% endfor %}
|
||||
<button class="btn btn-primary" type="submit">Submit</button>
|
||||
<a href="/" class="btn btn-default">Cancel</a>
|
||||
<a href="{{ base_href + "/" }}" class="btn btn-default">Cancel</a>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<title>Protocol Builder Mock</title>
|
||||
<base href="{{ APPLICATION_ROOT }}">
|
||||
<base href="/">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://use.typekit.net/kwp6dli.css">
|
||||
{% assets 'app_scss' %}
|
||||
<link href="{{ ASSET_URL }}" rel="stylesheet" type="text/css">
|
||||
<link href="{{ base_href + ASSET_URL }}" rel="stylesheet" type="text/css">
|
||||
{% endassets %}
|
||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||
<link rel="shortcut icon" href="{{ base_href + url_for('static', filename='favicon.ico') }}">
|
||||
</head>
|
||||
<body>
|
||||
<h2>Protocol Builder Mock</h2>
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
from werkzeug.exceptions import NotFound
|
||||
from werkzeug.middleware.dispatcher import DispatcherMiddleware
|
||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||
|
||||
from pb import app
|
||||
|
||||
if __name__ == "__main__":
|
||||
def no_app(environ, start_response):
|
||||
return NotFound()(environ, start_response)
|
||||
|
||||
|
||||
# Remove trailing slash, but add leading slash
|
||||
base_url = '/' + app.config['APPLICATION_ROOT'].strip('/')
|
||||
|
||||
app.wsgi_app = DispatcherMiddleware(no_app, {app.config['APPLICATION_ROOT']: app.wsgi_app})
|
||||
app.wsgi_app = ProxyFix(app.wsgi_app)
|
||||
|
||||
flask_port = app.config['FLASK_PORT']
|
||||
|
||||
app.run(host='0.0.0.0', port=flask_port)
|
Loading…
Reference in New Issue