Skip to content

Commit b5f9dd8

Browse files
authored
fix(invite-requests): Add invite request notification task (#15443)
1 parent 350ad4b commit b5f9dd8

14 files changed

+121
-125
lines changed

src/sentry/api/endpoints/organization_invite_request_index.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from sentry.api.paginator import OffsetPaginator
1111
from sentry.api.serializers import serialize, OrganizationMemberWithTeamsSerializer
1212
from sentry.models import AuditLogEntryEvent, OrganizationMember, InviteStatus
13+
from sentry.tasks.members import send_invite_request_notification_email
1314
from sentry.utils.retries import TimedRetryPolicy
1415

1516
from .organization_member_index import OrganizationMemberSerializer, save_team_assignments
@@ -95,6 +96,6 @@ def post(self, request, organization):
9596
event=AuditLogEntryEvent.INVITE_REQUEST_ADD,
9697
)
9798

98-
om.send_request_notification_email()
99+
send_invite_request_notification_email.delay(om.id)
99100

100101
return Response(serialize(om), status=201)

src/sentry/api/endpoints/organization_join_request.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from sentry.models import AuthProvider, InviteStatus, OrganizationMember
1515
from sentry.signals import join_request_created
1616

17+
from sentry.tasks.members import send_invite_request_notification_email
1718

1819
logger = logging.getLogger(__name__)
1920

@@ -30,24 +31,13 @@ def create_organization_join_request(organization, email, ip_address=None):
3031
return
3132

3233
try:
33-
om = OrganizationMember.objects.create(
34+
return OrganizationMember.objects.create(
3435
organization=organization,
3536
email=email,
3637
invite_status=InviteStatus.REQUESTED_TO_JOIN.value,
3738
)
3839
except IntegrityError:
3940
pass
40-
else:
41-
logger.info(
42-
"org-join-request.created",
43-
extra={
44-
"organization_id": organization.id,
45-
"member_id": om.id,
46-
"email": email,
47-
"ip_address": ip_address,
48-
},
49-
)
50-
return om
5141

5242

5343
class OrganizationJoinRequestEndpoint(OrganizationEndpoint):
@@ -65,7 +55,7 @@ def post(self, request, organization):
6555
)
6656

6757
# users can already join organizations with SSO enabled without an invite
68-
# so no need to allow requests to join as well
58+
# so they should join that way and not through a request to the admins
6959
if AuthProvider.objects.filter(organization=organization).exists():
7060
return Response(status=403)
7161

@@ -89,7 +79,7 @@ def post(self, request, organization):
8979
member = create_organization_join_request(organization, email, ip_address)
9080

9181
if member:
92-
member.send_request_notification_email()
82+
send_invite_request_notification_email.delay(member.id)
9383
join_request_created.send_robust(sender=self, member=member)
9484

9585
return Response(status=204)

src/sentry/conf/server.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ def SOCIAL_AUTH_DEFAULT_USERNAME():
530530
"sentry.tasks.deletion",
531531
"sentry.tasks.digests",
532532
"sentry.tasks.email",
533+
"sentry.tasks.members",
533534
"sentry.tasks.merge",
534535
"sentry.tasks.options",
535536
"sentry.tasks.ping",

src/sentry/models/organizationmember.py

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -233,60 +233,6 @@ def send_invite_email(self):
233233
logger = get_logger(name="sentry.mail")
234234
logger.exception(e)
235235

236-
def send_request_notification_email(self):
237-
from sentry.utils.email import MessageBuilder
238-
239-
link_args = {"organization_slug": self.organization.slug}
240-
241-
context = {
242-
"email": self.email,
243-
"inviter": self.inviter,
244-
"organization": self.organization,
245-
"organization_link": absolute_uri(
246-
reverse("sentry-organization-index", args=[self.organization.slug])
247-
),
248-
"pending_requests_link": absolute_uri(
249-
reverse("sentry-organization-members-requests", kwargs=link_args)
250-
),
251-
"settings_link": absolute_uri(
252-
reverse("sentry-organization-settings", args=[self.organization.slug])
253-
),
254-
}
255-
256-
if self.requested_to_join:
257-
email_args = {
258-
"template": "sentry/emails/organization-join-request.txt",
259-
"html_template": "sentry/emails/organization-join-request.html",
260-
}
261-
elif self.requested_to_be_invited:
262-
email_args = {
263-
"template": "sentry/emails/organization-invite-request.txt",
264-
"html_template": "sentry/emails/organization-invite-request.html",
265-
}
266-
else:
267-
raise RuntimeError("This member is not pending invitation")
268-
269-
recipients = OrganizationMember.objects.select_related("user").filter(
270-
organization_id=self.organization_id,
271-
user__isnull=False,
272-
invite_status=InviteStatus.APPROVED.value,
273-
role__in=(r.id for r in roles.get_all() if r.has_scope("member:write")),
274-
)
275-
276-
msg = MessageBuilder(
277-
subject="Access request to %s" % (self.organization.name,),
278-
type="organization.invite-request",
279-
context=context,
280-
**email_args
281-
)
282-
283-
for recipient in recipients:
284-
try:
285-
msg.send_async([recipient.get_email()])
286-
except Exception as e:
287-
logger = get_logger(name="sentry.mail")
288-
logger.exception(e)
289-
290236
def send_sso_link_email(self, actor, provider):
291237
from sentry.utils.email import MessageBuilder
292238

