Revise for multiple portfolios

This commit is contained in:
Rachid Mrad 2024-08-30 17:21:04 -04:00
parent fc2f4f08cc
commit 2af57c8aa8
No known key found for this signature in database
4 changed files with 65 additions and 31 deletions

View file

@ -10,6 +10,7 @@ from django.http import HttpResponseRedirect
from django.shortcuts import redirect from django.shortcuts import redirect
from django_fsm import get_available_FIELD_transitions, FSMField from django_fsm import get_available_FIELD_transitions, FSMField
from registrar.models.domain_information import DomainInformation from registrar.models.domain_information import DomainInformation
from registrar.models.user_portfolio_permission import UserPortfolioPermission
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
from waffle.decorators import flag_is_active from waffle.decorators import flag_is_active
from django.contrib import admin, messages from django.contrib import admin, messages
@ -3008,6 +3009,28 @@ class PortfolioAdmin(ListHeaderAdmin):
"creator", "creator",
] ]
def get_admin_users(self, obj):
# Filter UserPortfolioPermission objects related to the portfolio
admin_permissions = UserPortfolioPermission.objects.filter(
portfolio=obj, roles__contains=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
)
# Get the user objects associated with these permissions
admin_users = User.objects.filter(portfolio_permissions__in=admin_permissions)
return admin_users
def get_non_admin_users(self, obj):
# Filter UserPortfolioPermission objects related to the portfolio that do NOT have the "Admin" role
non_admin_permissions = UserPortfolioPermission.objects.filter(portfolio=obj).exclude(
roles__contains=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
)
# Get the user objects associated with these permissions
non_admin_users = User.objects.filter(portfolio_permissions__in=non_admin_permissions)
return non_admin_users
def display_admins(self, obj): def display_admins(self, obj):
"""Get joined users who are Admin, unpack and return an HTML block. """Get joined users who are Admin, unpack and return an HTML block.
@ -3016,7 +3039,7 @@ class PortfolioAdmin(ListHeaderAdmin):
data would display in a custom change form without extensive template customization. data would display in a custom change form without extensive template customization.
Will be used in the field_readonly block""" Will be used in the field_readonly block"""
admins = [user for user in obj.user.all() if "Admin" in user.portfolio_role_summary] admins = self.get_admin_users(obj)
if not admins: if not admins:
return format_html("<p>No admins found.</p>") return format_html("<p>No admins found.</p>")
@ -3030,13 +3053,13 @@ class PortfolioAdmin(ListHeaderAdmin):
admin_details += "<div class='admin-icon-group admin-icon-group__clipboard-link'>" admin_details += "<div class='admin-icon-group admin-icon-group__clipboard-link'>"
admin_details += f"<input aria-hidden='true' class='display-none' value='{portfolio_admin.email}'>" admin_details += f"<input aria-hidden='true' class='display-none' value='{portfolio_admin.email}'>"
admin_details += ( admin_details += (
"<button class='usa-button usa-button--unstyled padding-right-1 usa-button--icon" "<button class='usa-button usa-button--unstyled padding-right-1 usa-button--icon padding-left-05"
+ "button--clipboard copy-to-clipboard text-no-underline' type='button'>" + "button--clipboard copy-to-clipboard text-no-underline' type='button'>"
) )
admin_details += "<svg class='usa-icon'>" admin_details += "<svg class='usa-icon'>"
admin_details += "<use aria-hidden='true' xlink:href='/public/img/sprite.svg#content_copy'></use>" admin_details += "<use aria-hidden='true' xlink:href='/public/img/sprite.svg#content_copy'></use>"
admin_details += "</svg>" admin_details += "</svg>"
admin_details += "<span class='padding-left-05'>Copy</span>" admin_details += "Copy"
admin_details += "</button>" admin_details += "</button>"
admin_details += "</div><br>" admin_details += "</div><br>"
admin_details += f"{portfolio_admin.phone}" admin_details += f"{portfolio_admin.phone}"
@ -3053,7 +3076,7 @@ class PortfolioAdmin(ListHeaderAdmin):
data would display in a custom change form without extensive template customization. data would display in a custom change form without extensive template customization.
Will be used in the after_help_text block.""" Will be used in the after_help_text block."""
members = [user for user in obj.user.all() if "Admin" not in user.portfolio_role_summary] members = self.get_non_admin_users(obj)
if not members: if not members:
return "" return ""
@ -3073,7 +3096,7 @@ class PortfolioAdmin(ListHeaderAdmin):
member_details += f"<td>{member.email}</td>" member_details += f"<td>{member.email}</td>"
member_details += f"<td>{member.phone}</td>" member_details += f"<td>{member.phone}</td>"
member_details += "<td>" member_details += "<td>"
for role in member.portfolio_role_summary: for role in member.portfolio_role_summary(obj):
member_details += f"<span class='usa-tag'>{role}</span> " member_details += f"<span class='usa-tag'>{role}</span> "
member_details += "</td></tr>" member_details += "</td></tr>"
member_details += "</tbody></table>" member_details += "</tbody></table>"
@ -3083,7 +3106,7 @@ class PortfolioAdmin(ListHeaderAdmin):
def display_members_summary(self, obj): def display_members_summary(self, obj):
"""Will be passed as context and used in the field_readonly block.""" """Will be passed as context and used in the field_readonly block."""
members = [user for user in obj.user.all() if "Admin" not in user.portfolio_role_summary] members = self.get_non_admin_users(obj)
if not members: if not members:
return {} return {}

