From 665172a0193a6684eab24753d13471bae926ee77 Mon Sep 17 00:00:00 2001 From: johnyu95 Date: Wed, 24 Jun 2020 14:47:32 -0400 Subject: [PATCH 1/8] Added front end for health screening --- app/main/forms.py | 10 +++++++ app/main/views.py | 22 ++++++++++++++ app/templates/base.html | 1 + app/templates/main/health_screen_confirm.html | 30 +++++++++++++++++++ 4 files changed, 63 insertions(+) create mode 100644 app/templates/main/health_screen_confirm.html diff --git a/app/main/forms.py b/app/main/forms.py index 66bc39c..ea3aa71 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -10,6 +10,7 @@ BooleanField, SelectMultipleField, ValidationError, + RadioField ) from wtforms.validators import DataRequired, Optional, Length, Email @@ -281,3 +282,12 @@ class GenerateMultipleTimesheetsForm(Form): class ExportForm(Form): export = SubmitField("Export") + + +class HealthScreenForm(Form): + name = StringField("Name", validators=[DataRequired()]) + email = StringField("Email", validators=[DataRequired()]) + division = StringField("Division", validators=[DataRequired()]) + questionnaire_confirmation = BooleanField(validators=[DataRequired()]) + report_to_work = SelectField(choices=[("", ""), ("Yes", "Yes"), ("No", "No")], validators=[DataRequired()]) + submit = SubmitField("Submit") diff --git a/app/main/views.py b/app/main/views.py index a8f83fc..f16ef53 100644 --- a/app/main/views.py +++ b/app/main/views.py @@ -34,6 +34,7 @@ RequestVacationForm, FilterVacationForm, ExportForm, + HealthScreenForm ) from .modules import ( process_clock, @@ -913,3 +914,24 @@ def review_vacations(): clear=clear_form, query_has_results=query_has_results, ) + + +@main.route("/health_screen_confirm", methods=["GET", "POST"]) +def health_screen_confirm(): + form = HealthScreenForm() + + if form.validate_on_submit(): + name = request.form["name"] + email = request.form["email"] + division = request.form["division"] + questionnaire_confirmation = request.form["division"] + report_to_work = request.form["report_to_work"] + + # Generate and email PDF + + flash("Screening completed. You will receive a confirmation email shortly.", category="success") + return redirect(url_for("auth.login")) + return render_template( + "main/health_screen_confirm.html", + form=form + ) \ No newline at end of file diff --git a/app/templates/base.html b/app/templates/base.html index dca30d2..d7e1db3 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -33,6 +33,7 @@ + + +{% endblock %} + +{% block content %} +
+ {% for category, message in get_flashed_messages(with_categories=True) %} + {% if category == 'error' %} +
+ {% else %} +
+ {% endif %} + + {{ message }} +
+ {% endfor %} + + {% block page_content %} + {% endblock %} +
+ {% endblock %} + + + + {% block scripts %} + + {{ super() }} + {{ moment.include_moment() }} + + + + + + {% endblock %} \ No newline at end of file diff --git a/app/templates/main/email/employee_health_screen_results.html b/app/templates/main/email/employee_health_screen_results.html new file mode 100644 index 0000000..e0e95f6 --- /dev/null +++ b/app/templates/main/email/employee_health_screen_results.html @@ -0,0 +1 @@ +

Employee Health Screen results for {{ name }} attached.

\ No newline at end of file diff --git a/app/templates/main/health_screen_confirm.html b/app/templates/main/health_screen_confirm.html index 5975cd0..a991843 100644 --- a/app/templates/main/health_screen_confirm.html +++ b/app/templates/main/health_screen_confirm.html @@ -1,11 +1,68 @@ -{% extends "base.html" %} +{% extends "base_healthscreen.html" %} {% import "bootstrap/wtf.html" as wtf %} {% block title %}TimeClock - Employee Health Screening{% endblock %} {% block page_content %} -

Employee Health Screening

-

Please answer the questions below and click the Submit button when done.

+

Employee Health Screening

+ +

Please answer the following four (4) questions on your own before reporting to the office and then complete the health + screening confirmation at the bottom of this page.

+ +

By filling in the four (4) questions below you are not submitting your individual responses to your employer.

+ +

