Implement audit trail for status changes on domain request change form

This commit is contained in:
Rachid Mrad 2024-04-25 16:33:36 -04:00
parent ab1a63ee9c
commit ed9625e373
No known key found for this signature in database
3 changed files with 80 additions and 1 deletions

View file

@ -16,12 +16,21 @@ from .utility.time_stamped_model import TimeStampedModel
from ..utility.email import send_templated_email, EmailSendingError from ..utility.email import send_templated_email, EmailSendingError
from itertools import chain from itertools import chain
from auditlog.models import AuditlogHistoryField # type: ignore
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class DomainRequest(TimeStampedModel): class DomainRequest(TimeStampedModel):
"""A registrant's domain request for a new domain.""" """A registrant's domain request for a new domain."""
# https://django-auditlog.readthedocs.io/en/latest/usage.html#object-history
# If we note any performace degradation due to this addition,
# we can query the auditlogs table in admin.py and add the results to
# extra_context in the change_view method for DomainRequestAdmin
# This is the more straightforward way so trying it first.
history = AuditlogHistoryField()
# Constants for choice fields # Constants for choice fields
class DomainRequestStatus(models.TextChoices): class DomainRequestStatus(models.TextChoices):
STARTED = "started", "Started" STARTED = "started", "Started"

View file

@ -73,7 +73,37 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html)
{% block after_help_text %} {% block after_help_text %}
{% if field.field.name == "creator" %} {% if field.field.name == "status" and original_object.history.count > 0 %}
<div class="flex-container tablet:margin-top-1">
<label aria-label="Submitter contact details"></label>
<div class="usa-table-container--scrollable" tabindex="0">
<table class="usa-table usa-table--borderless">
<thead>
<tr>
<th data-sortable scope="col" role="columnheader">From</th>
<th data-sortable scope="col" role="columnheader">To</th>
<th data-sortable scope="col" role="columnheader">Changed By</th>
<th data-sortable scope="col" role="columnheader" aria-sort="ascending">Change Date</th>
</tr>
</thead>
<tbody>
{% for log_entry in original_object.history.all %}
{% for key, value in log_entry.changes_display_dict.items %}
{% if key == "status" %}
<tr>
<td>{{ value.0|default:"None" }}</td>
<td>{{ value.1|default:"None" }}</td>
<td>{{ log_entry.actor|default:"None" }}</td>
<td>{{ log_entry.timestamp|default:"None" }}</td>
</tr>
{% endif %}
{% endfor %}
{% endfor %}
</tbody>
</table>
</div>
</div>
{% elif field.field.name == "creator" %}
<div class="flex-container tablet:margin-top-1"> <div class="flex-container tablet:margin-top-1">
<label aria-label="Creator contact details"></label> <label aria-label="Creator contact details"></label>
{% include "django/admin/includes/contact_detail_list.html" with user=original_object.creator no_title_top_padding=field.is_readonly %} {% include "django/admin/includes/contact_detail_list.html" with user=original_object.creator no_title_top_padding=field.is_readonly %}

View file

@ -887,6 +887,46 @@ class TestDomainRequestAdmin(MockEppLib):
] ]
self.test_helper.assert_response_contains_distinct_values(response, expected_values) self.test_helper.assert_response_contains_distinct_values(response, expected_values)
@less_console_noise_decorator
def test_status_logs(self):
"""
Tests that the status changes are shown in a table on the domain request change form
"""
# Create a fake domain request and domain
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.STARTED)
p = "adminpass"
self.client.login(username="superuser", password=p)
response = self.client.get(
"/admin/registrar/domainrequest/{}/change/".format(domain_request.pk),
follow=True,
)
# Make sure the page loaded, and that we're on the right page
self.assertEqual(response.status_code, 200)
self.assertContains(response, domain_request.requested_domain.name)
# Table will contain From None To Started
self.assertContains(response, '<th data-sortable scope="col" role="columnheader">')
self.assertContains(response, "<td>None</td>")
self.assertContains(response, "<td>Started</td>", count=1)
self.assertNotContains(response, "<td>Submitted</td>")
domain_request.submit()
domain_request.save()
response = self.client.get(
"/admin/registrar/domainrequest/{}/change/".format(domain_request.pk),
follow=True,
)
# Table will contain From None To Started
# Table will contain From Started To Submitted
self.assertContains(response, "<td>None</td>")
self.assertContains(response, "<td>Started</td>", count=2)
self.assertContains(response, "<td>Submitted</td>")
@less_console_noise_decorator @less_console_noise_decorator
def test_analyst_can_see_and_edit_alternative_domain(self): def test_analyst_can_see_and_edit_alternative_domain(self):
"""Tests if an analyst can still see and edit the alternative domain field""" """Tests if an analyst can still see and edit the alternative domain field"""