Merge branch 'main' into nmb/submission-page

This commit is contained in:
Neil Martinsen-Burrell 2022-11-22 12:36:13 -06:00
commit 82e1fd45c0
No known key found for this signature in database
GPG key ID: 6A3C818CC10D0184
31 changed files with 1097 additions and 210 deletions

View file

@ -4,6 +4,20 @@
"http://app:8080/health/",
"http://app:8080/whoami/",
"http://app:8080/register/",
"http://app:8080/register/organization/",
"http://app:8080/register/org_federal/",
"http://app:8080/register/org_election/",
"http://app:8080/register/org_contact/",
"http://app:8080/register/authorizing_official/",
"http://app:8080/register/current_sites/",
"http://app:8080/register/dotgov_domain/",
"http://app:8080/register/purpose/",
"http://app:8080/register/your_contact/",
"http://app:8080/register/other_contacts/",
"http://app:8080/register/security_email/",
"http://app:8080/register/anything_else/",
"http://app:8080/register/requirements/",
"http://app:8080/register/review/",
"http://app:8080/register/finished/"
]
}

View file

@ -15,7 +15,14 @@ from registrar.models import DomainApplication, Website
logger = logging.getLogger(__name__)
class OrganizationForm(forms.Form):
# Subclass used to remove the default colon suffix from all fields
class RegistrarForm(forms.Form):
def __init__(self, *args, **kwargs):
kwargs.setdefault("label_suffix", "")
super(RegistrarForm, self).__init__(*args, **kwargs)
class OrganizationTypeForm(RegistrarForm):
organization_type = forms.ChoiceField(
required=True,
choices=[
@ -47,11 +54,7 @@ class OrganizationForm(forms.Form):
)
federal_type = forms.ChoiceField(
required=False,
choices=[
("Executive", "Executive"),
("Judicial", "Judicial"),
("Legislative", "Legislative"),
],
choices=DomainApplication.BRANCH_CHOICES,
widget=forms.RadioSelect,
)
is_election_board = forms.ChoiceField(
@ -60,34 +63,237 @@ class OrganizationForm(forms.Form):
("Yes", "Yes"),
("No", "No"),
],
widget=forms.RadioSelect(attrs={"class": "usa-radio__input"}),
)
class OrganizationFederalForm(RegistrarForm):
federal_type = forms.ChoiceField(
required=False,
choices=DomainApplication.BRANCH_CHOICES,
widget=forms.RadioSelect,
)
class ContactForm(forms.Form):
class OrganizationElectionForm(RegistrarForm):
is_election_board = forms.BooleanField(
widget=forms.RadioSelect(
choices=[
(True, "Yes"),
(False, "No"),
],
)
)
class OrganizationContactForm(RegistrarForm):
organization_name = forms.CharField(label="Organization Name")
street_address = forms.CharField(label="Street address")
address_line1 = forms.CharField(label="Address line 1")
address_line2 = forms.CharField(
required=False,
label="Address line 2",
)
us_state = forms.ChoiceField(
label="State",
choices=[
("AL", "Alabama"),
("AK", "Alaska"),
("AZ", "Arizona"),
("AR", "Arkansas"),
("CA", "California"),
("CO", "Colorado"),
("CT", "Connecticut"),
("DE", "Delaware"),
("DC", "District of Columbia"),
("FL", "Florida"),
("GA", "Georgia"),
("HI", "Hawaii"),
("ID", "Idaho"),
("IL", "Illinois"),
("IN", "Indiana"),
("IA", "Iowa"),
("KS", "Kansas"),
("KY", "Kentucky"),
("LA", "Louisiana"),
("ME", "Maine"),
("MD", "Maryland"),
("MA", "Massachusetts"),
("MI", "Michigan"),
("MN", "Minnesota"),
("MS", "Mississippi"),
("MO", "Missouri"),
("MT", "Montana"),
("NE", "Nebraska"),
("NV", "Nevada"),
("NH", "New Hampshire"),
("NJ", "New Jersey"),
("NM", "New Mexico"),
("NY", "New York"),
("NC", "North Carolina"),
("ND", "North Dakota"),
("OH", "Ohio"),
("OK", "Oklahoma"),
("OR", "Oregon"),
("PA", "Pennsylvania"),
("RI", "Rhode Island"),
("SC", "South Carolina"),
("SD", "South Dakota"),
("TN", "Tennessee"),
("TX", "Texas"),
("UT", "Utah"),
("VT", "Vermont"),
("VA", "Virginia"),
("WA", "Washington"),
("WV", "West Virginia"),
("WI", "Wisconsin"),
("WY", "Wyoming"),
("AS", "American Samoa"),
("GU", "Guam"),
("MP", "Northern Mariana Islands"),
("PR", "Puerto Rico"),
("VI", "Virgin Islands"),
],
)
zipcode = forms.CharField(label="ZIP code")
class AuthorizingOfficialForm(RegistrarForm):
first_name = forms.CharField(label="First name/given name")
middle_name = forms.CharField(
required=False,
label="Middle name (optional)",
)
last_name = forms.CharField(label="Last name/family name")
title = forms.CharField(label="Title or role in your organization")
email = forms.EmailField(label="Email")
phone = forms.CharField(label="Phone")
class CurrentSitesForm(RegistrarForm):
current_site = forms.CharField(
required=False,
label="Enter your organizations public website, if you have one. For example, "
"www.city.com.",
)
class DotGovDomainForm(RegistrarForm):
dotgov_domain = forms.CharField(label="What .gov domain do you want?")
alternative_domain = forms.CharField(
required=False,
label="Are there other domains youd like if we cant give you your first "
"choice? Entering alternative domains is optional.",
)
class PurposeForm(RegistrarForm):
purpose_field = forms.CharField(label="Purpose", widget=forms.Textarea())
class YourContactForm(RegistrarForm):
first_name = forms.CharField(label="First name/given name")
middle_name = forms.CharField(
required=False,
label="Middle name (optional)",
)
last_name = forms.CharField(label="Last name/family name")
title = forms.CharField(label="Title or role in your organization")
email = forms.EmailField(label="Email")
phone = forms.CharField(label="Phone")
class OtherContactsForm(RegistrarForm):
first_name = forms.CharField(label="First name/given name")
middle_name = forms.CharField(
required=False,
label="Middle name (optional)",
)
last_name = forms.CharField(label="Last name/family name")
title = forms.CharField(label="Title or role in your organization")
email = forms.EmailField(label="Email")
phone = forms.CharField(label="Phone")
class SecurityEmailForm(RegistrarForm):
email = forms.EmailField(
required=False,
label="Security email",
)
class AnythingElseForm(RegistrarForm):
anything_else = forms.CharField(
required=False, label="Anything else we should know", widget=forms.Textarea()
)
class RequirementsForm(RegistrarForm):
agree_check = forms.BooleanField(
label="I read and agree to the .gov domain requirements."
)
# Empty class for the review page which gets included as part of the form, but does not
# have any form fields itself
class ReviewForm(RegistrarForm):
pass
# List of forms in our wizard. Each entry is a tuple of a name and a form
# subclass
FORMS = [
("organization", OrganizationForm),
("contact", ContactForm),
("organization_type", OrganizationTypeForm),
("organization_federal", OrganizationFederalForm),
("organization_election", OrganizationElectionForm),
("organization_contact", OrganizationContactForm),
("authorizing_official", AuthorizingOfficialForm),
("current_sites", CurrentSitesForm),
("dotgov_domain", DotGovDomainForm),
("purpose", PurposeForm),
("your_contact", YourContactForm),
("other_contacts", OtherContactsForm),
("security_email", SecurityEmailForm),
("anything_else", AnythingElseForm),
("requirements", RequirementsForm),
("review", ReviewForm),
]
# Dict to match up the right template with the right step. Keys here must
# match the first elements of the tuples in FORMS
TEMPLATES = {
"organization": "application_organization.html",
"contact": "application_contact.html",
"organization_type": "application_org_type.html",
"organization_federal": "application_org_federal.html",
"organization_election": "application_org_election.html",
"organization_contact": "application_org_contact.html",
"authorizing_official": "application_authorizing_official.html",
"current_sites": "application_current_sites.html",
"dotgov_domain": "application_dotgov_domain.html",
"purpose": "application_purpose.html",
"your_contact": "application_your_contact.html",
"other_contacts": "application_other_contacts.html",
"security_email": "application_security_email.html",
"anything_else": "application_anything_else.html",
"requirements": "application_requirements.html",
"review": "application_review.html",
}
# We need to pass our page titles as context to the templates, indexed
# by the step names
TITLES = {
"organization": "About your organization",
"contact": "Your organization's contact information",
"organization_type": "Type of organization",
"organization_federal": "Type of organization — Federal",
"organization_election": "Type of organization — Election board",
"organization_contact": "Organization name and mailing address",
"authorizing_official": "Authorizing official",
"current_sites": "Organization website",
"dotgov_domain": ".gov domain",
"purpose": "Purpose of your domain",
"your_contact": "Your contact information",
"other_contacts": "Other contacts for your domain",
"security_email": "Security email for public use",
"anything_else": "Anything else we should know?",
"requirements": "Requirements for registration and operation of .gov domains",
"review": "Review and submit your domain request",
}
@ -120,16 +326,22 @@ class ApplicationWizard(LoginRequiredMixin, NamedUrlSessionWizardView):
"""Unpack the form responses onto the model object properties."""
application = DomainApplication.objects.create(creator=self.request.user)
# organization information
organization_data = form_dict["organization"].cleaned_data
application.organization_type = organization_data["organization_type"]
application.federal_branch = organization_data["federal_type"]
application.is_election_office = organization_data["is_election_board"]
# organization type information
organization_type_data = form_dict["organization_type"].cleaned_data
application.organization_type = organization_type_data["organization_type"]
# federal branch information
federal_branch_data = form_dict["organization_federal"].cleaned_data
application.federal_branch = federal_branch_data["federal_type"]
# election board information
election_board_data = form_dict["organization_election"].cleaned_data
application.is_election_office = election_board_data["is_election_board"]
# contact information
contact_data = form_dict["contact"].cleaned_data
contact_data = form_dict["organization_contact"].cleaned_data
application.organization_name = contact_data["organization_name"]
application.street_address = contact_data["street_address"]
application.street_address = contact_data["address_line1"]
# TODO: add the rest of these fields when they are created in the forms
# This isn't really the requested_domain field

