From 9886367dd641e0296a2f397549878bdcfd559807 Mon Sep 17 00:00:00 2001 From: Seamus Johnston Date: Wed, 28 Dec 2022 10:19:34 -0600 Subject: [PATCH 1/4] Remove formtools Move the ApplicationWizard from under forms/ into views/ where each page of the application is now its own view. --- src/.flake8 | 1 + src/Pipfile | 1 - src/registrar/config/settings.py | 5 + src/registrar/config/urls.py | 60 ++- src/registrar/forms/__init__.py | 6 +- src/registrar/forms/application_wizard.py | 318 ++----------- src/registrar/models/domain_application.py | 26 +- .../templates/application_anything_else.html | 7 +- .../application_authorizing_official.html | 29 +- .../templates/application_current_sites.html | 7 +- src/registrar/templates/application_done.html | 6 +- .../templates/application_dotgov_domain.html | 13 +- src/registrar/templates/application_form.html | 12 +- .../templates/application_org_contact.html | 35 +- .../templates/application_org_election.html | 5 +- .../templates/application_org_federal.html | 5 +- .../templates/application_org_type.html | 7 +- .../templates/application_other_contacts.html | 27 +- .../templates/application_purpose.html | 9 +- .../templates/application_requirements.html | 7 +- .../templates/application_review.html | 35 +- .../templates/application_security_email.html | 7 +- .../templates/application_sidebar.html | 9 +- .../templates/application_your_contact.html | 27 +- src/registrar/templates/base.html | 8 +- src/registrar/templates/home.html | 2 +- src/registrar/templates/includes/footer.html | 2 +- src/registrar/templates/whoami.html | 2 +- src/registrar/templatetags/namespaced_urls.py | 10 + src/registrar/tests/test_views.py | 62 +-- src/registrar/utility/__init__.py | 1 + src/registrar/utility/str_enum.py | 43 ++ src/registrar/views/__init__.py | 5 + src/registrar/views/application.py | 421 ++++++++++++++++++ src/registrar/views/profile.py | 2 +- src/registrar/views/utility/__init__.py | 2 + src/registrar/views/utility/always_404.py | 6 + src/registrar/views/utility/steps_helper.py | 136 ++++++ 38 files changed, 876 insertions(+), 490 deletions(-) create mode 100644 src/registrar/templatetags/namespaced_urls.py create mode 100644 src/registrar/utility/__init__.py create mode 100644 src/registrar/utility/str_enum.py create mode 100644 src/registrar/views/application.py create mode 100644 src/registrar/views/utility/__init__.py create mode 100644 src/registrar/views/utility/always_404.py create mode 100644 src/registrar/views/utility/steps_helper.py diff --git a/src/.flake8 b/src/.flake8 index 8c4d4851a..e1ca2cc9a 100644 --- a/src/.flake8 +++ b/src/.flake8 @@ -2,5 +2,6 @@ max-line-length = 88 max-complexity = 10 extend-ignore = E203 +per-file-ignores = __init__.py:F401,F403 # migrations are auto-generated and often break rules exclude=registrar/migrations/* diff --git a/src/Pipfile b/src/Pipfile index 5e036feb9..10be9752e 100644 --- a/src/Pipfile +++ b/src/Pipfile @@ -17,7 +17,6 @@ oic = "*" pyjwkest = "*" psycopg2-binary = "*" whitenoise = "*" -django-formtools = "*" django-widget-tweaks = "*" cachetools = "*" requests = "*" diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py index 048dfb108..1869ecb58 100644 --- a/src/registrar/config/settings.py +++ b/src/registrar/config/settings.py @@ -364,11 +364,13 @@ LOGGING = { "django": { "handlers": ["console"], "level": "INFO", + "propagate": False, }, # Django's template processor "django.template": { "handlers": ["console"], "level": "INFO", + "propagate": False, }, # Django's runserver "django.server": { @@ -386,16 +388,19 @@ LOGGING = { "oic": { "handlers": ["console"], "level": "INFO", + "propagate": False, }, # Django wrapper for OpenID Connect "djangooidc": { "handlers": ["console"], "level": "INFO", + "propagate": False, }, # Our app! "registrar": { "handlers": ["console"], "level": "DEBUG", + "propagate": False, }, }, # root logger catches anything, unless diff --git a/src/registrar/config/urls.py b/src/registrar/config/urls.py index 3bebba5df..b5d1f638a 100644 --- a/src/registrar/config/urls.py +++ b/src/registrar/config/urls.py @@ -9,30 +9,62 @@ from django.contrib import admin 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, WIZARD_CONDITIONS +from registrar import views +from registrar.views.application import Step +from registrar.views.utility import always_404 from api.views import available -APPLICATION_URL_NAME = "application_step" -application_wizard = ApplicationWizard.as_view( - url_name=APPLICATION_URL_NAME, - done_step_name="finished", - condition_dict=WIZARD_CONDITIONS, +application_urls = ( + [ + path("", views.ApplicationWizard.as_view(), name=""), + # dynamically generate the other paths + *[ + path(f"{step}/", view.as_view(), name=step) + for step, view in [ + # add/remove steps here + (Step.ORGANIZATION_TYPE, views.OrganizationType), + (Step.ORGANIZATION_FEDERAL, views.OrganizationFederal), + (Step.ORGANIZATION_ELECTION, views.OrganizationElection), + (Step.ORGANIZATION_CONTACT, views.OrganizationContact), + (Step.AUTHORIZING_OFFICIAL, views.AuthorizingOfficial), + (Step.CURRENT_SITES, views.CurrentSites), + (Step.DOTGOV_DOMAIN, views.DotgovDomain), + (Step.PURPOSE, views.Purpose), + (Step.YOUR_CONTACT, views.YourContact), + (Step.OTHER_CONTACTS, views.OtherContacts), + (Step.SECURITY_EMAIL, views.SecurityEmail), + (Step.ANYTHING_ELSE, views.AnythingElse), + (Step.REQUIREMENTS, views.Requirements), + (Step.REVIEW, views.Review), + ] + ], + path("finished/", views.Finished.as_view(), name="finished"), + ], + views.ApplicationWizard.URL_NAMESPACE, ) urlpatterns = [ - path("", index.index, name="home"), - path("whoami/", whoami.whoami, name="whoami"), + path("", views.index, name="home"), + path("whoami/", views.whoami, name="whoami"), path("admin/", admin.site.urls), - path("application//edit/", application_wizard, name="edit-application"), - path("health/", health.health), - path("edit_profile/", profile.edit_profile, name="edit-profile"), + path( + "application//edit/", + views.ApplicationWizard.as_view(), + name=views.ApplicationWizard.EDIT_URL_NAME, + ), + path("health/", views.health), + path("edit_profile/", views.edit_profile, name="edit-profile"), path("openid/", include("djangooidc.urls")), - path("register/", application_wizard, name="application"), - path("register//", application_wizard, name=APPLICATION_URL_NAME), + path("register/", include(application_urls)), path("api/v1/available/", available, name="available"), + path( + "todo", + lambda r: always_404(r, "We forgot to include this link, sorry."), + name="todo", + ), ] + if not settings.DEBUG: urlpatterns += [ # redirect to login.gov diff --git a/src/registrar/forms/__init__.py b/src/registrar/forms/__init__.py index 806a2309c..954fff109 100644 --- a/src/registrar/forms/__init__.py +++ b/src/registrar/forms/__init__.py @@ -1,4 +1,2 @@ -from .edit_profile import EditProfileForm -from .application_wizard import ApplicationWizard, WIZARD_CONDITIONS - -__all__ = ["EditProfileForm", "ApplicationWizard", "WIZARD_CONDITIONS"] +from .edit_profile import * +from .application_wizard import * diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index a9e990b61..59af6821b 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -1,27 +1,22 @@ -"""Forms Wizard for creating a new domain application.""" - from __future__ import annotations # allows forward references in annotations - import logging -from typing import Union - from django import forms -from django.shortcuts import render -from django.contrib.auth.mixins import LoginRequiredMixin -from django.urls import resolve - -from formtools.wizard.views import NamedUrlSessionWizardView # type: ignore -from formtools.wizard.storage.session import SessionStorage # type: ignore from registrar.models import Contact, DomainApplication, Domain - logger = logging.getLogger(__name__) class RegistrarForm(forms.Form): - """Subclass used to remove the default colon suffix from all fields.""" + """ + A common set of methods and configuration. + + The registrar's domain application is several pages of "steps". + Each step is an HTML form containing one or more Django "forms". + + Subclass this class to create new forms. + """ def __init__(self, *args, **kwargs): kwargs.setdefault("label_suffix", "") @@ -39,10 +34,14 @@ class RegistrarForm(forms.Form): setattr(obj, name, value) obj.save() - def from_database(self, obj: DomainApplication | Contact): + @classmethod + def from_database(cls, obj: DomainApplication | Contact | None): """Initializes this form's fields with values gotten from `obj`.""" - for name in self.declared_fields.keys(): - self.initial[name] = getattr(obj, name) # type: ignore + if obj is None: + return {} + return { + name: getattr(obj, name) for name in cls.declared_fields.keys() + } # type: ignore class OrganizationTypeForm(RegistrarForm): @@ -112,11 +111,11 @@ class AuthorizingOfficialForm(RegistrarForm): obj.authorizing_official = contact obj.save() - def from_database(self, obj): + @classmethod + def from_database(cls, obj): """Initializes this form's fields with values gotten from `obj`.""" contact = getattr(obj, "authorizing_official", None) - if contact is not None: - super().from_database(contact) + return super().from_database(contact) first_name = forms.CharField(label="First name/given name") middle_name = forms.CharField( @@ -140,11 +139,14 @@ class CurrentSitesForm(RegistrarForm): # TODO: ability to update existing records obj.current_websites.create(website=normalized) - def from_database(self, obj): + @classmethod + def from_database(cls, obj): """Initializes this form's fields with values gotten from `obj`.""" current_website = obj.current_websites.first() if current_website is not None: - self.initial["current_site"] = current_website.website + return {"current_site": current_website.website} + else: + return {} current_site = forms.CharField( required=False, @@ -179,15 +181,19 @@ class DotGovDomainForm(RegistrarForm): # TODO: ability to update existing records obj.alternative_domains.create(website=normalized) - def from_database(self, obj): + @classmethod + def from_database(cls, obj): """Initializes this form's fields with values gotten from `obj`.""" + values = {} requested_domain = getattr(obj, "requested_domain", None) if requested_domain is not None: - self.initial["requested_domain"] = requested_domain.sld + values["requested_domain"] = requested_domain.sld alternative_domain = obj.alternative_domains.first() if alternative_domain is not None: - self.initial["alternative_domain"] = alternative_domain.sld + values["alternative_domain"] = alternative_domain.sld + + return values requested_domain = forms.CharField(label="What .gov domain do you want?") alternative_domain = forms.CharField( @@ -215,11 +221,11 @@ class YourContactForm(RegistrarForm): obj.submitter = contact obj.save() - def from_database(self, obj): + @classmethod + def from_database(cls, obj): """Initializes this form's fields with values gotten from `obj`.""" contact = getattr(obj, "submitter", None) - if contact is not None: - super().from_database(contact) + return super().from_database(contact) first_name = forms.CharField(label="First name/given name") middle_name = forms.CharField( @@ -248,11 +254,11 @@ class OtherContactsForm(RegistrarForm): super().to_database(contact) obj.other_contacts.add(contact) - def from_database(self, obj): + @classmethod + def from_database(cls, obj): """Initializes this form's fields with values gotten from `obj`.""" other_contacts = obj.other_contacts.first() - if other_contacts is not None: - super().from_database(other_contacts) + return super().from_database(other_contacts) first_name = forms.CharField(label="First name/given name") middle_name = forms.CharField( @@ -287,255 +293,3 @@ class RequirementsForm(RegistrarForm): "and operating .gov domains." ) ) - - -class ReviewForm(RegistrarForm): - """ - Empty class for the review page. - - It gets included as part of the form, but does not have any form fields itself. - """ - - def to_database(self, _): - """This form has no data. Do nothing.""" - pass - - pass - - -class Step: - """Names for each page of the application wizard.""" - - ORGANIZATION_TYPE = "organization_type" - ORGANIZATION_FEDERAL = "organization_federal" - ORGANIZATION_ELECTION = "organization_election" - ORGANIZATION_CONTACT = "organization_contact" - AUTHORIZING_OFFICIAL = "authorizing_official" - CURRENT_SITES = "current_sites" - DOTGOV_DOMAIN = "dotgov_domain" - PURPOSE = "purpose" - YOUR_CONTACT = "your_contact" - OTHER_CONTACTS = "other_contacts" - SECURITY_EMAIL = "security_email" - ANYTHING_ELSE = "anything_else" - REQUIREMENTS = "requirements" - REVIEW = "review" - - -# List of forms in our wizard. -# Each entry is a tuple of a name and a form subclass -FORMS = [ - (Step.ORGANIZATION_TYPE, OrganizationTypeForm), - (Step.ORGANIZATION_FEDERAL, OrganizationFederalForm), - (Step.ORGANIZATION_ELECTION, OrganizationElectionForm), - (Step.ORGANIZATION_CONTACT, OrganizationContactForm), - (Step.AUTHORIZING_OFFICIAL, AuthorizingOfficialForm), - (Step.CURRENT_SITES, CurrentSitesForm), - (Step.DOTGOV_DOMAIN, DotGovDomainForm), - (Step.PURPOSE, PurposeForm), - (Step.YOUR_CONTACT, YourContactForm), - (Step.OTHER_CONTACTS, OtherContactsForm), - (Step.SECURITY_EMAIL, SecurityEmailForm), - (Step.ANYTHING_ELSE, AnythingElseForm), - (Step.REQUIREMENTS, RequirementsForm), - (Step.REVIEW, ReviewForm), -] - -# Dict to match up the right template with the right step. -TEMPLATES = { - Step.ORGANIZATION_TYPE: "application_org_type.html", - Step.ORGANIZATION_FEDERAL: "application_org_federal.html", - Step.ORGANIZATION_ELECTION: "application_org_election.html", - Step.ORGANIZATION_CONTACT: "application_org_contact.html", - Step.AUTHORIZING_OFFICIAL: "application_authorizing_official.html", - Step.CURRENT_SITES: "application_current_sites.html", - Step.DOTGOV_DOMAIN: "application_dotgov_domain.html", - Step.PURPOSE: "application_purpose.html", - Step.YOUR_CONTACT: "application_your_contact.html", - Step.OTHER_CONTACTS: "application_other_contacts.html", - Step.SECURITY_EMAIL: "application_security_email.html", - Step.ANYTHING_ELSE: "application_anything_else.html", - Step.REQUIREMENTS: "application_requirements.html", - Step.REVIEW: "application_review.html", -} - -# We need to pass our page titles as context to the templates -TITLES = { - Step.ORGANIZATION_TYPE: "Type of organization", - Step.ORGANIZATION_FEDERAL: "Type of organization — Federal", - Step.ORGANIZATION_ELECTION: "Type of organization — Election board", - Step.ORGANIZATION_CONTACT: "Organization name and mailing address", - Step.AUTHORIZING_OFFICIAL: "Authorizing official", - Step.CURRENT_SITES: "Organization website", - Step.DOTGOV_DOMAIN: ".gov domain", - Step.PURPOSE: "Purpose of your domain", - Step.YOUR_CONTACT: "Your contact information", - Step.OTHER_CONTACTS: "Other contacts for your domain", - Step.SECURITY_EMAIL: "Security email for public use", - Step.ANYTHING_ELSE: "Anything else we should know?", - Step.REQUIREMENTS: "Requirements for registration and operation of .gov domains", - Step.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, -} - - -class TrackingStorage(SessionStorage): - - """Storage subclass that keeps track of what the current_step has been.""" - - def _set_current_step(self, step): - super()._set_current_step(step) - - step_history = self.extra_data.setdefault("step_history", []) - # can't serialize a set, so keep list entries unique - if step not in step_history: - step_history.append(step) - - -class ApplicationWizard(LoginRequiredMixin, NamedUrlSessionWizardView): - - """Multi-page form ("wizard") for new domain applications. - - This sets up a sequence of forms that gather information for new - domain applications. Each form in the sequence has its own URL and - the progress through the form is stored in the Django session (thus - "NamedUrlSessionWizardView"). - - Caution: due to the redirect performed by using NamedUrlSessionWizardView, - many methods, such as `process_step`, are called TWICE per request. For - this reason, methods in this class need to be idempotent. - """ - - form_list = FORMS - storage_name = "registrar.forms.application_wizard.TrackingStorage" - - def get_template_names(self): - """Template for the current step. - - The return is a singleton list. - """ - return [TEMPLATES[self.steps.current]] - - def _is_federal(self) -> Union[bool, None]: - """Return whether this application is from a federal agency. - - Returns True if we know that this application is from a federal - agency, False if we know that it is not and None if there isn't an - answer yet for that question. - """ - return self.get_application_object().is_federal() - - def get_context_data(self, form, **kwargs): - """Add title information to the context for all steps.""" - context = super().get_context_data(form=form, **kwargs) - context["form_titles"] = TITLES - - # Add information about which steps should be unlocked - # TODO: sometimes the first step doesn't get added to the step history - # so add it here - context["visited"] = self.storage.extra_data.get("step_history", []) + [ - self.steps.first - ] - - if self.steps.current == Step.ORGANIZATION_CONTACT: - context["is_federal"] = self._is_federal() - if self.steps.current == Step.REVIEW: - context["step_cls"] = Step - application = self.get_application_object() - context["application"] = application - return context - - def get_application_object(self) -> DomainApplication: - """ - Attempt to match the current wizard with a DomainApplication. - - Will create an application if none exists. - """ - if "application_id" in self.storage.extra_data: - id = self.storage.extra_data["application_id"] - try: - return DomainApplication.objects.get( - creator=self.request.user, - pk=id, - ) - except DomainApplication.DoesNotExist: - logger.debug("Application id %s did not have a DomainApplication" % id) - - application = DomainApplication.objects.create(creator=self.request.user) - self.storage.extra_data["application_id"] = application.id - return application - - def form_to_database(self, form: RegistrarForm) -> DomainApplication: - """ - Unpack the form responses onto the model object properties. - - Saves the application to the database. - """ - application = self.get_application_object() - - if form is not None and hasattr(form, "to_database"): - form.to_database(application) - - return application - - def process_step(self, form): - """ - Hook called on every POST request, if the form is valid. - - Do not manipulate the form data here. - """ - # save progress - self.form_to_database(form=form) - return self.get_form_step_data(form) - - def get_form(self, step=None, data=None, files=None): - """This method constructs the form for a given step.""" - form = super().get_form(step, data, files) - - # restore from database, but only if a record has already - # been associated with this wizard instance - if "application_id" in self.storage.extra_data: - application = self.get_application_object() - form.from_database(application) - return form - - def post(self, *args, **kwargs): - """This method handles POST requests.""" - step = self.steps.current - # always call super() first, to do important pre-processing - rendered = super().post(*args, **kwargs) - # if user opted to save their progress, - # return them to the page they were already on - button = self.request.POST.get("submit_button", None) - if button == "save": - return self.render_goto_step(step) - # otherwise, proceed as normal - return rendered - - def get(self, *args, **kwargs): - """This method handles GET requests.""" - current_url = resolve(self.request.path_info).url_name - # always call super(), it handles important redirect logic - rendered = super().get(*args, **kwargs) - # if user visited via an "edit" url, associate the id of the - # application they are trying to edit to this wizard instance - if current_url == "edit-application" and "id" in kwargs: - self.storage.extra_data["application_id"] = kwargs["id"] - return rendered - - def done(self, form_list, form_dict, **kwargs): - """Called when the data for every form is submitted and validated.""" - application = self.get_application_object() - application.submit() # change the status to submitted - application.save() - 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 4795d0195..ab59192ac 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -1,5 +1,5 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Union +from typing import Union from django.apps import apps from django.db import models @@ -7,9 +7,6 @@ from django_fsm import FSMField, transition # type: ignore from .utility.time_stamped_model import TimeStampedModel -if TYPE_CHECKING: - from ..forms.application_wizard import ApplicationWizard - class DomainApplication(TimeStampedModel): @@ -460,30 +457,17 @@ class DomainApplication(TimeStampedModel): # 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: + def show_organization_federal(self) -> bool: """Show this step if the answer to the first question was "federal".""" - user_choice = DomainApplication._get_organization_type(wizard) + user_choice = self.organization_type return user_choice == DomainApplication.OrganizationChoices.FEDERAL - @staticmethod - def show_organization_election(wizard: ApplicationWizard) -> bool: + def show_organization_election(self) -> bool: """Show this step if the answer to the first question implies it. This shows for answers that aren't "Federal" or "Interstate". """ - user_choice = DomainApplication._get_organization_type(wizard) + user_choice = self.organization_type excluded = [ DomainApplication.OrganizationChoices.FEDERAL, DomainApplication.OrganizationChoices.INTERSTATE, diff --git a/src/registrar/templates/application_anything_else.html b/src/registrar/templates/application_anything_else.html index 153d547e2..1394ea093 100644 --- a/src/registrar/templates/application_anything_else.html +++ b/src/registrar/templates/application_anything_else.html @@ -6,14 +6,13 @@

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" }} + {{ forms.0.anything_else|add_label_class:"usa-label usa-sr-only" }} + {{ forms.0.anything_else|add_class:"usa-textarea usa-character-count__field"|attr:"aria-describedby:instructions"|attr:"maxlength=500" }} You can enter up to 500 characters
diff --git a/src/registrar/templates/application_authorizing_official.html b/src/registrar/templates/application_authorizing_official.html index db499ea82..0f786c868 100644 --- a/src/registrar/templates/application_authorizing_official.html +++ b/src/registrar/templates/application_authorizing_official.html @@ -8,7 +8,7 @@

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

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.

