diff --git a/atst/forms/officers.py b/atst/forms/officers.py index 4df1f5a7..1bbb14e3 100644 --- a/atst/forms/officers.py +++ b/atst/forms/officers.py @@ -1,7 +1,7 @@ from flask_wtf import FlaskForm from wtforms.fields import StringField from wtforms.fields.html5 import TelField -from wtforms.validators import Length, Optional +from wtforms.validators import Email, Length, Optional from atst.forms.validators import IsNumber, PhoneNumber @@ -12,7 +12,7 @@ from .fields import FormFieldWrapper class OfficerForm(FlaskForm): first_name = StringField("First Name") last_name = StringField("Last Name") - email = StringField("Email") + email = StringField("Email", validators=[Optional(), Email()]) phone_number = TelField("Phone Number", validators=[PhoneNumber()]) dod_id = StringField("DoD ID", validators=[Optional(), Length(min=10), IsNumber()]) diff --git a/atst/forms/task_order.py b/atst/forms/task_order.py index 9a536db1..7d1c2167 100644 --- a/atst/forms/task_order.py +++ b/atst/forms/task_order.py @@ -10,7 +10,7 @@ from wtforms.fields import ( ) from wtforms.fields.html5 import DateField, TelField from wtforms.widgets import ListWidget, CheckboxInput -from wtforms.validators import Length, Required, Optional +from wtforms.validators import Email, Length, Required, Optional from flask_wtf.file import FileAllowed from atst.forms.validators import IsNumber, PhoneNumber, RequiredIf @@ -132,7 +132,10 @@ class OversightForm(CacheableForm): translate("forms.task_order.oversight_first_name_label") ) ko_last_name = StringField(translate("forms.task_order.oversight_last_name_label")) - ko_email = StringField(translate("forms.task_order.oversight_email_label")) + ko_email = StringField( + translate("forms.task_order.oversight_email_label"), + validators=[Optional(), Email()], + ) ko_phone_number = TelField( translate("forms.task_order.oversight_phone_label"), validators=[Optional(), PhoneNumber()], @@ -151,7 +154,10 @@ class OversightForm(CacheableForm): translate("forms.task_order.oversight_first_name_label") ) cor_last_name = StringField(translate("forms.task_order.oversight_last_name_label")) - cor_email = StringField(translate("forms.task_order.oversight_email_label")) + cor_email = StringField( + translate("forms.task_order.oversight_email_label"), + validators=[Optional(), Email()], + ) cor_phone_number = TelField( translate("forms.task_order.oversight_phone_label"), validators=[ @@ -176,7 +182,10 @@ class OversightForm(CacheableForm): translate("forms.task_order.oversight_first_name_label") ) so_last_name = StringField(translate("forms.task_order.oversight_last_name_label")) - so_email = StringField(translate("forms.task_order.oversight_email_label")) + so_email = StringField( + translate("forms.task_order.oversight_email_label"), + validators=[Optional(), Email()], + ) so_phone_number = TelField( translate("forms.task_order.oversight_phone_label"), validators=[Optional(), PhoneNumber()], diff --git a/templates/components/user_info.html b/templates/components/user_info.html index cd5e8c6e..aa2507ee 100644 --- a/templates/components/user_info.html +++ b/templates/components/user_info.html @@ -13,7 +13,7 @@
- {{ TextInput(email, placeholder='name@mail.mil') }} + {{ TextInput(email, placeholder='name@mail.mil', validation='email') }}
diff --git a/templates/portfolios/task_orders/invitations.html b/templates/portfolios/task_orders/invitations.html index 3abc03e7..61d2ddd4 100644 --- a/templates/portfolios/task_orders/invitations.html +++ b/templates/portfolios/task_orders/invitations.html @@ -28,7 +28,7 @@
- {{ TextInput(form.email, placeholder='name@mail.mil') }} + {{ TextInput(form.email, placeholder='name@mail.mil', validation='email') }}
diff --git a/tests/forms/test_officers.py b/tests/forms/test_officers.py index ce6ca1eb..01d94be0 100644 --- a/tests/forms/test_officers.py +++ b/tests/forms/test_officers.py @@ -54,3 +54,10 @@ class TestEditTaskOrderOfficersForm: form.populate_obj(task_order) assert task_order.so_first_name == data["security_officer-first_name"] assert task_order.so_last_name == data["security_officer-last_name"] + + def test_email_validation(self): + data = {"contracting_officer-email": "not_really_an_email_address"} + formdata = ImmutableMultiDict(data) + form = EditTaskOrderOfficersForm(formdata) + assert not form.validate() + assert form.contracting_officer.email.errors == ["Invalid email address."] diff --git a/tests/routes/task_orders/test_new_task_order.py b/tests/routes/task_orders/test_new_task_order.py index bbe461e9..6e78a6f1 100644 --- a/tests/routes/task_orders/test_new_task_order.py +++ b/tests/routes/task_orders/test_new_task_order.py @@ -122,6 +122,26 @@ def test_task_order_form_shows_errors(client, user_session): assert "Not a valid decimal" in body +def test_task_order_validates_email_address(client, user_session): + to = task_order() + creator = to.creator + user_session(creator) + + task_order_data = TaskOrderFactory.dictionary() + oversight_data = slice_data_for_section(task_order_data, "oversight") + oversight_data.update({"ko_email": "not an email"}) + + response = client.post( + url_for("task_orders.update", screen=3, task_order_id=to.id), + data=oversight_data, + follow_redirects=False, + ) + + body = response.data.decode() + assert "There were some errors" in body + assert "Invalid email" in body + + @pytest.fixture def task_order(): user = UserFactory.create()