View file

@ -4,6 +4,7 @@
{% block title %}{% translate "Unauthorized" %}{% endblock %}
{% block content %}
<main id="main-content" class="grid-container">
<h1>{% translate "Unauthorized" %}</h1>
{% if friendly_message %}
@ -23,5 +24,5 @@
{% endif %}
TODO: Content team to create a "how to contact us" footer for the error pages
</main>
{% endblock %}

View file

@ -5,9 +5,11 @@
{% block title %}{% translate "Page not found" %}{% endblock %}
{% block content %}
<main id="main-content" class="grid-container">
<h2>{% translate "Page not found" %}</h2>
<p>{% translate "The requested page could not be found." %}</p>
</main>
{% endblock %}

View file

@ -4,6 +4,7 @@
{% block title %}{% translate "Server error" %}{% endblock %}
{% block content %}
<main id="main-content" class="grid-container">
<h1>{% translate "Server Error" %}</h1>
{% if friendly_message %}
@ -19,5 +20,5 @@
{% endif %}
TODO: Content team to create a "how to contact us" footer for the error pages
</main>
{% endblock %}

View file

@ -0,0 +1,25 @@
<!-- Test page -->
{% extends 'application_form.html' %}
{% load widget_tweaks %}
{% block form_content %}
<p id="instructions">Is there anything else we should know about your domain request?</p>
<form id="step__{{wizard.steps.current}}" class="usa-form usa-form--large" method="post">
<div class="usa-form-group">
{{ wizard.management_form }}
{% csrf_token %}
<div class="usa-character-count">
{{ wizard.form.anything_else|add_label_class:"usa-label usa-sr-only" }}
{{ wizard.form.anything_else|add_class:"usa-textarea usa-character-count__field"|attr:"aria-describedby:instructions"|attr:"maxlength=500" }}
<span class="usa-character-count__message" id="with-hint-textarea-info with-hint-textarea-hint"> You can enter up to 500 characters </span>
</div>
</div>
{{ block.super }}
</form>
{% endblock %}

