mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-29 05:56:30 +02:00
correct form validation and dynamic elements
This commit is contained in:
parent
190bca2cac
commit
065febd496
4 changed files with 32 additions and 83 deletions
|
@ -607,7 +607,8 @@ class DotGovDomainForm(RegistrarForm):
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
class ExecutiveNamingRequirementsYesNoForm(BaseYesNoForm):
|
|
||||||
|
class ExecutiveNamingRequirementsYesNoForm(BaseYesNoForm, BaseDeletableRegistrarForm):
|
||||||
"""
|
"""
|
||||||
Form for verifying if the domain request meets the Federal Executive Branch domain naming requirements.
|
Form for verifying if the domain request meets the Federal Executive Branch domain naming requirements.
|
||||||
If the "no" option is selected, details must be provided via the separate details form.
|
If the "no" option is selected, details must be provided via the separate details form.
|
||||||
|
@ -621,77 +622,25 @@ class ExecutiveNamingRequirementsYesNoForm(BaseYesNoForm):
|
||||||
Determines the initial checked state of the form based on the domain_request's attributes.
|
Determines the initial checked state of the form based on the domain_request's attributes.
|
||||||
"""
|
"""
|
||||||
return self.domain_request.feb_naming_requirements
|
return self.domain_request.feb_naming_requirements
|
||||||
|
|
||||||
def clean(self):
|
|
||||||
# Skip validation if this form is not applicable.
|
|
||||||
if not (self.domain_request.is_federal() and self.domain_request.federal_type == "Executive"):
|
|
||||||
# Initialize cleaned_data if it doesn't exist
|
|
||||||
if not hasattr(self, 'cleaned_data'):
|
|
||||||
self.cleaned_data = {}
|
|
||||||
# If not executive, default to None
|
|
||||||
self.cleaned_data["feb_naming_requirements"] = None
|
|
||||||
return self.cleaned_data
|
|
||||||
|
|
||||||
# Only validate the yes/no field here; details are handled by the separate details form.
|
|
||||||
cleaned = super().clean()
|
|
||||||
return cleaned
|
|
||||||
|
|
||||||
def to_database(self, obj: DomainRequest):
|
|
||||||
"""
|
|
||||||
Saves the cleaned data from this form to the DomainRequest object.
|
|
||||||
"""
|
|
||||||
if not self.is_valid():
|
|
||||||
return
|
|
||||||
obj.feb_naming_requirements = (self.cleaned_data.get("feb_naming_requirements", None) == "yes")
|
|
||||||
obj.save()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_database(cls, obj):
|
|
||||||
"""
|
|
||||||
Retrieves initial data from the DomainRequest object to prepopulate the form.
|
|
||||||
"""
|
|
||||||
initial = {}
|
|
||||||
if hasattr(obj, "feb_naming_requirements"):
|
|
||||||
initial["feb_naming_requirements"] = "yes" if obj.feb_naming_requirements else "no"
|
|
||||||
return initial
|
|
||||||
|
|
||||||
class ExecutiveNamingRequirementsDetailsForm(BaseDeletableRegistrarForm):
|
class ExecutiveNamingRequirementsDetailsForm(BaseDeletableRegistrarForm):
|
||||||
JOIN = "feb_naming_requirements_details"
|
|
||||||
|
|
||||||
# Text area for additional details; rendered conditionally when "no" is selected.
|
# Text area for additional details; rendered conditionally when "no" is selected.
|
||||||
feb_naming_requirements_details = forms.CharField(
|
feb_naming_requirements_details = forms.CharField(
|
||||||
widget=forms.Textarea(attrs={'maxlength': '2000'}),
|
widget=forms.Textarea(attrs={"maxlength": "2000"}),
|
||||||
max_length=2000,
|
max_length=2000,
|
||||||
required=True,
|
required=True,
|
||||||
error_messages={"required": ("This field is required.")},
|
error_messages={"required": ("This field is required.")},
|
||||||
|
validators=[
|
||||||
|
MaxLengthValidator(
|
||||||
|
2000,
|
||||||
|
message="Response must be less than 2000 characters.",
|
||||||
|
)
|
||||||
|
],
|
||||||
label="",
|
label="",
|
||||||
help_text="Maximum 2000 characters allowed.",
|
help_text="Maximum 2000 characters allowed.",
|
||||||
)
|
)
|
||||||
|
|
||||||
def to_database(self, obj: DomainRequest):
|
|
||||||
if not self.is_valid():
|
|
||||||
return
|
|
||||||
obj.feb_naming_requirements_details = self.cleaned_data["feb_naming_requirements_details"]
|
|
||||||
obj.save()
|
|
||||||
|
|
||||||
def is_valid(self):
|
|
||||||
"""
|
|
||||||
Validate that details are provided when required.
|
|
||||||
If the form is marked for deletion, bypass validation.
|
|
||||||
"""
|
|
||||||
if self.form_data_marked_for_deletion:
|
|
||||||
return True
|
|
||||||
|
|
||||||
is_valid = super().is_valid()
|
|
||||||
if not is_valid:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Check if the details field has content
|
|
||||||
details = self.cleaned_data.get('feb_naming_requirements_details', '').strip()
|
|
||||||
if not details:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
class PurposeForm(RegistrarForm):
|
class PurposeForm(RegistrarForm):
|
||||||
purpose = forms.CharField(
|
purpose = forms.CharField(
|
||||||
|
@ -710,7 +659,7 @@ class PurposeForm(RegistrarForm):
|
||||||
],
|
],
|
||||||
error_messages={"required": "Describe how you’ll use the .gov domain you’re requesting."},
|
error_messages={"required": "Describe how you’ll use the .gov domain you’re requesting."},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class OtherContactsYesNoForm(BaseYesNoForm):
|
class OtherContactsYesNoForm(BaseYesNoForm):
|
||||||
"""The yes/no field for the OtherContacts form."""
|
"""The yes/no field for the OtherContacts form."""
|
||||||
|
|
|
@ -1398,7 +1398,7 @@ class DomainRequest(TimeStampedModel):
|
||||||
if self.has_anything_else_text is None or self.has_cisa_representative is None:
|
if self.has_anything_else_text is None or self.has_cisa_representative is None:
|
||||||
has_details = False
|
has_details = False
|
||||||
return has_details
|
return has_details
|
||||||
|
|
||||||
def is_feb(self) -> bool:
|
def is_feb(self) -> bool:
|
||||||
"""Is this domain request for a Federal Executive Branch agency?"""
|
"""Is this domain request for a Federal Executive Branch agency?"""
|
||||||
if not self.generic_org_type:
|
if not self.generic_org_type:
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{% load static field_helpers url_helpers %}
|
{% load static field_helpers url_helpers %}
|
||||||
|
|
||||||
{% block form_instructions %}
|
{% block form_instructions %}
|
||||||
<p>Before requesting a .gov domain, please make sure it meets <a class="usa-link" rel="noopener noreferrer" target="_blank" href="{% if is_feb %}https://get.gov/domains/executive-branch-guidance/{% else %}{% public_site_url 'domains/choosing' %}{% endif %}">our naming requirements</a>. Your domain name must:
|
<p>Before requesting a .gov domain, please make sure it meets <a class="usa-link" rel="noopener noreferrer" target="_blank" href="{% if requires_feb_questions %}https://get.gov/domains/executive-branch-guidance/{% else %}{% public_site_url 'domains/choosing' %}{% endif %}">our naming requirements</a>. Your domain name must:
|
||||||
<ul class="usa-list">
|
<ul class="usa-list">
|
||||||
<li>Be available </li>
|
<li>Be available </li>
|
||||||
<li>Relate to your organization's name, location, and/or services </li>
|
<li>Relate to your organization's name, location, and/or services </li>
|
||||||
|
@ -101,7 +101,7 @@
|
||||||
{{ forms.2.management_form }}
|
{{ forms.2.management_form }}
|
||||||
{{ forms.3.management_form }}
|
{{ forms.3.management_form }}
|
||||||
|
|
||||||
{% if is_feb %}
|
{% if requires_feb_questions %}
|
||||||
<fieldset class="usa-fieldset margin-top-0 dotgov-domain-form">
|
<fieldset class="usa-fieldset margin-top-0 dotgov-domain-form">
|
||||||
<legend>
|
<legend>
|
||||||
<h2>Does this submission meet each domain naming requirement?</h2>
|
<h2>Does this submission meet each domain naming requirement?</h2>
|
||||||
|
|
|
@ -12,6 +12,7 @@ from registrar.forms.utility.wizard_form_helper import request_step_list
|
||||||
from registrar.models import DomainRequest
|
from registrar.models import DomainRequest
|
||||||
from registrar.models.contact import Contact
|
from registrar.models.contact import Contact
|
||||||
from registrar.models.user import User
|
from registrar.models.user import User
|
||||||
|
from registrar.utility.waffle import flag_is_active_for_user
|
||||||
from registrar.views.utility import StepsHelper
|
from registrar.views.utility import StepsHelper
|
||||||
from registrar.views.utility.permission_views import DomainRequestPermissionDeleteView
|
from registrar.views.utility.permission_views import DomainRequestPermissionDeleteView
|
||||||
from registrar.utility.enums import Step, PortfolioDomainRequestStep
|
from registrar.utility.enums import Step, PortfolioDomainRequestStep
|
||||||
|
@ -180,6 +181,9 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView):
|
||||||
"""Determines which step enum we should use for the wizard"""
|
"""Determines which step enum we should use for the wizard"""
|
||||||
return PortfolioDomainRequestStep if self.is_portfolio else Step
|
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")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def prefix(self):
|
def prefix(self):
|
||||||
"""Namespace the wizard to avoid clashes in session variable names."""
|
"""Namespace the wizard to avoid clashes in session variable names."""
|
||||||
|
@ -227,7 +231,12 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView):
|
||||||
if portfolio and not self._domain_request.generic_org_type:
|
if portfolio and not self._domain_request.generic_org_type:
|
||||||
self._domain_request.generic_org_type = portfolio.organization_type
|
self._domain_request.generic_org_type = portfolio.organization_type
|
||||||
self._domain_request.save()
|
self._domain_request.save()
|
||||||
|
if portfolio and not self._domain_request.federal_type:
|
||||||
|
logger.debug(f"Setting fed type to {portfolio.federal_type}")
|
||||||
|
self._domain_request.federal_type = portfolio.federal_type
|
||||||
|
self._domain_request.save()
|
||||||
else:
|
else:
|
||||||
|
logger.debug("Did not find domain request in DomainRequestWizard, creating new one.")
|
||||||
self._domain_request = DomainRequest.objects.create(creator=self.request.user)
|
self._domain_request = DomainRequest.objects.create(creator=self.request.user)
|
||||||
return self._domain_request
|
return self._domain_request
|
||||||
|
|
||||||
|
@ -654,7 +663,7 @@ class CurrentSites(DomainRequestWizard):
|
||||||
class DotgovDomain(DomainRequestWizard):
|
class DotgovDomain(DomainRequestWizard):
|
||||||
template_name = "domain_request_dotgov_domain.html"
|
template_name = "domain_request_dotgov_domain.html"
|
||||||
forms = [
|
forms = [
|
||||||
forms.DotGovDomainForm,
|
forms.DotGovDomainForm,
|
||||||
forms.AlternativeDomainFormSet,
|
forms.AlternativeDomainFormSet,
|
||||||
forms.ExecutiveNamingRequirementsYesNoForm,
|
forms.ExecutiveNamingRequirementsYesNoForm,
|
||||||
forms.ExecutiveNamingRequirementsDetailsForm,
|
forms.ExecutiveNamingRequirementsDetailsForm,
|
||||||
|
@ -662,8 +671,7 @@ class DotgovDomain(DomainRequestWizard):
|
||||||
|
|
||||||
def get_context_data(self):
|
def get_context_data(self):
|
||||||
context = super().get_context_data()
|
context = super().get_context_data()
|
||||||
context["generic_org_type"] = self.domain_request.generic_org_type
|
context["requires_feb_questions"] = self.requires_feb_questions()
|
||||||
context["is_feb"] = self.domain_request.is_feb()
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def is_valid(self, forms_list: list) -> bool:
|
def is_valid(self, forms_list: list) -> bool:
|
||||||
|
@ -675,34 +683,26 @@ class DotgovDomain(DomainRequestWizard):
|
||||||
3: ExecutiveNamingRequirementsDetailsForm
|
3: ExecutiveNamingRequirementsDetailsForm
|
||||||
"""
|
"""
|
||||||
logger.debug("Validating dotgov domain form")
|
logger.debug("Validating dotgov domain form")
|
||||||
# If not a federal executive branch agency, mark executive-related forms for deletion.
|
# If FEB questions aren't required, validate only non-FEB forms
|
||||||
if not (self.domain_request.is_feb()):
|
if not self.requires_feb_questions():
|
||||||
forms_list[2].mark_form_for_deletion()
|
forms_list[2].mark_form_for_deletion()
|
||||||
forms_list[3].mark_form_for_deletion()
|
forms_list[3].mark_form_for_deletion()
|
||||||
return all(form.is_valid() for form in forms_list)
|
return forms_list[0].is_valid() and forms_list[1].is_valid()
|
||||||
|
|
||||||
if not forms_list[2].is_valid():
|
if not forms_list[2].is_valid():
|
||||||
logger.debug("Dotgov domain form is invalid")
|
logger.debug("Dotgov domain form is invalid")
|
||||||
if forms_list[2].cleaned_data.get("feb_naming_requirements", None) != "no":
|
# mark details form for deletion so that its errors don't show up
|
||||||
forms_list[3].mark_form_for_deletion()
|
forms_list[3].mark_form_for_deletion()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
logger.debug(f"feb_naming_requirements: {forms_list[2].cleaned_data.get('feb_naming_requirements', None)}")
|
|
||||||
|
|
||||||
if forms_list[2].cleaned_data.get("feb_naming_requirements", None) != "no":
|
if forms_list[2].cleaned_data.get("feb_naming_requirements", None):
|
||||||
logger.debug("Marking details form for deletion")
|
logger.debug("Marking details form for deletion")
|
||||||
# If the user selects "yes" or has made no selection, no details are needed.
|
# If the user selects "yes" or has made no selection, no details are needed.
|
||||||
forms_list[3].mark_form_for_deletion()
|
forms_list[3].mark_form_for_deletion()
|
||||||
valid = all(
|
valid = all(form.is_valid() for i, form in enumerate(forms_list) if i != 3)
|
||||||
form.is_valid() for i, form in enumerate(forms_list) if i != 3
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
# "No" was selected – details are required.
|
# "No" was selected – details are required.
|
||||||
valid = (
|
valid = all(form.is_valid() for form in forms_list)
|
||||||
forms_list[2].is_valid() and
|
|
||||||
forms_list[3].is_valid() and
|
|
||||||
all(form.is_valid() for i, form in enumerate(forms_list) if i not in [2, 3])
|
|
||||||
)
|
|
||||||
return valid
|
return valid
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue