Merge branch 'main' into nl/3275-slowness-admin-tables

This commit is contained in:
CuriousX 2025-01-28 12:14:06 -07:00 committed by GitHub
commit 0881cf2fc6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 99 additions and 5 deletions

View file

@ -9,6 +9,7 @@ from django.utils import timezone
from registrar.models.domain import Domain
from registrar.models.federal_agency import FederalAgency
from registrar.models.utility.generic_helper import CreateOrUpdateOrganizationTypeHelper
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices
from registrar.utility.errors import FSMDomainRequestError, FSMErrorCodes
from registrar.utility.constants import BranchChoices
from auditlog.models import LogEntry
@ -903,6 +904,7 @@ class DomainRequest(TimeStampedModel):
email_template,
email_template_subject,
bcc_address="",
cc_addresses: list[str] = [],
context=None,
send_email=True,
wrap_email=False,
@ -955,12 +957,20 @@ class DomainRequest(TimeStampedModel):
if custom_email_content:
context["custom_email_content"] = custom_email_content
if self.requesting_entity_is_portfolio() or self.requesting_entity_is_suborganization():
portfolio_view_requests_users = self.portfolio.portfolio_users_with_permissions( # type: ignore
permissions=[UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS], include_admin=True
)
cc_addresses = list(portfolio_view_requests_users.values_list("email", flat=True))
send_templated_email(
email_template,
email_template_subject,
recipient.email,
context=context,
bcc_address=bcc_address,
cc_addresses=cc_addresses,
wrap_email=wrap_email,
)
logger.info(f"The {new_status} email sent to: {recipient.email}")

View file

@ -4,6 +4,7 @@ from registrar.models.domain_request import DomainRequest
from registrar.models.federal_agency import FederalAgency
from registrar.models.user import User
from registrar.models.utility.portfolio_helper import UserPortfolioRoleChoices
from django.db.models import Q
from .utility.time_stamped_model import TimeStampedModel
@ -144,6 +145,25 @@ class Portfolio(TimeStampedModel):
).values_list("user__id", flat=True)
return User.objects.filter(id__in=admin_ids)
def portfolio_users_with_permissions(self, permissions=[], include_admin=False):
"""Gets all users with specified additional permissions for this particular portfolio.
Returns a queryset of User."""
portfolio_users = self.portfolio_users
if permissions:
if include_admin:
portfolio_users = portfolio_users.filter(
Q(additional_permissions__overlap=permissions)
| Q(
roles__overlap=[
UserPortfolioRoleChoices.ORGANIZATION_ADMIN,
]
),
)
else:
portfolio_users = portfolio_users.filter(additional_permissions__overlap=permissions)
user_ids = portfolio_users.values_list("user__id", flat=True)
return User.objects.filter(id__in=user_ids)
# == Getters for domains == #
def get_domains(self, order_by=None):
"""Returns all DomainInformations associated with this portfolio"""

View file

@ -4,6 +4,7 @@ Hi, {{ recipient.first_name }}.
We've identified an action that youll need to complete before we continue reviewing your .gov domain request.
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
REQUESTED BY: {{ domain_request.creator.email }}
REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
STATUS: Action needed

View file

@ -4,6 +4,7 @@ Hi, {{ recipient.first_name }}.
We've identified an action that youll need to complete before we continue reviewing your .gov domain request.
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
REQUESTED BY: {{ domain_request.creator.email }}
REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
STATUS: Action needed

View file

@ -4,6 +4,7 @@ Hi, {{ recipient.first_name }}.
We've identified an action that youll need to complete before we continue reviewing your .gov domain request.
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
REQUESTED BY: {{ domain_request.creator.email }}
REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
STATUS: Action needed

View file

@ -4,6 +4,7 @@ Hi, {{ recipient.first_name }}.
We've identified an action that youll need to complete before we continue reviewing your .gov domain request.
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
REQUESTED BY: {{ domain_request.creator.email }}
REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
STATUS: Action needed

View file

@ -4,6 +4,7 @@ Hi, {{ recipient.first_name }}.
Your .gov domain request has been withdrawn and will not be reviewed by our team.
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
REQUESTED BY: {{ domain_request.creator.email }}
REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
STATUS: Withdrawn

View file

@ -4,6 +4,7 @@ Hi, {{ recipient.first_name }}.
Congratulations! Your .gov domain request has been approved.
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
REQUESTED BY: {{ domain_request.creator.email }}
REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
STATUS: Approved

View file

@ -4,6 +4,7 @@ Hi, {{ recipient.first_name }}.
Your .gov domain request has been rejected.
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
REQUESTED BY: {{ domain_request.creator.email }}
REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
STATUS: Rejected

View file