View file

@ -0,0 +1,55 @@
<!-- Test page -->
{% extends 'application_form.html' %}
{% load widget_tweaks %}
{% load static %}
{% block form_content %}
<h2>Who is the authorizing official for your organization</h2>
<div id="instructions">
<p>Your authorizing official is the person within your organization who can authorize your domain request. This is generally the highest ranking or highest elected official in your organization. Read more about <a href="#">who can serve as an authorizing official</a>.
</p>
<div class="ao-example">
{% include "includes/ao_example__city.html" %}
</div>
<p>Well contact your authorizing official to let them know that you made this request and to double check that they approve it.</p>
</div>
<p>All fields are required unless they are marked optional.</p>
<form class="usa-form usa-form--large" id="step__{{wizard.steps.current}}" method="post">
{{ wizard.management_form }}
{% csrf_token %}
<fieldset class="usa-fieldset">
<legend class="usa-sr-only">
Who is the authorizing official for your organization
</legend>
{{ wizard.form.first_name|add_label_class:"usa-label" }}
{{ wizard.form.first_name|add_class:"usa-input"}}
{{ wizard.form.middle_name|add_label_class:"usa-label" }}
{{ wizard.form.middle_name|add_class:"usa-input"}}
{{ wizard.form.last_name|add_label_class:"usa-label" }}
{{ wizard.form.last_name|add_class:"usa-input"}}
{{ wizard.form.title|add_label_class:"usa-label" }}
{{ wizard.form.title|add_class:"usa-input"}}
{{ wizard.form.email|add_label_class:"usa-label" }}
{{ wizard.form.email|add_class:"usa-input"}}
{{ wizard.form.phone|add_label_class:"usa-label" }}
{{ wizard.form.phone|add_class:"usa-input usa-input--medium" }}
</fieldset>
{{ block.super }}
</form>
{% endblock %}

View file

@ -1,35 +0,0 @@
<!-- Test page -->
{% extends 'application_form.html' %}
{% load widget_tweaks %}
{% block title %}Apply for a .gov domain - Your organization's contact information{% endblock %}
{% block form_content %}
<h1>Your organization's contact information</h1>
<h2>What is the name and mailing address of your organization?</h2>
<p id="instructions">Enter the name of the organization your represent. Your organization might be part
of a larger entity. If so, enter information about your part of the larger entity.</p>
<p>All fields are required unless they are marked optional.</p>
<form class="usa-form usa-form--large" method="post">
{{ wizard.management_form }}
{% csrf_token %}
{{ wizard.form.organization_name|add_label_class:"usa-label" }}
{{ wizard.form.organization_name|add_class:"usa-input"|attr:"aria-describedby:instructions" }}
<fieldset class="usa-fieldset">
{{ wizard.form.street_address|add_label_class:"usa-label" }}
{{ wizard.form.street_address|add_class:"usa-input"|attr:"validate:domain" }}
</fieldset>
{% if wizard.steps.prev %}
<button name="wizard_goto_step" type="submit" class="usa-button usa-button--base" value="{{ wizard.steps.prev }}">Previous</button>
{% endif %}
<button type="submit" class="usa-button">Submit</button>
</form>
{% endblock %}

View file

@ -0,0 +1,19 @@
<!-- Test page -->
{% extends 'application_form.html' %}
{% load widget_tweaks %}
{% load static %}
{% block form_content %}
<form class="usa-form usa-form--large" id="step__{{wizard.steps.current}}" method="post">
{{ wizard.management_form }}
{% csrf_token %}
{{ wizard.form.current_site|add_label_class:"usa-label" }}
{{ wizard.form.current_site|add_class:"usa-input" }}
{{ block.super }}
</form>
{% endblock %}

View file

@ -0,0 +1,61 @@
<!-- Test page -->
{% extends 'application_form.html' %}
{% load widget_tweaks static%}
{% block form_content %}
<p> Before requesting a .gov domain, <a href="#">please make sure it meets our naming requirements.</a> Your domain name must:
<ul class="usa-list">
<li>Be available </li>
<li>Be unique </li>
<li>Relate to your organizations name, location, and/or services </li>
<li>Be clear to the general public. Your domain name must not be easily confused with other organizations.</li>
</ul>
</p>
<p>Note that <strong> only federal agencies can request generic terms </strong>like vote.gov.</p>
<p>Well try to give you the domain you want. We first need to make sure your request meets our requirements. Well work with you to find the best domain for your organization.</p>
<p>Here are a few domain examples for your type of organization.</p>
<div class="domain-example">
{% include "includes/domain_example__city.html" %}
</div>
<form id="step__{{wizard.steps.current}}" class="usa-form usa-form--large" method="post">
<h2> What .gov domain do you want? </h2>
<p class="domain_instructions"> After you enter your domain, well make sure its available and that it meets some of our naming requirements. If your domain passes these initial checks, well verify that it meets all of our requirements once you complete and submit the rest of the domain request form. </p>
{{ wizard.management_form }}
{% csrf_token %}
{{ wizard.form.dotgov_domain|add_label_class:"usa-label" }}
<div class="display-flex flex-align-center">
<span class="padding-top-05 padding-right-2px">www.</span>
{{ wizard.form.dotgov_domain|add_class:"usa-input"|attr:"aria-describedby:domain_instructions" }}
<span class="padding-top-05 padding-left-2px">.gov </span>
</div>
<button type="button" class="usa-button">Check availability </button>
<h2>Alternative domains</h2>
<div>
{{ wizard.form.alternative_domain|add_label_class:"usa-label" }}
<div class="display-flex flex-align-center">
<span class="padding-top-05 padding-right-2px">www.</span>
{{ wizard.form.alternative_domain|add_class:"usa-input" }}
<span class="padding-top-05 padding-left-2px">.gov </span>
</div>
<button type="button" class="usa-button usa-button--unstyled">
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img">
<use xlink:href="{%static 'img/sprite.svg'%}#add_circle"></use>
</svg><span class="margin-left-05">Add another alternative</span>
</button>
</div>
<p>If youre not sure this is the domain you want, thats okay. You can change it later.</p>
{{ block.super }}
</form>
{% endblock %}

