Merge branch 'main' into dk/1352-nameservers

This commit is contained in:
David Kennedy 2023-12-27 13:26:17 -05:00
commit 1d2bb4a3e9
No known key found for this signature in database
GPG key ID: 6528A5386E66B96B
29 changed files with 1057 additions and 598 deletions

View file

@ -1,5 +1,6 @@
import logging
from django import forms
from django.db.models.functions import Concat
from django.http import HttpResponse
from django.shortcuts import redirect
from django_fsm import get_available_FIELD_transitions
@ -11,7 +12,7 @@ from django.http.response import HttpResponseRedirect
from django.urls import reverse
from epplibwrapper.errors import ErrorCode, RegistryError
from registrar.models.domain import Domain
from registrar.models.utility.admin_sort_fields import AdminSortFields
from registrar.models.user import User
from registrar.utility import csv_export
from . import models
from auditlog.models import LogEntry # type: ignore
@ -45,7 +46,44 @@ class CustomLogEntryAdmin(LogEntryAdmin):
add_form_template = "admin/change_form_no_submit.html"
class AuditedAdmin(admin.ModelAdmin, AdminSortFields):
class AdminSortFields:
def get_queryset(db_field):
"""This is a helper function for formfield_for_manytomany and formfield_for_foreignkey"""
# customize sorting
if db_field.name in (
"other_contacts",
"authorizing_official",
"submitter",
):
# Sort contacts by first_name, then last_name, then email
return models.Contact.objects.all().order_by(Concat("first_name", "last_name", "email"))
elif db_field.name in ("current_websites", "alternative_domains"):
# sort web sites
return models.Website.objects.all().order_by("website")
elif db_field.name in (
"creator",
"user",
"investigator",
):
# Sort users by first_name, then last_name, then email
return models.User.objects.all().order_by(Concat("first_name", "last_name", "email"))
elif db_field.name in (
"domain",
"approved_domain",
):
# Sort domains by name
return models.Domain.objects.all().order_by("name")
elif db_field.name in ("requested_domain",):
# Sort draft domains by name
return models.DraftDomain.objects.all().order_by("name")
elif db_field.name in ("domain_application",):
# Sort domain applications by name
return models.DomainApplication.objects.all().order_by("requested_domain__name")
else:
return None
class AuditedAdmin(admin.ModelAdmin):
"""Custom admin to make auditing easier."""
def history_view(self, request, object_id, extra_context=None):
@ -58,10 +96,27 @@ class AuditedAdmin(admin.ModelAdmin, AdminSortFields):
)
)
def formfield_for_manytomany(self, db_field, request, **kwargs):
"""customize the behavior of formfields with manytomany relationships. the customized
behavior includes sorting of objects in lists as well as customizing helper text"""
queryset = AdminSortFields.get_queryset(db_field)
if queryset:
kwargs["queryset"] = queryset
formfield = super().formfield_for_manytomany(db_field, request, **kwargs)
# customize the help text for all formfields for manytomany
formfield.help_text = (
formfield.help_text
+ " If more than one value is selected, the change/delete/view actions will be disabled."
)
return formfield
def formfield_for_foreignkey(self, db_field, request, **kwargs):
"""Used to sort dropdown fields alphabetically but can be expanded upon"""
form_field = super().formfield_for_foreignkey(db_field, request, **kwargs)
return self.form_field_order_helper(form_field, db_field)
"""customize the behavior of formfields with foreign key relationships. this will customize
the behavior of selects. customized behavior includes sorting of objects in list"""
queryset = AdminSortFields.get_queryset(db_field)
if queryset:
kwargs["queryset"] = queryset
return super().formfield_for_foreignkey(db_field, request, **kwargs)
class ListHeaderAdmin(AuditedAdmin):
@ -118,15 +173,6 @@ class ListHeaderAdmin(AuditedAdmin):
)
return filters
# customize the help_text for all formfields for manytomany
def formfield_for_manytomany(self, db_field, request, **kwargs):
formfield = super().formfield_for_manytomany(db_field, request, **kwargs)
formfield.help_text = (
formfield.help_text
+ " If more than one value is selected, the change/delete/view actions will be disabled."
)
return formfield
class UserContactInline(admin.StackedInline):
"""Edit a user's profile on the user page."""
@ -221,6 +267,10 @@ class MyUserAdmin(BaseUserAdmin):
"groups",
)
# this ordering effects the ordering of results
# in autocomplete_fields for user
ordering = ["first_name", "last_name", "email"]
# Let's define First group
# (which should in theory be the ONLY group)
def group(self, obj):
@ -489,12 +539,8 @@ class DomainInformationAdmin(ListHeaderAdmin):
# to activate the edit/delete/view buttons
filter_horizontal = ("other_contacts",)
# lists in filter_horizontal are not sorted properly, sort them
# by first_name
def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name in ("other_contacts",):
kwargs["queryset"] = models.Contact.objects.all().order_by("first_name") # Sort contacts
return super().formfield_for_manytomany(db_field, request, **kwargs)
# Table ordering
ordering = ["domain__name"]
def get_readonly_fields(self, request, obj=None):
"""Set the read-only state on form elements.
@ -547,6 +593,27 @@ class DomainApplicationAdmin(ListHeaderAdmin):
"""Custom domain applications admin class."""
class InvestigatorFilter(admin.SimpleListFilter):
"""Custom investigator filter that only displays users with the manager role"""
title = "investigator"
# Match the old param name to avoid unnecessary refactoring
parameter_name = "investigator__id__exact"
def lookups(self, request, model_admin):
"""Lookup reimplementation, gets users of is_staff.
Returns a list of tuples consisting of (user.id, user)
"""
privileged_users = User.objects.filter(is_staff=True).order_by("first_name", "last_name", "email")
return [(user.id, user) for user in privileged_users]
def queryset(self, request, queryset):
"""Custom queryset implementation, filters by investigator"""
if self.value() is None:
return queryset
else:
return queryset.filter(investigator__id__exact=self.value())
# Columns
list_display = [
"requested_domain",
@ -558,7 +625,7 @@ class DomainApplicationAdmin(ListHeaderAdmin):
]
# Filters
list_filter = ("status", "organization_type", "investigator")
list_filter = ("status", "organization_type", InvestigatorFilter)
# Search
search_fields = [
@ -634,6 +701,9 @@ class DomainApplicationAdmin(ListHeaderAdmin):
filter_horizontal = ("current_websites", "alternative_domains", "other_contacts")
# Table ordering
ordering = ["requested_domain__name"]
# lists in filter_horizontal are not sorted properly, sort them
# by website
def formfield_for_manytomany(self, db_field, request, **kwargs):
@ -641,6 +711,13 @@ class DomainApplicationAdmin(ListHeaderAdmin):
kwargs["queryset"] = models.Website.objects.all().order_by("website") # Sort websites
return super().formfield_for_manytomany(db_field, request, **kwargs)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
# Removes invalid investigator options from the investigator dropdown
if db_field.name == "investigator":
kwargs["queryset"] = User.objects.filter(is_staff=True)
return db_field.formfield(**kwargs)
return super().formfield_for_foreignkey(db_field, request, **kwargs)
# Trigger action when a fieldset is changed
def save_model(self, request, obj, form, change):
if obj and obj.creator.status != models.User.RESTRICTED:
@ -774,12 +851,27 @@ class DomainInformationInline(admin.StackedInline):
# to activate the edit/delete/view buttons
filter_horizontal = ("other_contacts",)
# lists in filter_horizontal are not sorted properly, sort them
# by first_name
def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name in ("other_contacts",):
kwargs["queryset"] = models.Contact.objects.all().order_by("first_name") # Sort contacts
return super().formfield_for_manytomany(db_field, request, **kwargs)
"""customize the behavior of formfields with manytomany relationships. the customized
behavior includes sorting of objects in lists as well as customizing helper text"""
queryset = AdminSortFields.get_queryset(db_field)
if queryset:
kwargs["queryset"] = queryset
formfield = super().formfield_for_manytomany(db_field, request, **kwargs)
# customize the help text for all formfields for manytomany
formfield.help_text = (
formfield.help_text
+ " If more than one value is selected, the change/delete/view actions will be disabled."
)
return formfield
def formfield_for_foreignkey(self, db_field, request, **kwargs):
"""customize the behavior of formfields with foreign key relationships. this will customize
the behavior of selects. customized behavior includes sorting of objects in list"""
queryset = AdminSortFields.get_queryset(db_field)
if queryset:
kwargs["queryset"] = queryset
return super().formfield_for_foreignkey(db_field, request, **kwargs)
def get_readonly_fields(self, request, obj=None):
return DomainInformationAdmin.get_readonly_fields(self, request, obj=None)
@ -797,6 +889,10 @@ class DomainAdmin(ListHeaderAdmin):
"state",
]
# this ordering effects the ordering of results
# in autocomplete_fields for domain
ordering = ["name"]
def organization_type(self, obj):
return obj.domain_info.get_organization_type_display()
@ -811,6 +907,9 @@ class DomainAdmin(ListHeaderAdmin):
change_list_template = "django/admin/domain_change_list.html"
readonly_fields = ["state", "expiration_date"]
# Table ordering
ordering = ["name"]
def export_data_type(self, request):
# match the CSV example with all the fields
response = HttpResponse(content_type="text/csv")