From 280bc23fa6d29cac792e65f57356ce41c2fbbb0a Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 23 Sep 2024 11:29:01 -0600 Subject: [PATCH] Fix migrations + readonly views --- src/registrar/admin.py | 11 ++++++- src/registrar/assets/js/get-gov-admin.js | 29 ++++++++++++++----- .../migrations/0129_portfolio_federal_type.py | 2 +- ...roups_v17.py => 0130_create_groups_v17.py} | 2 +- src/registrar/models/user_group.py | 2 +- .../models/user_portfolio_permission.py | 19 +++++++++++- .../models/utility/portfolio_helper.py | 8 +++++ .../admin/includes/portfolio_fieldset.html | 16 ++++++++++ .../user_portfolio_permission_fieldset.html | 26 +++++++++++++++++ ...user_portfolio_permission_change_form.html | 16 ++++++++++ 10 files changed, 118 insertions(+), 13 deletions(-) rename src/registrar/migrations/{0128_create_groups_v17.py => 0130_create_groups_v17.py} (94%) create mode 100644 src/registrar/templates/django/admin/includes/user_portfolio_permission_fieldset.html create mode 100644 src/registrar/templates/django/admin/user_portfolio_permission_change_form.html diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 10e6a9176..904701be7 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -1242,8 +1242,10 @@ class UserDomainRoleResource(resources.ModelResource): model = models.UserDomainRole +# Note: This is "viewonly" for analysts class UserPortfolioPermissionAdmin(ListHeaderAdmin): form = UserPortfolioPermissionsForm + change_form_template = "django/admin/user_portfolio_permission_change_form.html" class Meta: """Contains meta information about this class""" @@ -1261,6 +1263,14 @@ class UserPortfolioPermissionAdmin(ListHeaderAdmin): autocomplete_fields = ["user", "portfolio"] + def change_view(self, request, object_id, form_url="", extra_context=None): + """Adds a readonly display for roles and permissions""" + obj = self.get_object(request, object_id) + extra_context = extra_context or {} + extra_context["display_roles"] = ", ".join(obj.get_readable_roles()) + extra_context["display_permissions"] = ", ".join(obj.get_readable_additional_permissions()) + return super().change_view(request, object_id, form_url, extra_context) + class UserDomainRoleAdmin(ListHeaderAdmin, ImportExportModelAdmin): """Custom user domain role admin class.""" @@ -2961,7 +2971,6 @@ class PortfolioAdmin(ListHeaderAdmin): analyst_readonly_fields = [ "organization_name", - "organization_type", ] def get_readonly_fields(self, request, obj=None): diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index f621d5b07..fd673878d 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -858,11 +858,13 @@ function initializeWidgetOnList(list, parentId) { // $ symbolically denotes that this is using jQuery let $federalAgency = django.jQuery("#id_federal_agency"); let organizationType = document.getElementById("id_organization_type"); + let readonlyOrganizationType = document.querySelector(".field-organization_type .readonly"); + let federalType = document.getElementById("id_federal_type") - if ($federalAgency && organizationType && federalType) { + if ($federalAgency && (organizationType || readonlyOrganizationType) && federalType) { // Attach the change event listener $federalAgency.on("change", function() { - handleFederalAgencyChange($federalAgency, organizationType, federalType); + handleFederalAgencyChange($federalAgency, organizationType, readonlyOrganizationType, federalType); }); } @@ -880,7 +882,7 @@ function initializeWidgetOnList(list, parentId) { } }); - function handleFederalAgencyChange(federalAgency, organizationType, federalType) { + function handleFederalAgencyChange(federalAgency, organizationType, readonlyOrganizationType, federalType) { // Don't do anything on page load if (isInitialPageLoad) { isInitialPageLoad = false; @@ -895,13 +897,22 @@ function initializeWidgetOnList(list, parentId) { return; } + let organizationTypeValue = organizationType ? organizationType.value : readonlyOrganizationType.innerText.toLowerCase(); if (selectedText !== "Non-Federal Agency") { - if (organizationType.value !== "federal") { - organizationType.value = "federal"; + if (organizationTypeValue !== "federal") { + if (organizationType){ + organizationType.value = "federal"; + }else { + readonlyOrganizationType.innerText = "Federal" + } } }else { - if (organizationType.value === "federal") { - organizationType.value = ""; + if (organizationTypeValue === "federal") { + if (organizationType){ + organizationType.value = ""; + }else { + readonlyOrganizationType.innerText = "-" + } } } @@ -912,10 +923,12 @@ function initializeWidgetOnList(list, parentId) { return; } + organizationTypeValue = organizationType ? organizationType.value : readonlyOrganizationType.innerText.toLowerCase(); + // Determine if any changes are necessary to the display of portfolio type or federal type // based on changes to the Federal Agency let federalPortfolioApi = document.getElementById("federal_and_portfolio_types_from_agency_json_url").value; - fetch(`${federalPortfolioApi}?organization_type=${organizationType.value}&agency_name=${selectedText}`) + fetch(`${federalPortfolioApi}?organization_type=${organizationTypeValue}&agency_name=${selectedText}`) .then(response => { const statusCode = response.status; return response.json().then(data => ({ statusCode, data })); diff --git a/src/registrar/migrations/0129_portfolio_federal_type.py b/src/registrar/migrations/0129_portfolio_federal_type.py index 79548f314..c6d874678 100644 --- a/src/registrar/migrations/0129_portfolio_federal_type.py +++ b/src/registrar/migrations/0129_portfolio_federal_type.py @@ -6,7 +6,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0128_create_groups_v17"), + ("registrar", "0128_alter_domaininformation_state_territory_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0128_create_groups_v17.py b/src/registrar/migrations/0130_create_groups_v17.py similarity index 94% rename from src/registrar/migrations/0128_create_groups_v17.py rename to src/registrar/migrations/0130_create_groups_v17.py index 7ac392da7..943507267 100644 --- a/src/registrar/migrations/0128_create_groups_v17.py +++ b/src/registrar/migrations/0130_create_groups_v17.py @@ -25,7 +25,7 @@ def create_groups(apps, schema_editor) -> Any: class Migration(migrations.Migration): dependencies = [ - ("registrar", "0127_remove_domaininformation_submitter_and_more"), + ("registrar", "0129_portfolio_federal_type"), ] operations = [ diff --git a/src/registrar/models/user_group.py b/src/registrar/models/user_group.py index e6bcaa4f4..5c9bea8b4 100644 --- a/src/registrar/models/user_group.py +++ b/src/registrar/models/user_group.py @@ -79,7 +79,7 @@ class UserGroup(Group): { "app_label": "registrar", "model": "userportfoliopermission", - "permissions": ["add_userportfoliopermission", "change_userportfoliopermission", "delete_userportfoliopermission"], + "permissions": ["view_userportfoliopermission"], }, ] diff --git a/src/registrar/models/user_portfolio_permission.py b/src/registrar/models/user_portfolio_permission.py index f7bafc8c6..29e900ab6 100644 --- a/src/registrar/models/user_portfolio_permission.py +++ b/src/registrar/models/user_portfolio_permission.py @@ -75,7 +75,24 @@ class UserPortfolioPermission(TimeStampedModel): ) def __str__(self): - return f"User '{self.user}' on Portfolio '{self.portfolio}' " f"" if self.roles else "" + readable_roles = [] + if self.roles: + readable_roles = sorted([UserPortfolioRoleChoices.get_user_portfolio_role_label(role) for role in self.roles]) + return f"{self.user}' " f"" if self.roles else "" + + def get_readable_roles(self): + """Returns a list of labels of each role in self.roles""" + role_labels = [] + for role in self.roles: + role_labels.append(UserPortfolioRoleChoices.get_user_portfolio_role_label(role)) + return role_labels + + def get_readable_additional_permissions(self): + """Returns a list of labels of each additional_permission in self.additional_permissions""" + perm_labels = [] + for perm in self.additional_permissions: + perm_labels.append(UserPortfolioPermissionChoices.get_user_portfolio_permission_label(perm)) + return perm_labels def _get_portfolio_permissions(self): """ diff --git a/src/registrar/models/utility/portfolio_helper.py b/src/registrar/models/utility/portfolio_helper.py index 7f34221fd..24800fd19 100644 --- a/src/registrar/models/utility/portfolio_helper.py +++ b/src/registrar/models/utility/portfolio_helper.py @@ -10,6 +10,10 @@ class UserPortfolioRoleChoices(models.TextChoices): ORGANIZATION_ADMIN_READ_ONLY = "organization_admin_read_only", "Admin read only" ORGANIZATION_MEMBER = "organization_member", "Member" + @classmethod + def get_user_portfolio_role_label(cls, user_portfolio_role): + return cls(user_portfolio_role).label if user_portfolio_role else None + class UserPortfolioPermissionChoices(models.TextChoices): """ """ @@ -29,3 +33,7 @@ class UserPortfolioPermissionChoices(models.TextChoices): # Domain: field specific permissions VIEW_SUBORGANIZATION = "view_suborganization", "View suborganization" EDIT_SUBORGANIZATION = "edit_suborganization", "Edit suborganization" + + @classmethod + def get_user_portfolio_permission_label(cls, user_portfolio_permission): + return cls(user_portfolio_permission).label if user_portfolio_permission else None \ No newline at end of file diff --git a/src/registrar/templates/django/admin/includes/portfolio_fieldset.html b/src/registrar/templates/django/admin/includes/portfolio_fieldset.html index 001052b84..aae096a2e 100644 --- a/src/registrar/templates/django/admin/includes/portfolio_fieldset.html +++ b/src/registrar/templates/django/admin/includes/portfolio_fieldset.html @@ -13,6 +13,22 @@

