Add logic in admin to catch no reason error, add JS to manage UI

This commit is contained in:
Rachid Mrad 2024-02-16 15:16:42 -05:00
parent 1530d77ad8
commit ba53e74e26
No known key found for this signature in database
4 changed files with 60 additions and 3 deletions

View file

@ -793,7 +793,7 @@ class DomainApplicationAdmin(ListHeaderAdmin):
# Detail view # Detail view
form = DomainApplicationAdminForm form = DomainApplicationAdminForm
fieldsets = [ fieldsets = [
(None, {"fields": ["status", "investigator", "creator", "approved_domain", "notes"]}), (None, {"fields": ["status", "rejection_reason", "investigator", "creator", "approved_domain", "notes"]}),
( (
"Type of organization", "Type of organization",
{ {
@ -901,6 +901,24 @@ class DomainApplicationAdmin(ListHeaderAdmin):
"This action is not permitted. The domain is already active.", "This action is not permitted. The domain is already active.",
) )
elif (
obj
and obj.status == models.DomainApplication.ApplicationStatus.REJECTED
and not obj.rejection_reason
):
# This condition should never be triggered.
# The opposite of this condition is acceptable (rejected -> other status and rejection_reason)
# because we clean up the rejection reason in the transition in the model.
# Clear the success message
messages.set_level(request, messages.ERROR)
messages.error(
request,
"A rejection reason is required.",
)
else: else:
if obj.status != original_obj.status: if obj.status != original_obj.status:
status_method_mapping = { status_method_mapping = {

View file

@ -312,3 +312,27 @@ function enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, elementPk,
} }
})(); })();
/** An IIFE for admin in DjangoAdmin to listen to changes on the domain request
* status select amd to show/hide the rejection reason
*/
(function (){
// Get the rejection reason form row
let rejectionReasonFormGroup = document.querySelector('.field-rejection_reason')
if (rejectionReasonFormGroup) {
// Get the status select
let statusSelect = document.getElementById('id_status')
// If status is rejected, hide the rejection reason on load
if (statusSelect.value != 'rejected')
rejectionReasonFormGroup.style.display = 'none';
// Listen to status changes and toggle rejection reason
statusSelect.addEventListener('change', function() {
rejectionReasonFormGroup.style.display = statusSelect.value !== 'rejected' ? 'none' : 'block';
});
}
})();

View file

@ -26,7 +26,7 @@ class Migration(migrations.Migration):
"Research could not corroborate legitimacy of contacts or organization", "Research could not corroborate legitimacy of contacts or organization",
), ),
("organization_eligibility", "Organization isn't eligible for a .gov"), ("organization_eligibility", "Organization isn't eligible for a .gov"),
("naming_requirements", "naming requirements not met"), ("naming_requirements", "Naming requirements not met"),
], ],
null=True, null=True,
), ),

View file

@ -356,7 +356,7 @@ class DomainApplication(TimeStampedModel):
SECOND_DOMAIN_REASONING = "second_domain_reasoning", "Organization already has a domain and does not provide sufficient reasoning for a second domain" SECOND_DOMAIN_REASONING = "second_domain_reasoning", "Organization already has a domain and does not provide sufficient reasoning for a second domain"
CONTACTS_OR_ORGANIZATION_LEGITIMACY = "contacts_or_organization_legitimacy", "Research could not corroborate legitimacy of contacts or organization" CONTACTS_OR_ORGANIZATION_LEGITIMACY = "contacts_or_organization_legitimacy", "Research could not corroborate legitimacy of contacts or organization"
ORGANIZATION_ELIGIBILITY = "organization_eligibility", "Organization isn't eligible for a .gov" ORGANIZATION_ELIGIBILITY = "organization_eligibility", "Organization isn't eligible for a .gov"
NAMING_REQUIREMENTS = "naming_requirements", "naming requirements not met" NAMING_REQUIREMENTS = "naming_requirements", "Naming requirements not met"
# #### Internal fields about the application ##### # #### Internal fields about the application #####
status = FSMField( status = FSMField(
@ -694,12 +694,17 @@ class DomainApplication(TimeStampedModel):
This action is logged. This action is logged.
This action cleans up the rejection status if moving away from rejected.
As side effects this will delete the domain and domain_information As side effects this will delete the domain and domain_information
(will cascade) when they exist.""" (will cascade) when they exist."""
if self.status == self.ApplicationStatus.APPROVED: if self.status == self.ApplicationStatus.APPROVED:
self.delete_and_clean_up_domain("in_review") self.delete_and_clean_up_domain("in_review")
if self.status == self.ApplicationStatus.REJECTED:
self.rejection_reason = None
literal = DomainApplication.ApplicationStatus.IN_REVIEW literal = DomainApplication.ApplicationStatus.IN_REVIEW
# Check if the tuple exists, then grab its value # Check if the tuple exists, then grab its value
in_review = literal if literal is not None else "In Review" in_review = literal if literal is not None else "In Review"
@ -721,12 +726,17 @@ class DomainApplication(TimeStampedModel):
This action is logged. This action is logged.
This action cleans up the rejection status if moving away from rejected.
As side effects this will delete the domain and domain_information As side effects this will delete the domain and domain_information
(will cascade) when they exist.""" (will cascade) when they exist."""
if self.status == self.ApplicationStatus.APPROVED: if self.status == self.ApplicationStatus.APPROVED:
self.delete_and_clean_up_domain("reject_with_prejudice") self.delete_and_clean_up_domain("reject_with_prejudice")
if self.status == self.ApplicationStatus.REJECTED:
self.rejection_reason = None
literal = DomainApplication.ApplicationStatus.ACTION_NEEDED literal = DomainApplication.ApplicationStatus.ACTION_NEEDED
# Check if the tuple is setup correctly, then grab its value # Check if the tuple is setup correctly, then grab its value
action_needed = literal if literal is not None else "Action Needed" action_needed = literal if literal is not None else "Action Needed"
@ -745,6 +755,8 @@ class DomainApplication(TimeStampedModel):
def approve(self, send_email=True): def approve(self, send_email=True):
"""Approve an application that has been submitted. """Approve an application that has been submitted.
This action cleans up the rejection status if moving away from rejected.
This has substantial side-effects because it creates another database This has substantial side-effects because it creates another database
object for the approved Domain and makes the user who created the object for the approved Domain and makes the user who created the
application into an admin on that domain. It also triggers an email application into an admin on that domain. It also triggers an email
@ -767,6 +779,9 @@ class DomainApplication(TimeStampedModel):
user=self.creator, domain=created_domain, role=UserDomainRole.Roles.MANAGER user=self.creator, domain=created_domain, role=UserDomainRole.Roles.MANAGER
) )
if self.status == self.ApplicationStatus.REJECTED:
self.rejection_reason = None
self._send_status_update_email( self._send_status_update_email(
"application approved", "application approved",
"emails/status_change_approved.txt", "emails/status_change_approved.txt",