Skip to content

Commit

Permalink
[#3725] Started with failed registrations
Browse files Browse the repository at this point in the history
  • Loading branch information
vaszig committed Apr 3, 2024
1 parent f51704e commit 3077185
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 22 deletions.
85 changes: 70 additions & 15 deletions src/openforms/emails/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

from django.conf import settings
from django.template.loader import render_to_string
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

from django_yubin.models import Message
from furl import furl

from openforms.celery import app
from openforms.config.models import GlobalConfiguration
Expand All @@ -20,33 +22,86 @@ def send_email_digest() -> None:
if not (recipients := config.recipients_email_digest):
return

period_start = timezone.now() - timedelta(days=1)
desired_period = timezone.now() - timedelta(days=1)

logs = TimelineLogProxy.objects.filter(
timestamp__gt=period_start,
extra_data__status=Message.STATUS_FAILED,
extra_data__include_in_daily_digest=True,
).distinct("content_type", "extra_data__status", "extra_data__event")
failed_emails = collect_failed_emails(desired_period)
failed_registrations = collect_registrations_failures(desired_period)

if not logs:
if not (failed_emails or failed_registrations):
return

content = render_to_string(
"emails/admin_digest.html",
{
"logs": [
{
"submission_uuid": log.content_object.uuid,
"event": log.extra_data["event"],
}
for log in logs
],
"failed_emails": failed_emails,
"failed_registrations": failed_registrations,
},
)

send_mail_html(
_("[Open Forms] Daily summary of failed emails"),
_("[Open Forms] Daily summary of failed procedures"),
content,
settings.DEFAULT_FROM_EMAIL,
recipients,
)


def collect_failed_emails(desired_period) -> list[dict[str, str] | None]:
logs = TimelineLogProxy.objects.filter(
timestamp__gt=desired_period,
extra_data__status=Message.STATUS_FAILED,
extra_data__include_in_daily_digest=True,
).distinct("content_type", "extra_data__status", "extra_data__event")

if not logs:
return
failed_emails = [
{
"submission_uuid": log.content_object.uuid,
"event": log.extra_data["event"],
}
for log in logs
]

return failed_emails


def collect_registrations_failures(desired_period) -> list[dict[str, str] | None]:
logs = TimelineLogProxy.objects.filter(
timestamp__gt=desired_period,
extra_data__log_event="registration_failure",
extra_data__include_in_daily_digest=True,
).order_by("timestamp")

if not logs:
return

connected_forms = {}
for log in logs:
form = log.content_object.form

if form.uuid in connected_forms:
connected_forms[form.uuid]["failed_submissions_counter"] += 1
connected_forms[form.uuid]["last_failure_at"] = log.timestamp
else:
connected_forms[form.uuid] = {
"form_name": form.name,
"failed_submissions_counter": 1,
"initial_failure_at": log.timestamp,
"last_failure_at": log.timestamp,
"admin_link": build_filtered_submission_admin_url(
str(form.uuid), "failed", "24hAgo"
),
}

failed_registrations = [form_detail for form_detail in connected_forms.values()]

return failed_registrations


def build_filtered_submission_admin_url(
form_uuid: str, state: str, time_from: str
) -> str:
query_params = {"form": form_uuid, "state": state, "from": time_from}
submissions_admin_url = furl(reverse("admin:submissions_submission_changelist"))
return submissions_admin_url.add(query_params).url
24 changes: 19 additions & 5 deletions src/openforms/emails/templates/emails/admin_digest.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
{% load static i18n %}

<p>
{% blocktranslate %}Here is a summary of the emails that failed to send yesterday:{% endblocktranslate %}
{% blocktranslate %}Here is a summary of the failed procedures in the past 24 hours:{% endblocktranslate %}
</p>
<ul>
{% for log in logs %}<li>- Email for the event "{{ log.event }}" for submission {{ log.submission_uuid }}.</li>
{% endfor %}
</ul>

{% if failed_emails %}
<h2>{% trans "Emails" %}</h2>
<ul>
{% for email in failed_emails %}
<li>- Email for the event "{{ email.event }}" for submission {{ email.submission_uuid }}.</li>
{% endfor %}
</ul>
{% endif %}

{% if failed_registrations %}
<h2>{% trans "Registrations" %}</h2>
<ul>
{% for registration in failed_registrations %}
<li>- {{ registration.form_name }} failed {{ registration.failed_submissions_counter }} times between {{ registration.initial_failure_at|date:"H:i" }} and {{ registration.last_failure_at|date:"H:i" }}.</li>
<a href="{{ registration.admin_link }}" />
{% endfor %}
</ul>
{% endif %}
93 changes: 91 additions & 2 deletions src/openforms/emails/tests/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
from freezegun import freeze_time

from openforms.config.models import GlobalConfiguration
from openforms.forms.tests.factories import FormFactory
from openforms.logging.tests.factories import TimelineLogProxyFactory
from openforms.submissions.constants import RegistrationStatuses
from openforms.submissions.tests.factories import SubmissionFactory

from ..tasks import send_email_digest
Expand Down Expand Up @@ -72,8 +74,9 @@ def test_create_digest_email(self):
expected_content = dedent(
f"""
<p>
Here is a summary of the emails that failed to send yesterday:
Here is a summary of the failed procedures in the past 24 hours:
</p>
<h2>Emails</h2>
<ul>
<li>- Email for the event "registration" for submission {submission.uuid}.</li>
Expand Down Expand Up @@ -128,8 +131,9 @@ def test_that_repeated_failures_are_not_mentioned_multiple_times(self):
expected_content = dedent(
f"""
<p>
Here is a summary of the emails that failed to send yesterday:
Here is a summary of the failed procedures in the past 24 hours:
</p>
<h2>Emails</h2>
<ul>
<li>- Email for the event "registration" for submission {submission.uuid}.</li>
Expand Down Expand Up @@ -177,3 +181,88 @@ def test_no_recipients(self):
send_email_digest()

self.assertEqual(0, len(mail.outbox))

def test_failed_submissions_are_correctly_sent(self):
# 1st form with 2 failures in the past 24 hours
form_1 = FormFactory.create()
failed_submission_1 = SubmissionFactory.create(
form=form_1, registration_status=RegistrationStatuses.failed
)
failed_submission_2 = SubmissionFactory.create(
form=form_1, registration_status=RegistrationStatuses.failed
)

# 1st failure
with freeze_time("2023-01-02T12:30:00+01:00"):
TimelineLogProxyFactory.create(
template="logging/events/registration_failure.txt",
content_object=failed_submission_1,
extra_data={
"log_event": "registration_failure",
"include_in_daily_digest": True,
},
)

# 2nd failure
with freeze_time("2023-01-02T18:30:00+01:00"):
TimelineLogProxyFactory.create(
template="logging/events/registration_failure.txt",
content_object=failed_submission_2,
extra_data={
"log_event": "registration_failure",
"include_in_daily_digest": True,
},
)

# 2nd form with 1 failure in the past 24 hours
form_2 = FormFactory.create()
failed_submission = SubmissionFactory.create(
form=form_2, registration_status=RegistrationStatuses.failed
)

# failure
with freeze_time("2023-01-02T12:30:00+01:00"):
TimelineLogProxyFactory.create(
template="logging/events/registration_failure.txt",
content_object=failed_submission,
extra_data={
"log_event": "registration_failure",
"include_in_daily_digest": True,
},
)

with (
freeze_time("2023-01-03T01:00:00+01:00"),
patch(
"openforms.emails.tasks.GlobalConfiguration.get_solo",
return_value=GlobalConfiguration(
recipients_email_digest=["[email protected]"]
),
),
patch("openforms.emails.tasks.send_mail_html") as patch_email,
):
send_email_digest()

patch_email.assert_called_once()

args = patch_email.call_args.args
expected_content = dedent(
f"""
<p>
Here is a summary of the failed procedures in the past 24 hours:
</p>
<h2>Registrations</h2>
<ul>
<li>- {form_1.name} failed 2 times between 12:30 and 18:30.</li>
<a href="/admin/submissions/submission/?form={str(form_1.uuid)}&state=failed&from=24hAgo" />
<li>- {form_2.name} failed 1 times between 12:30 and 12:30.</li>
<a href="/admin/submissions/submission/?form={str(form_2.uuid)}&state=failed&from=24hAgo" />
</ul>
"""
).strip()

self.assertHTMLEqual(
expected_content,
args[1].strip(),
)

0 comments on commit 3077185

Please sign in to comment.