mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-28 21:46:33 +02:00
handle multiple domains in email notifications
This commit is contained in:
parent
3d237ba0f5
commit
b048ff96de
6 changed files with 119 additions and 67 deletions
|
@ -1480,8 +1480,9 @@ class DomainInvitationAdmin(ListHeaderAdmin):
|
||||||
send_domain_invitation_email(
|
send_domain_invitation_email(
|
||||||
email=requested_email,
|
email=requested_email,
|
||||||
requestor=requestor,
|
requestor=requestor,
|
||||||
domain=domain,
|
domains=domain,
|
||||||
is_member_of_different_org=member_of_a_different_org,
|
is_member_of_different_org=member_of_a_different_org,
|
||||||
|
requested_user=requested_user
|
||||||
)
|
)
|
||||||
if requested_user is not None:
|
if requested_user is not None:
|
||||||
# Domain Invitation creation for an existing User
|
# Domain Invitation creation for an existing User
|
||||||
|
|
|
@ -1,36 +1,46 @@
|
||||||
{% autoescape off %}{# In a text file, we don't want to have HTML entities escaped #}
|
{% autoescape off %}{# In a text file, we don't want to have HTML entities escaped #}
|
||||||
Hi.
|
{% if requested_user and requested_user.first_name %}
|
||||||
|
Hi, {{ requested_user.first_name }}.
|
||||||
|
{% else %}
|
||||||
|
Hi,
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{{ requestor_email }} has added you as a manager on {{ domain.name }}.
|
{{ requestor_email }} has invited you to manage:
|
||||||
|
{% for domain in domains %}
|
||||||
|
{{ domain.name }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
You can manage this domain on the .gov registrar <https://manage.get.gov>.
|
To manage domain information, visit the .gov registrar <https://manage.get.gov>.
|
||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
{% if not requested_user %}
|
||||||
|
|
||||||
YOU NEED A LOGIN.GOV ACCOUNT
|
YOU NEED A LOGIN.GOV ACCOUNT
|
||||||
You’ll need a Login.gov account to manage your .gov domain. Login.gov provides
|
You’ll need a Login.gov account to access the .gov registrar. That account needs to be
|
||||||
a simple and secure process for signing in to many government services with one
|
associated with the following email address: {{ invitee_email_address }}
|
||||||
account.
|
|
||||||
|
|
||||||
If you don’t already have one, follow these steps to create your
|
Login.gov provides a simple and secure process for signing in to many government
|
||||||
Login.gov account <https://login.gov/help/get-started/create-your-account/>.
|
services with one account. If you don’t already have one, follow these steps to create
|
||||||
|
your Login.gov account <https://login.gov/help/get-started/create-your-account/>.
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
DOMAIN MANAGEMENT
|
DOMAIN MANAGEMENT
|
||||||
As a .gov domain manager, you can add or update information about your domain.
|
As a .gov domain manager, you can add or update information like name servers. You’ll
|
||||||
You’ll also serve as a contact for your .gov domain. Please keep your contact
|
also serve as a contact for the domains you manage. Please keep your contact
|
||||||
information updated.
|
information updated.
|
||||||
|
|
||||||
Learn more about domain management <https://get.gov/help/domain-management>.
|
Learn more about domain management <https://get.gov/help/domain-management>.
|
||||||
|
|
||||||
|
|
||||||
SOMETHING WRONG?
|
SOMETHING WRONG?
|
||||||
If you’re not affiliated with {{ domain.name }} or think you received this
|
If you’re not affiliated with the .gov domains mentioned in this invitation or think you
|
||||||
message in error, reply to this email.
|
received this message in error, reply to this email.
|
||||||
|
|
||||||
|
|
||||||
THANK YOU
|
THANK YOU
|
||||||
.Gov helps the public identify official, trusted information. Thank you for using a .gov domain.
|
.Gov helps the public identify official, trusted information. Thank you for using a .gov
|
||||||
|
domain.
|
||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -38,5 +48,6 @@ The .gov team
|
||||||
Contact us: <https://get.gov/contact/>
|
Contact us: <https://get.gov/contact/>
|
||||||
Learn about .gov <https://get.gov>
|
Learn about .gov <https://get.gov>
|
||||||
|
|
||||||
The .gov registry is a part of the Cybersecurity and Infrastructure Security Agency (CISA) <https://cisa.gov/>
|
The .gov registry is a part of the Cybersecurity and Infrastructure Security Agency
|
||||||
|
(CISA) <https://cisa.gov/>
|
||||||
{% endautoescape %}
|
{% endautoescape %}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
You’ve been added to a .gov domain
|
You've been invited to manage {% if domains|length > 1 %}.gov domains{% else %}{{ domains.0.name }}{% endif %}
|
|
@ -1,5 +1,7 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from registrar.models import DomainInvitation
|
from registrar.models import DomainInvitation
|
||||||
|
from registrar.models.domain import Domain
|
||||||
|
from registrar.models.user import User
|
||||||
from registrar.utility.errors import (
|
from registrar.utility.errors import (
|
||||||
AlreadyDomainInvitedError,
|
AlreadyDomainInvitedError,
|
||||||
AlreadyDomainManagerError,
|
AlreadyDomainManagerError,
|
||||||
|
@ -13,7 +15,7 @@ import logging
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def send_domain_invitation_email(email: str, requestor, domain, is_member_of_different_org):
|
def send_domain_invitation_email(email: str, requestor, domains: Domain | list[Domain], is_member_of_different_org, requested_user=None):
|
||||||
"""
|
"""
|
||||||
Sends a domain invitation email to the specified address.
|
Sends a domain invitation email to the specified address.
|
||||||
|
|
||||||
|
@ -22,8 +24,9 @@ def send_domain_invitation_email(email: str, requestor, domain, is_member_of_dif
|
||||||
Args:
|
Args:
|
||||||
email (str): Email address of the recipient.
|
email (str): Email address of the recipient.
|
||||||
requestor (User): The user initiating the invitation.
|
requestor (User): The user initiating the invitation.
|
||||||
domain (Domain): The domain object for which the invitation is being sent.
|
domains (Domain or list of Domain): The domain objects for which the invitation is being sent.
|
||||||
is_member_of_different_org (bool): if an email belongs to a different org
|
is_member_of_different_org (bool): if an email belongs to a different org
|
||||||
|
requested_user (User | None): The recipient if the email belongs to a user in the registrar
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
MissingEmailError: If the requestor has no email associated with their account.
|
MissingEmailError: If the requestor has no email associated with their account.
|
||||||
|
@ -32,13 +35,19 @@ def send_domain_invitation_email(email: str, requestor, domain, is_member_of_dif
|
||||||
OutsideOrgMemberError: If the requested_user is part of a different organization.
|
OutsideOrgMemberError: If the requested_user is part of a different organization.
|
||||||
EmailSendingError: If there is an error while sending the email.
|
EmailSendingError: If there is an error while sending the email.
|
||||||
"""
|
"""
|
||||||
|
print('send_domain_invitation_email')
|
||||||
|
# Normalize domains
|
||||||
|
if isinstance(domains, Domain):
|
||||||
|
domains = [domains]
|
||||||
|
|
||||||
# Default email address for staff
|
# Default email address for staff
|
||||||
requestor_email = settings.DEFAULT_FROM_EMAIL
|
requestor_email = settings.DEFAULT_FROM_EMAIL
|
||||||
|
|
||||||
# Check if the requestor is staff and has an email
|
# Check if the requestor is staff and has an email
|
||||||
if not requestor.is_staff:
|
if not requestor.is_staff:
|
||||||
if not requestor.email or requestor.email.strip() == "":
|
if not requestor.email or requestor.email.strip() == "":
|
||||||
raise MissingEmailError(email=email, domain=domain)
|
domain_names = ", ".join([domain.name for domain in domains])
|
||||||
|
raise MissingEmailError(email=email, domain=domain_names)
|
||||||
else:
|
else:
|
||||||
requestor_email = requestor.email
|
requestor_email = requestor.email
|
||||||
|
|
||||||
|
@ -51,18 +60,19 @@ def send_domain_invitation_email(email: str, requestor, domain, is_member_of_dif
|
||||||
):
|
):
|
||||||
raise OutsideOrgMemberError
|
raise OutsideOrgMemberError
|
||||||
|
|
||||||
# Check for an existing invitation
|
# Check for an existing invitation for each domain
|
||||||
try:
|
for domain in domains:
|
||||||
invite = DomainInvitation.objects.get(email=email, domain=domain)
|
try:
|
||||||
if invite.status == DomainInvitation.DomainInvitationStatus.RETRIEVED:
|
invite = DomainInvitation.objects.get(email=email, domain=domain)
|
||||||
raise AlreadyDomainManagerError(email)
|
if invite.status == DomainInvitation.DomainInvitationStatus.RETRIEVED:
|
||||||
elif invite.status == DomainInvitation.DomainInvitationStatus.CANCELED:
|
raise AlreadyDomainManagerError(email)
|
||||||
invite.update_cancellation_status()
|
elif invite.status == DomainInvitation.DomainInvitationStatus.CANCELED:
|
||||||
invite.save()
|
invite.update_cancellation_status()
|
||||||
else:
|
invite.save()
|
||||||
raise AlreadyDomainInvitedError(email)
|
else:
|
||||||
except DomainInvitation.DoesNotExist:
|
raise AlreadyDomainInvitedError(email)
|
||||||
pass
|
except DomainInvitation.DoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
# Send the email
|
# Send the email
|
||||||
try:
|
try:
|
||||||
|
@ -71,12 +81,18 @@ def send_domain_invitation_email(email: str, requestor, domain, is_member_of_dif
|
||||||
"emails/domain_invitation_subject.txt",
|
"emails/domain_invitation_subject.txt",
|
||||||
to_address=email,
|
to_address=email,
|
||||||
context={
|
context={
|
||||||
"domain": domain,
|
"domains": domains,
|
||||||
"requestor_email": requestor_email,
|
"requestor_email": requestor_email,
|
||||||
|
"invitee_email_address": email,
|
||||||
|
"requested_user": requested_user,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
except EmailSendingError as err:
|
except EmailSendingError as err:
|
||||||
raise EmailSendingError(f"Could not send email invitation to {email} for domain {domain}.") from err
|
print('point of failure test')
|
||||||
|
domain_names = ", ".join([domain.name for domain in domains])
|
||||||
|
raise EmailSendingError(
|
||||||
|
f"Could not send email invitation to {email} for domains: {domain_names}"
|
||||||
|
) from err
|
||||||
|
|
||||||
|
|
||||||
def send_portfolio_invitation_email(email: str, requestor, portfolio):
|
def send_portfolio_invitation_email(email: str, requestor, portfolio):
|
||||||
|
|
|
@ -1204,7 +1204,7 @@ class DomainAddUserView(DomainFormBaseView):
|
||||||
send_domain_invitation_email(
|
send_domain_invitation_email(
|
||||||
email=email,
|
email=email,
|
||||||
requestor=requestor,
|
requestor=requestor,
|
||||||
domain=self.object,
|
domains=self.object,
|
||||||
is_member_of_different_org=member_of_different_org,
|
is_member_of_different_org=member_of_different_org,
|
||||||
)
|
)
|
||||||
DomainInvitation.objects.get_or_create(email=email, domain=self.object)
|
DomainInvitation.objects.get_or_create(email=email, domain=self.object)
|
||||||
|
@ -1215,8 +1215,9 @@ class DomainAddUserView(DomainFormBaseView):
|
||||||
send_domain_invitation_email(
|
send_domain_invitation_email(
|
||||||
email=email,
|
email=email,
|
||||||
requestor=requestor,
|
requestor=requestor,
|
||||||
domain=self.object,
|
domains=self.object,
|
||||||
is_member_of_different_org=member_of_different_org,
|
is_member_of_different_org=member_of_different_org,
|
||||||
|
requested_user=requested_user,
|
||||||
)
|
)
|
||||||
UserDomainRole.objects.create(
|
UserDomainRole.objects.create(
|
||||||
user=requested_user,
|
user=requested_user,
|
||||||
|
|
|
@ -8,13 +8,14 @@ from django.utils.safestring import mark_safe
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from registrar.forms import portfolio as portfolioForms
|
from registrar.forms import portfolio as portfolioForms
|
||||||
from registrar.models import Portfolio, User
|
from registrar.models import Portfolio, User
|
||||||
|
from registrar.models.domain import Domain
|
||||||
from registrar.models.domain_invitation import DomainInvitation
|
from registrar.models.domain_invitation import DomainInvitation
|
||||||
from registrar.models.portfolio_invitation import PortfolioInvitation
|
from registrar.models.portfolio_invitation import PortfolioInvitation
|
||||||
from registrar.models.user_domain_role import UserDomainRole
|
from registrar.models.user_domain_role import UserDomainRole
|
||||||
from registrar.models.user_portfolio_permission import 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 registrar.utility.email import EmailSendingError
|
from registrar.utility.email import EmailSendingError
|
||||||
from registrar.utility.email_invitations import send_portfolio_invitation_email
|
from registrar.utility.email_invitations import send_domain_invitation_email, send_portfolio_invitation_email
|
||||||
from registrar.utility.errors import MissingEmailError
|
from registrar.utility.errors import MissingEmailError
|
||||||
from registrar.utility.enums import DefaultUserValues
|
from registrar.utility.enums import DefaultUserValues
|
||||||
from registrar.views.utility.mixins import PortfolioMemberPermission
|
from registrar.views.utility.mixins import PortfolioMemberPermission
|
||||||
|
@ -33,6 +34,8 @@ from django.views.generic import View
|
||||||
from django.views.generic.edit import FormMixin
|
from django.views.generic.edit import FormMixin
|
||||||
from django.db import IntegrityError
|
from django.db import IntegrityError
|
||||||
|
|
||||||
|
from registrar.views.utility.portfolio_helper import get_org_membership
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -237,6 +240,7 @@ class PortfolioMemberDomainsEditView(PortfolioMemberDomainsEditPermissionView, V
|
||||||
removed_domains = request.POST.get("removed_domains")
|
removed_domains = request.POST.get("removed_domains")
|
||||||
portfolio_permission = get_object_or_404(UserPortfolioPermission, pk=pk)
|
portfolio_permission = get_object_or_404(UserPortfolioPermission, pk=pk)
|
||||||
member = portfolio_permission.user
|
member = portfolio_permission.user
|
||||||
|
portfolio = portfolio_permission.portfolio
|
||||||
|
|
||||||
added_domain_ids = self._parse_domain_ids(added_domains, "added domains")
|
added_domain_ids = self._parse_domain_ids(added_domains, "added domains")
|
||||||
if added_domain_ids is None:
|
if added_domain_ids is None:
|
||||||
|
@ -248,7 +252,7 @@ class PortfolioMemberDomainsEditView(PortfolioMemberDomainsEditPermissionView, V
|
||||||
|
|
||||||
if added_domain_ids or removed_domain_ids:
|
if added_domain_ids or removed_domain_ids:
|
||||||
try:
|
try:
|
||||||
self._process_added_domains(added_domain_ids, member)
|
self._process_added_domains(added_domain_ids, member, request.user, portfolio)
|
||||||
self._process_removed_domains(removed_domain_ids, member)
|
self._process_removed_domains(removed_domain_ids, member)
|
||||||
messages.success(request, "The domain assignment changes have been saved.")
|
messages.success(request, "The domain assignment changes have been saved.")
|
||||||
return redirect(reverse("member-domains", kwargs={"pk": pk}))
|
return redirect(reverse("member-domains", kwargs={"pk": pk}))
|
||||||
|
@ -263,7 +267,7 @@ class PortfolioMemberDomainsEditView(PortfolioMemberDomainsEditPermissionView, V
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
messages.error(
|
messages.error(
|
||||||
request,
|
request,
|
||||||
"An unexpected error occurred: {str(e)}. If the issue persists, "
|
f"An unexpected error occurred: {str(e)}. If the issue persists, "
|
||||||
f"please contact {DefaultUserValues.HELP_EMAIL}.",
|
f"please contact {DefaultUserValues.HELP_EMAIL}.",
|
||||||
)
|
)
|
||||||
logger.error(f"An unexpected error occurred: {str(e)}")
|
logger.error(f"An unexpected error occurred: {str(e)}")
|
||||||
|
@ -287,16 +291,26 @@ class PortfolioMemberDomainsEditView(PortfolioMemberDomainsEditPermissionView, V
|
||||||
logger.error(f"Invalid data for {domain_type}")
|
logger.error(f"Invalid data for {domain_type}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _process_added_domains(self, added_domain_ids, member):
|
def _process_added_domains(self, added_domain_ids, member, requestor, portfolio):
|
||||||
"""
|
"""
|
||||||
Processes added domains by bulk creating UserDomainRole instances.
|
Processes added domains by bulk creating UserDomainRole instances.
|
||||||
"""
|
"""
|
||||||
if added_domain_ids:
|
if added_domain_ids:
|
||||||
|
print('_process_added_domains')
|
||||||
|
added_domains = Domain.objects.filter(id__in=added_domain_ids)
|
||||||
|
member_of_a_different_org, _ = get_org_membership(portfolio, member.email, member)
|
||||||
|
send_domain_invitation_email(
|
||||||
|
email=member.email,
|
||||||
|
requestor=requestor,
|
||||||
|
domains=added_domains,
|
||||||
|
is_member_of_different_org=member_of_a_different_org,
|
||||||
|
requested_user=member,
|
||||||
|
)
|
||||||
# Bulk create UserDomainRole instances for added domains
|
# Bulk create UserDomainRole instances for added domains
|
||||||
UserDomainRole.objects.bulk_create(
|
UserDomainRole.objects.bulk_create(
|
||||||
[
|
[
|
||||||
UserDomainRole(domain_id=domain_id, user=member, role=UserDomainRole.Roles.MANAGER)
|
UserDomainRole(domain=domain, user=member, role=UserDomainRole.Roles.MANAGER)
|
||||||
for domain_id in added_domain_ids
|
for domain in added_domains
|
||||||
],
|
],
|
||||||
ignore_conflicts=True, # Avoid duplicate entries
|
ignore_conflicts=True, # Avoid duplicate entries
|
||||||
)
|
)
|
||||||
|
@ -443,6 +457,7 @@ class PortfolioInvitedMemberDomainsEditView(PortfolioMemberDomainsEditPermission
|
||||||
removed_domains = request.POST.get("removed_domains")
|
removed_domains = request.POST.get("removed_domains")
|
||||||
portfolio_invitation = get_object_or_404(PortfolioInvitation, pk=pk)
|
portfolio_invitation = get_object_or_404(PortfolioInvitation, pk=pk)
|
||||||
email = portfolio_invitation.email
|
email = portfolio_invitation.email
|
||||||
|
portfolio = portfolio_invitation.portfolio
|
||||||
|
|
||||||
added_domain_ids = self._parse_domain_ids(added_domains, "added domains")
|
added_domain_ids = self._parse_domain_ids(added_domains, "added domains")
|
||||||
if added_domain_ids is None:
|
if added_domain_ids is None:
|
||||||
|
@ -454,7 +469,7 @@ class PortfolioInvitedMemberDomainsEditView(PortfolioMemberDomainsEditPermission
|
||||||
|
|
||||||
if added_domain_ids or removed_domain_ids:
|
if added_domain_ids or removed_domain_ids:
|
||||||
try:
|
try:
|
||||||
self._process_added_domains(added_domain_ids, email)
|
self._process_added_domains(added_domain_ids, email, request.user, portfolio)
|
||||||
self._process_removed_domains(removed_domain_ids, email)
|
self._process_removed_domains(removed_domain_ids, email)
|
||||||
messages.success(request, "The domain assignment changes have been saved.")
|
messages.success(request, "The domain assignment changes have been saved.")
|
||||||
return redirect(reverse("invitedmember-domains", kwargs={"pk": pk}))
|
return redirect(reverse("invitedmember-domains", kwargs={"pk": pk}))
|
||||||
|
@ -469,7 +484,7 @@ class PortfolioInvitedMemberDomainsEditView(PortfolioMemberDomainsEditPermission
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
messages.error(
|
messages.error(
|
||||||
request,
|
request,
|
||||||
"An unexpected error occurred: {str(e)}. If the issue persists, "
|
f"An unexpected error occurred: {str(e)}. If the issue persists, "
|
||||||
f"please contact {DefaultUserValues.HELP_EMAIL}.",
|
f"please contact {DefaultUserValues.HELP_EMAIL}.",
|
||||||
)
|
)
|
||||||
logger.error(f"An unexpected error occurred: {str(e)}.")
|
logger.error(f"An unexpected error occurred: {str(e)}.")
|
||||||
|
@ -493,34 +508,41 @@ class PortfolioInvitedMemberDomainsEditView(PortfolioMemberDomainsEditPermission
|
||||||
logger.error(f"Invalid data for {domain_type}.")
|
logger.error(f"Invalid data for {domain_type}.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _process_added_domains(self, added_domain_ids, email):
|
def _process_added_domains(self, added_domain_ids, email, requestor, portfolio):
|
||||||
"""
|
"""
|
||||||
Processes added domain invitations by updating existing invitations
|
Processes added domain invitations by updating existing invitations
|
||||||
or creating new ones.
|
or creating new ones.
|
||||||
"""
|
"""
|
||||||
if not added_domain_ids:
|
if added_domain_ids:
|
||||||
return
|
added_domains = Domain.objects.filter(id__in=added_domain_ids)
|
||||||
|
member_of_a_different_org, _ = get_org_membership(portfolio, email, None)
|
||||||
# Update existing invitations from CANCELED to INVITED
|
send_domain_invitation_email(
|
||||||
existing_invitations = DomainInvitation.objects.filter(domain_id__in=added_domain_ids, email=email)
|
|
||||||
existing_invitations.update(status=DomainInvitation.DomainInvitationStatus.INVITED)
|
|
||||||
|
|
||||||
# Determine which domains need new invitations
|
|
||||||
existing_domain_ids = existing_invitations.values_list("domain_id", flat=True)
|
|
||||||
new_domain_ids = set(added_domain_ids) - set(existing_domain_ids)
|
|
||||||
|
|
||||||
# Bulk create new invitations
|
|
||||||
DomainInvitation.objects.bulk_create(
|
|
||||||
[
|
|
||||||
DomainInvitation(
|
|
||||||
domain_id=domain_id,
|
|
||||||
email=email,
|
email=email,
|
||||||
status=DomainInvitation.DomainInvitationStatus.INVITED,
|
requestor=requestor,
|
||||||
|
domains=added_domains,
|
||||||
|
is_member_of_different_org=member_of_a_different_org,
|
||||||
)
|
)
|
||||||
for domain_id in new_domain_ids
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
# Update existing invitations from CANCELED to INVITED
|
||||||
|
existing_invitations = DomainInvitation.objects.filter(domain__in=added_domains, email=email)
|
||||||
|
existing_invitations.update(status=DomainInvitation.DomainInvitationStatus.INVITED)
|
||||||
|
|
||||||
|
# Determine which domains need new invitations
|
||||||
|
existing_domain_ids = existing_invitations.values_list("domain_id", flat=True)
|
||||||
|
new_domain_ids = set(added_domain_ids) - set(existing_domain_ids)
|
||||||
|
|
||||||
|
# Bulk create new invitations
|
||||||
|
DomainInvitation.objects.bulk_create(
|
||||||
|
[
|
||||||
|
DomainInvitation(
|
||||||
|
domain_id=domain_id,
|
||||||
|
email=email,
|
||||||
|
status=DomainInvitation.DomainInvitationStatus.INVITED,
|
||||||
|
)
|
||||||
|
for domain_id in new_domain_ids
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
def _process_removed_domains(self, removed_domain_ids, email):
|
def _process_removed_domains(self, removed_domain_ids, email):
|
||||||
"""
|
"""
|
||||||
Processes removed domain invitations by updating their status to CANCELED.
|
Processes removed domain invitations by updating their status to CANCELED.
|
||||||
|
@ -755,8 +777,9 @@ class PortfolioAddMemberView(PortfolioMembersPermissionView, FormMixin):
|
||||||
if not requested_user or not permission_exists:
|
if not requested_user or not permission_exists:
|
||||||
send_portfolio_invitation_email(email=requested_email, requestor=requestor, portfolio=portfolio)
|
send_portfolio_invitation_email(email=requested_email, requestor=requestor, portfolio=portfolio)
|
||||||
portfolio_invitation = form.save()
|
portfolio_invitation = form.save()
|
||||||
portfolio_invitation.retrieve()
|
if requested_user is not None:
|
||||||
portfolio_invitation.save()
|
portfolio_invitation.retrieve()
|
||||||
|
portfolio_invitation.save()
|
||||||
messages.success(self.request, f"{requested_email} has been invited.")
|
messages.success(self.request, f"{requested_email} has been invited.")
|
||||||
else:
|
else:
|
||||||
if permission_exists:
|
if permission_exists:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue