Merge branch 'za/1852-user-contact-info-inline' into za/1848-copy-contact-email-to-clipboard

This commit is contained in:
zandercymatics 2024-03-28 12:06:54 -06:00
commit bcb1f80f57
No known key found for this signature in database
GPG key ID: FF4636ABEC9682B7
12 changed files with 287 additions and 231 deletions

View file

@ -925,6 +925,9 @@ class DomainInformationAdmin(ListHeaderAdmin):
),
]
# Readonly fields for analysts and superusers
readonly_fields = ("other_contacts",)
# Read only that we'll leverage for CISA Analysts
analyst_readonly_fields = [
"creator",
@ -936,7 +939,6 @@ class DomainInformationAdmin(ListHeaderAdmin):
"no_other_contacts_rationale",
"anything_else",
"is_policy_acknowledged",
"other_contacts",
]
# For each filter_horizontal, init in admin js extendFilterHorizontalWidgets
@ -1135,6 +1137,9 @@ class DomainRequestAdmin(ListHeaderAdmin):
),
]
# Readonly fields for analysts and superusers
readonly_fields = ("other_contacts", "current_websites", "alternative_domains")
# Read only that we'll leverage for CISA Analysts
analyst_readonly_fields = [
"creator",
@ -1142,8 +1147,6 @@ class DomainRequestAdmin(ListHeaderAdmin):
"requested_domain",
"approved_domain",
"alternative_domains",
"other_contacts",
"current_websites",
"purpose",
"submitter",
"no_other_contacts_rationale",
@ -1319,7 +1322,7 @@ class DomainRequestAdmin(ListHeaderAdmin):
readonly_fields.extend([field.name for field in self.model._meta.fields])
# Add the multi-select fields to readonly_fields:
# Complex fields like ManyToManyField require special handling
readonly_fields.extend(["current_websites", "other_contacts", "alternative_domains"])
readonly_fields.extend(["alternative_domains"])
if request.user.has_perm("registrar.full_access_permission"):
return readonly_fields
@ -1432,7 +1435,6 @@ class DomainAdmin(ListHeaderAdmin):
)
def queryset(self, request, queryset):
logger.debug(self.value())
if self.value() == "1":
return queryset.filter(domain_info__is_election_board=True)
if self.value() == "0":

View file

@ -230,32 +230,6 @@ function checkToListThenInitWidget(toListId, attempts) {
}
}
(function() {
function addUrlsToOtherContacts() {
document.addEventListener('DOMContentLoaded', function() {
// Select all table rows that have a data-contact-id attribute
let contactRows = document.querySelectorAll("tr[data-contact-url]");
if (contactRows){
// Add a click event listener to each row
let index = 1;
contactRows.forEach(function(row) {
let otherContactUrl = row.getAttribute("data-contact-url");
if (otherContactUrl){
let otherContact = document.querySelector(`.other-contact__${index}`);
if (otherContact) {
otherContact.href = otherContactUrl;
}
}
index++;
});
}
});
}
addUrlsToOtherContacts()
})();
// Initialize the widget:
// add related buttons to the widget for edit, delete and view
// add event listeners on the from list, the to list, and selector buttons which either enable or disable the related buttons

View file

@ -61,7 +61,6 @@
function createComparativeColumnChart(canvasId, title, labelOne, labelTwo) {
var canvas = document.getElementById(canvasId);
if (!canvas) {
console.log("Could not find canvas")
return
}

View file

@ -347,83 +347,103 @@ input.admin-confirm-button {
color: $dhs-blue-70;
}
.admin-icon-group {
position: relative;
display: flex;
align-items: center;
.usa-button__icon {
position: absolute;
right: 0;
height: 100%;
}
input {
// Allow for padding around the copy button
padding-right: 35px !important;
// Match the height of other inputs
min-height: 2.25rem !important;
}
}
td.font-size-sm {
button.usa-button__icon {
font-size: 16px;
}
}
details.dja-detail-table {
background-color: var(--darkened-bg);
display: inline-table;
background-color: var(--body-bg);
.dja-details-summary {
color: var(--header-link-color);
background-color: var(--primary);
cursor: pointer;
color: var(--body-quiet-color);
}
.dja-details-contents {
tr {
background-color: var(--darkened-bg);
@media (max-width: 1024px){
.dja-detail-contents {
max-width: 400px !important;
overflow-x: scroll !important;
}
}
}
table.dja-user-detail-table {
margin-left: 160px;
tr {
background-color: var(--body-bg);
}
}
.admin-icon-group {
position: relative;
display: flex;
align-items: center;
.usa-button__icon {
position: absolute;
right: 0;
height: 100%;
background-color: transparent;
}
input {
// Allow for padding around the copy button
padding-right: 35px !important;
// Match the height of other inputs
min-height: 2.25rem !important;
td, th {
padding-left: 12px;
border: none
}
thead > tr > th {
border-radius: 4px;
border-top: none;
border-bottom: none;
}
}
td.font-size-sm {
button.usa-button__icon {
font-size: 16px;
address.margin-top-neg-1__detail-list {
margin-top: -8px !important;
}
.dja-detail-list {
dl {
padding-left: 0px !important;
margin-top: 5px !important;
}
// Mimic the normal label size
dt {
font-size: 0.8125rem;
color: var(--body-quiet-color);
}
address {
font-size: 0.8125rem;
color: var(--body-quiet-color);
}
}
.no-outline-on-click:focus {
outline: none !important;
address.dja-address-contact-list {
font-size: 0.8125rem;
color: var(--body-quiet-color);
}
// Mimic the normal label size
@media (max-width: 1024px){
.dja-detail-list dt {
font-size: 0.875rem;
color: var(--body-quiet-color);
}
.dja-detail-list address {
font-size: 0.875rem;
color: var(--body-quiet-color);
}
}
.errors span.select2-selection {
border: 1px solid var(--error-fg) !important;
}
.admin-icon-group {
position: relative;
display: flex;
align-items: center;
.usa-button__icon {
position: absolute;
right: 0;
height: 100%;
}
input {
// Allow for padding around the copy button
padding-right: 35px !important;
// Match the height of other inputs
min-height: 2.25rem !important;
}
}
td.font-size-sm {
button.usa-button__icon {
font-size: 16px;
}
}

View file

@ -6,15 +6,11 @@ It is not inherently customizable on its own, so we can modify this instead.
https://github.com/django/django/blob/main/django/contrib/admin/templates/admin/includes/fieldset.html
{% endcomment %}
<fieldset class="module aligned {{ fieldset.classes }}">
{% block fieldset_title %}
{% if fieldset.name %}<h2>{{ fieldset.name }}</h2>{% endif %}
{% endblock fieldset_title %}
{% if fieldset.name %}<h2>{{ fieldset.name }}</h2>{% endif %}
{% block fieldset_description %}
{% if fieldset.description %}
<div class="description">{{ fieldset.description|safe }}</div>
{% endif %}
{% endblock fieldset_description %}
{% if fieldset.description %}
<div class="description">{{ fieldset.description|safe }}</div>
{% endif %}
{% for line in fieldset %}
<div class="form-row{% if line.fields|length == 1 and line.errors %} errors{% endif %}{% if not line.has_visible_field %} hidden{% endif %}{% for field in line %}{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% endfor %}">
@ -24,16 +20,19 @@ https://github.com/django/django/blob/main/django/contrib/admin/templates/admin/
{% if not line.fields|length == 1 and not field.is_readonly %}{{ field.errors }}{% endif %}
<div class="flex-container{% if not line.fields|length == 1 %} fieldBox{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% if not field.is_readonly and field.errors %} errors{% endif %}{% if field.field.is_hidden %} hidden{% endif %}{% elif field.is_checkbox %} checkbox-row{% endif %}">
{% if field.is_checkbox %}
{# .gov override #}
{% block field_checkbox %}
{{ field.field }}{{ field.label_tag }}
{% endblock field_checkbox%}
{% else %}
{{ field.label_tag }}
{% if field.is_readonly %}
{# .gov override #}
{% block field_readonly %}
<div class="readonly">{{ field.contents }}</div>
{% endblock field_readonly%}
{% else %}
{# .gov override #}
{% block field_other %}
{{ field.field }}
{% endblock field_other%}
@ -41,11 +40,8 @@ https://github.com/django/django/blob/main/django/contrib/admin/templates/admin/
{% endif %}
</div>
{% block before_help_text %}
{# For templating purposes #}
{% endblock before_help_text %}
{% if field.field.help_text %}
{# .gov override #}
{% block help_text %}
<div class="help"{% if field.field.id_for_label %} id="{{ field.field.id_for_label }}_helptext"{% endif %}>
<div>{{ field.field.help_text|safe }}</div>
@ -53,6 +49,7 @@ https://github.com/django/django/blob/main/django/contrib/admin/templates/admin/
{% endblock help_text %}
{% endif %}
{# .gov addition #}
{% block after_help_text %}
{# For templating purposes #}
{% endblock after_help_text %}

View file

@ -3,6 +3,13 @@
{% block field_sets %}
{% for fieldset in adminform %}
{% comment %}
TODO: this will eventually need to be changed to something like this
if we ever want to customize this file:
{% include "django/admin/includes/domain_information_fieldset.html" %}
Use detail_table_fieldset as an example, or just extend it.
{% endcomment %}
{% include "django/admin/includes/detail_table_fieldset.html" %}
{% endfor %}
{% endblock %}

View file

@ -4,8 +4,16 @@
{% block field_sets %}
{# Create an invisible <a> tag so that we can use a click event to toggle the modal. #}
<a id="invisible-ineligible-modal-toggler" class="display-none" href="#toggle-set-ineligible" aria-controls="toggle-set-ineligible" data-open-modal></a>
{% for fieldset in adminform %}
{% include "django/admin/includes/domain_request_fieldset.html" %}
{% comment %}
TODO: this will eventually need to be changed to something like this
if we ever want to customize this file:
{% include "django/admin/includes/domain_information_fieldset.html" %}
Use detail_table_fieldset as an example, or just extend it.
{% endcomment %}
{% include "django/admin/includes/detail_table_fieldset.html" %}
{% endfor %}
{% endblock %}

View file

@ -0,0 +1,51 @@
{% load i18n static %}
<address class="{% if no_title_top_padding %}margin-top-neg-1__detail-list{% endif %} dja-address-contact-list">
{% if show_formatted_name %}
{% if contact.get_formatted_name %}
<a href="{% url 'admin:registrar_contact_change' user.id %}">{{ user.get_formatted_name }}</a><br />
{% else %}
None<br />
{% endif %}
{% endif %}
{% if user.title or user.contact.title or user.email or user.contact.email or user.phone or user.contact.phone %}
{# Title #}
{% if user.title or user.contact.title %}
{% if user.contact.title %}
{{ user.contact.title }}
{% else %}
{{ user.title }}
{% endif %}
<br>
{% else %}
None<br>
{% endif %}
{# Email #}
{% if user.email or user.contact.email %}
{% if user.contact.email %}
{{ user.contact.email }}
{% else %}
{{ user.email }}
{% endif %}
<br>
{% else %}
None<br>
{% endif %}
{# Phone #}
{% if user.phone or user.contact.phone %}
{% if user.contact.phone %}
{{ user.contact.phone }}
{% else %}
{{ user.phone }}
{% endif %}
<br>
{% else %}
None<br>
{% endif %}
{% else %}
No additional contact information found.
{% endif %}
</address>

View file

@ -5,72 +5,102 @@
This is using a custom implementation fieldset.html (see admin/fieldset.html)
{% endcomment %}
{% block field_readonly %}
{% with all_contacts=original.other_contacts.all %}
{% if field.field.name == "other_contacts" %}
<div class="readonly">
{% for contact in field.contents|split:", " %}
<a href="#" class="other-contact__{{forloop.counter}}">{{ contact }}</a>{% if not forloop.last %}, {% endif %}
{% endfor %}
</div>
{% if all_contacts.count > 2 %}
<div class="readonly">
{% for contact in all_contacts %}
<a href="{% url 'admin:registrar_contact_change' contact.id %}">{{ contact.get_formatted_name }}</a>{% if not forloop.last %}, {% endif %}
{% endfor %}
</div>
{% else %}
<div class="flex-container dja-detail-list">
<dl class="usa-list usa-list--unstyled margin-0">
{% for contact in all_contacts %}
<dt class="{% if forloop.counter == 1%}margin-top-0{% endif %}">
Organization contact {{forloop.counter}}
</dt>
<dd>
{% include "django/admin/includes/contact_detail_list.html" with user=contact show_formatted_name=True %}
</dd>
{% endfor %}
</dl>
</div>
{% endif %}
{% elif field.field.name == "current_websites" %}
{% comment %}
The "website" model is essentially just a text field.
It is not useful to be redirected to the object definition,
rather it is more useful in this scenario to be redirected to the
actual website (as its just a plaintext string otherwise).
{% comment %}
The "website" model is essentially just a text field.
It is not useful to be redirected to the object definition,
rather it is more useful in this scenario to be redirected to the
actual website (as its just a plaintext string otherwise).
This ONLY applies to analysts. For superusers, its business as usual.
{% endcomment %}
{% for website in field.contents|split:", " %}
<a href="{{ website }}" class="padding-top-1 current-website__{{forloop.counter}}">{{ website }}</a>{% if not forloop.last %}, {% endif %}
{% endfor %}
This ONLY applies to analysts. For superusers, its business as usual.
{% endcomment %}
<div class="readonly">
{% with total_websites=field.contents|split:", " %}
{% for website in total_websites %}
<a href="{{ website }}" class="padding-top-1 current-website__{{forloop.counter}}">{{ website }}</a>{% if not forloop.last %}, {% endif %}
{# Acts as a <br> #}
{% if total_websites|length < 5 %}
<div class="display-block margin-top-1"></div>
{% endif %}
{% endfor %}
{% endwith %}
</div>
{% elif field.field.name == "alternative_domains" %}
<div class="readonly">
{% for alt_domain in original.alternative_domains.all %}
<a href="{% url 'admin:registrar_website_change' alt_domain.id %}">{{ alt_domain }}</a>{% if not forloop.last %}, {% endif %}
{% endfor %}
</div>
{% else %}
<div class="readonly">{{ field.contents }}</div>
{% endif %}
{% endwith %}
{% endblock field_readonly %}
{% block after_help_text %}
{% if field.field.name == "creator" %}
{% include "django/admin/includes/contact_detail_table.html" with user=original.creator field_name="creator" %}
<div class="flex-container">
<label aria-label="Creator contact details"></label>
{% include "django/admin/includes/contact_detail_list.html" with user=original.creator no_title_top_padding=field.is_readonly %}
</div>
{% elif field.field.name == "submitter" %}
{% include "django/admin/includes/contact_detail_table.html" with user=original.submitter field_name="submitter" %}
<div class="flex-container">
<label aria-label="Submitter contact details"></label>
{% include "django/admin/includes/contact_detail_list.html" with user=original.submitter no_title_top_padding=field.is_readonly %}
</div>
{% elif field.field.name == "authorizing_official" %}
{% include "django/admin/includes/contact_detail_table.html" with user=original.authorizing_official field_name="authorizing_official" %}
<div class="flex-container">
<label aria-label="Authorizing official contact details"></label>
{% include "django/admin/includes/contact_detail_list.html" with user=original.authorizing_official no_title_top_padding=field.is_readonly %}
</div>
{% elif field.field.name == "other_contacts" and original.other_contacts.all %}
<details class="margin-top-1 dja-detail-table">
<summary class="padding-1 dja-details-summary">Details</summary>
<div class="grid-container padding-left-0 padding-right-0 dja-details-contents">
<table>
<tbody>
{% for contact in original.other_contacts.all %}
{% comment %}
Since we can't get the id from field, we can embed this information here.
Then we can link these two fields using javascript.
{% endcomment %}
<tr data-contact-id="{{ contact.id }}" data-contact-url="{% url 'admin:registrar_contact_change' contact.id %}">
<th scope="row">{{contact.first_name}} {{contact.last_name}}</th>
<td>{{ contact.title }}</td>
<td>{{ contact.email }}</td>
<td>{{ contact.phone }}</td>
{# Copy button for the email #}
<td class="font-size-sm">
<input class="dja-clipboard-input" type="hidden" value="{{ contact.email }}">
<button
class="usa-button usa-button--unstyled usa-button__icon usa-button__clipboard text-no-underline"
type="button"
>
<svg
class="usa-icon"
>
<use aria-hidden="true" xlink:href="{%static 'img/sprite.svg'%}#content_copy"></use>
</svg>
Copy email
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</details>
{% with all_contacts=original.other_contacts.all %}
{% if all_contacts.count > 2 %}
<details class="margin-top-1 dja-detail-table" aria-role="button" open>
<summary class="padding-1 padding-left-0 dja-details-summary">Details</summary>
<div class="grid-container margin-left-0 padding-left-0 padding-right-0 dja-details-contents">
<table>
<thead>
<tr>
<th colspan="4">Other contact information</th>
<tr>
</thead>
<tbody>
{% for contact in all_contacts %}
<tr>
<th class="padding-left-1" scope="row">{{ contact.get_formatted_name }}</th>
<td class="padding-left-1">{{ contact.title }}</td>
<td class="padding-left-1">{{ contact.email }}</td>
<td class="padding-left-1">{{ contact.phone }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</details>
{% endif %}
{% endwith %}
{% endif %}
{% endblock after_help_text %}

View file

@ -1,2 +0,0 @@
{% extends "django/admin/includes/detail_table_fieldset.html" %}
{# Stubbed file for future expansion #}

View file

@ -1,2 +0,0 @@
{% extends "django/admin/includes/detail_table_fieldset.html" %}
{# Stubbed file for future expansion #}

View file

@ -1300,17 +1300,13 @@ class TestDomainRequestAdmin(MockEppLib):
# == Check for the creator == #
# Check for the right title, email, and phone number in the response.
# We only need to check for the end tag
# (Otherwise this test will fail if we change classes, etc)
expected_email = "meoward.jones@igorville.gov"
expected_creator_fields = [
# Field, expected value
("title", "Treat inspector</td>"),
("email", f"{expected_email}</td>"),
# Check for the existence of the copy button input.
# Lets keep things simple to minimize future conflicts.
("title", "Treat inspector"),
("email", "meoward.jones@igorville.gov"),
("phone", "(555) 123 12345"),
("email_copy_button_input", f'<input class="dja-clipboard-input" type="hidden" value="{expected_email}"'),
("phone", "(555) 123 12345</td>"),
]
self.test_helper.assert_response_contains_distinct_values(response, expected_creator_fields)
@ -1321,10 +1317,10 @@ class TestDomainRequestAdmin(MockEppLib):
expected_email = "mayor@igorville.gov"
expected_submitter_fields = [
# Field, expected value
("title", "Admin Tester</td>"),
("email", f"{expected_email}</td>"),
("title", "Admin Tester"),
("email", "mayor@igorville.gov"),
("phone", "(555) 555 5556"),
("email_copy_button_input", f'<input class="dja-clipboard-input" type="hidden" value="{expected_email}"'),
("phone", "(555) 555 5556</td>"),
]
self.test_helper.assert_response_contains_distinct_values(response, expected_submitter_fields)
self.assertContains(response, "Testy2 Tester2")
@ -1334,42 +1330,27 @@ class TestDomainRequestAdmin(MockEppLib):
expected_ao_fields = [
# Field, expected value
("title", "Chief Tester</td>"),
("email", f"{expected_email}</td>"),
("email_copy_button_input", f'<input class="dja-clipboard-input" type="hidden" value="{expected_email}"'),
("email", "testy@town.com</td>"),
("phone", "(555) 555 5555</td>"),
("email_copy_button_input", f'<input class="dja-clipboard-input" type="hidden" value="{expected_email}"'),
]
self.test_helper.assert_response_contains_distinct_values(response, expected_ao_fields)
# count=4 because the underlying domain has two users with this name.
# count=5 because the underlying domain has two users with this name.
# The dropdown has 3 of these.
self.assertContains(response, "Testy Tester", count=4)
# Check for table titles. We only need to check for the end tag
# (Otherwise this test will fail if we change classes, etc)
# Title. Count=3 because this table appears on three records.
self.assertContains(response, "Title</th>", count=3)
# Email. Count=3 because this table appears on three records.
self.assertContains(response, "Email</th>", count=3)
# Phone. Count=3 because this table appears on three records.
self.assertContains(response, "Phone</th>", count=3)
self.assertContains(response, "Testy Tester", count=5)
# == Test the other_employees field == #
expected_email = "testy@town.com"
expected_other_employees_fields = [
# Field, expected value
("title", "Another Tester</td>"),
("email", f"{expected_email}</td>"),
("title", "Another Tester"),
("email", "testy2@town.com"),
("phone", "(555) 555 5557"),
("email_copy_button_input", f'<input class="dja-clipboard-input" type="hidden" value="{expected_email}"'),
("phone", "(555) 555 5557</td>"),
]
self.test_helper.assert_response_contains_distinct_values(response, expected_other_employees_fields)
# count=1 as only one should exist in a table
self.assertContains(response, "Testy Tester</th>", count=1)
def test_save_model_sets_restricted_status_on_user(self):
with less_console_noise():
# make sure there is no user with this email
@ -1453,6 +1434,7 @@ class TestDomainRequestAdmin(MockEppLib):
self.assertContains(response, "Yes, select ineligible status")
def test_readonly_when_restricted_creator(self):
self.maxDiff = None
with less_console_noise():
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW)
with boto3_mocking.clients.handler_for("sesv2", self.mock_client):
@ -1465,6 +1447,9 @@ class TestDomainRequestAdmin(MockEppLib):
readonly_fields = self.admin.get_readonly_fields(request, domain_request)
expected_fields = [
"other_contacts",
"current_websites",
"alternative_domains",
"id",
"created_at",
"updated_at",
@ -1497,8 +1482,6 @@ class TestDomainRequestAdmin(MockEppLib):
"is_policy_acknowledged",
"submission_date",
"notes",
"current_websites",
"other_contacts",
"alternative_domains",
]
@ -1512,13 +1495,14 @@ class TestDomainRequestAdmin(MockEppLib):
readonly_fields = self.admin.get_readonly_fields(request)
expected_fields = [
"other_contacts",
"current_websites",
"alternative_domains",
"creator",
"about_your_organization",
"requested_domain",
"approved_domain",
"alternative_domains",
"other_contacts",
"current_websites",
"purpose",
"submitter",
"no_other_contacts_rationale",
@ -1535,7 +1519,11 @@ class TestDomainRequestAdmin(MockEppLib):
readonly_fields = self.admin.get_readonly_fields(request)
expected_fields = []
expected_fields = [
"other_contacts",
"current_websites",
"alternative_domains",
]
self.assertEqual(readonly_fields, expected_fields)
@ -1979,6 +1967,7 @@ class TestDomainInformationAdmin(TestCase):
p = "userpass"
self.client.login(username="staffuser", password=p)
response = self.client.get(
"/admin/registrar/domaininformation/{}/change/".format(domain_info.pk),
follow=True,
@ -2043,12 +2032,10 @@ class TestDomainInformationAdmin(TestCase):
expected_email = "meoward.jones@igorville.gov"
expected_creator_fields = [
# Field, expected value
("title", "Treat inspector</td>"),
("email", f"{expected_email}</td>"),
# Check for the existence of the copy button input.
# Lets keep things simple to minimize future conflicts.
("title", "Treat inspector"),
("email", "meoward.jones@igorville.gov"),
("phone", "(555) 123 12345"),
("email_copy_button_input", f'<input class="dja-clipboard-input" type="hidden" value="{expected_email}"'),
("phone", "(555) 123 12345</td>"),
]
self.test_helper.assert_response_contains_distinct_values(response, expected_creator_fields)
@ -2059,10 +2046,10 @@ class TestDomainInformationAdmin(TestCase):
expected_email = "mayor@igorville.gov"
expected_submitter_fields = [
# Field, expected value
("title", "Admin Tester</td>"),
("email", f"{expected_email}</td>"),
("title", "Admin Tester"),
("email", "mayor@igorville.gov"),
("phone", "(555) 555 5556"),
("email_copy_button_input", f'<input class="dja-clipboard-input" type="hidden" value="{expected_email}"'),
("phone", "(555) 555 5556</td>"),
]
self.test_helper.assert_response_contains_distinct_values(response, expected_submitter_fields)
self.assertContains(response, "Testy2 Tester2")
@ -2071,43 +2058,28 @@ class TestDomainInformationAdmin(TestCase):
expected_email = "testy@town.com"
expected_ao_fields = [
# Field, expected value
("title", "Chief Tester</td>"),
("email", "testy@town.com</td>"),
("title", "Chief Tester"),
("email", "testy@town.com"),
("phone", "(555) 555 5555"),
("email_copy_button_input", f'<input class="dja-clipboard-input" type="hidden" value="{expected_email}"'),
("phone", "(555) 555 5555</td>"),
]
self.test_helper.assert_response_contains_distinct_values(response, expected_ao_fields)
# count=4 because the underlying domain has two users with this name.
# count=5 because the underlying domain has two users with this name.
# The dropdown has 3 of these.
self.assertContains(response, "Testy Tester", count=4)
# Check for table titles. We only need to check for the end tag
# (Otherwise this test will fail if we change classes, etc)
# Title. Count=3 because this table appears on three records.
self.assertContains(response, "Title</th>", count=3)
# Email. Count=3 because this table appears on three records.
self.assertContains(response, "Email</th>", count=3)
# Phone. Count=3 because this table appears on three records.
self.assertContains(response, "Phone</th>", count=3)
self.assertContains(response, "Testy Tester", count=5)
# == Test the other_employees field == #
expected_email = "testy@town.com"
expected_other_employees_fields = [
# Field, expected value
("title", "Another Tester</td>"),
("email", f"{expected_email}</td>"),
("title", "Another Tester"),
("email", "testy2@town.com"),
("phone", "(555) 555 5557"),
("email_copy_button_input", f'<input class="dja-clipboard-input" type="hidden" value="{expected_email}"'),
("phone", "(555) 555 5557</td>"),
]
self.test_helper.assert_response_contains_distinct_values(response, expected_other_employees_fields)
# count=1 as only one should exist in a table
self.assertContains(response, "Testy Tester</th>", count=1)
def test_readonly_fields_for_analyst(self):
"""Ensures that analysts have their permissions setup correctly"""
with less_console_noise():
@ -2117,6 +2089,7 @@ class TestDomainInformationAdmin(TestCase):
readonly_fields = self.admin.get_readonly_fields(request)
expected_fields = [
"other_contacts",
"creator",
"type_of_work",
"more_organization_information",
@ -2126,7 +2099,6 @@ class TestDomainInformationAdmin(TestCase):
"no_other_contacts_rationale",
"anything_else",
"is_policy_acknowledged",
"other_contacts",
]
self.assertEqual(readonly_fields, expected_fields)