Merge branch 'main' into nmb/trim-field-labels

This commit is contained in:
Neil Martinsen-Burrell 2023-02-28 09:51:40 -06:00
commit c6d15cff20
No known key found for this signature in database
GPG key ID: 6A3C818CC10D0184
15 changed files with 140 additions and 20 deletions

View file

@ -105,7 +105,7 @@ $letter-space--xs: .0125em;
color: color('violet-70v'); //USWDS default
}
}
.register-form-step .usa-form-group:first-of-type,
.register-form-step .usa-label:first-of-type {
margin-top: units(1);
}

View file

@ -35,6 +35,7 @@ for step, view in [
(Step.PURPOSE, views.Purpose),
(Step.YOUR_CONTACT, views.YourContact),
(Step.OTHER_CONTACTS, views.OtherContacts),
(Step.NO_OTHER_CONTACTS, views.NoOtherContacts),
(Step.SECURITY_EMAIL, views.SecurityEmail),
(Step.ANYTHING_ELSE, views.AnythingElse),
(Step.REQUIREMENTS, views.Requirements),

View file

@ -662,11 +662,11 @@ OtherContactsFormSet = forms.formset_factory(
class NoOtherContactsForm(RegistrarForm):
no_other_contacts_rationale = forms.CharField(
required=False,
required=True,
# label has to end in a space to get the label_suffix to show
label=(
"If you cant provide other contacts for your organization,"
" please explain why."
"Please explain why there are no other employees from your organization"
" that we can contact."
),
widget=forms.Textarea(),
)

View file

@ -545,6 +545,10 @@ class DomainApplication(TimeStampedModel):
DomainApplication.OrganizationChoices.INTERSTATE,
]
def show_no_other_contacts_rationale(self) -> bool:
"""Show this step if the other contacts are blank."""
return not self.other_contacts.exists()
def is_federal(self) -> Union[bool, None]:
"""Is this application for a federal agency?

View file

@ -18,6 +18,10 @@
</a>
{% endif %}
{% block form_messages %}
{% include "includes/form_messages.html" %}
{% endblock %}
{% block form_errors %}
{% comment %}
to make sense of this loop, consider that

View file

@ -0,0 +1,6 @@
{% extends 'application_form.html' %}
{% load static field_helpers %}
{% block form_fields %}
{% input_with_errors forms.0.no_other_contacts_rationale %}
{% endblock %}

View file

@ -2,7 +2,7 @@
{% load field_helpers %}
{% block form_instructions %}
<h2 class="margin-bottom-5">
<h2 class="margin-bottom-05">
Which federal branch is your organization in?
</h2>

View file

@ -2,7 +2,7 @@
{% load static field_helpers %}
{% block form_instructions %}
<p>Wed like to contact other employees with administrative or technical responsibilities in your organization. For example, they could be involved in managing your organization or its technical infrastructure. This information will help us assess your eligibility and understand the purpose of the .gov domain. These contacts should be in addition to you and your authorizing official. They should be employees of your organization.</p>
<p>Wed like to contact other employees in your organization about your domain request. For example, they could be involved in managing your organization or its technical infrastructure. <strong>This information will help us assess your eligibility for a .gov domain.</strong> These contacts should be in addition to you and your authorizing official. They should be employees of your organization.</p>
<p>Well email these contacts to let them know that you made this request.</p>
{% endblock %}
@ -14,7 +14,7 @@
{% for form in forms.0.forms %}
<fieldset class="usa-fieldset">
<legend>
<h2>Administrative or technical contact {{ forloop.counter }}</h2>
<h2>Organization contact {{ forloop.counter }}</h2>
</legend>
{% input_with_errors form.first_name %}
@ -39,8 +39,4 @@
<use xlink:href="{%static 'img/sprite.svg'%}#add_circle"></use>
</svg><span class="margin-left-05">Add another contact</span>
</button>
<h2>No contacts</h2>
{% input_with_errors forms.1.no_other_contacts_rationale %}
{% endblock %}

View file

@ -36,7 +36,9 @@
{% endif %}
{% if step == Step.AUTHORIZING_OFFICIAL %}
{% if application.authorizing_official %}
{% include "includes/contact.html" with contact=application.authorizing_official %}
<div class="margin-bottom-105">
{% include "includes/contact.html" with contact=application.authorizing_official %}
</div>
{% else %}
Incomplete
{% endif %}
@ -51,8 +53,10 @@
</ul>
{% endif %}
{% if step == Step.DOTGOV_DOMAIN %}
<ul class="add-list-reset">
<ul class="add-list-reset margin-bottom-105">
<li>{{ application.requested_domain.name|default:"Incomplete" }}</li>
</ul>
<ul class="add-list-reset">
{% for site in application.alternative_domains.all %}
<li>{{ site.website }}</li>
{% endfor %}
@ -63,18 +67,25 @@
{% endif %}
{% if step == Step.YOUR_CONTACT %}
{% if application.submitter %}
{% include "includes/contact.html" with contact=application.submitter %}
<div class="margin-bottom-105">
{% include "includes/contact.html" with contact=application.submitter %}
</div>
{% else %}
Incomplete
{% endif %}
{% endif %}
{% if step == Step.OTHER_CONTACTS %}
{% for other in application.other_contacts.all %}
<div class="margin-bottom-105">
{% include "includes/contact.html" with contact=other %}
</div>
{% empty %}
None
{% endfor %}
{% endif %}
{% if step == Step.NO_OTHER_CONTACTS %}
{{ application.no_other_contacts_rationale|default:"Incomplete" }}
{% endif %}
{% if step == Step.SECURITY_EMAIL %}
{{ application.security_email|default:"None" }}
{% endif %}
@ -82,7 +93,7 @@
{{ application.anything_else|default:"No" }}
{% endif %}
{% if step == Step.REQUIREMENTS %}
{{ application.is_policy_acknowledged|yesno:"Agree,Do not agree,Do not agree" }}
{{ application.is_policy_acknowledged|yesno:"I agree.,I do not agree.,I do not agree." }}
{% endif %}
</div>
</div>

View file

@ -167,9 +167,11 @@
{% if messages %}
<ul class="messages">
{% for message in messages %}
{% if 'base' in message.extra_tags %}
<li{% if message.tags %} class="{{ message.tags }}" {% endif %}>
{{ message }}
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}

View file

@ -1,5 +1,9 @@
{% comment %}
Commenting the code below to turn off the error because
we are showing the caution dialog instead. But saving in
case we want to revert this.
{% if form.errors %}
{% for error in form.non_field_errors %}
{% for error in form.non_field_errors %}
<div class="usa-alert usa-alert--error usa-alert--slim margin-bottom-2">
<div class="usa-alert__body">
{{ error|escape }}
@ -15,4 +19,5 @@
</div>
{% endfor %}
{% endfor %}
{% endif %}
{% endif %}
{% endcomment %}

View file

@ -0,0 +1,10 @@
{% if messages %}
{% for message in messages %}
<div class="usa-alert usa-alert--{{ message.tags }} usa-alert--slim margin-bottom-2">
<div class="usa-alert__body">
{{ message }}
</div>
</div>
{% endfor %}
{% endif %}

View file

@ -124,7 +124,8 @@ class DomainApplicationTests(TestWithUser, WebTest):
this test work.
"""
num_pages_tested = 0
SKIPPED_PAGES = 3 # elections, type_of_work, tribal_government
# elections, type_of_work, tribal_government, no_other_contacts
SKIPPED_PAGES = 4
num_pages = len(self.TITLES) - SKIPPED_PAGES
type_page = self.app.get(reverse("application:")).follow()
@ -724,6 +725,24 @@ class DomainApplicationTests(TestWithUser, WebTest):
self.assertContains(contact_page, self.TITLES[Step.TYPE_OF_WORK])
def test_application_no_other_contacts(self):
"""Applicants with no other contacts have to give a reason."""
contacts_page = self.app.get(reverse("application:other_contacts"))
# django-webtest does not handle cookie-based sessions well because it keeps
# resetting the session key on each new request, thus destroying the concept
# of a "session". We are going to do it manually, saving the session ID here
# and then setting the cookie on each request.
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
result = contacts_page.form.submit()
# follow first redirect
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
no_contacts_page = result.follow()
expected_url_slug = str(Step.NO_OTHER_CONTACTS)
actual_url_slug = no_contacts_page.request.path.split("/")[-2]
self.assertEqual(expected_url_slug, actual_url_slug)
def test_application_type_of_work_interstate(self):
"""Special districts have to answer an additional question."""
type_page = self.app.get(reverse("application:")).follow()

View file

@ -6,6 +6,8 @@ from django.shortcuts import redirect, render
from django.urls import resolve, reverse
from django.utils.translation import gettext_lazy as _
from django.views.generic import TemplateView
from django.contrib import messages
from django.utils.safestring import mark_safe
from registrar.forms import application_wizard as forms
from registrar.models import DomainApplication
@ -35,6 +37,7 @@ class Step(StrEnum):
PURPOSE = "purpose"
YOUR_CONTACT = "your_contact"
OTHER_CONTACTS = "other_contacts"
NO_OTHER_CONTACTS = "no_other_contacts"
SECURITY_EMAIL = "security_email"
ANYTHING_ELSE = "anything_else"
REQUIREMENTS = "requirements"
@ -79,7 +82,8 @@ class ApplicationWizard(LoginRequiredMixin, TemplateView):
Step.DOTGOV_DOMAIN: _(".gov domain"),
Step.PURPOSE: _("Purpose of your domain"),
Step.YOUR_CONTACT: _("Your contact information"),
Step.OTHER_CONTACTS: _("Other contacts for your organization"),
Step.OTHER_CONTACTS: _("Other employees from your organization"),
Step.NO_OTHER_CONTACTS: _("No other employees from your organization?"),
Step.SECURITY_EMAIL: _("Security email for public use"),
Step.ANYTHING_ELSE: _("Anything else we should know?"),
Step.REQUIREMENTS: _(
@ -99,6 +103,9 @@ class ApplicationWizard(LoginRequiredMixin, TemplateView):
"show_organization_election", False
),
Step.TYPE_OF_WORK: lambda w: w.from_model("show_type_of_work", False),
Step.NO_OTHER_CONTACTS: lambda w: w.from_model(
"show_no_other_contacts_rationale", False
),
}
def __init__(self):
@ -319,6 +326,18 @@ class ApplicationWizard(LoginRequiredMixin, TemplateView):
self.save(forms)
else:
# unless there are errors
# no sec because this use of mark_safe does not introduce a cross-site
# scripting vulnerability because there is no untrusted content inside.
# It is only being used to pass a specific HTML entity into a template.
messages.warning(
request,
mark_safe( # nosec
"<b>We could not save all the fields.</b><br/> The highlighted "
+ "fields below <b>could not be saved</b> because they have "
+ "missing or invalid data. All other information on this page "
+ "has been saved."
),
)
context = self.get_context_data()
context["forms"] = forms
return render(request, self.template_name, context)
@ -326,6 +345,7 @@ class ApplicationWizard(LoginRequiredMixin, TemplateView):
# if user opted to save their progress,
# return them to the page they were already on
if button == "save":
messages.success(request, "Your progress has been saved!")
return self.goto(self.steps.current)
# otherwise, proceed as normal
return self.goto_next_step()
@ -410,7 +430,12 @@ class YourContact(ApplicationWizard):
class OtherContacts(ApplicationWizard):
template_name = "application_other_contacts.html"
forms = [forms.OtherContactsFormSet, forms.NoOtherContactsForm]
forms = [forms.OtherContactsFormSet]
class NoOtherContacts(ApplicationWizard):
template_name = "application_no_other_contacts.html"
forms = [forms.NoOtherContactsForm]
class SecurityEmail(ApplicationWizard):