View file

@ -1,13 +1,33 @@
{% extends 'base.html' %}
{% load static widget_tweaks %}
{% block title %}Apply for a .gov domain {{form_titles|get_item:wizard.steps.current}}{% endblock %}
{% block content %}
<div class="grid-row">
<div class="grid-container">
<div class="grid-row grid-gap">
<div class="grid-col-3">
{% include 'application_sidebar.html' %}
</div>
<div class="grid-col-9">
{% block form_content %}{% endblock %}
<main id="main-content" class="grid-container">
{% if wizard.steps.prev %}
<a href="{% url wizard.url_name step=wizard.steps.prev %}">
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img">
<use xlink:href="{%static 'img/sprite.svg'%}#arrow_back"></use>
</svg><span class="margin-left-05">Previous step </span>
</a>
{% endif %}
<h1> {{form_titles|get_item:wizard.steps.current}} </h1>
{% block form_content %}
{% if wizard.steps.next %}
<button type="submit" class="usa-button">Next</button>
{% else %}
<button type="submit" class="usa-button">Submit your domain request</button>
{% endif %}
<button type="button" class="usa-button usa-button--outline">Save</button>
</main>
</div>
{% endblock %}
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,44 @@
<!-- Test page -->
{% extends 'application_form.html' %}
{% load widget_tweaks %}
{% block form_content %}
<h2>What is the name and mailing address of your organization?</h2>
<div id="instructions">
<p>Enter the name of the organization your represent. Your organization might be part
of a larger entity. If so, enter information about your part of the larger entity.</p>
<p>Once your domain is approved, the name of your organization will be publicly listed as the domain registrant. </p>
<p>All fields are required unless they are marked optional.</p>
</div>
<form id="step__{{wizard.steps.current}}" class="usa-form usa-form--large" method="post">
{{ wizard.management_form }}
{% csrf_token %}
<fieldset class="usa-fieldset">
<legend class="usa-sr-only">What is the name and mailing address of your organization?</legend>
{{ wizard.form.organization_name|add_label_class:"usa-label" }}
{{ wizard.form.organization_name|add_class:"usa-input" }}
{{ wizard.form.address_line1|add_label_class:"usa-label" }}
{{ wizard.form.address_line1|add_class:"usa-input" }}
{{ wizard.form.address_line2|add_label_class:"usa-label" }}
{{ wizard.form.address_line2|add_class:"usa-input" }}
{{ wizard.form.us_state|add_label_class:"usa-label" }}
<div class="usa-combo-box">
{{ wizard.form.us_state|add_class:"usa-select" }}
</div>
{{ wizard.form.zipcode|add_label_class:"usa-label" }}
{{ wizard.form.zipcode|add_class:"usa-input usa-input--small" }}
</fieldset>
{{ block.super }}
</form>
{% endblock %}

View file

@ -0,0 +1,23 @@
<!-- Test page -->
{% extends 'application_form.html' %}
{% load widget_tweaks %}
{% load dynamic_question_tags %}
{% block form_content %}
<form id="step__{{wizard.steps.current}}" class="usa-form usa-form--large" method="post">
{{ wizard.management_form }}
{% csrf_token %}
<fieldset id="election_board__fieldset" class="usa-fieldset">
<legend>
<h2>Is your organization an election office?</h2>
</legend>
{% radio_buttons_by_value wizard.form.is_election_board as choices %}
{% include "includes/radio_button.html" with choice=choices|get_item:True %}
{% include "includes/radio_button.html" with choice=choices|get_item:False %}
</fieldset>
{{ block.super }}
</form>
{% endblock %}

View file

@ -0,0 +1,24 @@
<!-- Test page -->
{% extends 'application_form.html' %}
{% load widget_tweaks %}
{% load dynamic_question_tags %}
{% block form_content %}
<form id="step__{{wizard.steps.current}}" class="usa-form usa-form--large" method="post">
{{ wizard.management_form }}
{% csrf_token %}
<fieldset id="federal_type__fieldset" class="usa-fieldset">
<legend>
<h2>Which federal branch is your organization in?</h2>
</legend>
{% radio_buttons_by_value wizard.form.federal_type as federal_choices %}
{% include "includes/radio_button.html" with choice=federal_choices.Executive%}
{% include "includes/radio_button.html" with choice=federal_choices.Judicial%}
{% include "includes/radio_button.html" with choice=federal_choices.Legislative%}
</fieldset>
{{ block.super }}
</form>
{% endblock %}

View file

@ -0,0 +1,31 @@
<!-- Test page -->
{% extends 'application_form.html' %}
{% load widget_tweaks %}
{% load dynamic_question_tags %}
{% block form_content %}
<form id="step__{{wizard.steps.current}}" class="usa-form usa-form--large" method="post">
{{ wizard.management_form }}
{% csrf_token %}
{% radio_buttons_by_value wizard.form.organization_type as choices %}
<fieldset id="organization_type__fieldset" class="usa-fieldset">
<legend class="usa-legend">
<h2> What kind of government organization do you represent?</h2>
</legend>
{{ wizard.form.organization_type.errors }}
{% include "includes/radio_button.html" with choice=choices.Federal tile="true" %}
{% include "includes/radio_button.html" with choice=choices.Interstate tile="true" %}
{% include "includes/radio_button.html" with choice=choices.State_or_Territory tile="true" %}
{% include "includes/radio_button.html" with choice=choices.Tribal tile="true" %}
{% include "includes/radio_button.html" with choice=choices.County tile="true" %}
{% include "includes/radio_button.html" with choice=choices.City tile="true" %}
{% include "includes/radio_button.html" with choice=choices.Special_District tile="true" %}
</fieldset>
{{ block.super }}
</form>
{% endblock %}

View file

