diff --git a/docs/developer/README.md b/docs/developer/README.md index cd33aeea6..0d814250c 100644 --- a/docs/developer/README.md +++ b/docs/developer/README.md @@ -138,3 +138,17 @@ In an effort to keep our domain logic centralized, we are representing the state objects in the application using the [django-fsm](https://github.com/viewflow/django-fsm) library. See the [ADR number 15](../architecture/decisions/0015-use-django-fs.md) for more information on the topic. + +## Login Time Bug + +If you are seeing errors related to openid complaining about issuing a token from the future like this: + +``` +ERROR [djangooidc.oidc:243] Issued in the future +``` + +it may help to resync your laptop with time.nist.gov: + +``` +sudo sntp -sS time.nist.gov +``` diff --git a/src/.pa11yci b/src/.pa11yci index f93601af9..72d14bd93 100644 --- a/src/.pa11yci +++ b/src/.pa11yci @@ -3,6 +3,21 @@ "http://app:8080/", "http://app:8080/health/", "http://app:8080/whoami/", - "http://app:8080/register/" + "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/" ] } diff --git a/src/registrar/config/urls.py b/src/registrar/config/urls.py index b69a4b679..d3a6d0a46 100644 --- a/src/registrar/config/urls.py +++ b/src/registrar/config/urls.py @@ -10,12 +10,14 @@ from django.urls import include, path from django.views.generic import RedirectView from registrar.views import health, index, profile, whoami -from registrar.forms import ApplicationWizard +from registrar.forms import ApplicationWizard, WIZARD_CONDITIONS from api.views import available APPLICATION_URL_NAME = "application_step" application_wizard = ApplicationWizard.as_view( - url_name=APPLICATION_URL_NAME, done_step_name="finished" + url_name=APPLICATION_URL_NAME, + done_step_name="finished", + condition_dict=WIZARD_CONDITIONS, ) urlpatterns = [ diff --git a/src/registrar/forms/__init__.py b/src/registrar/forms/__init__.py index e1dff5082..806a2309c 100644 --- a/src/registrar/forms/__init__.py +++ b/src/registrar/forms/__init__.py @@ -1,4 +1,4 @@ from .edit_profile import EditProfileForm -from .application_wizard import ApplicationWizard +from .application_wizard import ApplicationWizard, WIZARD_CONDITIONS -__all__ = ["EditProfileForm", "ApplicationWizard"] +__all__ = ["EditProfileForm", "ApplicationWizard", "WIZARD_CONDITIONS"] diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index 0cf0eb6e0..bc7176297 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -1,9 +1,11 @@ """Forms Wizard for creating a new domain application.""" +from __future__ import annotations # allows forward references in annotations + import logging from django import forms -from django.shortcuts import redirect +from django.shortcuts import render from django.contrib.auth.mixins import LoginRequiredMixin @@ -15,7 +17,14 @@ from registrar.models import DomainApplication, Domain 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=[ @@ -45,49 +54,244 @@ class OrganizationForm(forms.Form): ], widget=forms.RadioSelect, ) + + +class OrganizationFederalForm(RegistrarForm): 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( + + +class OrganizationElectionForm(RegistrarForm): + is_election_board = forms.BooleanField( + widget=forms.RadioSelect( + choices=[ + (True, "Yes"), + (False, "No"), + ], + ), required=False, - choices=[ - ("Yes", "Yes"), - ("No", "No"), - ], - widget=forms.RadioSelect, ) -class ContactForm(forms.Form): +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 organization’s 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 you’d like if we can’t 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", +} + + +# We can use a dictionary with step names and callables that return booleans +# to show or hide particular steps based on the state of the process. +WIZARD_CONDITIONS = { + "organization_federal": DomainApplication.show_organization_federal, + "organization_election": DomainApplication.show_organization_election, } @@ -120,16 +324,26 @@ 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 may not exist + federal_branch_data = form_dict.get("organization_federal") + if federal_branch_data is not None: + federal_branch_data = federal_branch_data.cleaned_data + application.federal_branch = federal_branch_data["federal_type"] + + # election board information may not exist. + election_board_data = form_dict.get("organization_election") + if election_board_data is not None: + election_board_data = election_board_data.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 @@ -144,5 +358,7 @@ class ApplicationWizard(LoginRequiredMixin, NamedUrlSessionWizardView): application = self.forms_to_object(form_dict) application.submit() # change the status to submitted application.save() - logger.debug("Application object saved:", application.id) - return redirect("home") + logger.debug("Application object saved: %s", application.id) + return render( + self.request, "application_done.html", {"application_id": application.id} + ) diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index f1d611489..05fa051cf 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from django.db import models from django_fsm import FSMField, transition # type: ignore @@ -6,6 +8,11 @@ from .contact import Contact from .user import User from .website import Website +from typing import TYPE_CHECKING, Union + +if TYPE_CHECKING: + from ..forms.application_wizard import ApplicationWizard + class DomainApplication(TimeStampedModel): @@ -225,3 +232,36 @@ class DomainApplication(TimeStampedModel): # if no exception was raised, then we don't need to do anything # inside this method, keep the `pass` here to remind us of that pass + + # ## Form policies ### + # + # These methods control what questions need to be answered by applicants + # during the application flow. They are policies about the application so + # they appear here. + + @staticmethod + def _get_organization_type(wizard: ApplicationWizard) -> Union[str, None]: + """Extract the answer to the organization type question from the wizard.""" + # using the step data from the storage is a workaround for this + # bug in django-formtools version 2.4 + # https://github.com/jazzband/django-formtools/issues/220 + type_data = wizard.storage.get_step_data("organization_type") + if type_data: + return type_data.get("organization_type-organization_type") + return None + + @staticmethod + def show_organization_federal(wizard: ApplicationWizard) -> bool: + """Show this step if the answer to the first question was "federal".""" + return DomainApplication._get_organization_type(wizard) == "Federal" + + @staticmethod + def show_organization_election(wizard: ApplicationWizard) -> bool: + """Show this step if the answer to the first question implies it. + + This shows for answers that aren't "Federal" or "Interstate". + """ + type_answer = DomainApplication._get_organization_type(wizard) + if type_answer and type_answer not in ("Federal", "Interstate"): + return True + return False diff --git a/src/registrar/templates/401.html b/src/registrar/templates/401.html index 0785da4c5..64bcec563 100644 --- a/src/registrar/templates/401.html +++ b/src/registrar/templates/401.html @@ -4,24 +4,25 @@ {% block title %}{% translate "Unauthorized" %}{% endblock %} {% block content %} -

{% translate "Unauthorized" %}

+
+

{% translate "Unauthorized" %}

-{% if friendly_message %} -

{{ friendly_message }}

-{% else %} -

{% translate "Authorization failed." %}

-{% endif %} + {% if friendly_message %} +

{{ friendly_message }}

+ {% else %} +

{% translate "Authorization failed." %}

+ {% endif %} -

+

{% translate "Would you like to try logging in again?" %} -

+

-{% if log_identifier %} -

Here's a unique identifier for this error.

-
{{ log_identifier }}
-

{% translate "Please include it if you contact us." %}

-{% endif %} + {% if log_identifier %} +

Here's a unique identifier for this error.

+
{{ log_identifier }}
+

{% translate "Please include it if you contact us." %}

+ {% endif %} -TODO: Content team to create a "how to contact us" footer for the error pages - -{% endblock %} \ No newline at end of file + TODO: Content team to create a "how to contact us" footer for the error pages +
+{% endblock %} diff --git a/src/registrar/templates/404.html b/src/registrar/templates/404.html index cac4df5d0..f715e0fa9 100644 --- a/src/registrar/templates/404.html +++ b/src/registrar/templates/404.html @@ -5,9 +5,11 @@ {% block title %}{% translate "Page not found" %}{% endblock %} {% block content %} +
-

{% translate "Page not found" %}

+

{% translate "Page not found" %}

-

{% translate "The requested page could not be found." %}

+

{% translate "The requested page could not be found." %}

-{% endblock %} \ No newline at end of file +
+{% endblock %} diff --git a/src/registrar/templates/500.html b/src/registrar/templates/500.html index 9709d004f..5fbd30d2d 100644 --- a/src/registrar/templates/500.html +++ b/src/registrar/templates/500.html @@ -4,20 +4,21 @@ {% block title %}{% translate "Server error" %}{% endblock %} {% block content %} -

{% translate "Server Error" %}

+
+

{% translate "Server Error" %}

-{% if friendly_message %} -

{{ friendly_message }}

-{% else %} -

{% translate "An internal server error occurred." %}

-{% endif %} + {% if friendly_message %} +

{{ friendly_message }}

+ {% else %} +

{% translate "An internal server error occurred." %}

+ {% endif %} -{% if log_identifier %} -

Here's a unique identifier for this error.

-
{{ log_identifier }}
-

{% translate "Please include it if you contact us." %}

-{% endif %} + {% if log_identifier %} +

Here's a unique identifier for this error.

+
{{ log_identifier }}
+

{% translate "Please include it if you contact us." %}

+ {% endif %} -TODO: Content team to create a "how to contact us" footer for the error pages - -{% endblock %} \ No newline at end of file + TODO: Content team to create a "how to contact us" footer for the error pages +
+{% endblock %} diff --git a/src/registrar/templates/application_anything_else.html b/src/registrar/templates/application_anything_else.html new file mode 100644 index 000000000..153d547e2 --- /dev/null +++ b/src/registrar/templates/application_anything_else.html @@ -0,0 +1,25 @@ + +{% extends 'application_form.html' %} +{% load widget_tweaks %} + +{% block form_content %} + +

Is there anything else we should know about your domain request?

+ +
+
+ {{ wizard.management_form }} + {% csrf_token %} + +
+ {{ 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" }} + You can enter up to 500 characters +
+
+ + {{ block.super }} + +
+ +{% endblock %} diff --git a/src/registrar/templates/application_authorizing_official.html b/src/registrar/templates/application_authorizing_official.html new file mode 100644 index 000000000..70eb9d617 --- /dev/null +++ b/src/registrar/templates/application_authorizing_official.html @@ -0,0 +1,55 @@ + +{% extends 'application_form.html' %} +{% load widget_tweaks %} +{% load static %} + +{% block form_content %} + +

Who is the authorizing official for your organization

+ +
+

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 who can serve as an authorizing official. +

+ +
+ {% include "includes/ao_example__city.html" %} +
+ +

We’ll contact your authorizing official to let them know that you made this request and to double check that they approve it.

+
+ +

All fields are required unless they are marked optional.

+ +
+ {{ wizard.management_form }} + {% csrf_token %} + +
+ + Who is the authorizing official for your organization + + {{ 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" }} +
+ + + {{ block.super }} + +
+ +{% endblock %} diff --git a/src/registrar/templates/application_contact.html b/src/registrar/templates/application_contact.html deleted file mode 100644 index 08dbd0e37..000000000 --- a/src/registrar/templates/application_contact.html +++ /dev/null @@ -1,35 +0,0 @@ - -{% extends 'application_form.html' %} -{% load widget_tweaks %} - -{% block title %}Apply for a .gov domain - Your organization's contact information{% endblock %} - -{% block form_content %} -

Your organization's contact information

- -

What is the name and mailing address of your organization?

- -

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.

- -

All fields are required unless they are marked optional.

- -
- {{ 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" }} - -
- {{ wizard.form.street_address|add_label_class:"usa-label" }} - {{ wizard.form.street_address|add_class:"usa-input"|attr:"validate:domain" }} -
- - {% if wizard.steps.prev %} - - {% endif %} - -
- -{% endblock %} diff --git a/src/registrar/templates/application_current_sites.html b/src/registrar/templates/application_current_sites.html new file mode 100644 index 000000000..535a8f5dc --- /dev/null +++ b/src/registrar/templates/application_current_sites.html @@ -0,0 +1,19 @@ + +{% extends 'application_form.html' %} +{% load widget_tweaks %} +{% load static %} + +{% block form_content %} + +
+ {{ wizard.management_form }} + {% csrf_token %} + + {{ wizard.form.current_site|add_label_class:"usa-label" }} + {{ wizard.form.current_site|add_class:"usa-input" }} + + {{ block.super }} + +
+ +{% endblock %} diff --git a/src/registrar/templates/application_done.html b/src/registrar/templates/application_done.html new file mode 100644 index 000000000..4997ef87d --- /dev/null +++ b/src/registrar/templates/application_done.html @@ -0,0 +1,40 @@ +{% extends 'base.html' %} + +{% block title %}Thank you for your domain request{% endblock %} + +{% block content %} +

Thank you!

+ +

+Thank you for your domain request. We'll email a copy of your request to you, +your authorizing official, and any contacts you added.

+ +

Next steps in this process

+ + + +

Option to enter domain name server information

+ +

Before your domain can be used we'll need information about your +domain name servers. If you have this information you can enter it now. +If you don't have it, that's okay. You can enter it later on the +manage your domains page. +

+ +

Enter DNS name servers

+ +{% endblock %} diff --git a/src/registrar/templates/application_dotgov_domain.html b/src/registrar/templates/application_dotgov_domain.html new file mode 100644 index 000000000..abe3e774b --- /dev/null +++ b/src/registrar/templates/application_dotgov_domain.html @@ -0,0 +1,61 @@ + +{% extends 'application_form.html' %} +{% load widget_tweaks static%} + +{% block form_content %} +

Before requesting a .gov domain, please make sure it meets our naming requirements. Your domain name must: +

+

+ +

Note that only federal agencies can request generic terms like vote.gov.

+ +

We’ll try to give you the domain you want. We first need to make sure your request meets our requirements. We’ll work with you to find the best domain for your organization.

+ +

Here are a few domain examples for your type of organization.

+
+ {% include "includes/domain_example__city.html" %} +
+ +
+

What .gov domain do you want?

+

After you enter your domain, we’ll make sure it’s available and that it meets some of our naming requirements. If your domain passes these initial checks, we’ll verify that it meets all of our requirements once you complete and submit the rest of the domain request form.

+ + {{ wizard.management_form }} + {% csrf_token %} + {{ wizard.form.dotgov_domain|add_label_class:"usa-label" }} +
+ www. + {{ wizard.form.dotgov_domain|add_class:"usa-input"|attr:"aria-describedby:domain_instructions" }} + .gov +
+ + +

Alternative domains

+ +
+ {{ wizard.form.alternative_domain|add_label_class:"usa-label" }} +
+ www. + {{ wizard.form.alternative_domain|add_class:"usa-input" }} + .gov +
+ + +
+ +

If you’re not sure this is the domain you want, that’s okay. You can change it later.

+ + {{ block.super }} + +
+ +{% endblock %} diff --git a/src/registrar/templates/application_form.html b/src/registrar/templates/application_form.html index c187dd4b9..2977eaac2 100644 --- a/src/registrar/templates/application_form.html +++ b/src/registrar/templates/application_form.html @@ -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 %} -
-
- {% include 'application_sidebar.html' %} -
- -
- {% block form_content %}{% endblock %} +
+
+
+ {% include 'application_sidebar.html' %} +
+
+
+ {% if wizard.steps.prev %} + + Previous step + + {% endif %} +

{{form_titles|get_item:wizard.steps.current}}

+ {% block form_content %} + {% if wizard.steps.next %} + + {% else %} + + {% endif %} + +
+
+ {% endblock %}
{% endblock %} diff --git a/src/registrar/templates/application_org_contact.html b/src/registrar/templates/application_org_contact.html new file mode 100644 index 000000000..a879bd126 --- /dev/null +++ b/src/registrar/templates/application_org_contact.html @@ -0,0 +1,44 @@ + +{% extends 'application_form.html' %} +{% load widget_tweaks %} + +{% block form_content %} + + +

What is the name and mailing address of your organization?

+ +
+

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.

+ +

Once your domain is approved, the name of your organization will be publicly listed as the domain registrant.

+ +

All fields are required unless they are marked optional.

+
+ +
+ {{ wizard.management_form }} + {% csrf_token %} + +
+ What is the name and mailing address of your organization? + {{ 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" }} +
+ {{ wizard.form.us_state|add_class:"usa-select" }} +
+ {{ wizard.form.zipcode|add_label_class:"usa-label" }} + {{ wizard.form.zipcode|add_class:"usa-input usa-input--small" }} + +
+ + {{ block.super }} + +
+ +{% endblock %} diff --git a/src/registrar/templates/application_org_election.html b/src/registrar/templates/application_org_election.html new file mode 100644 index 000000000..1499c1e0b --- /dev/null +++ b/src/registrar/templates/application_org_election.html @@ -0,0 +1,23 @@ + +{% extends 'application_form.html' %} +{% load widget_tweaks %} +{% load dynamic_question_tags %} + +{% block form_content %} + +
+ {{ wizard.management_form }} + {% csrf_token %} +
+ +

Is your organization an election office?

+
+ {% 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 %} +
+ + {{ block.super }} + +
+{% endblock %} diff --git a/src/registrar/templates/application_org_federal.html b/src/registrar/templates/application_org_federal.html new file mode 100644 index 000000000..d10b2c442 --- /dev/null +++ b/src/registrar/templates/application_org_federal.html @@ -0,0 +1,24 @@ + +{% extends 'application_form.html' %} +{% load widget_tweaks %} +{% load dynamic_question_tags %} + +{% block form_content %} + +
+ {{ wizard.management_form }} + {% csrf_token %} +
+ +

Which federal branch is your organization in?

+
+ {% 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%} +
+ + {{ block.super }} + +
+{% endblock %} diff --git a/src/registrar/templates/application_org_type.html b/src/registrar/templates/application_org_type.html new file mode 100644 index 000000000..de399e5c3 --- /dev/null +++ b/src/registrar/templates/application_org_type.html @@ -0,0 +1,31 @@ + +{% extends 'application_form.html' %} +{% load widget_tweaks %} +{% load dynamic_question_tags %} + +{% block form_content %} + +
+ {{ wizard.management_form }} + {% csrf_token %} + + {% radio_buttons_by_value wizard.form.organization_type as choices %} + +
+ +

What kind of government organization do you represent?

+
+ {{ 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" %} +
+ + {{ block.super }} + +
+{% endblock %} diff --git a/src/registrar/templates/application_organization.html b/src/registrar/templates/application_organization.html deleted file mode 100644 index f994a7d1e..000000000 --- a/src/registrar/templates/application_organization.html +++ /dev/null @@ -1,54 +0,0 @@ - -{% 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 %} -

About your organization

- -
- {{ wizard.management_form }} - {% csrf_token %} - - {% radio_buttons_by_value wizard.form.organization_type as choices %} - -
- -

What kind of government organization do you represent?

-
- {{ 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 %} -
- -
- -

Which federal branch does your organization belong to?

-
- - {{ wizard.form.federal_type|add_class:"usa-radio" }} -
- -
- -

Is your organization an election office?

-
- - {{ wizard.form.is_election_board|add_class:"usa-radio" }} -
- - - -
-{% endblock %} diff --git a/src/registrar/templates/application_other_contacts.html b/src/registrar/templates/application_other_contacts.html new file mode 100644 index 000000000..d40d4e1fd --- /dev/null +++ b/src/registrar/templates/application_other_contacts.html @@ -0,0 +1,50 @@ + +{% extends 'application_form.html' %} +{% load widget_tweaks %} +{% load static %} + +{% block form_content %} + +

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.

+

All fields are required unless they are marked optional.

+ +
+ {{ wizard.management_form }} + {% csrf_token %} + +
+ +

Contact 2

+
+ {{ 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" }} +
+ +
+ +
+ + {{ block.super }} + +
+ +{% endblock %} diff --git a/src/registrar/templates/application_purpose.html b/src/registrar/templates/application_purpose.html new file mode 100644 index 000000000..b890ae0e1 --- /dev/null +++ b/src/registrar/templates/application_purpose.html @@ -0,0 +1,25 @@ + +{% extends 'application_form.html' %} +{% load widget_tweaks %} + +{% block form_content %} + +

Describe your organization’s 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 activities that are prohibited on .gov domains.

+ +
+
+ {{ wizard.management_form }} + {% csrf_token %} + +
+ {{ 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" }} + You can enter up to 500 characters +
+
+ + {{ block.super }} + +
+ +{% endblock %} diff --git a/src/registrar/templates/application_requirements.html b/src/registrar/templates/application_requirements.html new file mode 100644 index 000000000..f5f41a877 --- /dev/null +++ b/src/registrar/templates/application_requirements.html @@ -0,0 +1,72 @@ + +{% extends 'application_form.html' %} +{% load widget_tweaks %} + +{% block form_content %} + +

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.

+ +

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.

+ +

Prohibited activities for .gov domains

+ +

Commercial purposes

+

A .gov domain must not be used for commercial purposes, such as advertising benefitting private individuals or entities.

+ +

Political campaigns

+

A .gov domain must not be used for political campaigns.

+ +

Illegal content

+

A .gov domain must not be used to distribute or promote material whose distribution violates applicable law.

+ +

Malicious cyber activity

+

.gov is a trusted and safe space. .gov domains must not distribute malware, host open redirects, or otherwise engage in malicious cyber activity.

+ + +

Required activities for .gov domain registrants

+ +

Keep your contact information update

+

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.

+ +

Be responsive if we contact you

+

Registrants should respond in a timely manner to communications about required and prohibited activities.

+ + +

Domains can be suspended or terminated for violations

+

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.

+

When we discover a violation, we will make reasonable efforts to contact a registrant, including: +

+

+ +

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.

+ + +

HSTS preloading

+

The .gov program will preload all newly registered .gov domains for HTTP Strict Transport Security (HSTS).

+

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.)

+

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.

+ + +

Acknowledgement of .gov domain requirements

+ +
+
+ {{ wizard.management_form }} + {% csrf_token %} + +
+ {{ wizard.form.agree_check|add_class:"usa-checkbox__input"}} + {{ wizard.form.agree_check|add_label_class:"usa-checkbox__label" }} +
+
+ + {{ block.super }} + +
+ +{% endblock %} diff --git a/src/registrar/templates/application_review.html b/src/registrar/templates/application_review.html new file mode 100644 index 000000000..c4ac67c6e --- /dev/null +++ b/src/registrar/templates/application_review.html @@ -0,0 +1,27 @@ + +{% extends 'application_form.html' %} +{% load static widget_tweaks %} + +{% block form_content %} + +
+ {{ wizard.management_form }} + {% csrf_token %} + + {% for this_step in wizard.steps.all|slice:":-1" %} +
+
+ {{ form_titles|get_item:this_step }} + Edit +
+
+ <Answer value> +
+
+ {% endfor %} + + {{ block.super }} + +
+ +{% endblock %} diff --git a/src/registrar/templates/application_security_email.html b/src/registrar/templates/application_security_email.html new file mode 100644 index 000000000..86410f489 --- /dev/null +++ b/src/registrar/templates/application_security_email.html @@ -0,0 +1,21 @@ + +{% extends 'application_form.html' %} +{% load widget_tweaks %} +{% load static %} + +{% block form_content %} + +

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. Security emails are made public. We recommend using an alias, like security@<domain.gov>.

+ +
+ {{ 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 }} + +
+ +{% endblock %} diff --git a/src/registrar/templates/application_sidebar.html b/src/registrar/templates/application_sidebar.html index be713bbe8..33e06812f 100644 --- a/src/registrar/templates/application_sidebar.html +++ b/src/registrar/templates/application_sidebar.html @@ -1,16 +1,21 @@ -
+{% load static %} +