Merge remote-tracking branch 'origin/main' into rjm/1017-ux

This commit is contained in:
Rachid Mrad 2023-09-19 13:40:57 -04:00
commit fe1c443357
No known key found for this signature in database
GPG key ID: EF38E4CEC4A8F3CF
33 changed files with 1615 additions and 487 deletions

View file

@ -130,6 +130,7 @@ class MyUserAdmin(BaseUserAdmin):
inlines = [UserContactInline]
list_display = (
"username",
"email",
"first_name",
"last_name",
@ -159,10 +160,51 @@ class MyUserAdmin(BaseUserAdmin):
("Important dates", {"fields": ("last_login", "date_joined")}),
)
analyst_fieldsets = (
(
None,
{"fields": ("password", "status")},
),
("Personal Info", {"fields": ("first_name", "last_name", "email")}),
(
"Permissions",
{
"fields": (
"is_active",
"is_staff",
"is_superuser",
)
},
),
("Important dates", {"fields": ("last_login", "date_joined")}),
)
analyst_readonly_fields = [
"password",
"Personal Info",
"first_name",
"last_name",
"email",
"Permissions",
"is_active",
"is_staff",
"is_superuser",
"Important dates",
"last_login",
"date_joined",
]
def get_list_display(self, request):
if not request.user.is_superuser:
# Customize the list display for staff users
return ("email", "first_name", "last_name", "is_staff", "is_superuser")
return (
"email",
"first_name",
"last_name",
"is_staff",
"is_superuser",
"status",
)
# Use the default list display for non-staff users
return super().get_list_display(request)
@ -171,11 +213,18 @@ class MyUserAdmin(BaseUserAdmin):
if not request.user.is_superuser:
# If the user doesn't have permission to change the model,
# show a read-only fieldset
return ((None, {"fields": []}),)
return self.analyst_fieldsets
# If the user has permission to change the model, show all fields
return super().get_fieldsets(request, obj)
def get_readonly_fields(self, request, obj=None):
if request.user.is_superuser:
return () # No read-only fields for superusers
elif request.user.is_staff:
return self.analyst_readonly_fields # Read-only fields for staff
return () # No read-only fields for other users
class HostIPInline(admin.StackedInline):
"""Edit an ip address on the host page."""
@ -423,7 +472,7 @@ class DomainApplicationAdmin(ListHeaderAdmin):
# Detail view
form = DomainApplicationAdminForm
fieldsets = [
(None, {"fields": ["status", "investigator", "creator"]}),
(None, {"fields": ["status", "investigator", "creator", "approved_domain"]}),
(
"Type of organization",
{
@ -435,8 +484,7 @@ class DomainApplicationAdmin(ListHeaderAdmin):
"federal_agency",
"federal_type",
"is_election_board",
"type_of_work",
"more_organization_information",
"about_your_organization",
]
},
),
@ -474,8 +522,7 @@ class DomainApplicationAdmin(ListHeaderAdmin):
# Read only that we'll leverage for CISA Analysts
analyst_readonly_fields = [
"creator",
"type_of_work",
"more_organization_information",
"about_your_organization",
"address_line1",
"address_line2",
"zipcode",
@ -495,29 +542,57 @@ class DomainApplicationAdmin(ListHeaderAdmin):
# Get the original application from the database
original_obj = models.DomainApplication.objects.get(pk=obj.pk)
if obj.status != original_obj.status:
status_method_mapping = {
models.DomainApplication.STARTED: None,
models.DomainApplication.SUBMITTED: obj.submit,
models.DomainApplication.IN_REVIEW: obj.in_review,
models.DomainApplication.ACTION_NEEDED: obj.action_needed,
models.DomainApplication.APPROVED: obj.approve,
models.DomainApplication.WITHDRAWN: obj.withdraw,
models.DomainApplication.REJECTED: obj.reject,
models.DomainApplication.INELIGIBLE: obj.reject_with_prejudice,
}
selected_method = status_method_mapping.get(obj.status)
if selected_method is None:
logger.warning("Unknown status selected in django admin")
else:
# This is an fsm in model which will throw an error if the
# transition condition is violated, so we roll back the
# status to what it was before the admin user changed it and
# let the fsm method set it.
obj.status = original_obj.status
selected_method()
if (
obj
and original_obj.status == models.DomainApplication.APPROVED
and (
obj.status == models.DomainApplication.REJECTED
or obj.status == models.DomainApplication.INELIGIBLE
)
and not obj.domain_is_not_active()
):
# If an admin tried to set an approved application to
# rejected or ineligible and the related domain is already
# active, shortcut the action and throw a friendly
# error message. This action would still not go through
# shortcut or not as the rules are duplicated on the model,
# but the error would be an ugly Django error screen.
super().save_model(request, obj, form, change)
# Clear the success message
messages.set_level(request, messages.ERROR)
messages.error(
request,
"This action is not permitted. The domain "
+ "is already active.",
)
else:
if obj.status != original_obj.status:
status_method_mapping = {
models.DomainApplication.STARTED: None,
models.DomainApplication.SUBMITTED: obj.submit,
models.DomainApplication.IN_REVIEW: obj.in_review,
models.DomainApplication.ACTION_NEEDED: obj.action_needed,
models.DomainApplication.APPROVED: obj.approve,
models.DomainApplication.WITHDRAWN: obj.withdraw,
models.DomainApplication.REJECTED: obj.reject,
models.DomainApplication.INELIGIBLE: (
obj.reject_with_prejudice
),
}
selected_method = status_method_mapping.get(obj.status)
if selected_method is None:
logger.warning("Unknown status selected in django admin")
else:
# This is an fsm in model which will throw an error if the
# transition condition is violated, so we roll back the
# status to what it was before the admin user changed it and
# let the fsm method set it.
obj.status = original_obj.status
selected_method()
super().save_model(request, obj, form, change)
else:
# Clear the success message
messages.set_level(request, messages.ERROR)
@ -616,6 +691,8 @@ class DomainAdmin(ListHeaderAdmin):
"_place_client_hold": self.do_place_client_hold,
"_remove_client_hold": self.do_remove_client_hold,
"_edit_domain": self.do_edit_domain,
"_delete_domain": self.do_delete_domain,
"_get_status": self.do_get_status,
}
# Check which action button was pressed and call the corresponding function
@ -625,6 +702,31 @@ class DomainAdmin(ListHeaderAdmin):
# If no matching action button is found, return the super method
return super().response_change(request, obj)
def do_delete_domain(self, request, obj):
try:
obj.deleted()
obj.save()
except Exception as err:
self.message_user(request, err, messages.ERROR)
else:
self.message_user(
request,
("Domain %s Should now be deleted " ". Thanks!") % obj.name,
)
return HttpResponseRedirect(".")
def do_get_status(self, request, obj):
try:
statuses = obj.statuses
except Exception as err:
self.message_user(request, err, messages.ERROR)
else:
self.message_user(
request,
("Domain statuses are %s" ". Thanks!") % statuses,
)
return HttpResponseRedirect(".")
def do_place_client_hold(self, request, obj):
try:
@ -645,7 +747,7 @@ class DomainAdmin(ListHeaderAdmin):
def do_remove_client_hold(self, request, obj):
try:
obj.remove_client_hold()
obj.revert_client_hold()
obj.save()
except Exception as err:
self.message_user(request, err, messages.ERROR)
@ -693,5 +795,6 @@ admin.site.register(models.DraftDomain, ListHeaderAdmin)
admin.site.register(models.Host, MyHostAdmin)
admin.site.register(models.Nameserver, MyHostAdmin)
admin.site.register(models.Website, WebsiteAdmin)
admin.site.register(models.PublicContact, AuditedAdmin)
admin.site.register(models.DomainApplication, DomainApplicationAdmin)
admin.site.register(models.TransitionDomain, AuditedAdmin)