@ -1,54 +0,0 @@
<!-- Test page -->
{% extends 'application_form.html' %}
{% load widget_tweaks %}
{% load dynamic_question_tags %}
{% block title %}Apply for a .gov domain - About your organization{% endblock %}
{% block form_content %}
<h1>About your organization</h1>
<form class="usa-form usa-form--large" method="post">
{{ wizard.management_form }}
{% csrf_token %}
{% radio_buttons_by_value wizard.form.organization_type as choices %}
<fieldset id="organization_type__fieldset" class="usa-fieldset">
<legend>
<h2> What kind of government organization do you represent?</h2>
</legend>
{{ wizard.form.organization_type.errors }}
{% include "includes/radio_button.html" with choice=choices.Federal %}
{% include "includes/radio_button.html" with choice=choices.Interstate %}
{% include "includes/radio_button.html" with choice=choices.State_or_Territory %}
{% include "includes/radio_button.html" with choice=choices.Tribal %}
{% include "includes/radio_button.html" with choice=choices.County %}
{% include "includes/radio_button.html" with choice=choices.City %}
{% include "includes/radio_button.html" with choice=choices.Special_District %}
</fieldset>
<fieldset id="federal_type__fieldset" {% trigger wizard.form.federal_type choices.Federal %} class="usa-fieldset">
<legend>
<h2> Which federal branch does your organization belong to?</h2>
</legend>
<noscript>
Only required if you selected "Federal".
</noscript>
{{ wizard.form.federal_type|add_class:"usa-radio" }}
</fieldset>
<fieldset id="is_election_board__fieldset" {% trigger wizard.form.is_election_board choices.Tribal choices.County choices.City choices.Special_District%} class="usa-fieldset">
<legend>
<h2> Is your organization an election office?</h2>
</legend>
<noscript>
Only required if you selected "Tribal", "County", "City" or "Special District".
</noscript>
{{ wizard.form.is_election_board|add_class:"usa-radio" }}
</fieldset>
<button type="submit" class="usa-button">Next</button>
</form>
{% endblock %}

View file

@ -0,0 +1,50 @@
<!-- Test page -->
{% extends 'application_form.html' %}
{% load widget_tweaks %}
{% load static %}
{% block form_content %}
<p id="instructions">We strongly encourage you to have at least two points of contact for your domain. Many organizations have an administrative point of contact and a technical point of contact. We recommend that you add at least one more contact.</p>
<p>All fields are required unless they are marked optional.</p>
<form class="usa-form usa-form--large" id="step__{{wizard.steps.current}}" method="post">
{{ wizard.management_form }}
{% csrf_token %}
<fieldset class="usa-fieldset">
<legend>
<h2> Contact 2 </h2>
</legend>
{{ wizard.form.first_name|add_label_class:"usa-label" }}
{{ wizard.form.first_name|add_class:"usa-input"|attr:"aria-describedby:instructions" }}
{{ wizard.form.middle_name|add_label_class:"usa-label" }}
{{ wizard.form.middle_name|add_class:"usa-input"|attr:"aria-describedby:instructions" }}
{{ wizard.form.last_name|add_label_class:"usa-label" }}
{{ wizard.form.last_name|add_class:"usa-input"|attr:"aria-describedby:instructions" }}
{{ wizard.form.title|add_label_class:"usa-label" }}
{{ wizard.form.title|add_class:"usa-input"|attr:"aria-describedby:instructions" }}
{{ wizard.form.email|add_label_class:"usa-label" }}
{{ wizard.form.email|add_class:"usa-input"|attr:"aria-describedby:instructions" }}
{{ wizard.form.phone|add_label_class:"usa-label" }}
{{ wizard.form.phone|add_class:"usa-input usa-input--medium"|attr:"aria-describedby:instructions" }}
</fieldset>
<div>
<button type="button" class="usa-button usa-button--unstyled">
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img">
<use xlink:href="{%static '/img/sprite.svg'%}#add_circle"></use>
</svg><span class="margin-left-05">Add another contact</span>
</button>
</div>
{{ block.super }}
</form>
{% endblock %}

View file

@ -0,0 +1,25 @@
<!-- Test page -->
{% extends 'application_form.html' %}
{% load widget_tweaks %}
{% block form_content %}
<p id="instructions">Describe your organizations mission or the reason for your domain request. Explain how you plan to use this domain. Will you use it for a website and/or email? Are you moving your website from another top-level domain (like .com or .org)? Read about <a href="#">activities that are prohibited on .gov domains.</a></p>
<form id="step__{{wizard.steps.current}}" class="usa-form usa-form--large" method="post">
<div class="usa-form-group">
{{ wizard.management_form }}
{% csrf_token %}
<div class="usa-character-count">
{{ wizard.form.purpose_field|add_label_class:"usa-label usa-sr-only" }}
{{ wizard.form.purpose_field|add_class:"usa-textarea usa-character-count__field"|attr:"aria-describedby:instructions"|attr:"maxlength=500" }}
<span class="usa-character-count__message" id="with-hint-textarea-info with-hint-textarea-hint"> You can enter up to 500 characters </span>
</div>
</div>
{{ block.super }}
</form>
{% endblock %}

View file

