This commit is contained in:
Rachid Mrad 2024-01-04 19:46:43 -05:00
parent 5c1147c355
commit a313c5496b
No known key found for this signature in database
GPG key ID: EF38E4CEC4A8F3CF
6 changed files with 47 additions and 115 deletions

View file

@ -505,38 +505,35 @@ function toggleTwoDomElements(ele1, ele2, index) {
let radioButtons = document.querySelectorAll('input[name="other_contacts-has_other_contacts"]');
function handleRadioButtonChange() {
// Check the value of the selected radio button
// Attempt to find the radio button element that is checked
let radioButtonChecked = document.querySelector('input[name="other_contacts-has_other_contacts"]:checked');
// Check the value of the selected radio button
// Attempt to find the radio button element that is checked
let radioButtonChecked = document.querySelector('input[name="other_contacts-has_other_contacts"]:checked');
// Check if the element exists before accessing its value
let selectedValue = radioButtonChecked ? radioButtonChecked.value : null;
// Check if the element exists before accessing its value
let selectedValue = radioButtonChecked ? radioButtonChecked.value : null;
switch (selectedValue) {
case 'True':
console.log('Yes, I can name other employees.');
toggleTwoDomElements('other-employees', 'no-other-employees', 1);
break;
switch (selectedValue) {
case 'True':
toggleTwoDomElements('other-employees', 'no-other-employees', 1);
break;
case 'False':
console.log('No (We\'ll ask you to explain why).');
toggleTwoDomElements('other-employees', 'no-other-employees', 2);
break;
case 'False':
toggleTwoDomElements('other-employees', 'no-other-employees', 2);
break;
default:
console.log('Nothing selected');
toggleTwoDomElements('other-employees', 'no-other-employees', 0);
}
default:
toggleTwoDomElements('other-employees', 'no-other-employees', 0);
}
}
// Add event listener to each radio button
if (radioButtons) {
radioButtons.forEach(function (radioButton) {
radioButton.addEventListener('change', handleRadioButtonChange);
});
}
if (radioButtons.length) {
// Add event listener to each radio button
radioButtons.forEach(function (radioButton) {
radioButton.addEventListener('change', handleRadioButtonChange);
});
// initiaize
handleRadioButtonChange();
// initialize
handleRadioButtonChange();
}
})();

View file