View file

@ -245,39 +245,39 @@ class User(AbstractUser):
return permission.portfolio return permission.portfolio
return None return None
def has_edit_requests(self): def has_edit_requests(self, portfolio):
return self._has_portfolio_permission(UserPortfolioPermissionChoices.EDIT_REQUESTS) return self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.EDIT_REQUESTS)
@property def portfolio_role_summary(self, portfolio):
def portfolio_role_summary(self):
"""Returns a list of roles based on the user's permissions.""" """Returns a list of roles based on the user's permissions."""
roles = [] roles = []
# Define the conditions and their corresponding roles # Define the conditions and their corresponding roles
conditions_roles = [ conditions_roles = [
(self.has_edit_suborganization(), ["Admin"]), (self.has_edit_suborganization(portfolio), ["Admin"]),
( (
self.has_view_all_domains_permission() self.has_view_all_domains_permission(portfolio)
and self.has_domain_requests_portfolio_permission() and self.has_domain_requests_portfolio_permission(portfolio)
and self.has_edit_requests(), and self.has_edit_requests(portfolio),
["View-only admin", "Domain requestor"], ["View-only admin", "Domain requestor"],
), ),
( (
self.has_view_all_domains_permission() and self.has_domain_requests_portfolio_permission(), self.has_view_all_domains_permission(portfolio)
and self.has_domain_requests_portfolio_permission(portfolio),
["View-only admin"], ["View-only admin"],
), ),
( (
self.has_base_portfolio_permission() self.has_base_portfolio_permission(portfolio)
and self.has_edit_requests() and self.has_edit_requests(portfolio)
and self.has_domains_portfolio_permission(), and self.has_domains_portfolio_permission(portfolio),
["Domain requestor", "Domain manager"], ["Domain requestor", "Domain manager"],
), ),
(self.has_base_portfolio_permission() and self.has_edit_requests(), ["Domain requestor"]), (self.has_base_portfolio_permission(portfolio) and self.has_edit_requests(portfolio), ["Domain requestor"]),
( (
self.has_base_portfolio_permission() and self.has_domains_portfolio_permission(), self.has_base_portfolio_permission(portfolio) and self.has_domains_portfolio_permission(portfolio),
["Domain manager"], ["Domain manager"],
), ),
(self.has_base_portfolio_permission(), ["Member"]), (self.has_base_portfolio_permission(portfolio), ["Member"]),
] ]
# Evaluate conditions and add roles # Evaluate conditions and add roles

View file

