mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-22 10:46:06 +02:00
Merge pull request #1997 from cisagov/dk/1850-request-user-details
Issue #1850 : Indicate whether creator has other domains
This commit is contained in:
commit
64d0ec3f93
8 changed files with 180 additions and 2 deletions
|
@ -536,6 +536,18 @@ address.dja-address-contact-list {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dja-status-list {
|
||||||
|
border-top: solid 1px var(--border-color);
|
||||||
|
margin-left: 0 !important;
|
||||||
|
padding-left: 0 !important;
|
||||||
|
padding-top: 10px;
|
||||||
|
li {
|
||||||
|
line-height: 1.5;
|
||||||
|
font-family: "Source Sans Pro Web", "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif !important;
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Make the clipboard button "float" inside of the input box
|
// Make the clipboard button "float" inside of the input box
|
||||||
.admin-icon-group {
|
.admin-icon-group {
|
||||||
|
|
|
@ -94,6 +94,9 @@ class Contact(TimeStampedModel):
|
||||||
names = [n for n in [self.first_name, self.middle_name, self.last_name] if n]
|
names = [n for n in [self.first_name, self.middle_name, self.last_name] if n]
|
||||||
return " ".join(names) if names else "Unknown"
|
return " ".join(names) if names else "Unknown"
|
||||||
|
|
||||||
|
def has_contact_info(self):
|
||||||
|
return bool(self.title or self.email or self.phone)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
# Call the parent class's save method to perform the actual save
|
# Call the parent class's save method to perform the actual save
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
|
@ -9,6 +9,7 @@ from .domain_invitation import DomainInvitation
|
||||||
from .transition_domain import TransitionDomain
|
from .transition_domain import TransitionDomain
|
||||||
from .verified_by_staff import VerifiedByStaff
|
from .verified_by_staff import VerifiedByStaff
|
||||||
from .domain import Domain
|
from .domain import Domain
|
||||||
|
from .domain_request import DomainRequest
|
||||||
|
|
||||||
from phonenumber_field.modelfields import PhoneNumberField # type: ignore
|
from phonenumber_field.modelfields import PhoneNumberField # type: ignore
|
||||||
|
|
||||||
|
@ -67,6 +68,33 @@ class User(AbstractUser):
|
||||||
def is_restricted(self):
|
def is_restricted(self):
|
||||||
return self.status == self.RESTRICTED
|
return self.status == self.RESTRICTED
|
||||||
|
|
||||||
|
def get_approved_domains_count(self):
|
||||||
|
"""Return count of approved domains"""
|
||||||
|
allowed_states = [Domain.State.UNKNOWN, Domain.State.DNS_NEEDED, Domain.State.READY, Domain.State.ON_HOLD]
|
||||||
|
approved_domains_count = self.domains.filter(state__in=allowed_states).count()
|
||||||
|
return approved_domains_count
|
||||||
|
|
||||||
|
def get_active_requests_count(self):
|
||||||
|
"""Return count of active requests"""
|
||||||
|
allowed_states = [
|
||||||
|
DomainRequest.DomainRequestStatus.SUBMITTED,
|
||||||
|
DomainRequest.DomainRequestStatus.IN_REVIEW,
|
||||||
|
DomainRequest.DomainRequestStatus.ACTION_NEEDED,
|
||||||
|
]
|
||||||
|
active_requests_count = self.domain_requests_created.filter(status__in=allowed_states).count()
|
||||||
|
return active_requests_count
|
||||||
|
|
||||||
|
def get_rejected_requests_count(self):
|
||||||
|
"""Return count of rejected requests"""
|
||||||
|
return self.domain_requests_created.filter(status=DomainRequest.DomainRequestStatus.REJECTED).count()
|
||||||
|
|
||||||
|
def get_ineligible_requests_count(self):
|
||||||
|
"""Return count of ineligible requests"""
|
||||||
|
return self.domain_requests_created.filter(status=DomainRequest.DomainRequestStatus.INELIGIBLE).count()
|
||||||
|
|
||||||
|
def has_contact_info(self):
|
||||||
|
return bool(self.contact.title or self.contact.email or self.contact.phone)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def needs_identity_verification(cls, email, uuid):
|
def needs_identity_verification(cls, email, uuid):
|
||||||
"""A method used by our oidc classes to test whether a user needs email/uuid verification
|
"""A method used by our oidc classes to test whether a user needs email/uuid verification
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{% load i18n static %}
|
{% load i18n static %}
|
||||||
|
|
||||||
<address class="{% if no_title_top_padding %}margin-top-neg-1__detail-list{% endif %} dja-address-contact-list">
|
<address class="{% if no_title_top_padding %}margin-top-neg-1__detail-list{% endif %} {% if user.has_contact_info %}margin-bottom-1{% endif %} dja-address-contact-list">
|
||||||
|
|
||||||
{% if show_formatted_name %}
|
{% if show_formatted_name %}
|
||||||
{% if contact.get_formatted_name %}
|
{% if contact.get_formatted_name %}
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if user.title or user.contact.title or user.email or user.contact.email or user.phone or user.contact.phone %}
|
{% if user.has_contact_info %}
|
||||||
{# Title #}
|
{# Title #}
|
||||||
{% if user.title or user.contact.title %}
|
{% if user.title or user.contact.title %}
|
||||||
{% if user.contact.title %}
|
{% if user.contact.title %}
|
||||||
|
|
|
@ -71,6 +71,10 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html)
|
||||||
<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.creator no_title_top_padding=field.is_readonly %}
|
{% include "django/admin/includes/contact_detail_list.html" with user=original.creator no_title_top_padding=field.is_readonly %}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex-container">
|
||||||
|
<label aria-label="User summary details"></label>
|
||||||
|
{% include "django/admin/includes/user_detail_list.html" with user=original.creator no_title_top_padding=field.is_readonly %}
|
||||||
|
</div>
|
||||||
{% elif field.field.name == "submitter" %}
|
{% elif field.field.name == "submitter" %}
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<label aria-label="Submitter contact details"></label>
|
<label aria-label="Submitter contact details"></label>
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
{% load i18n static %}
|
||||||
|
|
||||||
|
{% with approved_domains_count=user.get_approved_domains_count %}
|
||||||
|
{% with active_requests_count=user.get_active_requests_count %}
|
||||||
|
{% with rejected_requests_count=user.get_rejected_requests_count %}
|
||||||
|
{% with ineligible_requests_count=user.get_ineligible_requests_count %}
|
||||||
|
{% if approved_domains_count|add:active_requests_count|add:rejected_requests_count|add:ineligible_requests_count > 0 %}
|
||||||
|
<ul class="dja-status-list">
|
||||||
|
{% if approved_domains_count > 0 %}
|
||||||
|
{# Approved domains #}
|
||||||
|
<li>Approved domains: {{ approved_domains_count }}</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if active_requests_count > 0 %}
|
||||||
|
{# Active requests #}
|
||||||
|
<li>Active requests: {{ active_requests_count }}</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if rejected_requests_count > 0 %}
|
||||||
|
{# Rejected requests #}
|
||||||
|
<li>Rejected requests: {{ rejected_requests_count }}</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if ineligible_requests_count > 0 %}
|
||||||
|
{# Ineligible requests #}
|
||||||
|
<li>Ineligible requests: {{ ineligible_requests_count }}</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endwith %}
|
|
@ -1676,6 +1676,10 @@ class TestDomainRequestAdmin(MockEppLib):
|
||||||
# Test for the copy link
|
# Test for the copy link
|
||||||
self.assertContains(response, "usa-button__clipboard", count=4)
|
self.assertContains(response, "usa-button__clipboard", count=4)
|
||||||
|
|
||||||
|
# Test that Creator counts display properly
|
||||||
|
self.assertNotContains(response, "Approved domains")
|
||||||
|
self.assertContains(response, "Active requests")
|
||||||
|
|
||||||
def test_save_model_sets_restricted_status_on_user(self):
|
def test_save_model_sets_restricted_status_on_user(self):
|
||||||
with less_console_noise():
|
with less_console_noise():
|
||||||
# make sure there is no user with this email
|
# make sure there is no user with this email
|
||||||
|
|
|
@ -1004,6 +1004,8 @@ class TestUser(TestCase):
|
||||||
Domain.objects.all().delete()
|
Domain.objects.all().delete()
|
||||||
DomainInvitation.objects.all().delete()
|
DomainInvitation.objects.all().delete()
|
||||||
DomainInformation.objects.all().delete()
|
DomainInformation.objects.all().delete()
|
||||||
|
DomainRequest.objects.all().delete()
|
||||||
|
DraftDomain.objects.all().delete()
|
||||||
TransitionDomain.objects.all().delete()
|
TransitionDomain.objects.all().delete()
|
||||||
User.objects.all().delete()
|
User.objects.all().delete()
|
||||||
UserDomainRole.objects.all().delete()
|
UserDomainRole.objects.all().delete()
|
||||||
|
@ -1060,6 +1062,91 @@ class TestUser(TestCase):
|
||||||
# Domain Invitation, then save routine should be called exactly once
|
# Domain Invitation, then save routine should be called exactly once
|
||||||
save_mock.assert_called_once()
|
save_mock.assert_called_once()
|
||||||
|
|
||||||
|
def test_approved_domains_count(self):
|
||||||
|
"""Test that the correct approved domain count is returned for a user"""
|
||||||
|
# with no associated approved domains, expect this to return 0
|
||||||
|
self.assertEquals(self.user.get_approved_domains_count(), 0)
|
||||||
|
# with one approved domain, expect this to return 1
|
||||||
|
UserDomainRole.objects.get_or_create(user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER)
|
||||||
|
self.assertEquals(self.user.get_approved_domains_count(), 1)
|
||||||
|
# with one approved domain, expect this to return 1 (domain2 is deleted, so not considered approved)
|
||||||
|
domain2, _ = Domain.objects.get_or_create(name="igorville2.gov", state=Domain.State.DELETED)
|
||||||
|
UserDomainRole.objects.get_or_create(user=self.user, domain=domain2, role=UserDomainRole.Roles.MANAGER)
|
||||||
|
self.assertEquals(self.user.get_approved_domains_count(), 1)
|
||||||
|
# with two approved domains, expect this to return 2
|
||||||
|
domain3, _ = Domain.objects.get_or_create(name="igorville3.gov", state=Domain.State.DNS_NEEDED)
|
||||||
|
UserDomainRole.objects.get_or_create(user=self.user, domain=domain3, role=UserDomainRole.Roles.MANAGER)
|
||||||
|
self.assertEquals(self.user.get_approved_domains_count(), 2)
|
||||||
|
# with three approved domains, expect this to return 3
|
||||||
|
domain4, _ = Domain.objects.get_or_create(name="igorville4.gov", state=Domain.State.ON_HOLD)
|
||||||
|
UserDomainRole.objects.get_or_create(user=self.user, domain=domain4, role=UserDomainRole.Roles.MANAGER)
|
||||||
|
self.assertEquals(self.user.get_approved_domains_count(), 3)
|
||||||
|
# with four approved domains, expect this to return 4
|
||||||
|
domain5, _ = Domain.objects.get_or_create(name="igorville5.gov", state=Domain.State.READY)
|
||||||
|
UserDomainRole.objects.get_or_create(user=self.user, domain=domain5, role=UserDomainRole.Roles.MANAGER)
|
||||||
|
self.assertEquals(self.user.get_approved_domains_count(), 4)
|
||||||
|
|
||||||
|
def test_active_requests_count(self):
|
||||||
|
"""Test that the correct active domain requests count is returned for a user"""
|
||||||
|
# with no associated active requests, expect this to return 0
|
||||||
|
self.assertEquals(self.user.get_active_requests_count(), 0)
|
||||||
|
# with one active request, expect this to return 1
|
||||||
|
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville1.gov")
|
||||||
|
DomainRequest.objects.create(
|
||||||
|
creator=self.user, requested_domain=draft_domain, status=DomainRequest.DomainRequestStatus.SUBMITTED
|
||||||
|
)
|
||||||
|
self.assertEquals(self.user.get_active_requests_count(), 1)
|
||||||
|
# with two active requests, expect this to return 2
|
||||||
|
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville2.gov")
|
||||||
|
DomainRequest.objects.create(
|
||||||
|
creator=self.user, requested_domain=draft_domain, status=DomainRequest.DomainRequestStatus.IN_REVIEW
|
||||||
|
)
|
||||||
|
self.assertEquals(self.user.get_active_requests_count(), 2)
|
||||||
|
# with three active requests, expect this to return 3
|
||||||
|
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville3.gov")
|
||||||
|
DomainRequest.objects.create(
|
||||||
|
creator=self.user, requested_domain=draft_domain, status=DomainRequest.DomainRequestStatus.ACTION_NEEDED
|
||||||
|
)
|
||||||
|
self.assertEquals(self.user.get_active_requests_count(), 3)
|
||||||
|
# with three active requests, expect this to return 3 (STARTED is not considered active)
|
||||||
|
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville4.gov")
|
||||||
|
DomainRequest.objects.create(
|
||||||
|
creator=self.user, requested_domain=draft_domain, status=DomainRequest.DomainRequestStatus.STARTED
|
||||||
|
)
|
||||||
|
self.assertEquals(self.user.get_active_requests_count(), 3)
|
||||||
|
|
||||||
|
def test_rejected_requests_count(self):
|
||||||
|
"""Test that the correct rejected domain requests count is returned for a user"""
|
||||||
|
# with no associated rejected requests, expect this to return 0
|
||||||
|
self.assertEquals(self.user.get_rejected_requests_count(), 0)
|
||||||
|
# with one rejected request, expect this to return 1
|
||||||
|
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville1.gov")
|
||||||
|
DomainRequest.objects.create(
|
||||||
|
creator=self.user, requested_domain=draft_domain, status=DomainRequest.DomainRequestStatus.REJECTED
|
||||||
|
)
|
||||||
|
self.assertEquals(self.user.get_rejected_requests_count(), 1)
|
||||||
|
|
||||||
|
def test_ineligible_requests_count(self):
|
||||||
|
"""Test that the correct ineligible domain requests count is returned for a user"""
|
||||||
|
# with no associated ineligible requests, expect this to return 0
|
||||||
|
self.assertEquals(self.user.get_ineligible_requests_count(), 0)
|
||||||
|
# with one ineligible request, expect this to return 1
|
||||||
|
draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville1.gov")
|
||||||
|
DomainRequest.objects.create(
|
||||||
|
creator=self.user, requested_domain=draft_domain, status=DomainRequest.DomainRequestStatus.INELIGIBLE
|
||||||
|
)
|
||||||
|
self.assertEquals(self.user.get_ineligible_requests_count(), 1)
|
||||||
|
|
||||||
|
def test_has_contact_info(self):
|
||||||
|
"""Test that has_contact_info properly returns"""
|
||||||
|
# test with a user with contact info defined
|
||||||
|
self.assertTrue(self.user.has_contact_info())
|
||||||
|
# test with a user without contact info defined
|
||||||
|
self.user.contact.title = None
|
||||||
|
self.user.contact.email = None
|
||||||
|
self.user.contact.phone = None
|
||||||
|
self.assertFalse(self.user.has_contact_info())
|
||||||
|
|
||||||
|
|
||||||
class TestContact(TestCase):
|
class TestContact(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -1162,6 +1249,16 @@ class TestContact(TestCase):
|
||||||
self.assertFalse(self.contact_as_ao.has_more_than_one_join("authorizing_official"))
|
self.assertFalse(self.contact_as_ao.has_more_than_one_join("authorizing_official"))
|
||||||
self.assertTrue(self.contact_as_ao.has_more_than_one_join("submitted_domain_requests"))
|
self.assertTrue(self.contact_as_ao.has_more_than_one_join("submitted_domain_requests"))
|
||||||
|
|
||||||
|
def test_has_contact_info(self):
|
||||||
|
"""Test that has_contact_info properly returns"""
|
||||||
|
# test with a contact with contact info defined
|
||||||
|
self.assertTrue(self.contact.has_contact_info())
|
||||||
|
# test with a contact without contact info defined
|
||||||
|
self.contact.title = None
|
||||||
|
self.contact.email = None
|
||||||
|
self.contact.phone = None
|
||||||
|
self.assertFalse(self.contact.has_contact_info())
|
||||||
|
|
||||||
|
|
||||||
class TestDomainRequestCustomSave(TestCase):
|
class TestDomainRequestCustomSave(TestCase):
|
||||||
"""Tests custom save behaviour on the DomainRequest object"""
|
"""Tests custom save behaviour on the DomainRequest object"""
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue