Skip to content

Commit e1a5922

Browse files
committed
Noitfy submissions status change
1 parent 320a4aa commit e1a5922

File tree

3 files changed

+140
-2
lines changed

3 files changed

+140
-2
lines changed

backend/notifications/models.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,8 @@ class EmailTemplate(TimeStampedModel):
6363
*BASE_PLACEHOLDERS,
6464
"conference_name",
6565
"proposal_title",
66-
"invitation_url",
66+
"proposal_type",
6767
"speaker_name",
68-
"is_reminder",
6968
],
7069
EmailTemplateIdentifier.proposal_scheduled: [
7170
*BASE_PLACEHOLDERS,

backend/submissions/admin.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
from django.urls import reverse
2+
from grants.tasks import get_name
3+
from notifications.models import EmailTemplate, EmailTemplateIdentifier
24
from custom_admin.admin import (
35
confirm_pending_status,
46
reset_pending_status_back_to_status,
@@ -322,6 +324,57 @@ class SubmissionCommentAdmin(admin.ModelAdmin):
322324
list_display = ("submission", "author", "text")
323325

324326

327+
@admin.action(description="Apply and notify status change")
328+
@validate_single_conference_selection
329+
def apply_and_notify_status_change(modeladmin, request, queryset):
330+
conference = queryset.first().conference
331+
count = queryset.count()
332+
333+
for submission in queryset.select_related("speaker").prefetch_related("type"):
334+
submission.status = submission.pending_status
335+
submission.save(update_fields=["status"])
336+
337+
match submission.status:
338+
case Submission.STATUS.accepted:
339+
template = EmailTemplateIdentifier.proposal_accepted
340+
placeholders = {
341+
"conference_name": conference.name.localize("en"),
342+
"proposal_title": submission.title.localize("en"),
343+
"proposal_type": submission.type.name,
344+
"speaker_name": get_name(submission.speaker, "there"),
345+
}
346+
case Submission.STATUS.rejected:
347+
template = EmailTemplateIdentifier.proposal_rejected
348+
placeholders = {
349+
"conference_name": conference.name.localize("en"),
350+
"speaker_name": get_name(submission.speaker, "there"),
351+
"proposal_title": submission.title.localize("en"),
352+
"proposal_type": submission.type.name,
353+
}
354+
case Submission.STATUS.waiting_list:
355+
template = EmailTemplateIdentifier.proposal_in_waiting_list
356+
placeholders = {
357+
"conference_name": conference.name.localize("en"),
358+
"speaker_name": get_name(submission.speaker, "there"),
359+
"proposal_title": submission.title.localize("en"),
360+
"proposal_type": submission.type.name,
361+
}
362+
363+
email_template = EmailTemplate.objects.for_conference(
364+
conference
365+
).get_by_identifier(template)
366+
email_template.send_email(
367+
recipient=submission.speaker,
368+
placeholders=placeholders,
369+
)
370+
371+
messages.add_message(
372+
request,
373+
messages.SUCCESS,
374+
f"Confirmed and notified {count} proposals",
375+
)
376+
377+
325378
@admin.register(SubmissionConfirmPendingStatusProxy)
326379
class SubmissionConfirmPendingStatusProxyAdmin(admin.ModelAdmin):
327380
list_display = (
@@ -338,6 +391,7 @@ class SubmissionConfirmPendingStatusProxyAdmin(admin.ModelAdmin):
338391
search_fields = ("speaker__full_name", "speaker__email", "title")
339392
list_display_links = None
340393
actions = [
394+
apply_and_notify_status_change,
341395
confirm_pending_status,
342396
reset_pending_status_back_to_status,
343397
]

backend/submissions/tests/test_admin.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
from unittest.mock import call
2+
from conferences.tests.factories import ConferenceFactory
3+
from notifications.tests.factories import EmailTemplateFactory
4+
from notifications.models import EmailTemplateIdentifier, SentEmail
25
import pytest
36
from submissions.admin import (
7+
apply_and_notify_status_change,
48
send_proposal_in_waiting_list_email_action,
59
send_proposal_rejected_email_action,
610
)
@@ -59,3 +63,84 @@ def test_send_proposal_in_waiting_list_email_action(rf, mocker):
5963
],
6064
any_order=True,
6165
)
66+
67+
68+
def test_apply_and_notify_status_change(rf, mocker):
69+
mocker.patch("submissions.admin.messages")
70+
71+
conference = ConferenceFactory()
72+
proposal_accepted_template = EmailTemplateFactory(
73+
identifier=EmailTemplateIdentifier.proposal_accepted,
74+
conference=conference,
75+
)
76+
proposal_rejected_template = EmailTemplateFactory(
77+
identifier=EmailTemplateIdentifier.proposal_rejected,
78+
conference=conference,
79+
)
80+
proposal_in_waiting_list_template = EmailTemplateFactory(
81+
identifier=EmailTemplateIdentifier.proposal_in_waiting_list,
82+
conference=conference,
83+
)
84+
85+
accepted_submission = SubmissionFactory(
86+
conference=conference,
87+
status=Submission.STATUS.proposed,
88+
pending_status=Submission.STATUS.accepted,
89+
speaker__full_name="Marco",
90+
)
91+
92+
rejected_submission = SubmissionFactory(
93+
conference=conference,
94+
status=Submission.STATUS.proposed,
95+
pending_status=Submission.STATUS.rejected,
96+
speaker__full_name="Jane",
97+
)
98+
99+
waiting_list_proposal = SubmissionFactory(
100+
conference=conference,
101+
status=Submission.STATUS.proposed,
102+
pending_status=Submission.STATUS.waiting_list,
103+
speaker__full_name="John",
104+
)
105+
106+
apply_and_notify_status_change(
107+
None,
108+
rf.post("/"),
109+
queryset=Submission.objects.filter(status=Submission.STATUS.proposed),
110+
)
111+
112+
assert SentEmail.objects.filter(
113+
recipient=accepted_submission.speaker,
114+
email_template=proposal_accepted_template,
115+
conference=conference,
116+
placeholders={
117+
"conference_name": conference.name.localize("en"),
118+
"proposal_title": accepted_submission.title.localize("en"),
119+
"proposal_type": accepted_submission.type.name,
120+
"speaker_name": "Marco",
121+
},
122+
).exists()
123+
124+
assert SentEmail.objects.filter(
125+
recipient=rejected_submission.speaker,
126+
email_template=proposal_rejected_template,
127+
conference=conference,
128+
placeholders={
129+
"conference_name": conference.name.localize("en"),
130+
"proposal_title": rejected_submission.title.localize("en"),
131+
"proposal_type": rejected_submission.type.name,
132+
"speaker_name": "Jane",
133+
},
134+
).exists()
135+
136+
assert SentEmail.objects.filter(
137+
recipient=waiting_list_proposal.speaker,
138+
email_template=proposal_in_waiting_list_template,
139+
conference=conference,
140+
placeholders={
141+
"conference_name": conference.name.localize("en"),
142+
"proposal_title": waiting_list_proposal.title.localize("en"),
143+
"proposal_type": waiting_list_proposal.type.name,
144+
"speaker_name": "John",
145+
},
146+
).exists()

0 commit comments

Comments
 (0)