User portfolio suggestions

This commit is contained in:
zandercymatics 2024-09-26 14:37:31 -06:00
parent 6aa7546c2e
commit d80287a428
No known key found for this signature in database
GPG key ID: FF4636ABEC9682B7
4 changed files with 38 additions and 14 deletions

View file

@ -10,8 +10,7 @@ from django.http import HttpResponseRedirect
from django.conf import settings from django.conf import settings
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 import DomainInformation, Portfolio, UserPortfolioPermission
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
@ -1257,9 +1256,18 @@ class UserPortfolioPermissionAdmin(ListHeaderAdmin):
list_display = [ list_display = [
"user", "user",
"portfolio", "portfolio",
"get_roles",
] ]
autocomplete_fields = ["user", "portfolio"] autocomplete_fields = ["user", "portfolio"]
search_fields = ["user__first_name", "user__last_name", "user__email", "portfolio__organization_name"]
search_help_text = "Search by first name, last name, email, or portfolio."
def get_roles(self, obj):
readable_roles = obj.get_readable_roles()
return ", ".join(readable_roles)
get_roles.short_description = "Roles"
class UserDomainRoleAdmin(ListHeaderAdmin, ImportExportModelAdmin): class UserDomainRoleAdmin(ListHeaderAdmin, ImportExportModelAdmin):
@ -3174,14 +3182,14 @@ class PortfolioAdmin(ListHeaderAdmin):
def change_view(self, request, object_id, form_url="", extra_context=None): def change_view(self, request, object_id, form_url="", extra_context=None):
"""Add related suborganizations and domain groups. """Add related suborganizations and domain groups.
Add the summary for the portfolio members field (list of members that link to change_forms).""" Add the summary for the portfolio members field (list of members that link to change_forms)."""
obj = self.get_object(request, object_id) obj: Portfolio = self.get_object(request, object_id)
extra_context = extra_context or {} extra_context = extra_context or {}
extra_context["skip_additional_contact_info"] = True extra_context["skip_additional_contact_info"] = True
extra_context["members"] = self.get_user_portfolio_permission_non_admins(obj) extra_context["members"] = self.get_user_portfolio_permission_non_admins(obj)
extra_context["admins"] = self.get_user_portfolio_permission_admins(obj) extra_context["admins"] = self.get_user_portfolio_permission_admins(obj)
extra_context["domains"] = obj.get_domains() extra_context["domains"] = obj.get_domains(order_by=["domain_information__name"])
extra_context["domain_requests"] = obj.get_domain_requests() extra_context["domain_requests"] = obj.get_domain_requests(order_by=["domain_information__name"])
return super().change_view(request, object_id, form_url, extra_context) return super().change_view(request, object_id, form_url, extra_context)
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):

View file

@ -132,13 +132,20 @@ class Portfolio(TimeStampedModel):
return federal_agency.federal_type if federal_agency else None return federal_agency.federal_type if federal_agency else None
# == Getters for domains == # # == Getters for domains == #
def get_domains(self): def get_domains(self, order_by=None):
"""Returns all DomainInformations associated with this portfolio""" """Returns all DomainInformations associated with this portfolio"""
return self.information_portfolio.all() if not order_by:
return self.information_portfolio.all()
else:
return self.information_portfolio.all().order_by(*order_by)
def get_domain_requests(self): def get_domain_requests(self, order_by=None):
"""Returns all DomainRequests associated with this portfolio""" """Returns all DomainRequests associated with this portfolio"""
return self.DomainRequest_portfolio.all() if not order_by:
return self.DomainRequest_portfolio.all()
else:
return self.DomainRequest_portfolio.all().order_by(*order_by)
# == Getters for suborganization == # # == Getters for suborganization == #
def get_suborganizations(self): def get_suborganizations(self):

View file

@ -77,11 +77,16 @@ class UserPortfolioPermission(TimeStampedModel):
def __str__(self): def __str__(self):
readable_roles = [] readable_roles = []
if self.roles: if self.roles:
readable_roles = sorted( readable_roles = self.get_readable_roles()
[UserPortfolioRoleChoices.get_user_portfolio_role_label(role) for role in self.roles]
)
return f"{self.user}" f" <Roles: {', '.join(readable_roles)}>" if self.roles else "" return f"{self.user}" f" <Roles: {', '.join(readable_roles)}>" if self.roles else ""
def get_readable_roles(self):
"""Returns a readable list of self.roles"""
readable_roles = []
if self.roles:
readable_roles = sorted([UserPortfolioRoleChoices.get_user_portfolio_role_label(role) for role in self.roles])
return readable_roles
def _get_portfolio_permissions(self): def _get_portfolio_permissions(self):
""" """
Retrieve the permissions for the user's portfolio roles. Retrieve the permissions for the user's portfolio roles.
@ -108,7 +113,8 @@ class UserPortfolioPermission(TimeStampedModel):
existing_permissions = UserPortfolioPermission.objects.filter(user=self.user) existing_permissions = UserPortfolioPermission.objects.filter(user=self.user)
if not flag_is_active_for_user(self.user, "multiple_portfolios") and existing_permissions.exists(): if not flag_is_active_for_user(self.user, "multiple_portfolios") and existing_permissions.exists():
raise ValidationError( raise ValidationError(
"Only one portfolio permission is allowed per user when multiple portfolios are disabled." "This user is already assigned to a portfolio. "
"Based on current waffle flag settings, users cannot be assigned to multiple portfolios."
) )
# Check if portfolio is set without accessing the related object. # Check if portfolio is set without accessing the related object.

View file

@ -1332,7 +1332,10 @@ class TestUserPortfolioPermission(TestCase):
self.assertEqual( self.assertEqual(
cm.exception.message, cm.exception.message,
"Only one portfolio permission is allowed per user when multiple portfolios are disabled.", (
"This user is already assigned to a portfolio. "
"Based on current waffle flag settings, users cannot be assigned to multiple portfolios."
),
) )