+ You are being asked to answer this questionnaire in order to determine whether you are experiencing any symptoms + that could be consistent with COVID-19. This is being done solely for the purpose of protecting your workplace from + potential spread of the disease. Any results you get, and/or any directive you receive to stay home, does not + constitute a diagnosis of COVID-19, nor are we advising you whether you need to get tested or contact a physician. + You can consult CDC and health department websites for guidance in that regard. +

+
    +
  1. + Do you currently have a fever of 100.4 degrees F or greater? + +
  2. +
  3. + Do you have a cough or shortness of breath that began within the past 14 days? + +
  4. +
  5. + In the past 14 days, have you gotten a positive result from a COVID-19 test that tested saliva or used a nose or + throat swab? (not a blood test) ? + +
  6. +
  7. + In the past 14 days, have you been in close contact (within 6 feet for at least 10 minutes) with anyone who + either tested positive for COVID-19 (not a blood test) or developed symptoms of COVID-19 (fever, cough, or + shortness of breath)? + +
  8. +
+ +

+ Questionnaire Results: +

+

+
+

To submit your health screening confirmation, please fill out the form below and click the Submit button when done. +

{{ form.csrf_token }}
@@ -25,10 +82,13 @@

Please answer the questions below and click the Submit button when done.

    -
  1. Click here to confirm you completed the entire questionnaire.  {{ form.questionnaire_confirmation }}

  2. -
  3. Based on your questionnaire results, you may report to work yes or no.  {{ form.report_to_work }}

  4. +
  5. Click here to confirm you completed the entire + questionnaire.  {{ form.questionnaire_confirmation }}

  6. +
  7. Based on your questionnaire results, you may report to work yes or + no.  {{ form.report_to_work }}

-

If your response is “No”, please contact Naomi Pacheco (napacheco@records.nyc.gov) in Human Resources.


- {{ form.submit(class="btn btn-default") }} +

If your response is “No”, please contact the Administration Division at healthcheck@records.nyc.gov