@@ -20,31 +20,30 @@

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"}} + {{ forms.0.first_name|add_label_class:"usa-label" }} + {{ forms.0.first_name|add_class:"usa-input"}} - {{ wizard.form.middle_name|add_label_class:"usa-label" }} - {{ wizard.form.middle_name|add_class:"usa-input"}} + {{ forms.0.middle_name|add_label_class:"usa-label" }} + {{ forms.0.middle_name|add_class:"usa-input"}} - {{ wizard.form.last_name|add_label_class:"usa-label" }} - {{ wizard.form.last_name|add_class:"usa-input"}} + {{ forms.0.last_name|add_label_class:"usa-label" }} + {{ forms.0.last_name|add_class:"usa-input"}} - {{ wizard.form.title|add_label_class:"usa-label" }} - {{ wizard.form.title|add_class:"usa-input"}} + {{ forms.0.title|add_label_class:"usa-label" }} + {{ forms.0.title|add_class:"usa-input"}} - {{ wizard.form.email|add_label_class:"usa-label" }} - {{ wizard.form.email|add_class:"usa-input"}} + {{ forms.0.email|add_label_class:"usa-label" }} + {{ forms.0.email|add_class:"usa-input"}} - {{ wizard.form.phone|add_label_class:"usa-label" }} - {{ wizard.form.phone|add_class:"usa-input usa-input--medium" }} + {{ forms.0.phone|add_label_class:"usa-label" }} + {{ forms.0.phone|add_class:"usa-input usa-input--medium" }}
diff --git a/src/registrar/templates/application_current_sites.html b/src/registrar/templates/application_current_sites.html index 535a8f5dc..9777d7695 100644 --- a/src/registrar/templates/application_current_sites.html +++ b/src/registrar/templates/application_current_sites.html @@ -5,12 +5,11 @@ {% 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" }} + {{ forms.0.current_site|add_label_class:"usa-label" }} + {{ forms.0.current_site|add_class:"usa-input" }} {{ block.super }} diff --git a/src/registrar/templates/application_done.html b/src/registrar/templates/application_done.html index 267a39ca6..70758baa6 100644 --- a/src/registrar/templates/application_done.html +++ b/src/registrar/templates/application_done.html @@ -19,7 +19,7 @@ your authorizing official, and any contacts you added.

meets our naming requirements. -
  • You can check the +
  • You can check the status of your request at any time.
  • @@ -32,9 +32,9 @@ your authorizing official, and any contacts you added.

    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. +manage your domains page.

    -

    Enter DNS name servers

    +

    Enter DNS name servers

    {% endblock %} diff --git a/src/registrar/templates/application_dotgov_domain.html b/src/registrar/templates/application_dotgov_domain.html index f1d64da17..ac7f6065c 100644 --- a/src/registrar/templates/application_dotgov_domain.html +++ b/src/registrar/templates/application_dotgov_domain.html @@ -3,7 +3,7 @@ {% load widget_tweaks static%} {% block form_content %} -

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

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

    • Be available
    • Be unique
    • @@ -21,16 +21,15 @@ {% 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 this form.

    - {{ wizard.management_form }} {% csrf_token %} - {{ wizard.form.requested_domain|add_label_class:"usa-label" }} + {{ forms.0.requested_domain|add_label_class:"usa-label" }}
    www. - {{ wizard.form.requested_domain|add_class:"usa-input"|attr:"aria-describedby:domain_instructions" }} + {{ forms.0.requested_domain|add_class:"usa-input"|attr:"aria-describedby:domain_instructions" }} .gov
    @@ -38,10 +37,10 @@

    Alternative domains

    - {{ wizard.form.alternative_domain|add_label_class:"usa-label" }} + {{ forms.0.alternative_domain|add_label_class:"usa-label" }}
    www. - {{ wizard.form.alternative_domain|add_class:"usa-input" }} + {{ forms.0.alternative_domain|add_class:"usa-input" }} .gov
    diff --git a/src/registrar/templates/application_form.html b/src/registrar/templates/application_form.html index 8eb57cdc7..e1e4dfa2b 100644 --- a/src/registrar/templates/application_form.html +++ b/src/registrar/templates/application_form.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} -{% load static widget_tweaks %} +{% load static widget_tweaks namespaced_urls %} -{% block title %}Apply for a .gov domain – {{form_titles|get_item:wizard.steps.current}}{% endblock %} +{% block title %}Apply for a .gov domain – {{form_titles|get_item:steps.current}}{% endblock %} {% block content %}
    @@ -10,17 +10,17 @@
    - {% if wizard.steps.prev %} - + {% if steps.prev %} + Previous step {% endif %} -

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

    +

    {{form_titles|get_item:steps.current}}

    {% block form_content %}
    - {% if wizard.steps.next %} + {% if steps.next %}
    - - {{ wizard.management_form }} + {% csrf_token %}
    What is the name and mailing address of your organization? {% if is_federal %} - {{ wizard.form.federal_agency|add_label_class:"usa-label" }} - {{ wizard.form.federal_agency|add_class:"usa-select" }} + {{ forms.0.federal_agency|add_label_class:"usa-label" }} + {{ forms.0.federal_agency|add_class:"usa-select" }} {% endif %} - {{ 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.city|add_label_class:"usa-label" }} - {{ wizard.form.city|add_class:"usa-input" }} - {{ wizard.form.state_territory|add_label_class:"usa-label" }} - {{ wizard.form.state_territory|add_class:"usa-select" }} - {{ wizard.form.zipcode|add_label_class:"usa-label" }} - {{ wizard.form.zipcode|add_class:"usa-input usa-input--small" }} - {{ wizard.form.urbanization|add_label_class:"usa-label" }} - {{ wizard.form.urbanization|add_class:"usa-input usa-input--small" }} + {{ forms.0.organization_name|add_label_class:"usa-label" }} + {{ forms.0.organization_name|add_class:"usa-input" }} + {{ forms.0.address_line1|add_label_class:"usa-label" }} + {{ forms.0.address_line1|add_class:"usa-input" }} + {{ forms.0.address_line2|add_label_class:"usa-label" }} + {{ forms.0.address_line2|add_class:"usa-input" }} + {{ forms.0.city|add_label_class:"usa-label" }} + {{ forms.0.city|add_class:"usa-input" }} + {{ forms.0.state_territory|add_label_class:"usa-label" }} + {{ forms.0.state_territory|add_class:"usa-select" }} + {{ forms.0.zipcode|add_label_class:"usa-label" }} + {{ forms.0.zipcode|add_class:"usa-input usa-input--small" }} + {{ forms.0.urbanization|add_label_class:"usa-label" }} + {{ forms.0.urbanization|add_class:"usa-input usa-input--small" }}
    diff --git a/src/registrar/templates/application_org_election.html b/src/registrar/templates/application_org_election.html index 877bdb81b..0a9f5b452 100644 --- a/src/registrar/templates/application_org_election.html +++ b/src/registrar/templates/application_org_election.html @@ -5,14 +5,13 @@ {% 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 %} + {% radio_buttons_by_value forms.0.is_election_board as choices %} {% for choice in choices.values %} {% include "includes/radio_button.html" with choice=choice tile="true" %} {% endfor %} diff --git a/src/registrar/templates/application_org_federal.html b/src/registrar/templates/application_org_federal.html index b4da3b2f0..29bed3fd2 100644 --- a/src/registrar/templates/application_org_federal.html +++ b/src/registrar/templates/application_org_federal.html @@ -5,14 +5,13 @@ {% block form_content %} - - {{ wizard.management_form }} + {% csrf_token %}

    Which federal branch is your organization in?

    - {% radio_buttons_by_value wizard.form.federal_type as choices %} + {% radio_buttons_by_value forms.0.federal_type as choices %} {% for choice in choices.values %} {% include "includes/radio_button.html" with choice=choice tile="true" %} {% endfor %} diff --git a/src/registrar/templates/application_org_type.html b/src/registrar/templates/application_org_type.html index 3c2b19a25..4f5632fda 100644 --- a/src/registrar/templates/application_org_type.html +++ b/src/registrar/templates/application_org_type.html @@ -5,17 +5,16 @@ {% block form_content %} - - {{ wizard.management_form }} + {% csrf_token %} - {% radio_buttons_by_value wizard.form.organization_type as choices %} + {% radio_buttons_by_value forms.0.organization_type as choices %}

    What kind of U.S.-based government organization do you represent?

    - {{ wizard.form.organization_type.errors }} + {{ forms.0.organization_type.errors }} {% for choice in choices.values %} {% include "includes/radio_button.html" with choice=choice tile="true" %} {% endfor %} diff --git a/src/registrar/templates/application_other_contacts.html b/src/registrar/templates/application_other_contacts.html index be79d6edc..10efd480b 100644 --- a/src/registrar/templates/application_other_contacts.html +++ b/src/registrar/templates/application_other_contacts.html @@ -8,31 +8,30 @@

    We’d 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.

    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" }} + {{ forms.0.first_name|add_label_class:"usa-label" }} + {{ forms.0.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" }} + {{ forms.0.middle_name|add_label_class:"usa-label" }} + {{ forms.0.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" }} + {{ forms.0.last_name|add_label_class:"usa-label" }} + {{ forms.0.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" }} + {{ forms.0.title|add_label_class:"usa-label" }} + {{ forms.0.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" }} + {{ forms.0.email|add_label_class:"usa-label" }} + {{ forms.0.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" }} + {{ forms.0.phone|add_label_class:"usa-label" }} + {{ forms.0.phone|add_class:"usa-input usa-input--medium"|attr:"aria-describedby:instructions" }}
    diff --git a/src/registrar/templates/application_purpose.html b/src/registrar/templates/application_purpose.html index ce0563036..0812534fe 100644 --- a/src/registrar/templates/application_purpose.html +++ b/src/registrar/templates/application_purpose.html @@ -6,16 +6,15 @@

    .Gov domain names are intended for use on the internet. They should be registered with an intent to deploy services, not simply to reserve a name. .Gov domains should not be registered for primarily internal use.

    -

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

    +

    Describe 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|add_label_class:"usa-label usa-sr-only" }} - {{ wizard.form.purpose|add_class:"usa-textarea usa-character-count__field"|attr:"aria-describedby:instructions"|attr:"maxlength=500" }} + {{ forms.0.purpose|add_label_class:"usa-label usa-sr-only" }} + {{ forms.0.purpose|add_class:"usa-textarea usa-character-count__field"|attr:"aria-describedby:instructions"|attr:"maxlength=500" }} You can enter up to 500 characters
    diff --git a/src/registrar/templates/application_requirements.html b/src/registrar/templates/application_requirements.html index e012f5b2c..f0e995851 100644 --- a/src/registrar/templates/application_requirements.html +++ b/src/registrar/templates/application_requirements.html @@ -127,14 +127,13 @@

    Acknowledgement of .gov domain requirements

    - +
    - {{ wizard.management_form }} {% csrf_token %}
    - {{ wizard.form.is_policy_acknowledged|add_class:"usa-checkbox__input"}} - {{ wizard.form.is_policy_acknowledged|add_label_class:"usa-checkbox__label" }} + {{ forms.0.is_policy_acknowledged|add_class:"usa-checkbox__input"}} + {{ forms.0.is_policy_acknowledged|add_label_class:"usa-checkbox__label" }}
    diff --git a/src/registrar/templates/application_review.html b/src/registrar/templates/application_review.html index 44dd6975c..5b3ce7e3b 100644 --- a/src/registrar/templates/application_review.html +++ b/src/registrar/templates/application_review.html @@ -1,44 +1,43 @@ {% extends 'application_form.html' %} -{% load static widget_tweaks %} +{% load static widget_tweaks namespaced_urls %} {% block form_content %} - - {{ wizard.management_form }} + {% csrf_token %} - {% for step in wizard.steps.all|slice:":-1" %} + {% for step in steps.all|slice:":-1" %}

    {{ form_titles|get_item:step }}
    - {% if step == step_cls.ORGANIZATION_TYPE %} + {% if step == Step.ORGANIZATION_TYPE %} {{ application.get_organization_type_display|default:"Incomplete" }} {% endif %} - {% if step == step_cls.ORGANIZATION_FEDERAL %} + {% if step == Step.ORGANIZATION_FEDERAL %} {{ application.get_federal_type_display|default:"Incomplete" }} {% endif %} - {% if step == step_cls.ORGANIZATION_ELECTION %} + {% if step == Step.ORGANIZATION_ELECTION %} {{ application.is_election_board|yesno:"Yes,No,Incomplete" }} {% endif %} - {% if step == step_cls.ORGANIZATION_CONTACT %} + {% if step == Step.ORGANIZATION_CONTACT %} {% if application.organization_name %} {% include "includes/organization_address.html" with organization=application %} {% else %} Incomplete {% endif %} {% endif %} - {% if step == step_cls.AUTHORIZING_OFFICIAL %} + {% if step == Step.AUTHORIZING_OFFICIAL %} {% if application.authorizing_official %} {% include "includes/contact.html" with contact=application.authorizing_official %} {% else %} Incomplete {% endif %} {% endif %} - {% if step == step_cls.CURRENT_SITES %} + {% if step == Step.CURRENT_SITES %}
      {% for site in application.current_websites.all %}
    • {{ site.website }}
    • @@ -47,7 +46,7 @@ {% endfor %}
    {% endif %} - {% if step == step_cls.DOTGOV_DOMAIN %} + {% if step == Step.DOTGOV_DOMAIN %}
    • {{ application.requested_domain.name|default:"Incomplete" }}
    • {% for site in application.alternative_domains.all %} @@ -55,37 +54,37 @@ {% endfor %}
    {% endif %} - {% if step == step_cls.PURPOSE %} + {% if step == Step.PURPOSE %} {{ application.purpose|default:"Incomplete" }} {% endif %} - {% if step == step_cls.YOUR_CONTACT %} + {% if step == Step.YOUR_CONTACT %} {% if application.submitter %} {% include "includes/contact.html" with contact=application.submitter %} {% else %} Incomplete {% endif %} {% endif %} - {% if step == step_cls.OTHER_CONTACTS %} + {% if step == Step.OTHER_CONTACTS %} {% for other in application.other_contacts.all %} {% include "includes/contact.html" with contact=other %} {% empty %} None {% endfor %} {% endif %} - {% if step == step_cls.SECURITY_EMAIL %} + {% if step == Step.SECURITY_EMAIL %} {{ application.security_email|default:"None" }} {% endif %} - {% if step == step_cls.ANYTHING_ELSE %} + {% if step == Step.ANYTHING_ELSE %} {{ application.anything_else|default:"No" }} {% endif %} - {% if step == step_cls.REQUIREMENTS %} + {% if step == Step.REQUIREMENTS %} {{ application.is_policy_acknowledged|yesno:"Agree,Do not agree,Do not agree" }} {% endif %}
    Edit {{ form_titles|get_item:step }}
    diff --git a/src/registrar/templates/application_security_email.html b/src/registrar/templates/application_security_email.html index 540952a63..1d0b6f640 100644 --- a/src/registrar/templates/application_security_email.html +++ b/src/registrar/templates/application_security_email.html @@ -7,12 +7,11 @@

    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.security_email|add_label_class:"usa-label" }} - {{ wizard.form.security_email|add_class:"usa-input"|attr:"aria-describedby:instructions" }} + {{ forms.0.security_email|add_label_class:"usa-label" }} + {{ forms.0.security_email|add_class:"usa-input"|attr:"aria-describedby:instructions" }} {{ block.super }} diff --git a/src/registrar/templates/application_sidebar.html b/src/registrar/templates/application_sidebar.html index be4f86509..4224a3f6b 100644 --- a/src/registrar/templates/application_sidebar.html +++ b/src/registrar/templates/application_sidebar.html @@ -1,12 +1,13 @@ -{% load static %} +{% load static namespaced_urls %} +