mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-08-16 14:34:10 +02:00
Cleanup
This commit is contained in:
parent
7075b72533
commit
3b378d3c81
5 changed files with 69 additions and 56 deletions
|
@ -1268,6 +1268,15 @@ class UserPortfolioPermissionAdmin(ListHeaderAdmin):
|
||||||
|
|
||||||
_meta = Meta()
|
_meta = Meta()
|
||||||
|
|
||||||
|
# Question for reviewers: should this include the invitation field?
|
||||||
|
# This is the same layout as before.
|
||||||
|
fieldsets = (
|
||||||
|
(
|
||||||
|
None,
|
||||||
|
{"fields": ("user", "portfolio", "invitation", "roles", "additional_permissions")},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
# Columns
|
# Columns
|
||||||
list_display = [
|
list_display = [
|
||||||
"user",
|
"user",
|
||||||
|
@ -1275,8 +1284,6 @@ class UserPortfolioPermissionAdmin(ListHeaderAdmin):
|
||||||
"get_roles",
|
"get_roles",
|
||||||
]
|
]
|
||||||
|
|
||||||
readonly_fields = ["invitation"]
|
|
||||||
|
|
||||||
autocomplete_fields = ["user", "portfolio"]
|
autocomplete_fields = ["user", "portfolio"]
|
||||||
search_fields = ["user__first_name", "user__last_name", "user__email", "portfolio__organization_name"]
|
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."
|
search_help_text = "Search by first name, last name, email, or portfolio."
|
||||||
|
|
|
@ -13,15 +13,22 @@ class Command(BaseCommand, PopulateScriptTemplate):
|
||||||
def handle(self, **kwargs):
|
def handle(self, **kwargs):
|
||||||
"""Loops through each DomainRequest object and populates
|
"""Loops through each DomainRequest object and populates
|
||||||
its last_status_update and first_submitted_date values"""
|
its last_status_update and first_submitted_date values"""
|
||||||
self.existing_invitations = PortfolioInvitation.objects.filter(portfolio__isnull=False, email__isnull=False).select_related('portfolio')
|
self.existing_invitations = PortfolioInvitation.objects.filter(
|
||||||
|
portfolio__isnull=False, email__isnull=False
|
||||||
|
).select_related("portfolio")
|
||||||
filter_condition = {"invitation__isnull": True, "portfolio__isnull": False, "user__email__isnull": False}
|
filter_condition = {"invitation__isnull": True, "portfolio__isnull": False, "user__email__isnull": False}
|
||||||
self.mass_update_records(UserPortfolioPermission, filter_condition, fields_to_update=["invitation"])
|
self.mass_update_records(UserPortfolioPermission, filter_condition, fields_to_update=["invitation"])
|
||||||
|
|
||||||
def update_record(self, record: UserPortfolioPermission):
|
def update_record(self, record: UserPortfolioPermission):
|
||||||
"""Associate the invitation to the right object"""
|
"""Associate the invitation to the right object"""
|
||||||
record.invitation = self.existing_invitations.filter(email=record.user.email, portfolio=record.portfolio).first()
|
record.invitation = self.existing_invitations.filter(
|
||||||
|
email=record.user.email, portfolio=record.portfolio
|
||||||
|
).first()
|
||||||
TerminalHelper.colorful_logger("INFO", "OKCYAN", f"{TerminalColors.OKCYAN}Adding invitation to {record}")
|
TerminalHelper.colorful_logger("INFO", "OKCYAN", f"{TerminalColors.OKCYAN}Adding invitation to {record}")
|
||||||
|
|
||||||
def should_skip_record(self, record) -> bool:
|
def should_skip_record(self, record) -> bool:
|
||||||
"""There is nothing to add if no invitation exists"""
|
"""There is nothing to add if no invitation exists"""
|
||||||
return not record or not self.existing_invitations.filter(email=record.user.email, portfolio=record.portfolio).exists()
|
return (
|
||||||
|
not record
|
||||||
|
or not self.existing_invitations.filter(email=record.user.email, portfolio=record.portfolio).exists()
|
||||||
|
)
|
||||||
|
|
|
@ -39,8 +39,10 @@ from django.db.models import (
|
||||||
Func,
|
Func,
|
||||||
Case,
|
Case,
|
||||||
When,
|
When,
|
||||||
|
Exists,
|
||||||
)
|
)
|
||||||
from django.db.models.functions import Concat, Coalesce, Cast
|
from django.db.models.functions import Concat, Coalesce, Cast
|
||||||
|
from registrar.models.user_group import UserGroup
|
||||||
from registrar.models.user_portfolio_permission import UserPortfolioPermission
|
from registrar.models.user_portfolio_permission import UserPortfolioPermission
|
||||||
from registrar.models.utility.generic_helper import convert_queryset_to_dict
|
from registrar.models.utility.generic_helper import convert_queryset_to_dict
|
||||||
from registrar.models.utility.orm_helper import ArrayRemove
|
from registrar.models.utility.orm_helper import ArrayRemove
|
||||||
|
@ -305,23 +307,8 @@ class UserPortfolioPermissionModelAnnotation(BaseModelAnnotation):
|
||||||
Value("Invalid date"),
|
Value("Invalid date"),
|
||||||
output_field=TextField(),
|
output_field=TextField(),
|
||||||
),
|
),
|
||||||
# TODO - replace this with a "creator" field on portfolio invitation. This should be another ticket.
|
"invited_by": PortfolioInvitationModelAnnotation.get_invited_by_from_audit_log_query(
|
||||||
# Grab the invitation creator from the audit log. This will need to be replaced with a creator field.
|
object_id_query=Cast(OuterRef("invitation__id"), output_field=TextField())
|
||||||
# When that happens, just replace this with F("invitation__creator")
|
|
||||||
"invited_by": Coalesce(
|
|
||||||
Subquery(
|
|
||||||
LogEntry.objects.filter(
|
|
||||||
content_type=ContentType.objects.get_for_model(PortfolioInvitation),
|
|
||||||
object_id=Cast(
|
|
||||||
OuterRef("invitation__id"), output_field=TextField()
|
|
||||||
), # Look up the invitation's ID
|
|
||||||
action_flag=ADDITION,
|
|
||||||
)
|
|
||||||
.order_by("action_time")
|
|
||||||
.values("user__email")[:1]
|
|
||||||
),
|
|
||||||
Value("Unknown"),
|
|
||||||
output_field=CharField(),
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,6 +349,37 @@ class PortfolioInvitationModelAnnotation(BaseModelAnnotation):
|
||||||
# Get all members on this portfolio
|
# Get all members on this portfolio
|
||||||
return Q(portfolio=portfolio)
|
return Q(portfolio=portfolio)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_invited_by_from_audit_log_query(cls, object_id_query):
|
||||||
|
return Coalesce(
|
||||||
|
Subquery(
|
||||||
|
LogEntry.objects.filter(
|
||||||
|
content_type=ContentType.objects.get_for_model(PortfolioInvitation),
|
||||||
|
object_id=object_id_query,
|
||||||
|
action_flag=ADDITION,
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
display_email=Case(
|
||||||
|
When(
|
||||||
|
Exists(
|
||||||
|
UserGroup.objects.filter(
|
||||||
|
name__in=["cisa_analysts_group", "full_access_group"],
|
||||||
|
user=OuterRef("user"),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
then=Value("help@get.gov")
|
||||||
|
),
|
||||||
|
default=F("user__email"),
|
||||||
|
output_field=CharField()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.order_by("action_time")
|
||||||
|
.values("display_email")
|
||||||
|
),
|
||||||
|
Value("Unknown"),
|
||||||
|
output_field=CharField(),
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_annotated_fields(cls, portfolio, csv_report=False):
|
def get_annotated_fields(cls, portfolio, csv_report=False):
|
||||||
"""
|
"""
|
||||||
|
@ -383,7 +401,6 @@ class PortfolioInvitationModelAnnotation(BaseModelAnnotation):
|
||||||
email=OuterRef("email"), # Check if email matches the OuterRef("email")
|
email=OuterRef("email"), # Check if email matches the OuterRef("email")
|
||||||
domain__domain_info__portfolio=portfolio, # Check if the domain's portfolio matches the given portfolio
|
domain__domain_info__portfolio=portfolio, # Check if the domain's portfolio matches the given portfolio
|
||||||
).annotate(domain_info=domain_query)
|
).annotate(domain_info=domain_query)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"first_name": Value(None, output_field=CharField()),
|
"first_name": Value(None, output_field=CharField()),
|
||||||
"last_name": Value(None, output_field=CharField()),
|
"last_name": Value(None, output_field=CharField()),
|
||||||
|
@ -406,19 +423,8 @@ class PortfolioInvitationModelAnnotation(BaseModelAnnotation):
|
||||||
# TODO - replace this with a "creator" field on portfolio invitation. This should be another ticket.
|
# TODO - replace this with a "creator" field on portfolio invitation. This should be another ticket.
|
||||||
# Grab the invitation creator from the audit log. This will need to be replaced with a creator field.
|
# Grab the invitation creator from the audit log. This will need to be replaced with a creator field.
|
||||||
# When that happens, just replace this with F("invitation__creator")
|
# When that happens, just replace this with F("invitation__creator")
|
||||||
"invited_by": Coalesce(
|
"invited_by": cls.get_invited_by_from_audit_log_query(
|
||||||
Subquery(
|
object_id_query=Cast(OuterRef("id"), output_field=TextField())
|
||||||
LogEntry.objects.filter(
|
|
||||||
content_type=ContentType.objects.get_for_model(PortfolioInvitation),
|
|
||||||
# Look up the invitation's ID. LogEntry expects a string as this it is stored as json.
|
|
||||||
object_id=Cast(OuterRef("id"), output_field=TextField()),
|
|
||||||
action_flag=ADDITION,
|
|
||||||
)
|
|
||||||
.order_by("action_time")
|
|
||||||
.values("user__email")[:1]
|
|
||||||
),
|
|
||||||
Value("Unknown"),
|
|
||||||
output_field=CharField(),
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
from django.db.models import Value, F, CharField, TextField, Q, Case, When, OuterRef, Subquery
|
from django.db.models import F, Q
|
||||||
from django.db.models.expressions import Func
|
|
||||||
from django.db.models.functions import Cast, Coalesce, Concat
|
|
||||||
from django.contrib.postgres.aggregates import ArrayAgg
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.views import View
|
from django.views import View
|
||||||
|
|
||||||
|
|
|
@ -385,22 +385,18 @@ class PortfolioMembersView(PortfolioMembersPermissionView, View):
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Add additional context data to the template."""
|
"""Add additional context data to the template."""
|
||||||
return render(request, "portfolio_members.html")
|
# Get portfolio from session
|
||||||
|
portfolio = request.session.get("portfolio")
|
||||||
def get_context_data(self, **kwargs):
|
context = {}
|
||||||
"""Add additional context data to the template."""
|
if portfolio:
|
||||||
|
|
||||||
context = super().get_context_data(**kwargs)
|
|
||||||
portfolio = self.request.session.get("portfolio")
|
|
||||||
user_count = portfolio.portfolio_users.count()
|
user_count = portfolio.portfolio_users.count()
|
||||||
invitation_count = PortfolioInvitation.objects.filter(
|
invitation_count = PortfolioInvitation.objects.filter(
|
||||||
portfolio=portfolio
|
portfolio=portfolio
|
||||||
).count()
|
).count()
|
||||||
context["member_count"] = user_count + invitation_count
|
context.update({
|
||||||
|
"member_count": user_count + invitation_count
|
||||||
# check if any portfolio invitations exist 4 portfolio
|
})
|
||||||
# check if any userportfolioroles exist 4 portfolio
|
return render(request, "portfolio_members.html", context=context)
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class NewMemberView(PortfolioMembersPermissionView, FormMixin):
|
class NewMemberView(PortfolioMembersPermissionView, FormMixin):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue