mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-04 10:13:30 +02:00
DELETE working on backend
This commit is contained in:
parent
eae2eda4f2
commit
6692eebfe3
1 changed files with 139 additions and 4 deletions
|
@ -14,9 +14,12 @@ from api.views import DOMAIN_API_MESSAGES
|
|||
from registrar.models import Contact, DomainApplication, DraftDomain, Domain
|
||||
from registrar.templatetags.url_helpers import public_site_url
|
||||
from registrar.utility import errors
|
||||
from django.utils.translation import gettext_lazy as _, ngettext
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
TOTAL_FORM_COUNT = 'TOTAL_FORMS'
|
||||
INITIAL_FORM_COUNT = 'INITIAL_FORMS'
|
||||
|
||||
class RegistrarForm(forms.Form):
|
||||
"""
|
||||
|
@ -95,7 +98,119 @@ class RegistrarFormSet(forms.BaseFormSet):
|
|||
Hint: Subclass should call `self._to_database(...)`.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def full_clean(self):
|
||||
"""
|
||||
Clean all of self.data and populate self._errors and
|
||||
self._non_form_errors.
|
||||
"""
|
||||
logger.info("in full_clean")
|
||||
self._errors = []
|
||||
self._non_form_errors = self.error_class()
|
||||
empty_forms_count = 0
|
||||
|
||||
if not self.is_bound: # Stop further processing.
|
||||
return
|
||||
|
||||
logger.info("about to test management form ")
|
||||
if not self.management_form.is_valid():
|
||||
error = forms.ValidationError(
|
||||
self.error_messages['missing_management_form'],
|
||||
params={
|
||||
'field_names': ', '.join(
|
||||
self.management_form.add_prefix(field_name)
|
||||
for field_name in self.management_form.errors
|
||||
),
|
||||
},
|
||||
code='missing_management_form',
|
||||
)
|
||||
self._non_form_errors.append(error)
|
||||
|
||||
logger.info("about to test forms in self.forms")
|
||||
for i, form in enumerate(self.forms):
|
||||
logger.info(f"checking form {i}")
|
||||
# Empty forms are unchanged forms beyond those with initial data.
|
||||
if not form.has_changed() and i >= self.initial_form_count():
|
||||
empty_forms_count += 1
|
||||
# Accessing errors calls full_clean() if necessary.
|
||||
# _should_delete_form() requires cleaned_data.
|
||||
form_errors = form.errors
|
||||
if self.can_delete and self._should_delete_form(form):
|
||||
continue
|
||||
self._errors.append(form_errors)
|
||||
logger.info("at the end of for loop processing")
|
||||
try:
|
||||
logger.info("about to test validate max and min")
|
||||
if (self.validate_max and
|
||||
self.total_form_count() - len(self.deleted_forms) > self.max_num) or \
|
||||
self.management_form.cleaned_data[TOTAL_FORM_COUNT] > self.absolute_max:
|
||||
raise forms.ValidationError(ngettext(
|
||||
"Please submit at most %d form.",
|
||||
"Please submit at most %d forms.", self.max_num) % self.max_num,
|
||||
code='too_many_forms',
|
||||
)
|
||||
logger.info("between validate max and validate min")
|
||||
if (self.validate_min and
|
||||
self.total_form_count() - len(self.deleted_forms) - empty_forms_count < self.min_num):
|
||||
raise forms.ValidationError(ngettext(
|
||||
"Please submit at least %d form.",
|
||||
"Please submit at least %d forms.", self.min_num) % self.min_num,
|
||||
code='too_few_forms')
|
||||
# Give self.clean() a chance to do cross-form validation.
|
||||
logger.info("about to call clean on formset")
|
||||
self.clean()
|
||||
except forms.ValidationError as e:
|
||||
logger.info(f"hit an exception {e}")
|
||||
self._non_form_errors = self.error_class(e.error_list)
|
||||
|
||||
def total_form_count(self):
|
||||
"""Return the total number of forms in this FormSet."""
|
||||
logger.info("in total_form_count")
|
||||
if self.is_bound:
|
||||
logger.info("is_bound")
|
||||
# return absolute_max if it is lower than the actual total form
|
||||
# count in the data; this is DoS protection to prevent clients
|
||||
# from forcing the server to instantiate arbitrary numbers of
|
||||
# forms
|
||||
return min(self.management_form.cleaned_data[TOTAL_FORM_COUNT], self.absolute_max)
|
||||
else:
|
||||
initial_forms = self.initial_form_count()
|
||||
total_forms = max(initial_forms, self.min_num) + self.extra
|
||||
# Allow all existing related objects/inlines to be displayed,
|
||||
# but don't allow extra beyond max_num.
|
||||
if initial_forms > self.max_num >= 0:
|
||||
total_forms = initial_forms
|
||||
elif total_forms > self.max_num >= 0:
|
||||
total_forms = self.max_num
|
||||
return total_forms
|
||||
|
||||
def initial_form_count(self):
|
||||
"""Return the number of forms that are required in this FormSet."""
|
||||
logger.info("in initial_form_count")
|
||||
if self.is_bound:
|
||||
return self.management_form.cleaned_data[INITIAL_FORM_COUNT]
|
||||
else:
|
||||
# Use the length of the initial data if it's there, 0 otherwise.
|
||||
initial_forms = len(self.initial) if self.initial else 0
|
||||
return initial_forms
|
||||
|
||||
def is_valid(self):
|
||||
"""Return True if every form in self.forms is valid."""
|
||||
if not self.is_bound:
|
||||
return False
|
||||
# Accessing errors triggers a full clean the first time only.
|
||||
logger.info("before self.errors")
|
||||
self.errors
|
||||
# List comprehension ensures is_valid() is called for all forms.
|
||||
# Forms due to be deleted shouldn't cause the formset to be invalid.
|
||||
logger.info("before all isvalid")
|
||||
forms_valid = all([
|
||||
form.is_valid() for form in self.forms
|
||||
if not (self.can_delete and self._should_delete_form(form))
|
||||
])
|
||||
logger.info(f"forms_valid = {forms_valid}")
|
||||
return forms_valid and not self.non_form_errors()
|
||||
|
||||
def test_if_more_than_one_join(self, db_obj, rel, related_name):
|
||||
"""Helper for finding whether an object is joined more than once."""
|
||||
# threshold is the number of related objects that are acceptable
|
||||
|
@ -165,6 +280,7 @@ class RegistrarFormSet(forms.BaseFormSet):
|
|||
|
||||
logger.info(post_data)
|
||||
logger.info(cleaned)
|
||||
logger.info(db_obj)
|
||||
# matching database object exists, update it
|
||||
if db_obj is not None and cleaned:
|
||||
if should_delete(cleaned):
|
||||
|
@ -181,8 +297,12 @@ class RegistrarFormSet(forms.BaseFormSet):
|
|||
|
||||
# no matching database object, create it
|
||||
# make sure not to create a database object if cleaned has 'delete' attribute
|
||||
elif db_obj is None and cleaned and not cleaned.get("delete", False):
|
||||
elif db_obj is None and cleaned and not cleaned.get("DELETE", False):
|
||||
logger.info(cleaned.get("DELETE",False))
|
||||
logger.info("about to pre_create")
|
||||
kwargs = pre_create(db_obj, cleaned)
|
||||
logger.info("after pre_create")
|
||||
logger.info(kwargs)
|
||||
getattr(obj, join).create(**kwargs)
|
||||
|
||||
@classmethod
|
||||
|
@ -679,9 +799,14 @@ class OtherContactsForm(RegistrarForm):
|
|||
# return empty object with only 'delete' attribute defined.
|
||||
# this will prevent _to_database from creating an empty
|
||||
# database object
|
||||
return {"delete": True}
|
||||
return {"DELETE": True}
|
||||
|
||||
return self.cleaned_data
|
||||
|
||||
def is_valid(self):
|
||||
val = super().is_valid()
|
||||
logger.info(f"othercontactsform validation yields: {val}")
|
||||
return val
|
||||
|
||||
|
||||
class BaseOtherContactsFormSet(RegistrarFormSet):
|
||||
|
@ -708,8 +833,15 @@ class BaseOtherContactsFormSet(RegistrarFormSet):
|
|||
|
||||
def should_delete(self, cleaned):
|
||||
empty = (isinstance(v, str) and (v.strip() == "" or v is None) for v in cleaned.values())
|
||||
return all(empty) or self.formset_data_marked_for_deletion
|
||||
return all(empty) or self.formset_data_marked_for_deletion or cleaned.get("DELETE", False)
|
||||
|
||||
def pre_create(self, db_obj, cleaned):
|
||||
"""Code to run before an item in the formset is created in the database."""
|
||||
# remove DELETE from cleaned
|
||||
if "DELETE" in cleaned:
|
||||
cleaned.pop('DELETE')
|
||||
return cleaned
|
||||
|
||||
def to_database(self, obj: DomainApplication):
|
||||
logger.info("in to_database for BaseOtherContactsFormSet")
|
||||
self._to_database(obj, self.JOIN, self.REVERSE_JOINS, self.should_delete, self.pre_update, self.pre_create)
|
||||
|
@ -733,7 +865,10 @@ class BaseOtherContactsFormSet(RegistrarFormSet):
|
|||
number of other contacts when contacts marked for deletion"""
|
||||
if self.formset_data_marked_for_deletion:
|
||||
self.validate_min = False
|
||||
return super().is_valid()
|
||||
logger.info("in is_valid()")
|
||||
val = super().is_valid()
|
||||
logger.info(f"formset validation yields: {val}")
|
||||
return val
|
||||
|
||||
|
||||
OtherContactsFormSet = forms.formset_factory(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue