mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-15 17:17:02 +02:00
Merge branch 'main' into za/1456-sorting-not-working-correctly
This commit is contained in:
commit
c01b241ea3
2 changed files with 261 additions and 10 deletions
|
@ -12,6 +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.user import User
|
||||
from registrar.utility import csv_export
|
||||
from registrar.views.utility.mixins import OrderableFieldsMixin
|
||||
from django.contrib.admin.views.main import ORDER_VAR
|
||||
|
@ -628,6 +629,9 @@ class DomainInformationAdmin(ListHeaderAdmin):
|
|||
# to activate the edit/delete/view buttons
|
||||
filter_horizontal = ("other_contacts",)
|
||||
|
||||
# Table ordering
|
||||
ordering = ["domain__name"]
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
"""Set the read-only state on form elements.
|
||||
We have 1 conditions that determine which fields are read-only:
|
||||
|
@ -679,6 +683,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",
|
||||
|
@ -696,7 +721,7 @@ class DomainApplicationAdmin(ListHeaderAdmin):
|
|||
]
|
||||
|
||||
# Filters
|
||||
list_filter = ("status", "organization_type", "investigator")
|
||||
list_filter = ("status", "organization_type", InvestigatorFilter)
|
||||
|
||||
# Search
|
||||
search_fields = [
|
||||
|
@ -772,6 +797,23 @@ 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):
|
||||
if db_field.name in ("current_websites", "alternative_domains"):
|
||||
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:
|
||||
|
@ -961,6 +1003,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")
|
||||
|
|
|
@ -15,14 +15,7 @@ from registrar.admin import (
|
|||
DomainInformationAdmin,
|
||||
UserDomainRoleAdmin,
|
||||
)
|
||||
from registrar.models import (
|
||||
Domain,
|
||||
DomainApplication,
|
||||
DomainInformation,
|
||||
User,
|
||||
DomainInvitation,
|
||||
Contact,
|
||||
)
|
||||
from registrar.models import Domain, DomainApplication, DomainInformation, User, DomainInvitation, Contact, Website
|
||||
from registrar.models.user_domain_role import UserDomainRole
|
||||
from .common import (
|
||||
AuditedAdminMockData,
|
||||
|
@ -325,6 +318,7 @@ class TestDomainApplicationAdmin(MockEppLib):
|
|||
self.admin = DomainApplicationAdmin(model=DomainApplication, admin_site=self.site)
|
||||
self.superuser = create_superuser()
|
||||
self.staffuser = create_user()
|
||||
self.client = Client(HTTP_HOST="localhost:8080")
|
||||
self.test_helper = GenericTestHelper(
|
||||
factory=self.factory,
|
||||
user=self.superuser,
|
||||
|
@ -924,12 +918,224 @@ class TestDomainApplicationAdmin(MockEppLib):
|
|||
with self.assertRaises(DomainInformation.DoesNotExist):
|
||||
domain_information.refresh_from_db()
|
||||
|
||||
def test_has_correct_filters(self):
|
||||
"""
|
||||
This test verifies that DomainApplicationAdmin has the correct filters set up.
|
||||
|
||||
It retrieves the current list of filters from DomainApplicationAdmin
|
||||
and checks that it matches the expected list of filters.
|
||||
"""
|
||||
request = self.factory.get("/")
|
||||
request.user = self.superuser
|
||||
|
||||
# Grab the current list of table filters
|
||||
readonly_fields = self.admin.get_list_filter(request)
|
||||
expected_fields = ("status", "organization_type", DomainApplicationAdmin.InvestigatorFilter)
|
||||
|
||||
self.assertEqual(readonly_fields, expected_fields)
|
||||
|
||||
def test_table_sorted_alphabetically(self):
|
||||
"""
|
||||
This test verifies that the DomainApplicationAdmin table is sorted alphabetically
|
||||
by the 'requested_domain__name' field.
|
||||
|
||||
It creates a list of DomainApplication instances in a non-alphabetical order,
|
||||
then retrieves the queryset from the DomainApplicationAdmin and checks
|
||||
that it matches the expected queryset,
|
||||
which is sorted alphabetically by the 'requested_domain__name' field.
|
||||
"""
|
||||
# Creates a list of DomainApplications in scrambled order
|
||||
multiple_unalphabetical_domain_objects("application")
|
||||
|
||||
request = self.factory.get("/")
|
||||
request.user = self.superuser
|
||||
|
||||
# Get the expected list of alphabetically sorted DomainApplications
|
||||
expected_order = DomainApplication.objects.order_by("requested_domain__name")
|
||||
|
||||
# Get the returned queryset
|
||||
queryset = self.admin.get_queryset(request)
|
||||
|
||||
# Check the order
|
||||
self.assertEqual(
|
||||
list(queryset),
|
||||
list(expected_order),
|
||||
)
|
||||
|
||||
def test_displays_investigator_filter(self):
|
||||
"""
|
||||
This test verifies that the investigator filter in the admin interface for
|
||||
the DomainApplication model displays correctly.
|
||||
|
||||
It creates two DomainApplication instances, each with a different investigator.
|
||||
It then simulates a staff user logging in and applying the investigator filter
|
||||
on the DomainApplication admin page.
|
||||
|
||||
We then test if the page displays the filter we expect, but we do not test
|
||||
if we get back the correct response in the table. This is to isolate if
|
||||
the filter displays correctly, when the filter isn't filtering correctly.
|
||||
"""
|
||||
|
||||
# Create a mock DomainApplication object, with a fake investigator
|
||||
application: DomainApplication = generic_domain_object("application", "SomeGuy")
|
||||
investigator_user = User.objects.filter(username=application.investigator.username).get()
|
||||
investigator_user.is_staff = True
|
||||
investigator_user.save()
|
||||
|
||||
p = "userpass"
|
||||
self.client.login(username="staffuser", password=p)
|
||||
response = self.client.get(
|
||||
"/admin/registrar/domainapplication/",
|
||||
{
|
||||
"investigator__id__exact": investigator_user.id,
|
||||
},
|
||||
follow=True,
|
||||
)
|
||||
|
||||
# Then, test if the filter actually exists
|
||||
self.assertIn("filters", response.context)
|
||||
|
||||
# Assert the content of filters and search_query
|
||||
filters = response.context["filters"]
|
||||
|
||||
self.assertEqual(
|
||||
filters,
|
||||
[
|
||||
{
|
||||
"parameter_name": "investigator",
|
||||
"parameter_value": "SomeGuy first_name:investigator SomeGuy last_name:investigator",
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
def test_investigator_filter_filters_correctly(self):
|
||||
"""
|
||||
This test verifies that the investigator filter in the admin interface for
|
||||
the DomainApplication model works correctly.
|
||||
|
||||
It creates two DomainApplication instances, each with a different investigator.
|
||||
It then simulates a staff user logging in and applying the investigator filter
|
||||
on the DomainApplication admin page.
|
||||
|
||||
It then verifies that it was applied correctly.
|
||||
The test checks that the response contains the expected DomainApplication pbjects
|
||||
in the table.
|
||||
"""
|
||||
|
||||
# Create a mock DomainApplication object, with a fake investigator
|
||||
application: DomainApplication = generic_domain_object("application", "SomeGuy")
|
||||
investigator_user = User.objects.filter(username=application.investigator.username).get()
|
||||
investigator_user.is_staff = True
|
||||
investigator_user.save()
|
||||
|
||||
# Create a second mock DomainApplication object, to test filtering
|
||||
application: DomainApplication = generic_domain_object("application", "BadGuy")
|
||||
another_user = User.objects.filter(username=application.investigator.username).get()
|
||||
another_user.is_staff = True
|
||||
another_user.save()
|
||||
|
||||
p = "userpass"
|
||||
self.client.login(username="staffuser", password=p)
|
||||
response = self.client.get(
|
||||
"/admin/registrar/domainapplication/",
|
||||
{
|
||||
"investigator__id__exact": investigator_user.id,
|
||||
},
|
||||
follow=True,
|
||||
)
|
||||
|
||||
expected_name = "SomeGuy first_name:investigator SomeGuy last_name:investigator"
|
||||
# We expect to see this four times, two of them are from the html for the filter,
|
||||
# and the other two are the html from the list entry in the table.
|
||||
self.assertContains(response, expected_name, count=4)
|
||||
|
||||
# Check that we don't also get the thing we aren't filtering for.
|
||||
# We expect to see this two times in the filter
|
||||
unexpected_name = "BadGuy first_name:investigator BadGuy last_name:investigator"
|
||||
self.assertContains(response, unexpected_name, count=2)
|
||||
|
||||
def test_investigator_dropdown_displays_only_staff(self):
|
||||
"""
|
||||
This test verifies that the dropdown for the 'investigator' field in the DomainApplicationAdmin
|
||||
interface only displays users who are marked as staff.
|
||||
|
||||
It creates two DomainApplication instances, one with an investigator
|
||||
who is a staff user and another with an investigator who is not a staff user.
|
||||
|
||||
It then retrieves the queryset for the 'investigator' dropdown from DomainApplicationAdmin
|
||||
and checks that it matches the expected queryset, which only includes staff users.
|
||||
"""
|
||||
# Create a mock DomainApplication object, with a fake investigator
|
||||
application: DomainApplication = generic_domain_object("application", "SomeGuy")
|
||||
investigator_user = User.objects.filter(username=application.investigator.username).get()
|
||||
investigator_user.is_staff = True
|
||||
investigator_user.save()
|
||||
|
||||
# Create a mock DomainApplication object, with a user that is not staff
|
||||
application_2: DomainApplication = generic_domain_object("application", "SomeOtherGuy")
|
||||
investigator_user_2 = User.objects.filter(username=application_2.investigator.username).get()
|
||||
investigator_user_2.is_staff = False
|
||||
investigator_user_2.save()
|
||||
|
||||
p = "userpass"
|
||||
self.client.login(username="staffuser", password=p)
|
||||
|
||||
request = self.factory.post("/admin/registrar/domainapplication/{}/change/".format(application.pk))
|
||||
|
||||
# Get the actual field from the model's meta information
|
||||
investigator_field = DomainApplication._meta.get_field("investigator")
|
||||
|
||||
# We should only be displaying staff users, in alphabetical order
|
||||
expected_dropdown = list(User.objects.filter(is_staff=True))
|
||||
current_dropdown = list(self.admin.formfield_for_foreignkey(investigator_field, request).queryset)
|
||||
|
||||
self.assertEqual(expected_dropdown, current_dropdown)
|
||||
|
||||
# Non staff users should not be in the list
|
||||
self.assertNotIn(application_2, current_dropdown)
|
||||
|
||||
def test_investigator_list_is_alphabetically_sorted(self):
|
||||
"""
|
||||
This test verifies that filter list for the 'investigator'
|
||||
is displayed alphabetically
|
||||
"""
|
||||
# Create a mock DomainApplication object, with a fake investigator
|
||||
application: DomainApplication = generic_domain_object("application", "SomeGuy")
|
||||
investigator_user = User.objects.filter(username=application.investigator.username).get()
|
||||
investigator_user.is_staff = True
|
||||
investigator_user.save()
|
||||
|
||||
application_2: DomainApplication = generic_domain_object("application", "AGuy")
|
||||
investigator_user_2 = User.objects.filter(username=application_2.investigator.username).get()
|
||||
investigator_user_2.first_name = "AGuy"
|
||||
investigator_user_2.is_staff = True
|
||||
investigator_user_2.save()
|
||||
|
||||
application_3: DomainApplication = generic_domain_object("application", "FinalGuy")
|
||||
investigator_user_3 = User.objects.filter(username=application_3.investigator.username).get()
|
||||
investigator_user_3.first_name = "FinalGuy"
|
||||
investigator_user_3.is_staff = True
|
||||
investigator_user_3.save()
|
||||
|
||||
p = "userpass"
|
||||
self.client.login(username="staffuser", password=p)
|
||||
request = RequestFactory().get("/")
|
||||
|
||||
expected_list = list(User.objects.filter(is_staff=True).order_by("first_name", "last_name", "email"))
|
||||
|
||||
# Get the actual sorted list of investigators from the lookups method
|
||||
actual_list = [item for _, item in self.admin.InvestigatorFilter.lookups(self, request, self.admin)]
|
||||
|
||||
self.assertEqual(expected_list, actual_list)
|
||||
|
||||
def tearDown(self):
|
||||
super().tearDown()
|
||||
Domain.objects.all().delete()
|
||||
DomainInformation.objects.all().delete()
|
||||
DomainApplication.objects.all().delete()
|
||||
User.objects.all().delete()
|
||||
Contact.objects.all().delete()
|
||||
Website.objects.all().delete()
|
||||
|
||||
|
||||
class DomainInvitationAdminTest(TestCase):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue