Added inline form to Portfolio to manage related domain groups and suborganizations

This commit is contained in:
CocoByte 2024-07-10 16:14:30 -06:00
parent 160ad1209e
commit 6a5db18481
No known key found for this signature in database
GPG key ID: BBFAA2526384C97F
2 changed files with 103 additions and 10 deletions

View file

@ -9,6 +9,8 @@ from django.db.models.functions import Concat, Coalesce
from django.http import HttpResponseRedirect 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_group import DomainGroup
from registrar.models.suborganization import Suborganization
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
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
@ -598,6 +600,33 @@ class ListHeaderAdmin(AuditedAdmin, OrderableFieldsMixin):
return filters return filters
class UserContactInline(admin.StackedInline):
"""Edit a user's profile on the user page."""
model = models.Contact
# Read only that we'll leverage for CISA Analysts
analyst_readonly_fields = [
"user",
"email",
]
def get_readonly_fields(self, request, obj=None):
"""Set the read-only state on form elements.
We have 1 conditions that determine which fields are read-only:
admin user permissions.
"""
readonly_fields = list(self.readonly_fields)
if request.user.has_perm("registrar.full_access_permission"):
return readonly_fields
# Return restrictive Read-only fields for analysts and
# users who might not belong to groups
readonly_fields.extend([field for field in self.analyst_readonly_fields])
return readonly_fields # Read-only fields for analysts
class MyUserAdmin(BaseUserAdmin, ImportExportModelAdmin): class MyUserAdmin(BaseUserAdmin, ImportExportModelAdmin):
"""Custom user admin class to use our inlines.""" """Custom user admin class to use our inlines."""
@ -614,6 +643,8 @@ class MyUserAdmin(BaseUserAdmin, ImportExportModelAdmin):
_meta = Meta() _meta = Meta()
inlines = [UserContactInline]
list_display = ( list_display = (
"username", "username",
"overridden_email_field", "overridden_email_field",
@ -891,20 +922,30 @@ class ContactAdmin(ListHeaderAdmin, ImportExportModelAdmin):
list_display = [ list_display = [
"name", "name",
"email", "email",
"user_exists",
] ]
# this ordering effects the ordering of results # this ordering effects the ordering of results
# in autocomplete_fields # in autocomplete_fields for user
ordering = ["first_name", "last_name", "email"] ordering = ["first_name", "last_name", "email"]
fieldsets = [ fieldsets = [
( (
None, None,
{"fields": ["first_name", "middle_name", "last_name", "title", "email", "phone"]}, {"fields": ["user", "first_name", "middle_name", "last_name", "title", "email", "phone"]},
) )
] ]
autocomplete_fields = ["user"]
change_form_template = "django/admin/email_clipboard_change_form.html" change_form_template = "django/admin/email_clipboard_change_form.html"
def user_exists(self, obj):
"""Check if the Contact has a related User"""
return "Yes" if obj.user is not None else "No"
user_exists.short_description = "Is user" # type: ignore
user_exists.admin_order_field = "user" # type: ignore
# We name the custom prop 'contact' because linter # We name the custom prop 'contact' because linter
# is not allowing a short_description attr on it # is not allowing a short_description attr on it
# This gets around the linter limitation, for now. # This gets around the linter limitation, for now.
@ -922,7 +963,10 @@ class ContactAdmin(ListHeaderAdmin, ImportExportModelAdmin):
name.admin_order_field = "first_name" # type: ignore name.admin_order_field = "first_name" # type: ignore
# Read only that we'll leverage for CISA Analysts # Read only that we'll leverage for CISA Analysts
analyst_readonly_fields: list[str] = ["email"] analyst_readonly_fields = [
"user",
"email",
]
def get_readonly_fields(self, request, obj=None): def get_readonly_fields(self, request, obj=None):
"""Set the read-only state on form elements. """Set the read-only state on form elements.
@ -1285,10 +1329,11 @@ class DomainInformationAdmin(ListHeaderAdmin, ImportExportModelAdmin):
] ]
# Readonly fields for analysts and superusers # Readonly fields for analysts and superusers
readonly_fields = ("other_contacts", "is_election_board", "federal_agency") readonly_fields = ("other_contacts", "is_election_board")
# Read only that we'll leverage for CISA Analysts # Read only that we'll leverage for CISA Analysts
analyst_readonly_fields = [ analyst_readonly_fields = [
"federal_agency",
"creator", "creator",
"type_of_work", "type_of_work",
"more_organization_information", "more_organization_information",
@ -1601,13 +1646,13 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin):
"current_websites", "current_websites",
"alternative_domains", "alternative_domains",
"is_election_board", "is_election_board",
"federal_agency",
"status_history", "status_history",
"action_needed_reason_email", "action_needed_reason_email",
) )
# Read only that we'll leverage for CISA Analysts # Read only that we'll leverage for CISA Analysts
analyst_readonly_fields = [ analyst_readonly_fields = [
"federal_agency",
"creator", "creator",
"about_your_organization", "about_your_organization",
"requested_domain", "requested_domain",
@ -2643,21 +2688,33 @@ class VerifiedByStaffAdmin(ListHeaderAdmin):
obj.requestor = request.user if request.user.is_authenticated else None obj.requestor = request.user if request.user.is_authenticated else None
super().save_model(request, obj, form, change) super().save_model(request, obj, form, change)
class PortfolioAdmin(ListHeaderAdmin): class PortfolioAdmin(ListHeaderAdmin):
# NOTE: these are just placeholders. Not part of ACs (haven't been defined yet). Update in future tickets.
change_form_template = "django/admin/portfolio_change_form.html"
list_display = ("organization_name", "federal_agency", "creator") list_display = ("organization_name", "federal_agency", "creator")
search_fields = ["organization_name"] search_fields = ["organization_name"]
search_help_text = "Search by organization name." search_help_text = "Search by organization name."
# readonly_fields = [
# "requestor",
# ]
# Creates select2 fields (with search bars) # Creates select2 fields (with search bars)
autocomplete_fields = [ autocomplete_fields = [
"creator", "creator",
"federal_agency", "federal_agency",
] ]
def change_view(self, request, object_id, form_url="", extra_context=None):
"""Add related suborganizations and domain groups"""
obj = self.get_object(request, object_id)
# ---- Domain Groups
domain_groups = DomainGroup.objects.filter(portfolio=obj)
# ---- Suborganizations
suborganizations = Suborganization.objects.filter(portfolio=obj)
extra_context = {"domain_groups": domain_groups, "suborganizations": suborganizations}
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):
if obj.creator is not None: if obj.creator is not None:

View file

@ -0,0 +1,36 @@
{% extends 'django/admin/email_clipboard_change_form.html' %}
{% load i18n static %}
{% block after_related_objects %}
<div class="module aligned padding-3">
<h2>Associated requests and domains</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>Domain requests</h3>
<ul class="margin-0 padding-0">
{% for domain_request in domain_requests %}
<li>
<a href="{% url 'admin:registrar_domainrequest_change' domain_request.pk %}">
{{ domain_request.requested_domain }}
</a>
({{ domain_request.status }})
</li>
{% endfor %}
</ul>
</div>
<div class="mobile:grid-col-12 tablet:grid-col-6 desktop:grid-col-4">
<h3>Domains</h3>
<ul class="margin-0 padding-0">
{% for domain in domains %}
<li>
<a href="{% url 'admin:registrar_domain_change' domain.pk %}">
{{ domain.name }}
</a>
({{ domain.state }})
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endblock %}