tests and requirements form

This commit is contained in:
matthewswspence 2025-03-11 14:15:50 -05:00
parent 10d3225cc0
commit 2644839e9a
No known key found for this signature in database
GPG key ID: FB458202A7852BA4
7 changed files with 191 additions and 127 deletions

View file

@ -885,6 +885,28 @@ class CisaRepresentativeYesNoForm(BaseYesNoForm):
field_name = "has_cisa_representative"
class PurposeDetailsForm(BaseDeletableRegistrarForm):
field_name = "purpose"
purpose = forms.CharField(
label="Purpose",
widget=forms.Textarea(
attrs={
"aria-label": "What is the purpose of your requested domain? Describe how youll use your .gov domain. \
Will it be used for a website, email, or something else?"
}
),
validators=[
MaxLengthValidator(
2000,
message="Response must be less than 2000 characters.",
)
],
error_messages={"required": "Describe how youll use the .gov domain youre requesting."},
)
class AnythingElseForm(BaseDeletableRegistrarForm):
anything_else = forms.CharField(
required=True,
@ -934,6 +956,7 @@ class AnythingElseYesNoForm(BaseYesNoForm):
class RequirementsForm(RegistrarForm):
is_policy_acknowledged = forms.BooleanField(
label="I read and agree to the requirements for operating a .gov domain.",
error_messages={

View file

@ -1,85 +0,0 @@
from django import forms
from django.core.validators import MaxLengthValidator
from registrar.forms.utility.wizard_form_helper import BaseDeletableRegistrarForm, BaseYesNoForm
from registrar.models.contact import Contact
class WorkingWithEOPYesNoForm(BaseDeletableRegistrarForm, BaseYesNoForm):
"""
Form for determining if the Federal Executive Branch (FEB) agency is working with the
Executive Office of the President (EOP) on the domain request.
"""
field_name = "working_with_eop"
@property
def form_is_checked(self):
"""
Determines the initial checked state of the form based on the domain_request's attributes.
"""
return self.domain_request.working_with_eop
class EOPContactForm(BaseDeletableRegistrarForm):
"""
Form for contact information of the representative of the
Executive Office of the President (EOP) that the Federal
Executive Branch (FEB) agency is working with.
"""
field_name = "eop_contact"
first_name = forms.CharField(
label="First name / given name",
error_messages={"required": "Enter the first name / given name of this contact."},
required=True,
)
last_name = forms.CharField(
label="Last name / family name",
error_messages={"required": "Enter the last name / family name of this contact."},
required=True,
)
email = forms.EmailField(
label="Email",
max_length=None,
error_messages={
"required": ("Enter an email address in the required format, like name@example.com."),
"invalid": ("Enter an email address in the required format, like name@example.com."),
},
validators=[
MaxLengthValidator(
320,
message="Response must be less than 320 characters.",
)
],
required=True,
help_text="Enter an email address in the required format, like name@example.com.",
)
@classmethod
def from_database(cls, obj):
# if not obj.eop_contact:
# return {}
# return {
# "first_name": obj.feb_eop_contact.first_name,
# "last_name": obj.feb_eop_contact.last_name,
# "email": obj.feb_eop_contact.email,
# }
return {}
def to_database(self, obj):
if not self.is_valid():
return
obj.eop_contact = Contact.objects.create(
first_name=self.cleaned_data["first_name"],
last_name=self.cleaned_data["last_name"],
email=self.cleaned_data["email"],
)
obj.save()
class FEBAnythingElseYesNoForm(BaseYesNoForm, BaseDeletableRegistrarForm):
"""Yes/no toggle for the anything else question on additional details"""
form_is_checked = property(lambda self: self.domain_request.has_anything_else_text) # type: ignore
field_name = "has_anything_else_text"

View file

@ -1,7 +1,7 @@
from django import forms
from django.core.validators import MaxLengthValidator
from registrar.forms.utility.wizard_form_helper import BaseDeletableRegistrarForm, BaseYesNoForm
from registrar.models.contact import Contact
class FEBPurposeOptionsForm(BaseDeletableRegistrarForm):
@ -24,28 +24,6 @@ class FEBPurposeOptionsForm(BaseDeletableRegistrarForm):
)
class PurposeDetailsForm(BaseDeletableRegistrarForm):
field_name = "purpose"
purpose = forms.CharField(
label="Purpose",
widget=forms.Textarea(
attrs={
"aria-label": "What is the purpose of your requested domain? Describe how youll use your .gov domain. \
Will it be used for a website, email, or something else?"
}
),
validators=[
MaxLengthValidator(
2000,
message="Response must be less than 2000 characters.",
)
],
error_messages={"required": "Describe how youll use the .gov domain youre requesting."},
)
class FEBTimeFrameYesNoForm(BaseDeletableRegistrarForm, BaseYesNoForm):
"""
Form for determining whether the domain request comes with a target timeframe for launch.
@ -109,3 +87,84 @@ class FEBInteragencyInitiativeDetailsForm(BaseDeletableRegistrarForm):
],
error_messages={"required": "Name the agencies that will be involved in this initiative."},
)
class WorkingWithEOPYesNoForm(BaseDeletableRegistrarForm, BaseYesNoForm):
"""
Form for determining if the Federal Executive Branch (FEB) agency is working with the
Executive Office of the President (EOP) on the domain request.
"""
field_name = "working_with_eop"
@property
def form_is_checked(self):
"""
Determines the initial checked state of the form based on the domain_request's attributes.
"""
return self.domain_request.working_with_eop
class EOPContactForm(BaseDeletableRegistrarForm):
"""
Form for contact information of the representative of the
Executive Office of the President (EOP) that the Federal
Executive Branch (FEB) agency is working with.
"""
field_name = "eop_contact"
first_name = forms.CharField(
label="First name / given name",
error_messages={"required": "Enter the first name / given name of this contact."},
required=True,
)
last_name = forms.CharField(
label="Last name / family name",
error_messages={"required": "Enter the last name / family name of this contact."},
required=True,
)
email = forms.EmailField(
label="Email",
max_length=None,
error_messages={
"required": ("Enter an email address in the required format, like name@example.com."),
"invalid": ("Enter an email address in the required format, like name@example.com."),
},
validators=[
MaxLengthValidator(
320,
message="Response must be less than 320 characters.",
)
],
required=True,
help_text="Enter an email address in the required format, like name@example.com.",
)
@classmethod
def from_database(cls, obj):
# if not obj.eop_contact:
# return {}
# return {
# "first_name": obj.feb_eop_contact.first_name,
# "last_name": obj.feb_eop_contact.last_name,
# "email": obj.feb_eop_contact.email,
# }
return {}
def to_database(self, obj):
if not self.is_valid():
return
obj.eop_contact = Contact.objects.create(
first_name=self.cleaned_data["first_name"],
last_name=self.cleaned_data["last_name"],
email=self.cleaned_data["email"],
)
obj.save()
class FEBAnythingElseYesNoForm(BaseYesNoForm, BaseDeletableRegistrarForm):
"""Yes/no toggle for the anything else question on additional details"""
form_is_checked = property(lambda self: self.domain_request.has_anything_else_text) # type: ignore
field_name = "has_anything_else_text"

View file

@ -1,4 +1,4 @@
# Generated by Django 4.2.17 on 2025-03-05 15:48
# Generated by Django 4.2.17 on 2025-03-11 18:10
from django.db import migrations, models
import django.db.models.deletion
@ -7,7 +7,7 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("registrar", "0142_domainrequest_feb_purpose_choice_and_more"),
("registrar", "0141_domainrequest_feb_naming_requirements_and_more"),
]
operations = [

View file

@ -2,6 +2,10 @@
{% load field_helpers %}
{% load url_helpers %}
{% block form_required_fields_help_text %}
{# commented out so it does not appear on this page #}
{% endblock %}
{% block form_instructions %}
<p>Please read this page. Check the box at the bottom to show that you agree to the requirements for operating a .gov domain.</p>
<p>The .gov domain space exists to support a broad diversity of government missions. Generally, we dont review or audit how government organizations use their registered domains. However, misuse of a .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>
@ -53,19 +57,34 @@
<p>Though a domain may expire, it will not automatically be put on hold or deleted. Well make extensive efforts to contact your organization before holding or deleting a domain.</p>
{% endblock %}
{% if requires_feb_questions %}
<h2>Required and prohibited activities</h2>
<h3>Prohibitions on non-governmental use</h3>
{% block form_required_fields_help_text %}
{# commented out so it does not appear on this page #}
{% endblock %}
<p>Agencies may not use a .gov domain name:
<ul class="usa-list">
<li>On behalf of a non-federal executive branch entity</li>
<li>For a non-governmental purpose</li>
</ul>
</p>
{% block form_fields %}
<h3>Compliance with the 21st Century IDEA Act is required</h3>
<p>As required by the DOTGOV Act, agencies must ensure
that any website or digital service that uses a .gov
domain name is in compliance with the
<a href="https://digital.gov/resources/delivering-digital-first-public-experience-act/" target="_blank" rel="noopener noreferrer">21st Century Integrated Digital Experience Act</a>.
and
<a href="https://bidenwhitehouse.gov/wp-content/uploads/2023/09/M-23-22-Delivering-a-Digital-First-Public-Experience.pdf" target="_blank" rel="noopener noreferrer">Guidance for Agencies</a>.
</p>
<h2>Acknowledgement of .gov domain requirements</h2>
{% input_with_errors forms.0.is_policy_acknowledged %}
{% else %}
<fieldset class="usa-fieldset">
<legend>
<h2>Acknowledgement of .gov domain requirements</h2>
</legend>
{% input_with_errors forms.0.is_policy_acknowledged %}
</fieldset>
{% endif %}
{% endblock %}

View file

@ -2644,6 +2644,21 @@ class DomainRequestTests(TestWithUser, WebTest):
additional_details_page = purpose_result.follow()
self.feb_additional_details_page_tests(additional_details_page)
additional_details_form = additional_details_page.forms[0]
additional_details_form["portfolio_additional_details-working_with_eop"] = "True"
additional_details_form["portfolio_additional_details-first_name"] = "Testy"
additional_details_form["portfolio_additional_details-last_name"] = "Tester"
additional_details_form["portfolio_additional_details-email"] = "testy@town.com"
additional_details_form["portfolio_additional_details-has_anything_else_text"] = "True"
additional_details_form["portfolio_additional_details-anything_else"] = "test"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
additional_details_result = additional_details_form.submit()
# ---- REQUIREMENTS PAGE ----
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
requirements_page = additional_details_result.follow()
self.feb_requirements_page_tests(requirements_page)
def feb_purpose_page_tests(self, purpose_page):
self.assertContains(purpose_page, "What is the purpose of your requested domain?")
@ -2701,6 +2716,15 @@ class DomainRequestTests(TestWithUser, WebTest):
self.assertContains(additional_details_page, "additional_details-has_anything_else_text")
self.assertContains(additional_details_page, "additional_details-anything_else")
def feb_requirements_page_tests(self, requirements_page):
# Check for the 21st Century IDEA Act links
self.assertContains(requirements_page, "https://digital.gov/resources/delivering-digital-first-public-experience-act/")
self.assertContains(requirements_page, "https://bidenwhitehouse.gov/wp-content/uploads/2023/09/M-23-22-Delivering-a-Digital-First-Public-Experience.pdf")
# Check for the policy acknowledgement form
self.assertContains(requirements_page, "is_policy_acknowledged")
self.assertContains(requirements_page, "I read and understand the guidance outlined in the DOTGOV Act for operating a .gov domain.")
@less_console_noise_decorator
def test_domain_request_formsets(self):
"""Users are able to add more than one of some fields."""

View file

@ -15,7 +15,7 @@ from registrar.decorators import (
grant_access,
)
from registrar.forms import domain_request_wizard as forms
from registrar.forms.domainrequestwizard import (purpose, additional_details)
from registrar.forms import feb
from registrar.forms.utility.wizard_form_helper import request_step_list
from registrar.models import DomainRequest
from registrar.models.contact import Contact
@ -183,7 +183,9 @@ class DomainRequestWizard(TemplateView):
return PortfolioDomainRequestStep if self.is_portfolio else Step
def requires_feb_questions(self) -> bool:
return self.domain_request.is_feb() and flag_is_active_for_user(self.request.user, "organization_feature")
# TODO: remove this
return True
# return self.domain_request.is_feb() and flag_is_active_for_user(self.request.user, "organization_feature")
@property
def prefix(self):
@ -606,9 +608,9 @@ class PortfolioAdditionalDetails(DomainRequestWizard):
template_name = "portfolio_domain_request_additional_details.html"
forms = [
additional_details.WorkingWithEOPYesNoForm,
additional_details.EOPContactForm,
additional_details.FEBAnythingElseYesNoForm,
feb.WorkingWithEOPYesNoForm,
feb.EOPContactForm,
feb.FEBAnythingElseYesNoForm,
forms.PortfolioAnythingElseForm,
]
@ -642,6 +644,8 @@ class PortfolioAdditionalDetails(DomainRequestWizard):
anything_else_forms_valid = False
if forms[2].cleaned_data.get("has_anything_else_text"):
forms[3].fields["anything_else"].required = True
forms[3].fields["anything_else"].error_messages["required"] = "Please provide additional details you'd like us to know. \
If you have nothing to add, select 'No'."
anything_else_forms_valid = forms[3].is_valid()
return (eop_forms_valid and anything_else_forms_valid)
@ -745,12 +749,12 @@ class Purpose(DomainRequestWizard):
template_name = "domain_request_purpose.html"
forms = [
purpose.FEBPurposeOptionsForm,
purpose.PurposeDetailsForm,
purpose.FEBTimeFrameYesNoForm,
purpose.FEBTimeFrameDetailsForm,
purpose.FEBInteragencyInitiativeYesNoForm,
purpose.FEBInteragencyInitiativeDetailsForm,
feb.FEBPurposeOptionsForm,
forms.PurposeDetailsForm,
feb.FEBTimeFrameYesNoForm,
feb.FEBTimeFrameDetailsForm,
feb.FEBInteragencyInitiativeYesNoForm,
feb.FEBInteragencyInitiativeDetailsForm,
]
def get_context_data(self):
@ -927,6 +931,25 @@ class Requirements(DomainRequestWizard):
template_name = "domain_request_requirements.html"
forms = [forms.RequirementsForm]
def get_context_data(self):
context = super().get_context_data()
context["requires_feb_questions"] = self.requires_feb_questions()
return context
# Override the get_forms method to set the policy acknowledgement label conditionally based on feb status
def get_forms(self, step=None, use_post=False, use_db=False, files=None):
forms_list = super().get_forms(step, use_post, use_db, files)
# Pass the is_federal context to the form
for form in forms_list:
if isinstance(form, forms.RequirementsForm):
if self.requires_feb_questions():
form.fields['is_policy_acknowledged'].label = "I read and understand the guidance outlined in the DOTGOV Act for operating a .gov domain." # noqa: E501
else:
form.fields['is_policy_acknowledged'].label = "I read and agree to the requirements for operating a .gov domain." # noqa: E501
return forms_list
class Review(DomainRequestWizard):
template_name = "domain_request_review.html"
@ -939,6 +962,7 @@ class Review(DomainRequestWizard):
context = super().get_context_data()
context["Step"] = self.get_step_enum().__members__
context["domain_request"] = self.domain_request
context["requires_feb_questions"] = self.requires_feb_questions()
return context
def goto_next_step(self):