@ -4,6 +4,7 @@ Hi, {{ recipient.first_name }}.
We received your .gov domain request.
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
REQUESTED BY: {{ domain_request.creator.email }}
REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
STATUS: Submitted
@ -11,13 +12,15 @@ STATUS: Submitted
NEXT STEPS
Well review your request. This review period can take 30 business days. Due to the volume of requests, the wait time is longer than usual. We appreciate your patience.
{% if is_org_user %}
During our review well verify that your requested domain meets our naming requirements.
{% else %}
During our review, well verify that:
- Your organization is eligible for a .gov domain
- You work at the organization and/or can make requests on its behalf
- Your requested domain meets our naming requirements
Well email you if we have questions. Well also email you as soon as we complete our review. You can check the status of your request at any time on the registrar. <https://manage.get.gov>
{% endif %}
Well email you if we have questions. Well also email you as soon as we complete our review. You can check the status of your request at any time on the registrar. <https://manage.get.gov>.
NEED TO MAKE CHANGES?

View file

@ -16,7 +16,9 @@ from registrar.models import (
AllowedEmail,
Portfolio,
Suborganization,
UserPortfolioPermission,
)
from registrar.models.utility.portfolio_helper import UserPortfolioRoleChoices
import boto3_mocking
from registrar.utility.constants import BranchChoices
@ -46,6 +48,14 @@ class TestDomainRequest(TestCase):
self.dummy_user_2, _ = User.objects.get_or_create(
username="intern@igorville.com", email="intern@igorville.com", first_name="Lava", last_name="World"
)
self.dummy_user_3, _ = User.objects.get_or_create(
username="portfolioadmin@igorville.com",
email="portfolioadmin@igorville.com",
first_name="Portfolio",
last_name="Admin",
)
self.started_domain_request = completed_domain_request(
status=DomainRequest.DomainRequestStatus.STARTED,
name="started.gov",
@ -273,7 +283,14 @@ class TestDomainRequest(TestCase):
self.assertEqual(domain_request.status, domain_request.DomainRequestStatus.SUBMITTED)
def check_email_sent(
self, domain_request, msg, action, expected_count, expected_content=None, expected_email="mayor@igorville.com"
self,
domain_request,
msg,
action,
expected_count,
expected_content=None,
expected_email="mayor@igorville.com",
expected_cc=[],
):
"""Check if an email was sent after performing an action."""
email_allowed, _ = AllowedEmail.objects.get_or_create(email=expected_email)
@ -292,6 +309,11 @@ class TestDomainRequest(TestCase):
]
self.assertEqual(len(sent_emails), expected_count)
if expected_cc:
sent_cc_adddresses = sent_emails[0]["kwargs"]["Destination"]["CcAddresses"]
for cc_address in expected_cc:
self.assertIn(cc_address, sent_cc_adddresses)
if expected_content:
email_content = sent_emails[0]["kwargs"]["Content"]["Simple"]["Body"]["Text"]["Data"]
self.assertIn(expected_content, email_content)
@ -1074,6 +1096,36 @@ class TestDomainRequest(TestCase):
self.assertEqual(domain_request2.generic_org_type, domain_request2.converted_generic_org_type)
self.assertEqual(domain_request2.federal_agency, domain_request2.converted_federal_agency)
@less_console_noise_decorator
def test_portfolio_domain_requests_cc_requests_viewers(self):
"""test that portfolio domain request emails cc portfolio members who have read requests access"""
fed_agency = FederalAgency.objects.filter(agency="Non-Federal Agency").first()
portfolio = Portfolio.objects.create(
organization_name="Test Portfolio",
creator=self.dummy_user_2,
federal_agency=fed_agency,
organization_type=DomainRequest.OrganizationChoices.FEDERAL,
)
user_portfolio_permission = UserPortfolioPermission.objects.create( # noqa: F841
user=self.dummy_user_3, portfolio=portfolio, roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
)
# Adds cc'ed email in this test's allow list
AllowedEmail.objects.create(email="portfolioadmin@igorville.com")
msg = "Create a domain request and submit it and see if email cc's portfolio admin and members who can view \
requests."
domain_request = completed_domain_request(
name="test.gov", user=self.dummy_user_2, portfolio=portfolio, organization_name="Test Portfolio"
)
self.check_email_sent(
domain_request,
msg,
"submit",
1,
expected_email="intern@igorville.com",
expected_cc=["portfolioadmin@igorville.com"],
)
class TestDomainRequestSuborganization(TestCase):
"""Tests for the suborganization fields on domain requests"""

View file

@ -36,7 +36,7 @@ def send_templated_email( # noqa
to_address and bcc_address currently only support single addresses.
cc_address is a list and can contain many addresses. Emails not in the
cc_addresses is a list and can contain many addresses. Emails not in the
whitelist (if applicable) will be filtered out before sending.
template_name and subject_template_name are relative to the same template

View file

@ -1336,6 +1336,8 @@ class DomainDeleteUserView(UserDomainRolePermissionDeleteView):
# Is the user deleting themselves? If so, display a different message
delete_self = self.request.user == self.object.user
# Email domain managers
# Add a success message
messages.success(self.request, self.get_success_message(delete_self))
return redirect(self.get_success_url())