@ -17,7 +17,7 @@ Template for an input field with a clipboard
> >
<use aria-hidden="true" xlink:href="{%static 'img/sprite.svg'%}#content_copy"></use> <use aria-hidden="true" xlink:href="{%static 'img/sprite.svg'%}#content_copy"></use>
</svg> </svg>
<span>Copy</span> Copy
</div> </div>
</button> </button>
</div> </div>
@ -25,7 +25,7 @@ Template for an input field with a clipboard
<div class="admin-icon-group admin-icon-group__clipboard-link"> <div class="admin-icon-group admin-icon-group__clipboard-link">
<input aria-hidden="true" class="display-none" value="{{ field.email }}" /> <input aria-hidden="true" class="display-none" value="{{ field.email }}" />
<button <button
class="usa-button usa-button--unstyled padding-right-1 usa-button--icon button--clipboard copy-to-clipboard text-no-underline" class="usa-button usa-button--unstyled padding-right-1 usa-button--icon button--clipboard copy-to-clipboard text-no-underline padding-left-05"
type="button" type="button"
> >
<svg <svg
@ -33,7 +33,7 @@ Template for an input field with a clipboard
> >
<use aria-hidden="true" xlink:href="{%static 'img/sprite.svg'%}#content_copy"></use> <use aria-hidden="true" xlink:href="{%static 'img/sprite.svg'%}#content_copy"></use>
</svg> </svg>
<span class="padding-left-05">Copy</span> Copy
</button> </button>
</div> </div>
{% endif %} {% endif %}

View file

@ -45,6 +45,7 @@ from registrar.models import (
from registrar.models.portfolio_invitation import PortfolioInvitation from registrar.models.portfolio_invitation import PortfolioInvitation
from registrar.models.senior_official import SeniorOfficial from registrar.models.senior_official import SeniorOfficial
from registrar.models.user_domain_role import UserDomainRole 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.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
from registrar.models.verified_by_staff import VerifiedByStaff from registrar.models.verified_by_staff import VerifiedByStaff
from .common import ( from .common import (
@ -2129,8 +2130,10 @@ class TestPortfolioAdmin(TestCase):
last_name="Meoward", last_name="Meoward",
title="Captain", title="Captain",
email="meaoward@gov.gov", email="meaoward@gov.gov",
portfolio=self.portfolio, )
portfolio_roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN],
UserPortfolioPermission.objects.all().create(
user=admin_user_1, portfolio=self.portfolio, roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
) )
admin_user_2 = User.objects.create( admin_user_2 = User.objects.create(
@ -2139,8 +2142,10 @@ class TestPortfolioAdmin(TestCase):
last_name="Poopy", last_name="Poopy",
title="Major", title="Major",
email="poopy@gov.gov", email="poopy@gov.gov",
portfolio=self.portfolio, )
portfolio_roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN],
UserPortfolioPermission.objects.all().create(
user=admin_user_2, portfolio=self.portfolio, roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
) )
admin_user_3 = User.objects.create( admin_user_3 = User.objects.create(
@ -2149,8 +2154,10 @@ class TestPortfolioAdmin(TestCase):
last_name="Max", last_name="Max",
title="Road warrior", title="Road warrior",
email="madmax@gov.gov", email="madmax@gov.gov",
portfolio=self.portfolio, )
portfolio_roles=[UserPortfolioRoleChoices.ORGANIZATION_MEMBER],
UserPortfolioPermission.objects.all().create(
user=admin_user_3, portfolio=self.portfolio, roles=[UserPortfolioRoleChoices.ORGANIZATION_MEMBER]
) )
admin_user_4 = User.objects.create( admin_user_4 = User.objects.create(
@ -2159,8 +2166,12 @@ class TestPortfolioAdmin(TestCase):
last_name="Smith", last_name="Smith",
title="Program", title="Program",
email="thematrix@gov.gov", email="thematrix@gov.gov",
)
UserPortfolioPermission.objects.all().create(
user=admin_user_4,
portfolio=self.portfolio, portfolio=self.portfolio,
portfolio_additional_permissions=[ additional_permissions=[
UserPortfolioPermissionChoices.VIEW_PORTFOLIO, UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
UserPortfolioPermissionChoices.EDIT_REQUESTS, UserPortfolioPermissionChoices.EDIT_REQUESTS,
], ],