@ -39,11 +39,9 @@ class RegistrarForm(forms.Form):
Does nothing if form is not valid.
"""
logger.info(f"to_database called on {self.__class__.__name__}")
if not self.is_valid():
return
for name, value in self.cleaned_data.items():
logger.info(f"{name}: {value}")
setattr(obj, name, value)
obj.save()
@ -98,9 +96,7 @@ class RegistrarFormSet(forms.BaseFormSet):
raise NotImplementedError
def test_if_more_than_one_join(self, db_obj, rel, related_name):
logger.info(f"rel: {rel} | related_name: {related_name}")
"""Helper for finding whether an object is joined more than once."""
threshold = 0
if rel == related_name:
threshold = 1
@ -127,25 +123,20 @@ class RegistrarFormSet(forms.BaseFormSet):
obj.save()
query = getattr(obj, join).order_by("created_at").all() # order matters
logger.info(obj._meta.get_field(join).related_query_name())
related_name = obj._meta.get_field(join).related_query_name()
# the use of `zip` pairs the forms in the formset with the
# related objects gotten from the database -- there should always be
# at least as many forms as database entries: extra forms means new
# entries, but fewer forms is _not_ the correct way to delete items
# (likely a client-side error or an attempt at data tampering)
for db_obj, post_data in zip_longest(query, self.forms, fillvalue=None):
cleaned = post_data.cleaned_data if post_data is not None else {}
logger.info(f"in _to_database for {self.__class__.__name__}")
logger.info(db_obj)
logger.info(cleaned)
# matching database object exists, update it
if db_obj is not None and cleaned:
if should_delete(cleaned):
if any(self.test_if_more_than_one_join(db_obj, rel, related_name) for rel in reverse_joins):
logger.info("Object is joined to something")
# Remove the specific relationship without deleting the object
getattr(db_obj, related_name).remove(self.application)
else:
@ -389,6 +380,8 @@ class BaseCurrentSitesFormSet(RegistrarFormSet):
return website.strip() == ""
def to_database(self, obj: DomainApplication):
# If we want to test against multiple joins for a website object, replace the empty array
# and change the JOIN in the models to allow for reverse references
self._to_database(obj, self.JOIN, [], self.should_delete, self.pre_update, self.pre_create)
@classmethod
@ -446,6 +439,8 @@ class BaseAlternativeDomainFormSet(RegistrarFormSet):
return {}
def to_database(self, obj: DomainApplication):
# If we want to test against multiple joins for a website object, replace the empty array and
# change the JOIN in the models to allow for reverse references
self._to_database(obj, self.JOIN, [], self.should_delete, self.pre_update, self.pre_create)
@classmethod
@ -522,7 +517,7 @@ class PurposeForm(RegistrarForm):
],
error_messages={"required": "Describe how you'll use the .gov domain youre requesting."},
)
class YourContactForm(RegistrarForm):
def to_database(self, obj):
@ -578,6 +573,7 @@ class OtherContactsYesNoForm(RegistrarForm):
elif self.application and self.application.has_rationale():
default_value = False
else:
# No pre-selection for new applications
default_value = None
self.fields['has_other_contacts'] = forms.TypedChoiceField(
@ -589,11 +585,6 @@ class OtherContactsYesNoForm(RegistrarForm):
initial=default_value,
widget=forms.RadioSelect
)
def is_valid(self):
val = super().is_valid()
logger.info(f"yes no form is valid = {val}")
return val
class OtherContactsForm(RegistrarForm):
@ -631,8 +622,6 @@ class OtherContactsForm(RegistrarForm):
super().__init__(*args, **kwargs)
def mark_form_for_deletion(self):
logger.info("removing form data from other contact")
# self.data = {}
self.form_data_marked_for_deletion = True
def clean(self):
@ -645,35 +634,20 @@ class OtherContactsForm(RegistrarForm):
"""
if self.form_data_marked_for_deletion:
# Set form_is_empty to True initially
# form_is_empty = True
# for name, field in self.fields.items():
# # get the value of the field from the widget
# value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
# # if any field in the submitted form is not empty, set form_is_empty to False
# if value is not None and value != "":
# form_is_empty = False
# if form_is_empty:
# # clear any errors raised by the form fields
# # (before this clean() method is run, each field
# # performs its own clean, which could result in
# # errors that we wish to ignore at this point)
# #
# # NOTE: we cannot just clear() the errors list.
# # That causes problems.
# clear any errors raised by the form fields
# (before this clean() method is run, each field
# performs its own clean, which could result in
# errors that we wish to ignore at this point)
#
# NOTE: we cannot just clear() the errors list.
# That causes problems.
for field in self.fields:
if field in self.errors:
del self.errors[field]
return {'delete': True}
return self.cleaned_data
def is_valid(self):
val = super().is_valid()
logger.info(f"other contacts form is valid = {val}")
return val
class BaseOtherContactsFormSet(RegistrarFormSet):
JOIN = "other_contacts"
@ -684,28 +658,21 @@ class BaseOtherContactsFormSet(RegistrarFormSet):
self.application = kwargs.pop("application", None)
super(RegistrarFormSet, self).__init__(*args, **kwargs)
# quick workaround to ensure that the HTML `required`
# attribute shows up on required fields for any forms
# in the formset which have data already (stated another
# way: you can leave a form in the formset blank, but
# if you opt to fill it out, you must fill it out _right_)
# attribute shows up on required fields for the first form
# in the formset plus those that have data already.
for index in range(max(self.initial_form_count(), 1)):
self.forms[index].use_required_attribute = True
# self.forms[0].use_required_attribute = True
def pre_update(self, db_obj, cleaned):
"""Code to run before an item in the formset is saved."""
for key, value in cleaned.items():
setattr(db_obj, key, value)
def should_delete(self, cleaned):
empty = (isinstance(v, str) and (v.strip() == "" or v is None) for v in cleaned.values())
logger.info(f"should_delete => {all(empty) or self.formset_data_marked_for_deletion}")
return all(empty) or self.formset_data_marked_for_deletion
def to_database(self, obj: DomainApplication):
logger.info("to_database called on BaseOtherContactsFormSet")
self._to_database(obj, self.JOIN, self.REVERSE_JOINS, self.should_delete, self.pre_update, self.pre_create)
@classmethod
@ -717,7 +684,6 @@ class BaseOtherContactsFormSet(RegistrarFormSet):
Updates forms in formset as well to mark them for deletion.
This has an effect on validity checks and to_database methods.
"""
logger.info("removing form data from other contact set")
self.formset_data_marked_for_deletion = True
for form in self.forms:
form.mark_form_for_deletion()
@ -725,9 +691,7 @@ class BaseOtherContactsFormSet(RegistrarFormSet):
def is_valid(self):
if self.formset_data_marked_for_deletion:
self.validate_min = False
val = super().is_valid()
logger.info(f"other contacts form set is valid = {val}")
return val
return super().is_valid()
OtherContactsFormSet = forms.formset_factory(
@ -736,7 +700,6 @@ OtherContactsFormSet = forms.formset_factory(
absolute_max=1500, # django default; use `max_num` to limit entries
min_num=1,
validate_min=True,
# can_delete=True,
formset=BaseOtherContactsFormSet,
)
@ -772,7 +735,6 @@ class NoOtherContactsForm(RegistrarForm):
"""Marks no_other_contacts form for deletion.
This changes behavior of validity checks and to_database
methods."""
logger.info("removing form data from no other contacts")
self.form_data_marked_for_deletion = True
def clean(self):
@ -804,24 +766,15 @@ class NoOtherContactsForm(RegistrarForm):
to None before saving.
Do nothing if form is not valid.
"""
logger.info(f"to_database called on {self.__class__.__name__}")
if not self.is_valid():
return
if self.form_data_marked_for_deletion:
for field_name, _ in self.fields.items():
logger.info(f"{field_name}: None")
setattr(obj, field_name, None)
else:
for name, value in self.cleaned_data.items():
logger.info(f"{name}: {value}")
setattr(obj, name, value)
obj.save()
def is_valid(self):
"""This is for debugging only and can be deleted"""
val = super().is_valid()
logger.info(f"no other contacts form is valid = {val}")
return val
class AnythingElseForm(RegistrarForm):

View file

@ -832,20 +832,13 @@ class DomainApplication(TimeStampedModel):
]
def has_rationale(self) -> bool:
"""Does this application have no_other_contacts_rationale"""
"""Does this application have no_other_contacts_rationale?"""
return bool(self.no_other_contacts_rationale)
def has_other_contacts(self) -> bool:
"""Does this application have other contacts listed?"""
return self.other_contacts.exists()
# def __setattr__(self, name, value):
# # Check if the attribute exists in the class
# if not hasattr(self, name):
# logger.info(f"{self.__class__.__name__} object has no attribute '{name}'")
# # If the attribute exists, set its value
# super().__setattr__(name, value)
def is_federal(self) -> Union[bool, None]:
"""Is this application for a federal agency?

View file

@ -12,12 +12,8 @@
{% endblock %}
{% block form_required_fields_help_text %}
{# commenting out to remove this block from this point in the page #}
{% endblock %}
{% block form_fields %}
<fieldset class="usa-fieldset margin-top-2">
<legend>
<h2>Are there other employees who can help verify your request?</h2>
@ -48,6 +44,10 @@
{% input_with_errors form.title %}
{% comment %} There seems to be an issue with the character counter on emails.
It's not counting anywhere, and in this particular instance it's
affecting the margin of this block. The wrapper div is a
temporary workaround. {% endcomment %}
<div class="margin-top-3">
{% input_with_errors form.email %}
</div>
@ -75,5 +75,4 @@
{% input_with_errors forms.2.no_other_contacts_rationale %}
{% endwith %}
</div>
{% endblock %}

View file

@ -446,7 +446,6 @@ class TestDomainApplication(TestCase):
"""has_rationale() returns true when an application has no_other_contacts_rationale"""
self.started_application.no_other_contacts_rationale = "You talkin' to me?"
self.started_application.save()
self.assertEquals(
self.started_application.has_rationale(),
True

View file

@ -370,9 +370,6 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView):
def post(self, request, *args, **kwargs) -> HttpResponse:
"""This method handles POST requests."""
# Log the keys and values of request.POST
for key, value in request.POST.items():
logger.info("Key: %s, Value: %s", key, value)
# if accessing this class directly, redirect to the first step
if self.__class__ == ApplicationWizard:
return self.goto(self.steps.first)
@ -385,7 +382,6 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView):
# always save progress
self.save(forms)
else:
logger.info("all forms are not valid")
context = self.get_context_data()
context["forms"] = forms
return render(request, self.template_name, context)
@ -410,7 +406,6 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView):
"""
for form in forms:
if form is not None and hasattr(form, "to_database"):
logger.info(f"saving form {form.__class__.__name__}")
form.to_database(self.application)
@ -498,21 +493,17 @@ class OtherContacts(ApplicationWizard):
all_forms_valid = True
# test first for yes_no_form validity
if other_contacts_yes_no_form.is_valid():
logger.info("yes no form is valid")
# test for has_contacts
if other_contacts_yes_no_form.cleaned_data.get('has_other_contacts'):
logger.info("has other contacts")
# mark the no_other_contacts_form for deletion
no_other_contacts_form.mark_form_for_deletion()
# test that the other_contacts_forms and no_other_contacts_forms are valid
all_forms_valid = all(form.is_valid() for form in forms[1:])
else:
logger.info("has no other contacts")
# mark the other_contacts_forms formset for deletion
other_contacts_forms.mark_formset_for_deletion()
all_forms_valid = all(form.is_valid() for form in forms[1:])
else:
logger.info("yes no form is invalid")
# if yes no form is invalid, no choice has been made
# mark other forms for deletion so that their errors are not
# returned