+ {{ form.submit(class="btn btn-default") }} -{% endblock %} + {% endblock %} \ No newline at end of file diff --git a/app/utils.py b/app/utils.py index 292232b..dad6023 100644 --- a/app/utils.py +++ b/app/utils.py @@ -9,12 +9,11 @@ ("Administration", "Administration"), ("Archives", "Archives"), ("Executive", "Executive"), - ("Grants", "Grants"), + ("External Affairs", "External Affairs"), + ("IT", "IT"), ("Library", "Library"), ("Records Management", "Records Management"), ("Reference Room", "Reference Room"), - ("Social Media", "Social Media"), - ("Tech", "Tech"), ] roles = [("User", "User"), ("Administrator", "Administrator")] diff --git a/config.py b/config.py index 4602ea9..402677e 100644 --- a/config.py +++ b/config.py @@ -28,7 +28,7 @@ class DevelopmentConfig(Config): DEBUG = True SQLALCHEMY_DATABASE_URI = ( os.environ.get("DATABASE_URL") - or "postgresql://timeclock_db@127.0.0.1:5432/timeclock_dev" + or "postgresql://developer@127.0.0.1:5432/timeclock_dev" ) From 8f44c9722e381a5ffba3caa4239cbb58893c329f Mon Sep 17 00:00:00 2001 From: Joel Castillo Date: Thu, 25 Jun 2020 14:15:15 -0400 Subject: [PATCH 6/8] Update to validation on submission for email field. Co-authored-by: Gary Zhou Co-authored-by: Jonathan Yu --- Pipfile | 1 + Pipfile.lock | 27 ++++++++++++++----- app/email_notification.py | 4 ++- app/main/forms.py | 8 +++++- app/main/modules.py | 5 ++-- app/main/views.py | 7 ++++- app/templates/main/health_screen_confirm.html | 5 ++++ timeclock.py | 2 +- 8 files changed, 47 insertions(+), 12 deletions(-) diff --git a/Pipfile b/Pipfile index 02cd5d1..d3c9f58 100644 --- a/Pipfile +++ b/Pipfile @@ -61,6 +61,7 @@ sphinx = "*" sphinx-rtd-theme = "*" python-dotenv = "*" email-validator = "*" +faker = "*" [requires] python_version = "3.6" diff --git a/Pipfile.lock b/Pipfile.lock index 9607588..3da5c64 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "b0e3e31ebd3424e7149c196b708d30f6b7d85e55b7cafefe7a67a79a835138ce" + "sha256": "ecfa9708c5cb052a44e4a88ec846962d8f357f3147d300d588d128714ec46a3c" }, "pipfile-spec": 6, "requires": { @@ -120,7 +120,7 @@ "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" ], - "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==7.1.2" }, "cssselect": { @@ -179,6 +179,14 @@ "index": "pypi", "version": "==1.1.1" }, + "faker": { + "hashes": [ + "sha256:1290f589648bc470b8d98fff1fdff773fe3f46b4ca2cac73ac74668b12cf008e", + "sha256:c006b3664c270a2cfd4785c5e41ff263d48101c4e920b5961cf9c237131d8418" + ], + "index": "pypi", + "version": "==4.1.1" + }, "flask": { "hashes": [ "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060", @@ -761,6 +769,13 @@ "index": "pypi", "version": "==1.3.17" }, + "text-unidecode": { + "hashes": [ + "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", + "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93" + ], + "version": "==1.3" + }, "tinycss": { "hashes": [ "sha256:12306fb50e5e9e7eaeef84b802ed877488ba80e35c672867f548c0924a76716e" @@ -850,7 +865,7 @@ "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" ], - "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==7.1.2" }, "decorator": { @@ -862,11 +877,11 @@ }, "faker": { "hashes": [ - "sha256:2d3f866ef25e1a5af80e7b0ceeacc3c92dec5d0fdbad3e2cb6adf6e60b22188f", - "sha256:b89aa33837498498e15c709eb40c31386408a901a53c7a5e12a425737a767976" + "sha256:1290f589648bc470b8d98fff1fdff773fe3f46b4ca2cac73ac74668b12cf008e", + "sha256:c006b3664c270a2cfd4785c5e41ff263d48101c4e920b5961cf9c237131d8418" ], "index": "pypi", - "version": "==4.0.2" + "version": "==4.1.1" }, "flask": { "hashes": [ diff --git a/app/email_notification.py b/app/email_notification.py index 6b1c223..e03ff1a 100644 --- a/app/email_notification.py +++ b/app/email_notification.py @@ -42,7 +42,9 @@ def send_health_screen_confirmation_email(to, bcc, subject, filename, attachment app = current_app._get_current_object() msg = Message(subject, sender="healthcheck@records.nyc.gov", recipients=to, bcc=bcc) - msg.html = render_template("main/email/employee_health_screen_results.html", name=name) + msg.html = render_template( + "main/email/employee_health_screen_results.html", name=name + ) msg.attach(filename, "application/pdf", attachment) thr = Thread(target=send_async_email, args=[app, msg]) diff --git a/app/main/forms.py b/app/main/forms.py index e18eb0e..3e5acf3 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -285,7 +285,13 @@ class ExportForm(Form): class HealthScreenForm(Form): name = StringField("Name", validators=[DataRequired()]) - email = StringField("Email", validators=[DataRequired()]) + email = StringField( + "Email", + validators=[ + DataRequired(), + Email("You must provide a valid @records.nyc.gov email address."), + ], + ) date = StringField( "Date", default=datetime.today().strftime("%-m/%-d/%Y"), diff --git a/app/main/modules.py b/app/main/modules.py index 1c73a65..d2957d5 100644 --- a/app/main/modules.py +++ b/app/main/modules.py @@ -572,7 +572,8 @@ def process_health_screen_confirmation( buffer.close() filename = "{username}-health-check-{date}.pdf".format( - username=email.split("@")[0], date=datetime.strptime(date,'%m/%d/%Y').strftime('%Y-%m-%d') + username=email.split("@")[0], + date=datetime.strptime(date, "%m/%d/%Y").strftime("%Y-%m-%d"), ) print(date) @@ -582,5 +583,5 @@ def process_health_screen_confirmation( "Health Screening Confirmation - " + name, filename, pdf, - name + name, ) diff --git a/app/main/views.py b/app/main/views.py index 794366b..ee7608c 100644 --- a/app/main/views.py +++ b/app/main/views.py @@ -924,7 +924,12 @@ def health_screen_confirm(): form = HealthScreenForm() if form.validate_on_submit(): - name = request.form["name"] + if ( + not request.form.get("email", "").split("@")[-1] + == current_app.config["EMAIL_DOMAIN"] + ): + form.email.errors.append("You must enter a @records.nyc.gov email address.") + return render_template("main/health_screen_confirm.html", form=form) email = request.form["email"] date = request.form["date"] division = request.form["division"] diff --git a/app/templates/main/health_screen_confirm.html b/app/templates/main/health_screen_confirm.html index a991843..a834829 100644 --- a/app/templates/main/health_screen_confirm.html +++ b/app/templates/main/health_screen_confirm.html @@ -63,6 +63,11 @@


To submit your health screening confirmation, please fill out the form below and click the Submit button when done.

+ {% for field, errors in form.errors.items() %} +
+ {{ ', '.join(errors) }} +
+{% endfor %}
{{ form.csrf_token }}
diff --git a/timeclock.py b/timeclock.py index d689c82..f120c5f 100644 --- a/timeclock.py +++ b/timeclock.py @@ -15,7 +15,7 @@ Tag, ) -if os.getenv('FLASK_ENV') == 'development': +if os.getenv("FLASK_ENV") == "development": from faker import Faker from app.utils import divisions, tags From 67cfaf7b6e186d50e5fdef23fce2efaa65c2cf64 Mon Sep 17 00:00:00 2001 From: Joel Castillo Date: Thu, 25 Jun 2020 14:29:50 -0400 Subject: [PATCH 7/8] Make email lowercase and hide confirmation questions --- app/main/views.py | 5 +++-- app/templates/base_healthscreen.html | 4 ++-- app/templates/main/health_screen_confirm.html | 12 ++++++++---- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/app/main/views.py b/app/main/views.py index ee7608c..7d10f59 100644 --- a/app/main/views.py +++ b/app/main/views.py @@ -925,12 +925,13 @@ def health_screen_confirm(): if form.validate_on_submit(): if ( - not request.form.get("email", "").split("@")[-1] + not request.form.get("email", "").split("@")[-1].lower() == current_app.config["EMAIL_DOMAIN"] ): form.email.errors.append("You must enter a @records.nyc.gov email address.") return render_template("main/health_screen_confirm.html", form=form) - email = request.form["email"] + name = request.form["name"] + email = request.form["email"].lower() date = request.form["date"] division = request.form["division"] questionnaire_confirmation = request.form["division"] diff --git a/app/templates/base_healthscreen.html b/app/templates/base_healthscreen.html index ce7da9c..e1958d2 100644 --- a/app/templates/base_healthscreen.html +++ b/app/templates/base_healthscreen.html @@ -99,7 +99,7 @@ src="https://cdnjs.cloudflare.com/ajax/libs/jquery-timepicker/1.10.0/jquery.timepicker.js"> - --> {% endblock %} \ No newline at end of file diff --git a/app/templates/main/health_screen_confirm.html b/app/templates/main/health_screen_confirm.html index a834829..47d1547 100644 --- a/app/templates/main/health_screen_confirm.html +++ b/app/templates/main/health_screen_confirm.html @@ -4,8 +4,8 @@ {% block title %}TimeClock - Employee Health Screening{% endblock %} {% block page_content %} -

Employee Health Screening

- +

Employee Health Screening

+ +

To submit your health screening confirmation, please fill out the form below and click the Submit button when done.

{% for field, errors in form.errors.items() %}
@@ -96,4 +97,7 @@

To submit your health screening confirmation, please fill out the form below href="mailto:healthcheck@records.nyc.gov">healthcheck@records.nyc.gov


{{ form.submit(class="btn btn-default") }} - {% endblock %} \ No newline at end of file + \ No newline at end of file From 302f4cd0b46119050f26591a261e371818a2c3b5 Mon Sep 17 00:00:00 2001 From: Joel Castillo Date: Thu, 25 Jun 2020 14:42:14 -0400 Subject: [PATCH 8/8] Remove print statement --- app/main/modules.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/main/modules.py b/app/main/modules.py index d2957d5..84052d2 100644 --- a/app/main/modules.py +++ b/app/main/modules.py @@ -575,8 +575,6 @@ def process_health_screen_confirmation( username=email.split("@")[0], date=datetime.strptime(date, "%m/%d/%Y").strftime("%Y-%m-%d"), ) - print(date) - send_health_screen_confirmation_email( ["healthcheck@records.nyc.gov"], [email],