No additional members found.

{% endif %} + {% elif field.field.name == "roles" %} +
+ {% if get_readable_roles %} + {{ get_readable_roles }} + {% else %} +

No roles found.

+ {% endif %} +
+ {% elif field.field.name == "additional_permissions" %} +
+ {% if display_permissions %} + {{ display_permissions }} + {% else %} +

No additional permissions found.

+ {% endif %} +
{% else %}
{{ field.contents }}
{% endif %} diff --git a/src/registrar/templates/django/admin/includes/user_portfolio_permission_fieldset.html b/src/registrar/templates/django/admin/includes/user_portfolio_permission_fieldset.html new file mode 100644 index 000000000..a7ffc889c --- /dev/null +++ b/src/registrar/templates/django/admin/includes/user_portfolio_permission_fieldset.html @@ -0,0 +1,26 @@ +{% extends "django/admin/includes/detail_table_fieldset.html" %} +{% load custom_filters %} +{% load static url_helpers %} + + +{% block field_readonly %} + {% if field.field.name == "roles" %} +
+ {% if display_roles %} + {{ display_roles }} + {% else %} + No roles found. + {% endif %} +
+ {% elif field.field.name == "additional_permissions" %} +
+ {% if display_permissions %} + {{ display_permissions }} + {% else %} + No additional permissions found. + {% endif %} +
+ {% else %} +
{{ field.contents }}
+ {% endif %} +{% endblock field_readonly%} \ No newline at end of file diff --git a/src/registrar/templates/django/admin/user_portfolio_permission_change_form.html b/src/registrar/templates/django/admin/user_portfolio_permission_change_form.html new file mode 100644 index 000000000..1249a486c --- /dev/null +++ b/src/registrar/templates/django/admin/user_portfolio_permission_change_form.html @@ -0,0 +1,16 @@ +{% extends 'django/admin/email_clipboard_change_form.html' %} +{% load custom_filters %} +{% load i18n static %} + +{% block field_sets %} + {% for fieldset in adminform %} + {% comment %} + This is a placeholder for now. + + Disclaimer: + When extending the fieldset view consider whether you need to make a new one that extends from detail_table_fieldset. + detail_table_fieldset is used on multiple admin pages, so a change there can have unintended consequences. + {% endcomment %} + {% include "django/admin/includes/user_portfolio_permission_fieldset.html" with original_object=original %} + {% endfor %} +{% endblock %} \ No newline at end of file