@ -0,0 +1,72 @@
<!-- Test page -->
{% extends 'application_form.html' %}
{% load widget_tweaks %}
{% block form_content %}
<p>The .gov domain exists to support a broad diversity of government missions and public initiatives. Generally, the .gov registry does not review or audit how government organizations use their domains.</p>
<p>However, misuse of an individual .gov domain can reflect upon the integrity of the entire .gov space. There are categories of misuse that are statutorily prohibited or abusive in nature.</p>
<h2>Prohibited activities for .gov domains</h2>
<h3>Commercial purposes </h3>
<p>A .gov domain must not be used for commercial purposes, such as advertising benefitting private individuals or entities.</p>
<h3>Political campaigns</h3>
<p>A .gov domain must not be used for political campaigns.</p>
<h3>Illegal content</h3>
<p>A .gov domain must not be used to distribute or promote material whose distribution violates applicable law.</p>
<h3>Malicious cyber activity </h3>
<p>.gov is a trusted and safe space. .gov domains must not distribute malware, host open redirects, or otherwise engage in malicious cyber activity.</p>
<h2>Required activities for .gov domain registrants </h2>
<h3>Keep your contact information update</h3>
<p>As a .gov domain registrant, maintain current and accurate contact information in the .gov registrar. We strongly recommend that you create and use a security contact.</p>
<h3>Be responsive if we contact you</h3>
<p>Registrants should respond in a timely manner to communications about required and prohibited activities.</p>
<h2>Domains can be suspended or terminated for violations</h2>
<p>The .gov program may need to suspend or terminate a domain registration for violations. Registrants should respond in a timely manner to communications about prohibited activities.</p>
<p>When we discover a violation, we will make reasonable efforts to contact a registrant, including:
<ul class="usa-list">
<li>Emails to domain contacts </li>
<li>Phone calls to domain contacts</li>
<li>Email or phone call to the authorizing official</li>
<li>Email or phone call to the government organization, a parent organization, or affiliated entities</li>
</ul>
</p>
<p>We understand the critical importance of the availability of .gov domains. Suspending or terminating a .gov domain is reserved only for prolonged, unresolved serious violations where the registrant is non-responsive. We will make extensive efforts to contact registrants and to identify potential solutions, and will make reasonable accommodations for remediation timelines proportional to the severity of the issue.</p>
<h2>HSTS preloading</h2>
<p>The .gov program will preload all newly registered .gov domains for HTTP Strict Transport Security (HSTS).</p>
<p>HSTS is a simple and widely-supported standard that protects visitors by ensuring that their browsers always connect to a website over HTTPS. HSTS removes the need to redirect users from http:// to https:// URLs. (This redirection is a security risk that HSTS eliminates.)</p>
<p>HSTS preloading impacts web traffic only. Once a domain is on the HSTS preload list, modern web browsers will enforce HTTPS connections for all websites hosted on the .gov domain. Users will not be able to click through warnings to reach a site. Non-web uses of .gov (email, VPN, APIs, etc.) are not affected.</p>
<h2>Acknowledgement of .gov domain requirements</h2>
<form id="step__{{wizard.steps.current}}" class="usa-form usa-form--large" method="post">
<div class="usa-form-group">
{{ wizard.management_form }}
{% csrf_token %}
<div class="usa-checkbox">
{{ wizard.form.agree_check|add_class:"usa-checkbox__input"}}
{{ wizard.form.agree_check|add_label_class:"usa-checkbox__label" }}
</div>
</div>
{{ block.super }}
</form>
{% endblock %}

View file

@ -0,0 +1,27 @@
<!-- Test page -->
{% extends 'application_form.html' %}
{% load static widget_tweaks %}
{% block form_content %}
<form id="step__{{wizard.steps.current}}" class="usa-form usa-form--large" method="post">
{{ wizard.management_form }}
{% csrf_token %}
{% for this_step in wizard.steps.all|slice:":-1" %}
<div class="review__step margin-top-2">
<div class="review__step__title display-flex flex-justify">
<span class="review__step__name">{{ form_titles|get_item:this_step }}</span>
<a href="{% url wizard.url_name step=this_step %}">Edit </a>
</div>
<div class="review__step__value">
&lt;Answer value&gt;
</div>
</div>
{% endfor %}
{{ block.super }}
</form>
{% endblock %}

View file

@ -0,0 +1,21 @@
<!-- Test page -->
{% extends 'application_form.html' %}
{% load widget_tweaks %}
{% load static %}
{% block form_content %}
<p id="instructions"> We strongly recommend that you provide a security email. This email will allow the public to report observed or suspected security issues on your domain. <strong> Security emails are made public.</strong> We recommend using an alias, like security@&lt;domain.gov&gt;.</p>
<form class="usa-form usa-form--large" id="step__{{wizard.steps.current}}" method="post">
{{ wizard.management_form }}
{% csrf_token %}
{{ wizard.form.email|add_label_class:"usa-label" }}
{{ wizard.form.email|add_class:"usa-input"|attr:"aria-describedby:instructions" }}
{{ block.super }}
</form>
{% endblock %}

View file

@ -1,15 +1,20 @@
<div class="tablet:grid-col-4 margin-bottom-4 tablet:margin-bottom-0">
{% load static %}
<div class="margin-bottom-4 tablet:margin-bottom-0">
<nav aria-label="Form steps,">
<ul class="usa-sidenav">
{% for this_step in wizard.steps.all %}
<li class="usa-sidenav__item">
{% if forloop.counter <= wizard.steps.step1 %}
<li class="usa-sidenav__item">
<a href="{% url wizard.url_name step=this_step %}"
{% if this_step == wizard.steps.current %}class="usa-current"{% endif%}>
{{ form_titles|get_item:this_step }}
</a>
{% else %}
<li class="usa-sidenav__item step--locked">
{{ form_titles|get_item:this_step }}
<svg class="usa-icon" aria-labelledby="locked-step" role="img">
<title id="locked-step__{{forloop.counter}}">locked until previous steps have been completed </title>
<use xlink:href="{%static 'img/sprite.svg'%}#lock"></use>
{% endif %}
</li>
{% endfor %}

View file

@ -0,0 +1,50 @@
<!-- Test page -->
{% extends 'application_form.html' %}
{% load widget_tweaks %}
{% load static %}
{% block form_content %}
<div id="instructions">
<p> Well use the following information to contact you about your domain request and, once your request is approved, about managing your domain.</p>
<p>If youd like us to use a different name, email, or phone number you can make those changes below. Changing your contact information here wont affect your login.gov account information.</p>
<p>The contact information you provide here wont be public and will only be used for the .gov registry.</p>
<div>
<p>All fields are required unless they are marked optional.</p>
<form class="usa-form usa-form--large" id="step__{{wizard.steps.current}}" method="post">
{{ wizard.management_form }}
{% csrf_token %}
<fieldset class="usa-fieldset">
<legend class="usa-sr-only">
Your contact information
</legend>
{{ wizard.form.first_name|add_label_class:"usa-label" }}
{{ wizard.form.first_name|add_class:"usa-input"|attr:"aria-describedby:instructions" }}
{{ wizard.form.middle_name|add_label_class:"usa-label" }}
{{ wizard.form.middle_name|add_class:"usa-input"|attr:"aria-describedby:instructions" }}
{{ wizard.form.last_name|add_label_class:"usa-label" }}
{{ wizard.form.last_name|add_class:"usa-input"|attr:"aria-describedby:instructions" }}
{{ wizard.form.title|add_label_class:"usa-label" }}
{{ wizard.form.title|add_class:"usa-input"|attr:"aria-describedby:instructions" }}
{{ wizard.form.email|add_label_class:"usa-label" }}
{{ wizard.form.email|add_class:"usa-input"|attr:"aria-describedby:instructions" }}
{{ wizard.form.phone|add_label_class:"usa-label" }}
{{ wizard.form.phone|add_class:"usa-input usa-input--medium"|attr:"aria-describedby:instructions" }}
</fieldset>
{{ block.super }}
</form>
{% endblock %}