src/sentry/tasks/members.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from __future__ import absolute_import, print_function
2+
3+
from django.core.urlresolvers import reverse
4+
from structlog import get_logger
5+
6+
from sentry import roles
7+
from sentry.models import InviteStatus, OrganizationMember
8+
from sentry.tasks.base import instrumented_task
9+
from sentry.utils.email import MessageBuilder
10+
from sentry.utils.http import absolute_uri
11+
12+
13+
@instrumented_task(name="sentry.tasks.send_invite_request_notification_email", queue="email")
14+
def send_invite_request_notification_email(member_id):
15+
try:
16+
om = OrganizationMember.objects.select_related("inviter", "organization").get(id=member_id)
17+
except OrganizationMember.DoesNotExist:
18+
return
19+
20+
link_args = {"organization_slug": om.organization.slug}
21+
22+
context = {
23+
"email": om.email,
24+
"organization_name": om.organization.name,
25+
"pending_requests_link": absolute_uri(
26+
reverse("sentry-organization-members-requests", kwargs=link_args)
27+
),
28+
}
29+
30+
if om.requested_to_join:
31+
email_args = {
32+
"template": "sentry/emails/organization-join-request.txt",
33+
"html_template": "sentry/emails/organization-join-request.html",
34+
}
35+
context["settings_link"] = absolute_uri(
36+
reverse("sentry-organization-settings", args=[om.organization.slug])
37+
)
38+
39+
elif om.requested_to_be_invited:
40+
email_args = {
41+
"template": "sentry/emails/organization-invite-request.txt",
42+
"html_template": "sentry/emails/organization-invite-request.html",
43+
}
44+
context["inviter_name"] = om.inviter.get_salutation_name
45+
else:
46+
raise RuntimeError("This member is not pending invitation")
47+
48+
recipients = OrganizationMember.objects.select_related("user").filter(
49+
organization_id=om.organization_id,
50+
user__isnull=False,
51+
invite_status=InviteStatus.APPROVED.value,
52+
role__in=(r.id for r in roles.get_all() if r.has_scope("member:write")),
53+
)
54+
55+
msg = MessageBuilder(
56+
subject="Access request to %s" % (om.organization.name,),
57+
type="organization.invite-request",
58+
context=context,
59+
**email_args
60+
)
61+
62+
for recipient in recipients:
63+
try:
64+
msg.send_async([recipient.get_email()])
65+
except Exception as e:
66+
logger = get_logger(name="sentry.mail")
67+
logger.exception(e)

src/sentry/templates/sentry/emails/organization-invite-request.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
{% block main %}
66
<h3>Request for Access</h3>
77

8-
<p><strong>{{ inviter.get_salutation_name }}</strong> has requested to invite <strong>{{ email }}</strong> to the <a href="{{ organization_link }}">{{ organization.name }}</a> organization.</p>
8+
<p><strong>{{ inviter_name }}</strong> has requested to invite <strong>{{ email }}</strong> to the {{ organization_name }} organization.</p>
99

1010
<a href="{{ pending_requests_link }}" class="btn">View access requests</a>
1111

src/sentry/templates/sentry/emails/organization-invite-request.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Request for Access
22

3-
{{ inviter.get_salutation_name }} has requested to invite {{ email }} to the {{ organization.name }} organization.
3+
{{ inviter_name }} has requested to invite {{ email }} to the {{ organization_name }} organization.
44

55
View access requests by clicking the link below:
66

src/sentry/templates/sentry/emails/organization-join-request.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
{% block main %}
66
<h3>Request for Access</h3>
77

8-
<p><strong>{{ email }}</strong> is requesting to join the <a href="{{ organization_link }}">{{ organization.name }}</a> organization.</p>
8+
<p><strong>{{ email }}</strong> is requesting to join the {{ organization_name }} organization.</p>
99

1010
<a href="{{ pending_requests_link }}" class="btn">View access requests</a>
1111

src/sentry/templates/sentry/emails/organization-join-request.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Request for Access
22

3-
{{ email }} is requesting to join the {{ organization.name }} organization.
3+
{{ email }} is requesting to join the {{ organization_name }} organization.
44

55
View access requests by clicking the link below:
66

src/sentry/web/frontend/debug/debug_organization_invite_request.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,9 @@ def get(self, request):
1515
user = User(name="Rick Swan")
1616

1717
context = {
18-
"organization": org,
19-
"inviter": user,
18+
"organization_name": org.name,
19+
"inviter_name": user.get_salutation_name,
2020
"email": "[email protected]",
21-
"organization_link": absolute_uri(
22-
reverse("sentry-organization-index", args=[org.slug])
23-
),
2421
"pending_requests_link": absolute_uri(
2522
reverse("sentry-organization-members-requests", args=[org.slug])
2623
),

0 commit comments

Comments
 (0)