Merge pull request #2708 from cisagov/za/2671-show-portfolios-on-user-table

Ticket #2671: Show portfolios on user table
This commit is contained in:
zandercymatics 2024-09-12 13:02:54 -06:00 committed by GitHub
commit b25a441838
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 50 additions and 9 deletions

View file

@ -963,7 +963,9 @@ class MyUserAdmin(BaseUserAdmin, ImportExportModelAdmin):
domain_ids = user_domain_roles.values_list("domain_id", flat=True) domain_ids = user_domain_roles.values_list("domain_id", flat=True)
domains = Domain.objects.filter(id__in=domain_ids).exclude(state=Domain.State.DELETED) domains = Domain.objects.filter(id__in=domain_ids).exclude(state=Domain.State.DELETED)
extra_context = {"domain_requests": domain_requests, "domains": domains} portfolio_ids = obj.get_portfolios().values_list("portfolio", flat=True)
portfolios = models.Portfolio.objects.filter(id__in=portfolio_ids)
extra_context = {"domain_requests": domain_requests, "domains": domains, "portfolios": portfolios}
return super().change_view(request, object_id, form_url, extra_context) return super().change_view(request, object_id, form_url, extra_context)

View file

@ -298,6 +298,9 @@ class User(AbstractUser):
return roles return roles
def get_portfolios(self):
return self.portfolio_permissions.all()
@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

View file

@ -17,6 +17,26 @@
{% endblock %} {% endblock %}
{% block after_related_objects %} {% block after_related_objects %}
{% if portfolios %}
<div class="module aligned padding-3">
<h2>Portfolio information</h2>
<div class="grid-row grid-gap mobile:padding-x-1 desktop:padding-x-4">
<div class="mobile:grid-col-12 tablet:grid-col-6 desktop:grid-col-4">
<h3>Portfolios</h3>
<ul class="margin-0 padding-0">
{% for portfolio in portfolios %}
<li>
<a href="{% url 'admin:registrar_portfolio_change' portfolio.pk %}">
{{ portfolio }}
</a>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endif %}
<div class="module aligned padding-3"> <div class="module aligned padding-3">
<h2>Associated requests and domains</h2> <h2>Associated requests and domains</h2>
<div class="grid-row grid-gap mobile:padding-x-1 desktop:padding-x-4"> <div class="grid-row grid-gap mobile:padding-x-1 desktop:padding-x-4">

View file

@ -2,6 +2,7 @@ from datetime import datetime
from django.utils import timezone from django.utils import timezone
from django.test import TestCase, RequestFactory, Client from django.test import TestCase, RequestFactory, Client
from django.contrib.admin.sites import AdminSite from django.contrib.admin.sites import AdminSite
from django_webtest import WebTest # type: ignore
from api.tests.common import less_console_noise_decorator from api.tests.common import less_console_noise_decorator
from django.urls import reverse from django.urls import reverse
from registrar.admin import ( from registrar.admin import (
@ -41,13 +42,12 @@ from registrar.models import (
TransitionDomain, TransitionDomain,
Portfolio, Portfolio,
Suborganization, Suborganization,
UserPortfolioPermission,
UserDomainRole,
SeniorOfficial,
PortfolioInvitation,
VerifiedByStaff,
) )
from registrar.models.portfolio_invitation import PortfolioInvitation
from registrar.models.senior_official import SeniorOfficial
from registrar.models.user_domain_role import UserDomainRole
from registrar.models.user_portfolio_permission import UserPortfolioPermission
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
from registrar.models.verified_by_staff import VerifiedByStaff
from .common import ( from .common import (
MockDbForSharedTests, MockDbForSharedTests,
AuditedAdminMockData, AuditedAdminMockData,
@ -60,10 +60,11 @@ from .common import (
multiple_unalphabetical_domain_objects, multiple_unalphabetical_domain_objects,
GenericTestHelper, GenericTestHelper,
) )
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
from django.contrib.sessions.backends.db import SessionStore from django.contrib.sessions.backends.db import SessionStore
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from unittest.mock import ANY, patch, Mock from unittest.mock import ANY, patch, Mock
from django_webtest import WebTest # type: ignore
import logging import logging
@ -973,7 +974,7 @@ class TestListHeaderAdmin(TestCase):
) )
class TestMyUserAdmin(MockDbForSharedTests): class TestMyUserAdmin(MockDbForSharedTests, WebTest):
"""Tests for the MyUserAdmin class as super or staff user """Tests for the MyUserAdmin class as super or staff user
Notes: Notes:
@ -993,6 +994,7 @@ class TestMyUserAdmin(MockDbForSharedTests):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.app.set_user(self.superuser.username)
self.client = Client(HTTP_HOST="localhost:8080") self.client = Client(HTTP_HOST="localhost:8080")
def tearDown(self): def tearDown(self):
@ -1227,6 +1229,20 @@ class TestMyUserAdmin(MockDbForSharedTests):
self.assertNotContains(response, "Portfolio roles:") self.assertNotContains(response, "Portfolio roles:")
self.assertNotContains(response, "Portfolio additional permissions:") self.assertNotContains(response, "Portfolio additional permissions:")
@less_console_noise_decorator
def test_user_can_see_related_portfolios(self):
"""Tests if a user can see the portfolios they are associated with on the user page"""
portfolio, _ = Portfolio.objects.get_or_create(organization_name="test", creator=self.superuser)
permission, _ = UserPortfolioPermission.objects.get_or_create(
user=self.superuser, portfolio=portfolio, roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
)
response = self.app.get(reverse("admin:registrar_user_change", args=[self.superuser.pk]))
expected_href = reverse("admin:registrar_portfolio_change", args=[portfolio.pk])
self.assertContains(response, expected_href)
self.assertContains(response, str(portfolio))
permission.delete()
portfolio.delete()
class AuditedAdminTest(TestCase): class AuditedAdminTest(TestCase):