View file

@ -171,10 +171,8 @@
{% block section_nav %}{% endblock %}
<main id="main-content" class="grid-container">
{% block hero %}{% endblock %}
{% block content %}{% endblock %}
</main>
<div role="complementary">{% block complementary %}{% endblock %}</div>

View file

@ -14,6 +14,7 @@
{% endblock %}
{% block content %}
<main id="main-content" class="grid-container">
<p>This is the .gov registrar.</p>
{% if user.is_authenticated %}
@ -21,5 +22,5 @@
{% else %}
<p><a href="/openid/login/">Click here to log in.</a></p>
{% endif %}
</main>
{% endblock %}

View file

@ -0,0 +1 @@
<p>Domain requests from <strong>cities</strong> must be authorized by the mayor or the equivalent highest elected official.</p>

View file

@ -0,0 +1,15 @@
<p> Most city domains must include the two-letter state abbreviation or clearly spell out the state name. Using phrases like “City of” or “Town of” is optional.</p>
<p>Examples:
<ul class="usa-list">
<li>www.BlufftonIndiana.gov</li>
<li>www.CityofEudoraKS.gov</li>
<li>www.WallawallaWA.gov</li>
</ul>
</p>
<p> Some cities dont have to refer to their state.
<ul class="usa-list">
<li> City names that are not shared by any other U.S. city, town, or village can be requested without referring to the state. We use the Census Bureaus National Places Gazetteer Files to determine if names are unique. </li>
<li>Certain cities are so well-known that they may not require a state reference to communicate location. We use the list of U.S. “dateline cities” in the Associated Press Stylebook to make this determination.</li>
<li>The 50 largest cities, as measured by population according to the Census Bureau, can have .gov domain names that dont refer to their state.</li>
</ul>
</p>

View file

@ -1,14 +1,14 @@
<div>
<label for="{{ choice.id_for_label }}"
><input
<div class="usa-radio">
<input
type="{{ choice.data.type }}"
name="{{ choice.data.name }}"
value="{{ choice.data.value }}"
class="usa-radio"
class="usa-radio__input {% if tile %}usa-radio__input--tile {%endif%}"
id="{{ choice.id_for_label }}"
{% if choice.data.attrs.required %}required{% endif %}
{% if choice.data.selected %}checked{% endif %}
/>
{{ choice.data.label }}</label
>
<label class="usa-radio__label" for="{{ choice.id_for_label }}" >
{{ choice.data.label }}
</label >
</div>

View file

@ -5,6 +5,7 @@ Edit your User Profile
{% endblock title %}
{% block content %}
<main id="main-content" class="grid-container">
<form class="usa-form usa-form--large" method="post" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="usa-fieldset">
@ -13,8 +14,7 @@ Edit your User Profile
Required fields are marked with an asterisk (<abbr
title="required"
class="usa-hint usa-hint--required"
>*</abbr
>).
>*</abbr>).
</p>
{% for field in profile_form %}
<label class="usa-label" for="id_{{ field.name }}">{{ field.label }}</label>
@ -23,4 +23,6 @@ Edit your User Profile
</fieldset>
<button type="submit" class="usa-button usa-button--big">Save Changes</button>
</form>
</main>
{% endblock content %}

View file

@ -3,7 +3,9 @@
{% block title %} Hello {% endblock %}
{% block content %}
<main id="main-content" class="grid-container">
<p> Hello {{ user.last_name|default:"No last name given" }}, {{ user.first_name|default:"No first name given" }} &lt;{{ user.email }}&gt;! </p>
<p><a href="/openid/logout">Click here to log out</a></p>
</main>
{% endblock %}

View file

