Merge pull request #1369 from cisagov/ky/required-optional-form-fields

Fix inconsistent representation of required/optional fields
This commit is contained in:
Kristina Yin 2023-12-05 13:34:50 -08:00 committed by GitHub
commit 939f34269f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 150 additions and 58 deletions

View file

@ -454,7 +454,7 @@ class DomainInformationAdmin(ListHeaderAdmin):
"No other employees from your organization?", "No other employees from your organization?",
{"fields": ["no_other_contacts_rationale"]}, {"fields": ["no_other_contacts_rationale"]},
), ),
("Anything else we should know?", {"fields": ["anything_else"]}), ("Anything else?", {"fields": ["anything_else"]}),
( (
"Requirements for operating .gov domains", "Requirements for operating .gov domains",
{"fields": ["is_policy_acknowledged"]}, {"fields": ["is_policy_acknowledged"]},
@ -600,7 +600,7 @@ class DomainApplicationAdmin(ListHeaderAdmin):
"No other employees from your organization?", "No other employees from your organization?",
{"fields": ["no_other_contacts_rationale"]}, {"fields": ["no_other_contacts_rationale"]},
), ),
("Anything else we should know?", {"fields": ["anything_else"]}), ("Anything else?", {"fields": ["anything_else"]}),
( (
"Requirements for operating .gov domains", "Requirements for operating .gov domains",
{"fields": ["is_policy_acknowledged"]}, {"fields": ["is_policy_acknowledged"]},

View file

@ -244,7 +244,7 @@ class OrganizationContactForm(RegistrarForm):
) )
address_line2 = forms.CharField( address_line2 = forms.CharField(
required=False, required=False,
label="Street address line 2", label="Street address line 2 (optional)",
) )
city = forms.CharField( city = forms.CharField(
label="City", label="City",
@ -268,7 +268,7 @@ class OrganizationContactForm(RegistrarForm):
) )
urbanization = forms.CharField( urbanization = forms.CharField(
required=False, required=False,
label="Urbanization (Puerto Rico only)", label="Urbanization (required for Puerto Rico only)",
) )
def clean_federal_agency(self): def clean_federal_agency(self):
@ -331,7 +331,7 @@ class AuthorizingOfficialForm(RegistrarForm):
) )
middle_name = forms.CharField( middle_name = forms.CharField(
required=False, required=False,
label="Middle name", label="Middle name (optional)",
) )
last_name = forms.CharField( last_name = forms.CharField(
label="Last name / family name", label="Last name / family name",
@ -407,7 +407,7 @@ class AlternativeDomainForm(RegistrarForm):
alternative_domain = forms.CharField( alternative_domain = forms.CharField(
required=False, required=False,
label="Alternative domain", label="",
) )
@ -533,7 +533,7 @@ class YourContactForm(RegistrarForm):
) )
middle_name = forms.CharField( middle_name = forms.CharField(
required=False, required=False,
label="Middle name", label="Middle name (optional)",
) )
last_name = forms.CharField( last_name = forms.CharField(
label="Last name / family name", label="Last name / family name",
@ -562,7 +562,7 @@ class OtherContactsForm(RegistrarForm):
) )
middle_name = forms.CharField( middle_name = forms.CharField(
required=False, required=False,
label="Middle name", label="Middle name (optional)",
) )
last_name = forms.CharField( last_name = forms.CharField(
label="Last name / family name", label="Last name / family name",
@ -624,7 +624,7 @@ class NoOtherContactsForm(RegistrarForm):
class AnythingElseForm(RegistrarForm): class AnythingElseForm(RegistrarForm):
anything_else = forms.CharField( anything_else = forms.CharField(
required=False, required=False,
label="Anything else we should know?", label="Anything else?",
widget=forms.Textarea(), widget=forms.Textarea(),
validators=[ validators=[
MaxLengthValidator( MaxLengthValidator(

View file

@ -181,6 +181,9 @@ class ContactForm(forms.ModelForm):
for field_name in self.required: for field_name in self.required:
self.fields[field_name].required = True self.fields[field_name].required = True
# Set custom form label
self.fields["middle_name"].label = "Middle name (optional)"
# Set custom error messages # Set custom error messages
self.fields["first_name"].error_messages = {"required": "Enter your first name / given name."} self.fields["first_name"].error_messages = {"required": "Enter your first name / given name."}
self.fields["last_name"].error_messages = {"required": "Enter your last name / family name."} self.fields["last_name"].error_messages = {"required": "Enter your last name / family name."}
@ -220,7 +223,7 @@ class DomainSecurityEmailForm(forms.Form):
"""Form for adding or editing a security email to a domain.""" """Form for adding or editing a security email to a domain."""
security_email = forms.EmailField( security_email = forms.EmailField(
label="Security email", label="Security email (optional)",
required=False, required=False,
error_messages={ error_messages={
"invalid": str(SecurityEmailError(code=SecurityEmailErrorCodes.BAD_DATA)), "invalid": str(SecurityEmailError(code=SecurityEmailErrorCodes.BAD_DATA)),

View file

@ -0,0 +1,37 @@
# Generated by Django 4.2.7 on 2023-11-20 20:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("registrar", "0049_alter_domainapplication_current_websites_and_more"),
]
operations = [
migrations.AlterField(
model_name="contact",
name="middle_name",
field=models.TextField(blank=True, help_text="Middle name (optional)", null=True),
),
migrations.AlterField(
model_name="domainapplication",
name="address_line2",
field=models.TextField(blank=True, help_text="Street address line 2 (optional)", null=True),
),
migrations.AlterField(
model_name="domaininformation",
name="address_line2",
field=models.TextField(
blank=True,
help_text="Street address line 2 (optional)",
null=True,
verbose_name="Street address line 2 (optional)",
),
),
migrations.AlterField(
model_name="transitiondomain",
name="middle_name",
field=models.TextField(blank=True, help_text="Middle name (optional)", null=True),
),
]

View file

@ -0,0 +1,27 @@
# Generated by Django 4.2.7 on 2023-11-22 20:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("registrar", "0050_alter_contact_middle_name_and_more"),
]
operations = [
migrations.AlterField(
model_name="domainapplication",
name="urbanization",
field=models.TextField(blank=True, help_text="Urbanization (required for Puerto Rico only)", null=True),
),
migrations.AlterField(
model_name="domaininformation",
name="urbanization",
field=models.TextField(
blank=True,
help_text="Urbanization (required for Puerto Rico only)",
null=True,
verbose_name="Urbanization (required for Puerto Rico only)",
),
),
]

View file

@ -0,0 +1,22 @@
# Generated by Django 4.2.7 on 2023-11-29 19:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("registrar", "0051_alter_domainapplication_urbanization_and_more"),
]
operations = [
migrations.AlterField(
model_name="domainapplication",
name="anything_else",
field=models.TextField(blank=True, help_text="Anything else?", null=True),
),
migrations.AlterField(
model_name="domaininformation",
name="anything_else",
field=models.TextField(blank=True, help_text="Anything else?", null=True),
),
]

View file

@ -26,7 +26,7 @@ class Contact(TimeStampedModel):
middle_name = models.TextField( middle_name = models.TextField(
null=True, null=True,
blank=True, blank=True,
help_text="Middle name", help_text="Middle name (optional)",
) )
last_name = models.TextField( last_name = models.TextField(
null=True, null=True,

View file

@ -442,7 +442,7 @@ class DomainApplication(TimeStampedModel):
address_line2 = models.TextField( address_line2 = models.TextField(
null=True, null=True,
blank=True, blank=True,
help_text="Street address line 2", help_text="Street address line 2 (optional)",
) )
city = models.TextField( city = models.TextField(
null=True, null=True,
@ -465,7 +465,7 @@ class DomainApplication(TimeStampedModel):
urbanization = models.TextField( urbanization = models.TextField(
null=True, null=True,
blank=True, blank=True,
help_text="Urbanization (Puerto Rico only)", help_text="Urbanization (required for Puerto Rico only)",
) )
about_your_organization = models.TextField( about_your_organization = models.TextField(
@ -545,7 +545,7 @@ class DomainApplication(TimeStampedModel):
anything_else = models.TextField( anything_else = models.TextField(
null=True, null=True,
blank=True, blank=True,
help_text="Anything else we should know?", help_text="Anything else?",
) )
is_policy_acknowledged = models.BooleanField( is_policy_acknowledged = models.BooleanField(

View file

@ -106,8 +106,8 @@ class DomainInformation(TimeStampedModel):
address_line2 = models.TextField( address_line2 = models.TextField(
null=True, null=True,
blank=True, blank=True,
help_text="Street address line 2", help_text="Street address line 2 (optional)",
verbose_name="Street address line 2", verbose_name="Street address line 2 (optional)",
) )
city = models.TextField( city = models.TextField(
null=True, null=True,
@ -131,8 +131,8 @@ class DomainInformation(TimeStampedModel):
urbanization = models.TextField( urbanization = models.TextField(
null=True, null=True,
blank=True, blank=True,
help_text="Urbanization (Puerto Rico only)", help_text="Urbanization (required for Puerto Rico only)",
verbose_name="Urbanization (Puerto Rico only)", verbose_name="Urbanization (required for Puerto Rico only)",
) )
about_your_organization = models.TextField( about_your_organization = models.TextField(
@ -191,7 +191,7 @@ class DomainInformation(TimeStampedModel):
anything_else = models.TextField( anything_else = models.TextField(
null=True, null=True,
blank=True, blank=True,
help_text="Anything else we should know?", help_text="Anything else?",
) )
is_policy_acknowledged = models.BooleanField( is_policy_acknowledged = models.BooleanField(

View file

@ -84,7 +84,7 @@ class TransitionDomain(TimeStampedModel):
middle_name = models.TextField( middle_name = models.TextField(
null=True, null=True,
blank=True, blank=True,
help_text="Middle name", help_text="Middle name (optional)",
) )
last_name = models.TextField( last_name = models.TextField(
null=True, null=True,

View file

@ -13,7 +13,7 @@
{% endblock %} {% endblock %}
{% block form_required_fields_help_text %} {% block form_required_fields_help_text %}
<p class="text-semibold"><abbr class="usa-hint usa-hint--required" title="required">*</abbr>This question is required.</p> {# commented out so it does not appear on this page #}
{% endblock %} {% endblock %}
{% block form_fields %} {% block form_fields %}

View file

@ -2,7 +2,7 @@
{% load field_helpers %} {% load field_helpers %}
{% block form_instructions %} {% block form_instructions %}
<p>Is there anything else we should know about your domain request?</p> <p>Is there anything else you'd like us to know about your domain request? This question is optional.</p>
{% endblock %} {% endblock %}
{% block form_required_fields_help_text %} {% block form_required_fields_help_text %}

View file

@ -4,7 +4,7 @@
{% block form_instructions %} {% block form_instructions %}
<p>Enter your organizations current public website, if you have one. For example, <p>Enter your organizations current public website, if you have one. For example,
www.city.com. We can better evaluate your domain request if we know about domains www.city.com. We can better evaluate your domain request if we know about domains
youre already using. If you already have any .gov domains please include them.</p> youre already using. If you already have any .gov domains please include them. This question is optional.</p>
{% endblock %} {% endblock %}
{% block form_required_fields_help_text %} {% block form_required_fields_help_text %}

View file

@ -38,8 +38,7 @@
<fieldset class="usa-fieldset margin-top-2"> <fieldset class="usa-fieldset margin-top-2">
<legend> <legend>
<h2>What .gov domain do you want?&nbsp;<abbr class="usa-hint usa-hint--required <h2>What .gov domain do you want?</h2>
text-super" title="required">*</abbr></h2>
</legend> </legend>
<p id="domain_instructions" class="margin-top-05">After you enter your domain, well make sure its <p id="domain_instructions" class="margin-top-05">After you enter your domain, well make sure its
@ -47,8 +46,6 @@
these initial checks, well verify that it meets all of our requirements once you these initial checks, well verify that it meets all of our requirements once you
complete and submit the rest of this form.</p> complete and submit the rest of this form.</p>
<p class="text-semibold"><abbr class="usa-hint usa-hint--required" title="required">*</abbr> This question is required.</p>
{% with attr_aria_describedby="domain_instructions domain_instructions2" %} {% with attr_aria_describedby="domain_instructions domain_instructions2" %}
{# attr_validate / validate="domain" invokes code in get-gov.js #} {# attr_validate / validate="domain" invokes code in get-gov.js #}
{% with append_gov=True attr_validate="domain" add_label_class="usa-sr-only" %} {% with append_gov=True attr_validate="domain" add_label_class="usa-sr-only" %}
@ -66,11 +63,11 @@
<fieldset class="usa-fieldset margin-top-1"> <fieldset class="usa-fieldset margin-top-1">
<legend> <legend>
<h2>Alternative domains</h2> <h2>Alternative domains (optional)</h2>
</legend> </legend>
<p id="alt_domain_instructions" class="margin-top-05">Are there other domains youd like if we cant give <p id="alt_domain_instructions" class="margin-top-05">Are there other domains youd like if we cant give
you your first choice? Entering alternative domains is optional.</p> you your first choice?</p>
{% with attr_aria_describedby="alt_domain_instructions" %} {% with attr_aria_describedby="alt_domain_instructions" %}
{# attr_validate / validate="domain" invokes code in get-gov.js #} {# attr_validate / validate="domain" invokes code in get-gov.js #}

View file

@ -56,9 +56,12 @@
{% block form_instructions %} {% block form_instructions %}
{% endblock %} {% endblock %}
<!-- The "No other employees from your organization?" page is a one-field form and should not have the required fields sentence -->
{% if steps.current != "no_other_contacts" %}
{% block form_required_fields_help_text %} {% block form_required_fields_help_text %}
{% include "includes/required_fields.html" %} {% include "includes/required_fields.html" %}
{% endblock %} {% endblock %}
{% endif %}
<form id="step__{{steps.current}}" class="usa-form usa-form--large" method="post" novalidate> <form id="step__{{steps.current}}" class="usa-form usa-form--large" method="post" novalidate>
{% csrf_token %} {% csrf_token %}

View file

@ -2,9 +2,7 @@
{% load field_helpers %} {% load field_helpers %}
{% block form_instructions %} {% block form_instructions %}
<h2 class="margin-bottom-05"> <h2 class="margin-bottom-05">Is your organization an election office?</h2>
Is your organization an election office? <abbr class="usa-hint usa-hint--required" title="required">*</abbr>
</h2>
<p>An election office is a government entity whose <em>primary</em> responsibility is overseeing elections and/or conducting voter registration.</p> <p>An election office is a government entity whose <em>primary</em> responsibility is overseeing elections and/or conducting voter registration.</p>
@ -13,7 +11,7 @@
{% endblock %} {% endblock %}
{% block form_required_fields_help_text %} {% block form_required_fields_help_text %}
<p class="text-semibold"><abbr class="usa-hint usa-hint--required" title="required">*</abbr> This question is required.</p> {# commented out so it does not appear on this page #}
{% endblock %} {% endblock %}
{% block form_fields %} {% block form_fields %}

View file

@ -3,15 +3,14 @@
{% block form_instructions %} {% block form_instructions %}
<h2 class="margin-bottom-05"> <h2 class="margin-bottom-05">
Which federal branch is your organization&nbsp;in?&nbsp;<abbr class="usa-hint usa-hint--required text-super" title="required">*</abbr> Which federal branch is your organization in?
</h2> </h2>
{% endblock %} {% endblock %}
{% block form_required_fields_help_text %} {% block form_required_fields_help_text %}
<p class="text-semibold"><abbr class="usa-hint usa-hint--required" title="required">*</abbr> This question is required.</p> {# commented out so it does not appear on this page #}
{% endblock %} {% endblock %}
{% block form_fields %} {% block form_fields %}
{% with add_class="usa-radio__input--tile" add_legend_class="usa-sr-only" %} {% with add_class="usa-radio__input--tile" add_legend_class="usa-sr-only" %}
{% input_with_errors forms.0.federal_type %} {% input_with_errors forms.0.federal_type %}

View file

@ -3,16 +3,15 @@
{% block form_instructions %} {% block form_instructions %}
<h2 class="margin-bottom-05"> <h2 class="margin-bottom-05">
What kind of U.S.-based government organization do you represent? <abbr class="usa-hint usa-hint--required text-super" title="required">*</abbr> What kind of U.S.-based government organization do you represent?
</h2> </h2>
{% endblock %} {% endblock %}
{% block form_required_fields_help_text %} {% block form_required_fields_help_text %}
<p class="text-semibold"><abbr class="usa-hint usa-hint--required" title="required">*</abbr> This question is required.</p> {# commented out so it does not appear on this page #}
{% endblock %} {% endblock %}
{% block form_fields %} {% block form_fields %}
{% with add_class="usa-radio__input--tile" add_legend_class="usa-sr-only" %} {% with add_class="usa-radio__input--tile" add_legend_class="usa-sr-only" %}
{% input_with_errors forms.0.organization_type %} {% input_with_errors forms.0.organization_type %}

View file

@ -13,18 +13,16 @@
{% endblock %} {% endblock %}
{% block form_required_fields_help_text %} {% block form_required_fields_help_text %}
{# there are no required fields on this page so don't show this #} {% include "includes/required_fields.html" %}
{% endblock %} {% endblock %}
{% block form_fields %} {% block form_fields %}
{{ forms.0.management_form }} {{ forms.0.management_form }}
{# forms.0 is a formset and this iterates over its forms #} {# forms.0 is a formset and this iterates over its forms #}
{% for form in forms.0.forms %} {% for form in forms.0.forms %}
<fieldset class="usa-fieldset"> <fieldset class="usa-fieldset">
<legend> <legend>
<h2>Organization contact {{ forloop.counter }}</h2> <h2>Organization contact {{ forloop.counter }} (optional)</h2>
</legend> </legend>
{% input_with_errors form.first_name %} {% input_with_errors form.first_name %}

View file

@ -13,11 +13,9 @@ Read about <a class="usa-link" rel="noopener noreferrer" target="_blank" href="{
{% endblock %} {% endblock %}
{% block form_required_fields_help_text %} {% block form_required_fields_help_text %}
<p class="text-semibold"><abbr class="usa-hint usa-hint--required" title="required">*</abbr> This question is required.</p> {# commented out so it does not appear on this page #}
{% endblock %} {% endblock %}
{% block form_fields %} {% block form_fields %}
{% with attr_maxlength=1000 add_label_class="usa-sr-only" %} {% with attr_maxlength=1000 add_label_class="usa-sr-only" %}
{% input_with_errors forms.0.purpose %} {% input_with_errors forms.0.purpose %}

View file

@ -50,6 +50,10 @@
<p>We understand the critical importance of the availability of .gov domains. Suspending or terminating a .gov domain is reserved for prolonged, unresolved, serious violations where the registrant is non-responsive. We'll make extensive efforts to contact registrants and to identify potential solutions. We'll make reasonable accommodations for remediation timelines based on the severity of the issue.</p> <p>We understand the critical importance of the availability of .gov domains. Suspending or terminating a .gov domain is reserved for prolonged, unresolved, serious violations where the registrant is non-responsive. We'll make extensive efforts to contact registrants and to identify potential solutions. We'll make reasonable accommodations for remediation timelines based on the severity of the issue.</p>
{% endblock %} {% endblock %}
{% block form_required_fields_help_text %}
{# commented out so it does not appear on this page #}
{% endblock %}
{% block form_fields %} {% block form_fields %}
<fieldset class="usa-fieldset"> <fieldset class="usa-fieldset">
<legend> <legend>

View file

@ -111,7 +111,7 @@
{% include "includes/summary_item.html" with title='Other employees from your organization' value=domainapplication.other_contacts.all contact='true' list='true' heading_level=heading_level %} {% include "includes/summary_item.html" with title='Other employees from your organization' value=domainapplication.other_contacts.all contact='true' list='true' heading_level=heading_level %}
{% include "includes/summary_item.html" with title='Anything else we should know' value=domainapplication.anything_else|default:"No" heading_level=heading_level %} {% include "includes/summary_item.html" with title='Anything else?' value=domainapplication.anything_else|default:"No" heading_level=heading_level %}
{% endwith %} {% endwith %}
</div> </div>

View file

@ -7,7 +7,13 @@
{% else %} {% else %}
{{ field.label }} {{ field.label }}
{% endif %} {% endif %}
{% if widget.attrs.required %} {% if widget.attrs.required %}
<!--Don't add asterisk to one-field forms -->
{% if field.label == "Is your organization an election office?" or field.label == "What .gov domain do you want?" or field.label == "I read and agree to the requirements for operating .gov domains." or field.label == "Please explain why there are no other employees from your organization we can contact to help us assess your eligibility for a .gov domain." %}
{% else %}
<abbr class="usa-hint usa-hint--required" title="required">*</abbr> <abbr class="usa-hint usa-hint--required" title="required">*</abbr>
{% endif %} {% endif %}
{% endif %}
</{{ label_tag }}> </{{ label_tag }}>

View file

@ -34,6 +34,6 @@ Other employees from your organization:
{% for other in application.other_contacts.all %} {% for other in application.other_contacts.all %}
{% spaceless %}{% include "emails/includes/contact.txt" with contact=other %}{% endspaceless %} {% spaceless %}{% include "emails/includes/contact.txt" with contact=other %}{% endspaceless %}
{% endfor %}{% endif %}{% if application.anything_else %} {% endfor %}{% endif %}{% if application.anything_else %}
Anything else we should know? Anything else?
{{ application.anything_else }} {{ application.anything_else }}
{% endif %} {% endif %}

View file

@ -1,3 +1,3 @@
<p class="margin-top-3"> <p class="margin-top-3">
Required fields are marked with an asterisk (<abbr class="usa-hint usa-hint--required" title="required">*</abbr>). <em>Required fields are marked with an asterisk (<abbr class="usa-hint usa-hint--required" title="required">*</abbr>).</em>
</p> </p>

View file

@ -158,7 +158,7 @@ class TestEmails(TestCase):
_, kwargs = self.mock_client.send_email.call_args _, kwargs = self.mock_client.send_email.call_args
body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"]
# spacing should be right between adjacent elements # spacing should be right between adjacent elements
self.assertRegex(body, r"5557\n\nAnything else we should know?") self.assertRegex(body, r"5557\n\nAnything else?")
@boto3_mocking.patching @boto3_mocking.patching
def test_submission_confirmation_no_anything_else_spacing(self): def test_submission_confirmation_no_anything_else_spacing(self):
@ -168,6 +168,6 @@ class TestEmails(TestCase):
application.submit() application.submit()
_, kwargs = self.mock_client.send_email.call_args _, kwargs = self.mock_client.send_email.call_args
body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"]
self.assertNotIn("Anything else we should know", body) self.assertNotIn("Anything else", body)
# spacing should be right between adjacent elements # spacing should be right between adjacent elements
self.assertRegex(body, r"5557\n\n----") self.assertRegex(body, r"5557\n\n----")

View file

@ -86,7 +86,7 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView):
Step.YOUR_CONTACT: _("Your contact information"), Step.YOUR_CONTACT: _("Your contact information"),
Step.OTHER_CONTACTS: _("Other employees from your organization"), Step.OTHER_CONTACTS: _("Other employees from your organization"),
Step.NO_OTHER_CONTACTS: _("No other employees from your organization?"), Step.NO_OTHER_CONTACTS: _("No other employees from your organization?"),
Step.ANYTHING_ELSE: _("Anything else we should know?"), Step.ANYTHING_ELSE: _("Anything else?"),
Step.REQUIREMENTS: _("Requirements for operating .gov domains"), Step.REQUIREMENTS: _("Requirements for operating .gov domains"),
Step.REVIEW: _("Review and submit your domain request"), Step.REVIEW: _("Review and submit your domain request"),
} }

View file

@ -280,6 +280,7 @@ class DomainNameserversView(DomainFormBaseView):
form.fields["server"].required = True form.fields["server"].required = True
else: else:
form.fields["server"].required = False form.fields["server"].required = False
form.fields["server"].label += " (optional)"
form.fields["domain"].initial = self.object.name form.fields["domain"].initial = self.object.name
return formset return formset