Merge branch 'feature/application_root' into 'master'
Added env variable for application root See merge request caimira/caimira!434
This commit is contained in:
commit
68dba71cc7
16 changed files with 127 additions and 88 deletions
|
|
@ -106,6 +106,12 @@ To run with a specific template theme created:
|
|||
python -m caimira.apps.calculator --theme=caimira/apps/templates/{theme}
|
||||
```
|
||||
|
||||
To run the entire app in a different `APPLICATION_ROOT` path:
|
||||
|
||||
```
|
||||
python -m caimira.apps.calculator --app_root=/myroot
|
||||
```
|
||||
|
||||
To run the calculator on a different URL path:
|
||||
|
||||
```
|
||||
|
|
|
|||
|
|
@ -6,13 +6,16 @@ if [[ "$APP_NAME" == "caimira-webservice" ]]; then
|
|||
args+=("--no-debug")
|
||||
fi
|
||||
|
||||
if [ ! -z "$CAIMIRA_THEME" ]; then
|
||||
args+=("--theme=${CAIMIRA_THEME}")
|
||||
if [ ! -z "$APPLICATION_ROOT" ]; then
|
||||
args+=("--app_root=${APPLICATION_ROOT}")
|
||||
fi
|
||||
|
||||
if [ ! -z "$CAIMIRA_CALCULATOR_PREFIX" ]; then
|
||||
args+=("--prefix=${CAIMIRA_CALCULATOR_PREFIX}")
|
||||
fi
|
||||
if [ ! -z "$CAIMIRA_THEME" ]; then
|
||||
args+=("--theme=${CAIMIRA_THEME}")
|
||||
fi
|
||||
|
||||
export "ARVE_API_KEY"="$ARVE_API_KEY"
|
||||
export "ARVE_CLIENT_ID"="$ARVE_CLIENT_ID"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ services:
|
|||
environment:
|
||||
- COOKIE_SECRET
|
||||
- APP_NAME=caimira-webservice
|
||||
- APPLICATION_ROOT=/
|
||||
- CAIMIRA_CALCULATOR_PREFIX=/calculator-cern
|
||||
- CAIMIRA_THEME=caimira/apps/templates/cern
|
||||
user: ${CURRENT_UID}
|
||||
|
|
@ -20,6 +21,7 @@ services:
|
|||
environment:
|
||||
- COOKIE_SECRET
|
||||
- APP_NAME=caimira-webservice
|
||||
- APPLICATION_ROOT=/
|
||||
- CAIMIRA_CALCULATOR_PREFIX=/calculator-open
|
||||
user: ${CURRENT_UID}
|
||||
|
||||
|
|
|
|||
|
|
@ -205,6 +205,8 @@
|
|||
value: '3'
|
||||
- name: APP_NAME
|
||||
value: caimira-webservice
|
||||
- name: APPLICATION_ROOT
|
||||
value: /
|
||||
- name: CAIMIRA_CALCULATOR_PREFIX
|
||||
value: /calculator-cern
|
||||
- name: CAIMIRA_THEME
|
||||
|
|
@ -297,6 +299,8 @@
|
|||
env:
|
||||
- name: APP_NAME
|
||||
value: caimira-webservice
|
||||
- name: APPLICATION_ROOT
|
||||
value: /
|
||||
- name: CAIMIRA_CALCULATOR_PREFIX
|
||||
value: /calculator-open
|
||||
image: '${PROJECT_NAME}/caimira-webservice'
|
||||
|
|
|
|||
|
|
@ -73,7 +73,8 @@ class BaseRequestHandler(RequestHandler):
|
|||
print(traceback.format_exc())
|
||||
self.finish(template.render(
|
||||
user=self.current_user,
|
||||
calculator_prefix=self.settings["calculator_prefix"],
|
||||
get_url = template.globals['get_url'],
|
||||
get_calculator_url = template.globals["get_calculator_url"],
|
||||
active_page='Error',
|
||||
contents=contents
|
||||
))
|
||||
|
|
@ -87,7 +88,8 @@ class Missing404Handler(BaseRequestHandler):
|
|||
"page.html.j2")
|
||||
self.finish(template.render(
|
||||
user=self.current_user,
|
||||
calculator_prefix=self.settings["calculator_prefix"],
|
||||
get_url = template.globals['get_url'],
|
||||
get_calculator_url = template.globals["get_calculator_url"],
|
||||
active_page='Error',
|
||||
contents='Unfortunately the page you were looking for does not exist.<br><br><br><br>'
|
||||
))
|
||||
|
|
@ -193,8 +195,9 @@ class LandingPage(BaseRequestHandler):
|
|||
"index.html.j2")
|
||||
report = template.render(
|
||||
user=self.current_user,
|
||||
calculator_prefix=self.settings["calculator_prefix"],
|
||||
text_blocks=template_environment.globals['common_text'],
|
||||
get_url = template_environment.globals['get_url'],
|
||||
get_calculator_url = template_environment.globals['get_calculator_url'],
|
||||
text_blocks=template_environment.globals["common_text"],
|
||||
)
|
||||
self.finish(report)
|
||||
|
||||
|
|
@ -205,9 +208,10 @@ class AboutPage(BaseRequestHandler):
|
|||
template = template_environment.get_template("about.html.j2")
|
||||
report = template.render(
|
||||
user=self.current_user,
|
||||
calculator_prefix=self.settings["calculator_prefix"],
|
||||
get_url = template.globals['get_url'],
|
||||
get_calculator_url = template.globals["get_calculator_url"],
|
||||
active_page="about",
|
||||
text_blocks=template_environment.globals['common_text']
|
||||
text_blocks=template_environment.globals["common_text"]
|
||||
)
|
||||
self.finish(report)
|
||||
|
||||
|
|
@ -220,9 +224,10 @@ class CalculatorForm(BaseRequestHandler):
|
|||
report = template.render(
|
||||
user=self.current_user,
|
||||
xsrf_form_html=self.xsrf_form_html(),
|
||||
calculator_prefix=self.settings["calculator_prefix"],
|
||||
get_url = template.globals['get_url'],
|
||||
get_calculator_url = template.globals["get_calculator_url"],
|
||||
calculator_version=__version__,
|
||||
text_blocks=template_environment.globals['common_text'],
|
||||
text_blocks=template_environment.globals["common_text"],
|
||||
)
|
||||
self.finish(report)
|
||||
|
||||
|
|
@ -236,8 +241,9 @@ class CompressedCalculatorFormInputs(BaseRequestHandler):
|
|||
except Exception as err: # noqa
|
||||
self.set_status(400)
|
||||
return self.finish("Invalid calculator data: it seems incomplete. Was there an error copying & pasting the URL?")
|
||||
self.redirect(f'{self.settings["calculator_prefix"]}?{args}')
|
||||
|
||||
template_environment = self.settings["template_environment"]
|
||||
self.redirect(f'{template_environment.globals["get_calculator_url"]()}?{args}')
|
||||
|
||||
|
||||
class ReadmeHandler(BaseRequestHandler):
|
||||
def get(self):
|
||||
|
|
@ -246,8 +252,9 @@ class ReadmeHandler(BaseRequestHandler):
|
|||
readme = template.render(
|
||||
active_page="calculator/user-guide",
|
||||
user=self.current_user,
|
||||
calculator_prefix=self.settings["calculator_prefix"],
|
||||
text_blocks=template_environment.globals['common_text'],
|
||||
get_url = template.globals['get_url'],
|
||||
get_calculator_url = template.globals["get_calculator_url"],
|
||||
text_blocks=template_environment.globals["common_text"],
|
||||
)
|
||||
self.finish(readme)
|
||||
|
||||
|
|
@ -337,28 +344,39 @@ class CasesData(BaseRequestHandler):
|
|||
# If any of the 'New_cases' is 0, it means the data is not updated.
|
||||
if (cases.loc[eight_days_ago:current_date]['New_cases'] == 0).any(): return self.finish('')
|
||||
return self.finish(str(round(cases.loc[eight_days_ago:current_date]['New_cases'].mean())))
|
||||
|
||||
|
||||
def get_url(app_root: str, relative_path: str = '/'):
|
||||
return app_root.rstrip('/') + relative_path.rstrip('/')
|
||||
|
||||
def get_calculator_url(app_root: str, calculator_prefix: str, relative_path: str = '/'):
|
||||
return app_root.rstrip('/') + calculator_prefix.rstrip('/') + relative_path.rstrip('/')
|
||||
|
||||
def make_app(
|
||||
debug: bool = False,
|
||||
APPLICATION_ROOT: str = '/',
|
||||
calculator_prefix: str = '/calculator',
|
||||
theme_dir: typing.Optional[Path] = None,
|
||||
) -> Application:
|
||||
static_dir = Path(__file__).absolute().parent.parent / 'static'
|
||||
calculator_static_dir = Path(__file__).absolute().parent / 'static'
|
||||
|
||||
get_root_url = functools.partial(get_url, APPLICATION_ROOT)
|
||||
get_root_calculator_url = functools.partial(get_calculator_url, APPLICATION_ROOT, calculator_prefix)
|
||||
|
||||
urls: typing.Any = [
|
||||
(r'/?', LandingPage),
|
||||
(r'/_c/(.*)', CompressedCalculatorFormInputs),
|
||||
(r'/about', AboutPage),
|
||||
(r'/static/(.*)', StaticFileHandler, {'path': static_dir}),
|
||||
(calculator_prefix + r'/?', CalculatorForm),
|
||||
(calculator_prefix + r'/report', ConcentrationModel),
|
||||
(calculator_prefix + r'/report-json', ConcentrationModelJsonResponse),
|
||||
(calculator_prefix + r'/baseline-model/result', StaticModel),
|
||||
(calculator_prefix + r'/user-guide', ReadmeHandler),
|
||||
(calculator_prefix + r'/api/arve/v1/(.*)/(.*)', ArveData),
|
||||
(calculator_prefix + r'/cases/(.*)', CasesData),
|
||||
(calculator_prefix + r'/static/(.*)', StaticFileHandler, {'path': calculator_static_dir}),
|
||||
(get_root_url(r'/?'), LandingPage),
|
||||
(get_root_url(r'/_c/(.*)'), CompressedCalculatorFormInputs),
|
||||
(get_root_url(r'/about'), AboutPage),
|
||||
(get_root_url(r'/static/(.*)'), StaticFileHandler, {'path': static_dir}),
|
||||
(get_root_calculator_url(r'/?'), CalculatorForm),
|
||||
(get_root_calculator_url(r'/report'), ConcentrationModel),
|
||||
(get_root_calculator_url(r'/report-json'), ConcentrationModelJsonResponse),
|
||||
(get_root_calculator_url(r'/baseline-model/result'), StaticModel),
|
||||
(get_root_calculator_url(r'/user-guide'), ReadmeHandler),
|
||||
(get_root_calculator_url(r'/api/arve/v1/(.*)/(.*)'), ArveData),
|
||||
(get_root_calculator_url(r'/cases/(.*)'), CasesData),
|
||||
(get_root_calculator_url(r'/static/(.*)'), StaticFileHandler, {'path': calculator_static_dir}),
|
||||
]
|
||||
|
||||
caimira_templates = Path(__file__).parent.parent / "templates"
|
||||
|
|
@ -372,9 +390,11 @@ def make_app(
|
|||
undefined=jinja2.StrictUndefined, # fail when rendering any undefined template context variable
|
||||
)
|
||||
|
||||
template_environment.globals['common_text'] = markdown_tools.extract_rendered_markdown_blocks(
|
||||
template_environment.globals["common_text"] = markdown_tools.extract_rendered_markdown_blocks(
|
||||
template_environment.get_template('common_text.md.j2')
|
||||
)
|
||||
template_environment.globals['get_url']=get_root_url
|
||||
template_environment.globals['get_calculator_url']=get_root_calculator_url
|
||||
|
||||
if debug:
|
||||
tornado.log.enable_pretty_logging()
|
||||
|
|
@ -382,10 +402,11 @@ def make_app(
|
|||
return Application(
|
||||
urls,
|
||||
debug=debug,
|
||||
calculator_prefix=calculator_prefix,
|
||||
# calculator_prefix=calculator_prefix,
|
||||
# APPLICATION_ROOT=APPLICATION_ROOT,
|
||||
template_environment=template_environment,
|
||||
default_handler_class=Missing404Handler,
|
||||
report_generator=ReportGenerator(loader, calculator_prefix),
|
||||
report_generator=ReportGenerator(loader, get_root_url, get_root_calculator_url),
|
||||
xsrf_cookies=True,
|
||||
# COOKIE_SECRET being undefined will result in no login information being
|
||||
# presented to the user.
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@ def configure_parser(parser) -> argparse.ArgumentParser:
|
|||
help="A directory containing extensions for templates and static data",
|
||||
default=None,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--app_root",
|
||||
help="Change the APPLICATION_ROOT of the app",
|
||||
default="/"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--prefix",
|
||||
help="Change the URL path prefix to the calculator app",
|
||||
|
|
@ -36,7 +41,7 @@ def main():
|
|||
if theme_dir is not None:
|
||||
theme_dir = Path(theme_dir).absolute()
|
||||
assert theme_dir.exists()
|
||||
app = make_app(debug=args.no_debug, calculator_prefix=args.prefix, theme_dir=theme_dir)
|
||||
app = make_app(debug=args.no_debug, APPLICATION_ROOT=args.app_root, calculator_prefix=args.prefix, theme_dir=theme_dir)
|
||||
app.listen(args.port)
|
||||
IOLoop.instance().start()
|
||||
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ def calculate_report_data(form: FormData, model: models.ExposureModel) -> typing
|
|||
}
|
||||
|
||||
|
||||
def generate_permalink(base_url, calculator_prefix, form: FormData):
|
||||
def generate_permalink(base_url, get_root_url, get_root_calculator_url, form: FormData):
|
||||
form_dict = FormData.to_dict(form, strip_defaults=True)
|
||||
|
||||
# Generate the calculator URL arguments that would be needed to re-create this
|
||||
|
|
@ -165,8 +165,8 @@ def generate_permalink(base_url, calculator_prefix, form: FormData):
|
|||
# Then zlib compress + base64 encode the string. To be inverted by the
|
||||
# /_c/ endpoint.
|
||||
compressed_args = base64.b64encode(zlib.compress(args.encode())).decode()
|
||||
qr_url = f"{base_url}/_c/{compressed_args}"
|
||||
url = f"{base_url}{calculator_prefix}?{args}"
|
||||
qr_url = f"{base_url}{get_root_url()}/_c/{compressed_args}"
|
||||
url = f"{base_url}{get_root_calculator_url()}?{args}"
|
||||
|
||||
return {
|
||||
'link': url,
|
||||
|
|
@ -342,7 +342,8 @@ def comparison_report(
|
|||
@dataclasses.dataclass
|
||||
class ReportGenerator:
|
||||
jinja_loader: jinja2.BaseLoader
|
||||
calculator_prefix: str
|
||||
get_root_url: typing.Any
|
||||
get_root_calculator_url: typing.Any
|
||||
|
||||
def build_report(
|
||||
self,
|
||||
|
|
@ -377,8 +378,9 @@ class ReportGenerator:
|
|||
context['alternative_scenarios'] = comparison_report(
|
||||
form, report_data, alternative_scenarios, scenario_sample_times, executor_factory=executor_factory,
|
||||
)
|
||||
context['permalink'] = generate_permalink(base_url, self.calculator_prefix, form)
|
||||
context['calculator_prefix'] = self.calculator_prefix
|
||||
context['permalink'] = generate_permalink(base_url, self.get_root_url, self.get_root_calculator_url, form)
|
||||
context['get_url'] = self.get_root_url
|
||||
context['get_calculator_url'] = self.get_root_calculator_url
|
||||
|
||||
return context
|
||||
|
||||
|
|
@ -387,7 +389,7 @@ class ReportGenerator:
|
|||
loader=self.jinja_loader,
|
||||
undefined=jinja2.StrictUndefined,
|
||||
)
|
||||
env.globals['common_text'] = markdown_tools.extract_rendered_markdown_blocks(
|
||||
env.globals["common_text"] = markdown_tools.extract_rendered_markdown_blocks(
|
||||
env.get_template('common_text.md.j2')
|
||||
)
|
||||
env.filters['non_zero_percentage'] = non_zero_percentage
|
||||
|
|
@ -401,4 +403,4 @@ class ReportGenerator:
|
|||
|
||||
def render(self, context: dict) -> str:
|
||||
template = self._template_environment().get_template("calculator.report.html.j2")
|
||||
return template.render(**context, text_blocks=template.globals['common_text'])
|
||||
return template.render(**context, text_blocks=template.globals["common_text"])
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ For information on the Airborne Transmission of SARS-CoV-2, feel free to check o
|
|||
CAiMIRA stands for CERN Airborne Model for Indoor Risk Assessment, previously known as CARA - COVID Airborne Risk Assessment, developed in the spring of 2020 to better understand and quantify the risk of long-range airborne spread of SARS-CoV-2 virus in workplaces.
|
||||
Since then, the model has evolved and now is capable of simulating the short-range component. CAiMIRA comes with different applications that allow more or less flexibility in the input parameters:
|
||||
<ul>
|
||||
<li><a href='{{ calculator_prefix }}'>CAiMIRA calculator app</a></li>
|
||||
<li><a href='{{ get_calculator_url() }}'>CAiMIRA calculator app</a></li>
|
||||
<li><a href='/expert-app'>CAiMIRA expert app</a></li>
|
||||
</ul>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@
|
|||
|
||||
{% block extra_headers %}
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" integrity="sha512-aOG0c6nPNzGk+5zjwyJaoRUgCdOrfSDhmMID2u4+OIslr0GjpLKo7Xm0Ao3xmpM4T8AmIouRkqwj1nrdVsLKEQ==" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="{{ calculator_prefix }}/static/css/form.css">
|
||||
<link rel="stylesheet" href="{{ get_calculator_url('/static/css') }}/form.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css"/>
|
||||
{% endblock extra_headers %}
|
||||
|
||||
{% block body_scripts %}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js" integrity="sha512-uto9mlQzrs59VwILcLiRYeLKPPbS/bT71da/OEBYEwcdNUk8jYIy+D176RYoop1Da+f9mvkYrmj5MCLZWEtQuA==" crossorigin="anonymous"></script>
|
||||
<script src="{{ calculator_prefix }}/static/js/form.js"></script>
|
||||
<script src="{{ get_calculator_url('/static/js') }}/form.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||
{% endblock body_scripts %}
|
||||
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
{% if DEBUG %}
|
||||
<form id="covid_calculator" name="covid_calculator" onsubmit="return debug_submit(this)" class="form-inline">
|
||||
{% else %}
|
||||
<form id="covid_calculator" name="covid_calculator" action="{{ calculator_prefix }}/report" onsubmit="return validate_form(this)" method="POST">
|
||||
<form id="covid_calculator" name="covid_calculator" action="{{ get_calculator_url() }}/report" onsubmit="return validate_form(this)" method="POST">
|
||||
{% endif %}
|
||||
{{ xsrf_form_html }}
|
||||
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
<div class="container container--padding">
|
||||
<div class="d-flex header-height">
|
||||
<h1 class="align-self-center">Calculator</h1>
|
||||
<img src="/static/images/caimira_logo.200x200.png" class="logo_form align-self-center ml-3">
|
||||
<img src="{{ get_url('/static/images') }}/caimira_logo.200x200.png" class="logo_form align-self-center ml-3">
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
|
@ -222,7 +222,7 @@
|
|||
If these conditions are not met, the air exchange might not be homogenous producing an artificially lower risk further away from the window.
|
||||
<br>
|
||||
<br>
|
||||
<img src="/static/images/nat_vent_dimensions.png" id="nat_vent_image">
|
||||
<img src="{{ get_url('/static/images') }}/nat_vent_dimensions.png" id="nat_vent_image">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -327,14 +327,14 @@
|
|||
<input type="radio" id="mask_type_1" name="mask_type" value="Type I" checked="checked" onclick="require_fields(this)">
|
||||
<label for="mask_type_1">
|
||||
Surgical/Type I
|
||||
<img class="mask_icons" src="/static/images/masks/t1.png">
|
||||
<img class="mask_icons" src="{{ get_url('/static/images/masks') }}/t1.png">
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="mask_type_ffp2" name="mask_type" value="FFP2" onclick="require_fields(this)">
|
||||
<label for="mask_type_ffp2">
|
||||
Respirator/FFP2
|
||||
<img class="mask_icons" src="/static/images/masks/ffp2.png">
|
||||
<img class="mask_icons" src="{{ get_url('/static/images/masks') }}/ffp2.png">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -342,7 +342,7 @@
|
|||
<input type="radio" id="mask_type_cloth" name="mask_type" value="Cloth" onclick="require_fields(this)">
|
||||
<label for="mask_type_cloth">
|
||||
Cloth
|
||||
<img class="mask_icons" src="/static/images/masks/cloth.png">
|
||||
<img class="mask_icons" src="{{ get_url('/static/images/masks') }}/cloth.png">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -717,13 +717,13 @@
|
|||
<li>If coffee breaks are included, they are spread out evenly throughout the day,
|
||||
in addition to any lunch break (if applicable).</li>
|
||||
</ul>
|
||||
Refer to <a href="{{ calculator_prefix }}/user-guide"> Calculator App user guide </a>
|
||||
Refer to <a href="{{ get_calculator_url() }}/user-guide"> Calculator App user guide </a>
|
||||
for more detailed explanations on how to use this tool. <br>
|
||||
</div>
|
||||
|
||||
<div class="center container--padding pr-3 pl-3">
|
||||
<button class="btn btn-primary bigButton">
|
||||
<a href="{{ calculator_prefix }}/user-guide" class="{{ "nav-link active" if "user-guide" in active_page else "nav-link" }}" style="color:white">User guide</a>
|
||||
<a href="{{ get_calculator_url() }}/user-guide" class="{{ "nav-link active" if "user-guide" in active_page else "nav-link" }}" style="color:white">User guide</a>
|
||||
</button>
|
||||
<button class="btn btn-primary bigButton ml-2" type="button" data-toggle="collapse" data-target="#collapseDisclaimer" aria-expanded="false" aria-controls="collapseDisclaimer">
|
||||
Disclaimer
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@
|
|||
|
||||
<title>Report | CAiMIRA (CERN Airborne Model for Indoor Risk Assessment)</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="{{ calculator_prefix }}/static/css/report.css">
|
||||
<link rel="stylesheet" type="text/css" href="{{ get_calculator_url('/static/css') }}/report.css">
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="/static/css/style.css">
|
||||
<link rel="icon" type="image/x-icon" href="static/icons/favicon.ico">
|
||||
<link rel="stylesheet" href="{{ get_url('/static/css') }}/style.css">
|
||||
<link rel="icon" type="image/x-icon" href="{{ get_url('/static/icons') }}/favicon.ico">
|
||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||
<script src="{{ calculator_prefix }}/static/js/report.js" type="application/javascript"></script>
|
||||
<script src="{{ get_calculator_url('/static/js') }}/report.js" type="application/javascript"></script>
|
||||
|
||||
</head>
|
||||
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
{% block report_header %}
|
||||
|
||||
<div id="report-header-div" class="d-flex flex-row" style="margin: 1%">
|
||||
<a href="/" class="align-self-center"><img id="report_logo" src="/static/images/caimira_logo.200x200.png" class="d-inline-block align-middle mr-3"></a>
|
||||
<a href="{{ get_url() }}" class="align-self-center"><img id="report_logo" src="{{ get_url('/static/images') }}/caimira_logo.200x200.png" class="d-inline-block align-middle mr-3"></a>
|
||||
<div style="margin-right: -105px" class='align-self-center mr-auto'>
|
||||
<h2 class="header_text mb-0"><a href="{{ permalink.shortened }}" style="color: #2f4858">REPORT - {{ form.simulation_name }}</a></h2>
|
||||
<p class="mb-0" id="report_version"> Created {{ creation_date }} using CAiMIRA calculator version v{{ form.calculator_version }}</p>
|
||||
|
|
@ -85,7 +85,7 @@
|
|||
{% endif %}
|
||||
</h6>
|
||||
<br>
|
||||
<img src="/static/images/long_range_anim.png" class="align-middle mb-3 pi-image">
|
||||
<img src="{{ get_url('/static/images') }}/long_range_anim.png" class="align-middle mb-3 pi-image">
|
||||
<div class="d-flex" style="min-height: 160px">
|
||||
{% block long_range_warning_animation %}
|
||||
<div class="intro-banner-vdo-play-btn animation-color m-auto d-flex align-items-center justify-content-center">
|
||||
|
|
@ -106,7 +106,7 @@
|
|||
With <b>short-range interactions</b>
|
||||
</h6>
|
||||
<br>
|
||||
<img src="/static/images/short_range_anim.png" class="align-middle mb-3 pi-image">
|
||||
<img src="{{ get_url('/static/images') }}/short_range_anim.png" class="align-middle mb-3 pi-image">
|
||||
<div class="d-flex" style="min-height: 160px">
|
||||
{% block warning_animation %}
|
||||
<div class="intro-banner-vdo-play-btn animation-color m-auto d-flex align-items-center justify-content-center">
|
||||
|
|
@ -609,7 +609,7 @@
|
|||
<br><br><br>
|
||||
<div id="disclaimer" style="border: #dee2e6 1px solid; margin: 1%; padding: 20px" class="rounded">
|
||||
{% block disclaimer %}
|
||||
<p class="image"> <img align="middle" src="{{ calculator_prefix }}/static/images/disclaimer.jpg" width="40" height="40"><b>Disclaimer:</b><br><br></p>
|
||||
<p class="image"> <img align="middle" src="{{ get_calculator_url('/static/images') }}/disclaimer.jpg" width="40" height="40"><b>Disclaimer:</b><br><br></p>
|
||||
{{ text_blocks['Disclaimer'] }}
|
||||
{% endblock disclaimer %}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@
|
|||
{% block main %}
|
||||
<header class= "bg-light">
|
||||
<div class="container container--padding">
|
||||
<img src="/static/images/caimira_full_text.png" class="logo d-block m-auto" id="desktop_logo">
|
||||
<img src="/static/images/caimira_full_logo.png" class="logo d-none m-auto" id="mobile_logo">
|
||||
<img src="{{ get_url('/static/images') }}/caimira_full_text.png" class="logo d-block m-auto" id="desktop_logo">
|
||||
<img src="{{ get_url('/static/images') }}/caimira_full_logo.png" class="logo d-none m-auto" id="mobile_logo">
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="container container--padding">
|
||||
<div class="d-flex mb-3 justify-content-center" id="calculator_app_button">
|
||||
<div><a href="{{ calculator_prefix }}" role="button" class="btn btn-outline-primary"><div class="d-flex d-row"><i class="icon-calculator"></i><span class="pl-1">Calculator</div></a></div>
|
||||
<div><a href="{{ get_calculator_url() }}" role="button" class="btn btn-outline-primary"><div class="d-flex d-row"><i class="icon-calculator"></i><span class="pl-1">Calculator</div></a></div>
|
||||
</div>
|
||||
<div class="split">
|
||||
<div class="col-lg-8 col-md-7 pl-0">
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
<p>
|
||||
CAiMIRA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions.
|
||||
It does this by simulating the airborne spread SARS-CoV-2 virus in a finite volume, assuming homogenous mixing for the long-range component and a two-stage jet model for short-range, and estimates the risk of COVID-19 airborne transmission therein.
|
||||
Please see the <a href="/about">About</a> page for more details on the methodology, assumptions and limitations of CAiMIRA.
|
||||
Please see the <a href="{{ get_url('/about') }}">About</a> page for more details on the methodology, assumptions and limitations of CAiMIRA.
|
||||
</p>
|
||||
<p>
|
||||
The full CAiMIRA source code can be accessed freely under an Apache 2.0 open source license from our <a href="https://gitlab.cern.ch/caimira/caimira">code repository</a>.
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
</div>
|
||||
<div id="apps_section" class="d-none">
|
||||
<div class="d-flex flex-row" >
|
||||
<div class="pr-3"><a href="{{ calculator_prefix }}" role="button" class="btn btn-lg btn-outline-primary"><div class="d-flex d-row"><i class="icon-calculator"></i><span class="pl-2">Calculator</div></a></div>
|
||||
<div class="pr-3"><a href="{{ get_calculator_url() }}" role="button" class="btn btn-lg btn-outline-primary"><div class="d-flex d-row"><i class="icon-calculator"></i><span class="pl-2">Calculator</div></a></div>
|
||||
<br>
|
||||
<div class="expert_app_button"><a href="/expert-app" role="button" class="btn btn-lg btn-outline-secondary"><div class="d-flex d-row"><i class="icon-expert"></i><span class="pl-2">Expert (beta)</div></a></div>
|
||||
</div>
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="align-self-center">
|
||||
<img src="static/images/CAiMIRA_1_Vs3_Colour.jpg" class="caimira_home_image">
|
||||
<img src="{{ get_url('/static/images') }}/CAiMIRA_1_Vs3_Colour.jpg" class="caimira_home_image">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -46,11 +46,11 @@
|
|||
<div class="split">
|
||||
<div class="w-25 mobile-sub-section"><hr width="95%">
|
||||
<div class="d-flex m-2 align-items-center"><i class="bi bi-window" style="font-size: 25px"></i><div><p class="paragraph-title ml-2">Applications</p></div></div>
|
||||
<div class="m-2">CAiMIRA is composed of two applications, the <a href="{{ calculator_prefix }}">Calculator</a> and the <a href="/expert-app">Expert App</a>.</div>
|
||||
<div class="m-2">CAiMIRA is composed of two applications, the <a href="{{ get_calculator_url() }}">Calculator</a> and the <a href="/expert-app">Expert App</a>.</div>
|
||||
</div>
|
||||
<div class="w-25 mobile-sub-section"><hr width="95%">
|
||||
<div class="d-flex m-2 align-items-center"><i class="bi bi-info-square-fill" style="font-size: 25px"></i><div><p class="paragraph-title ml-2">About</p></div></div>
|
||||
<div class="m-2"><a href="/about">About</a> page for details on methodology, assumptions and limitations of CAiMIRA.</div>
|
||||
<div class="m-2"><a href="{{ get_url('/about') }}">About</a> page for details on methodology, assumptions and limitations of CAiMIRA.</div>
|
||||
</div>
|
||||
<div class="w-25 mobile-sub-section"><hr width="95%">
|
||||
<div class="d-flex m-2 align-items-center"><i class="bi bi-journal-text" style="font-size: 25px"></i><div><p class="paragraph-title ml-2">Documentation</p></div></div>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<meta id="url_prefix" data-calculator_prefix="{{ calculator_prefix }}">
|
||||
<meta id="url_prefix" data-calculator_prefix="{{ get_calculator_url() }}">
|
||||
|
||||
<title>
|
||||
{% block title %}
|
||||
|
|
@ -14,10 +14,10 @@
|
|||
</title>
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="/static/css/style.css">
|
||||
<link rel="stylesheet" href="{{ get_url('/static/css') }}/style.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,500,600,700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css">
|
||||
<link rel="icon" type="image/x-icon" href="static/icons/favicon.ico">
|
||||
<link rel="icon" type="image/x-icon" href="{{ get_url('/static/icons') }}/favicon.ico">
|
||||
|
||||
{% block extra_headers %}
|
||||
{% endblock extra_headers %}
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
<nav class="navbar navbar-dark navbar-expand-lg">
|
||||
<div class="container">
|
||||
|
||||
<a href="/" class="navbar-brand"><img src="/static/images/caimira_logo_white_text.png" alt="Logo" title="Logo"></a>
|
||||
<a href="{{ get_url() }}/" class="navbar-brand"><img src="{{ get_url('/static/images') }}/caimira_logo_white_text.png" alt="Logo" title="Logo"></a>
|
||||
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
|
|
@ -36,26 +36,26 @@
|
|||
|
||||
<div class="collapse navbar-collapse" id="navbarResponsive">
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<li class="nav-link"><a href="/" class="{{ "header-navbar nav-link active" if "home/" == active_page else "header-navbar nav-link" }}">Home</a></li>
|
||||
<li class="nav-link"><a href="{{ get_url() }}/" class="{{ "header-navbar nav-link active" if "home/" == active_page else "header-navbar nav-link" }}">Home</a></li>
|
||||
<div id="apps_dropdown">
|
||||
<li class="nav-item dropdown p-2">
|
||||
<a class="nav-link dropdown-toggle {{ "header-navbar nav-link active" if "calculator/" in active_page else "header-navbar nav-link" }}" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
Apps
|
||||
</a>
|
||||
<ul class="dropdown-menu dropwown-navbar-colors" style="min-width: 12rem;" aria-labelledby="navbarDropdown">
|
||||
<li><a href="{{ calculator_prefix }}" class="{{ "header-navbar nav-link active" if "calculator/" == active_page else "header-navbar nav-link" }}">Calculator</a></li>
|
||||
<li><div class="d-flex"><span class="d-flex align-self-center submenu-division"></span><a href="{{ calculator_prefix }}/user-guide" class="{{ "header-navbar nav-link active" if "user-guide" in active_page else "header-navbar nav-link" }}">User Guide</a></div></li>
|
||||
<li><a href="{{ get_calculator_url() }}" class="{{ "header-navbar nav-link active" if "calculator/" == active_page else "header-navbar nav-link" }}">Calculator</a></li>
|
||||
<li><div class="d-flex"><span class="d-flex align-self-center submenu-division"></span><a href="{{ get_calculator_url() }}/user-guide" class="{{ "header-navbar nav-link active" if "user-guide" in active_page else "header-navbar nav-link" }}">User Guide</a></div></li>
|
||||
<li><a href="/expert-app" class="{{ "header-navbar nav-link active" if "/expert-app" == active_page else "header-navbar nav-link" }}">Expert app (beta)</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</div>
|
||||
<div id="mobile_calculator_option">
|
||||
<li class="nav-link"><a href="{{ calculator_prefix }}" class="{{ "header-navbar nav-link active" if "calculator/" == active_page else "header-navbar nav-link" }}">Calculator</a></li>
|
||||
<li class="nav-link"><a href="{{ calculator_prefix }}/user-guide" class="{{ "header-navbar nav-link active" if "user-guide" in active_page else "header-navbar nav-link" }}">User Guide</a></li>
|
||||
<li class="nav-link"><a href="{{ get_calculator_url() }}" class="{{ "header-navbar nav-link active" if "calculator/" == active_page else "header-navbar nav-link" }}">Calculator</a></li>
|
||||
<li class="nav-link"><a href="{{ get_calculator_url() }}/user-guide" class="{{ "header-navbar nav-link active" if "user-guide" in active_page else "header-navbar nav-link" }}">User Guide</a></li>
|
||||
</div>
|
||||
{% block covid_information%}
|
||||
{% endblock covid_information%}
|
||||
<li class="nav-link"><a href="/about" class="{{ "header-navbar nav-link active" if "about" == active_page else "header-navbar nav-link" }}">About</a></li>
|
||||
<li class="nav-link"><a href="{{ get_url('/about') }}" class="{{ "header-navbar nav-link active" if "about" == active_page else "header-navbar nav-link" }}">About</a></li>
|
||||
{% if user.is_authenticated() %}
|
||||
<li class="nav-item dropdown p-2">
|
||||
<a class="nav-link active dropdown-toggle d-inline-block" href="https://cern.ch/users-portal" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
|
|
@ -85,7 +85,7 @@
|
|||
<div class="row text-light text-center py-4 justify-content-center">
|
||||
|
||||
<div class="col-sm-10 col-md-8 col-lg-6">
|
||||
<img src="/static/images/caimira_logo_white_text.png" alt="Logo">
|
||||
<img src="{{ get_url('/static/images') }}/caimira_logo_white_text.png" alt="Logo">
|
||||
<p><span style="font-size:10px;"><em>CERN strives to deploy its know-how and technologies to help solve
|
||||
the challenges arising in the local and global fight against COVID-19. As a particle physics
|
||||
research organisation, CERN is not in a position to advise on medical research, health or health
|
||||
|
|
@ -103,17 +103,12 @@
|
|||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="/static/js/js_packaged_for_theme.js"></script>
|
||||
<script src="{{ get_url('/static/js') }}/js_packaged_for_theme.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script>
|
||||
<script src="/static/js/jquery.colorbox-min.js"></script>
|
||||
<script src="/static/js/ScrollMagic.min.js"></script>
|
||||
<script src="{{ get_url('/static/js') }}/jquery.colorbox-min.js"></script>
|
||||
<script src="{{ get_url('/static/js') }}/ScrollMagic.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.3/js/bootstrap.min.js" integrity="sha512-8qmis31OQi6hIRgvkht0s6mCOittjMa9GMqtK9hes5iEQBQE/Ca6yGE5FsW36vyipGoWQswBj/QBm2JR086Rkw==" crossorigin="anonymous"></script>
|
||||
<script src="/static/js/usage-tracking.js"></script>
|
||||
|
||||
<!-- Popper JS -->
|
||||
<script src="/static/js/popper.min.js"></script>
|
||||
<!-- Font Awesome -->
|
||||
<script src="/static/js/all.min.js"></script>
|
||||
<script src="{{ get_url('/static/js') }}/usage-tracking.js"></script>
|
||||
|
||||
{% block body_scripts %}
|
||||
{% endblock body_scripts %}
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@
|
|||
<div class="alert alert-warning" role="alert">Events with a <strong>P(i) between 2% and 10%</strong> shall be subject to ALARA principles (see footnote) to minimise the risk before proceeding.</div>
|
||||
<div class="alert alert-danger mb-0" role="alert">Events with a <strong>P(i) exceeding 10% or a number of expected new cases that exceeds 1</strong> may not take place until additional measures are in place and a risk reduction has been performed.</div>
|
||||
</div>
|
||||
<div class="col-xl-3 align-self-center text-center"><img id="scale_warning" class="rounded" src="{{ calculator_prefix }}/static/images/warning_scale/{{ cern_level }}.png"></div>
|
||||
<div class="col-xl-3 align-self-center text-center"><img id="scale_warning" class="rounded" src="{{ get_calculator_url('/static/images/warning_scale') }}/{{ cern_level }}.png"></div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<div>
|
||||
<p>
|
||||
CAiMIRA has been developed by CERN with the intention of allowing members of personnel with roles related to supervision, health & safety or space management to simulate the concerned workplaces on CERN sites.
|
||||
A hosted <a href="{{ calculator_prefix }}">CERN version of the CAiMIRA Calculator</a> is available on this site to members of the CERN personnel.
|
||||
A hosted <a href="{{ get_calculator_url() }}">CERN version of the CAiMIRA Calculator</a> is available on this site to members of the CERN personnel.
|
||||
</p>
|
||||
</div>
|
||||
{% endblock caimira_at_cern %}
|
||||
|
|
@ -103,7 +103,7 @@ class TestOpenApp(tornado.testing.AsyncHTTPTestCase):
|
|||
|
||||
async def test_permalink_urls(http_server_client, baseline_form):
|
||||
base_url = 'proto://hostname/prefix'
|
||||
permalink_data = generate_permalink(base_url, "/calculator", baseline_form)
|
||||
permalink_data = generate_permalink(base_url, lambda: "", lambda: "/calculator", baseline_form)
|
||||
expected = f'{base_url}/calculator?exposed_coffee_break_option={baseline_form.exposed_coffee_break_option}&'
|
||||
assert permalink_data['link'].startswith(expected)
|
||||
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -43,6 +43,7 @@ REQUIREMENTS: dict = {
|
|||
'test': [
|
||||
'pytest',
|
||||
'pytest-mypy != v0.10.1',
|
||||
'mypy != 1.1.1',
|
||||
'pytest-tornasync',
|
||||
'numpy-stubs @ git+https://github.com/numpy/numpy-stubs.git',
|
||||
'types-dataclasses',
|
||||
|
|
|
|||
Loading…
Reference in a new issue