@ -67,7 +67,9 @@ class LoggedInTests(TestWithUser):
def test_application_form_view(self):
response = self.client.get("/register/", follow=True)
self.assertContains(response, "About your organization")
self.assertContains(
response, "What kind of government organization do you represent?"
)
class FormTests(TestWithUser, WebTest):
@ -92,56 +94,229 @@ class FormTests(TestWithUser, WebTest):
page = self.app.get(reverse("application")).follow()
# submitting should get back the same page if the required field is empty
result = page.form.submit()
self.assertIn("About your organization", result)
self.assertIn("What kind of government organization do you represent?", result)
def test_application_form_organization(self):
# 302 redirect to the first form
page = self.app.get(reverse("application")).follow()
form = page.form
form["organization-organization_type"] = "Federal"
form["organization_type-organization_type"] = "Federal"
result = page.form.submit().follow()
# Got the next form page
self.assertContains(result, "contact information")
def test_application_form_submission(self):
"""Can fill out the entire form and submit.
As we add additional form pages, we need to include them here to make
this test work.
"""
page = self.app.get(reverse("application")).follow()
type_page = self.app.get(reverse("application")).follow()
# 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]
form = page.form
form["organization-organization_type"] = "Federal"
form["organization-federal_type"] = "Executive"
# ---- TYPE PAGE ----
type_form = type_page.form
type_form["organization_type-organization_type"] = "Federal"
# set the session ID before .submit()
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
result = page.form.submit()
type_result = type_page.form.submit()
# the post request should return a redirect to the next form in
# the application
self.assertEquals(result.status_code, 302)
self.assertEquals(result["Location"], "/register/contact/")
self.assertEquals(type_result.status_code, 302)
self.assertEquals(type_result["Location"], "/register/organization_federal/")
# TODO: In the future this should be conditionally dispalyed based on org type
# ---- FEDERAL BRANCH PAGE ----
# Follow the redirect to the next form page
next_page = result.follow()
contact_form = next_page.form
contact_form["contact-organization_name"] = "test"
contact_form["contact-street_address"] = "100 Main Street"
federal_page = type_result.follow()
federal_form = federal_page.form
federal_form["organization_federal-federal_type"] = "Executive"
# set the session ID before .submit()
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
result = contact_form.submit()
federal_result = federal_form.submit()
self.assertEquals(federal_result.status_code, 302)
self.assertEquals(
federal_result["Location"], "/register/organization_election/"
)
# ---- ELECTION BOARD BRANCH PAGE ----
# Follow the redirect to the next form page
election_page = federal_result.follow()
election_form = election_page.form
election_form["organization_election-is_election_board"] = True
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
election_result = election_form.submit()
self.assertEquals(election_result.status_code, 302)
self.assertEquals(
election_result["Location"], "/register/organization_contact/"
)
# ---- ORG CONTACT PAGE ----
# Follow the redirect to the next form page
org_contact_page = election_result.follow()
org_contact_form = org_contact_page.form
org_contact_form["organization_contact-organization_name"] = "Testorg"
org_contact_form["organization_contact-address_line1"] = "address 1"
org_contact_form["organization_contact-us_state"] = "NY"
org_contact_form["organization_contact-zipcode"] = "10002"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
org_contact_result = org_contact_form.submit()
self.assertEquals(org_contact_result.status_code, 302)
self.assertEquals(
org_contact_result["Location"], "/register/authorizing_official/"
)
# ---- AUTHORIZING OFFICIAL PAGE ----
# Follow the redirect to the next form page
ao_page = org_contact_result.follow()
ao_form = ao_page.form
ao_form["authorizing_official-first_name"] = "Testy"
ao_form["authorizing_official-last_name"] = "Tester"
ao_form["authorizing_official-title"] = "Chief Tester"
ao_form["authorizing_official-email"] = "testy@town.com"
ao_form["authorizing_official-phone"] = "(555) 555 5555"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
ao_result = ao_form.submit()
self.assertEquals(ao_result.status_code, 302)
self.assertEquals(ao_result["Location"], "/register/current_sites/")
# ---- CURRENT SITES PAGE ----
# Follow the redirect to the next form page
current_sites_page = ao_result.follow()
current_sites_form = current_sites_page.form
current_sites_form["current_sites-current_site"] = "www.city.com"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
current_sites_result = current_sites_form.submit()
self.assertEquals(current_sites_result.status_code, 302)
self.assertEquals(current_sites_result["Location"], "/register/dotgov_domain/")
# ---- DOTGOV DOMAIN PAGE ----
# Follow the redirect to the next form page
dotgov_page = current_sites_result.follow()
dotgov_form = dotgov_page.form
dotgov_form["dotgov_domain-dotgov_domain"] = "city"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
dotgov_result = dotgov_form.submit()
self.assertEquals(dotgov_result.status_code, 302)
self.assertEquals(dotgov_result["Location"], "/register/purpose/")
# ---- PURPOSE DOMAIN PAGE ----
# Follow the redirect to the next form page
purpose_page = dotgov_result.follow()
purpose_form = purpose_page.form
purpose_form["purpose-purpose_field"] = "Purpose of the site"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
purpose_result = purpose_form.submit()
self.assertEquals(purpose_result.status_code, 302)
self.assertEquals(purpose_result["Location"], "/register/your_contact/")
# ---- YOUR CONTACT INFO PAGE ----
# Follow the redirect to the next form page
your_contact_page = purpose_result.follow()
your_contact_form = your_contact_page.form
your_contact_form["your_contact-first_name"] = "Testy you"
your_contact_form["your_contact-last_name"] = "Tester you"
your_contact_form["your_contact-title"] = "Admin Tester"
your_contact_form["your_contact-email"] = "testy-admin@town.com"
your_contact_form["your_contact-phone"] = "(555) 555 5556"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
your_contact_result = your_contact_form.submit()
self.assertEquals(your_contact_result.status_code, 302)
self.assertEquals(your_contact_result["Location"], "/register/other_contacts/")
# ---- OTHER CONTACTS PAGE ----
# Follow the redirect to the next form page
other_contacts_page = your_contact_result.follow()
other_contacts_form = other_contacts_page.form
other_contacts_form["other_contacts-first_name"] = "Testy2"
other_contacts_form["other_contacts-last_name"] = "Tester2"
other_contacts_form["other_contacts-title"] = "Another Tester"
other_contacts_form["other_contacts-email"] = "testy2@town.com"
other_contacts_form["other_contacts-phone"] = "(555) 555 5557"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
other_contacts_result = other_contacts_form.submit()
self.assertEquals(other_contacts_result.status_code, 302)
self.assertEquals(
other_contacts_result["Location"], "/register/security_email/"
)
# ---- SECURITY EMAIL PAGE ----
# Follow the redirect to the next form page
security_email_page = other_contacts_result.follow()
security_email_form = security_email_page.form
security_email_form["security_email-email"] = "security@city.com"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
security_email_result = security_email_form.submit()
self.assertEquals(security_email_result.status_code, 302)
self.assertEquals(security_email_result["Location"], "/register/anything_else/")
# ---- ANYTHING ELSE PAGE ----
# Follow the redirect to the next form page
anything_else_page = security_email_result.follow()
anything_else_form = anything_else_page.form
anything_else_form["anything_else-anything_else"] = "No"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
anything_else_result = anything_else_form.submit()
self.assertEquals(anything_else_result.status_code, 302)
self.assertEquals(anything_else_result["Location"], "/register/requirements/")
# ---- REQUIREMENTS PAGE ----
# Follow the redirect to the next form page
requirements_page = anything_else_result.follow()
requirements_form = requirements_page.form
requirements_form["requirements-agree_check"] = True
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
requirements_result = requirements_form.submit()
self.assertEquals(requirements_result.status_code, 302)
self.assertEquals(requirements_result["Location"], "/register/review/")
# ---- REVIEW AND FINSIHED PAGES ----
# Follow the redirect to the next form page
review_page = requirements_result.follow()
review_form = review_page.form
# final submission results in a redirect to the "finished" URL
self.assertEquals(result.status_code, 302)
self.assertEquals(result["Location"], "/register/finished/")
# the finished URL (for now) returns a redirect to /
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
review_result = review_form.submit()
self.assertEquals(review_result.status_code, 302)
self.assertEquals(review_result["Location"], "/register/finished/")
# following this redirect is a GET request, so include the cookie
# here too.
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)