Skip to content

Commit f52326f

Browse files
use template to send mail for export job completion
1 parent afe519b commit f52326f

File tree

9 files changed

+149
-24
lines changed

9 files changed

+149
-24
lines changed

docker-compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ services:
1717
- ./pyenv:/home/test
1818
celery:
1919
build: .
20-
entrypoint: poetry run celery -A project.celery worker
20+
entrypoint: poetry run celery -A project.celery worker -l info
2121
links:
2222
- postgres
2323
- redis

example/poetry.lock

Lines changed: 14 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/project/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .celery import app as celery_app
2+
3+
__all__ = ("celery_app",)

example/project/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
TEMPLATES = [
5959
{
6060
"BACKEND": "django.template.backends.django.DjangoTemplates",
61-
"DIRS": [],
61+
"DIRS": ["templates"],
6262
"APP_DIRS": True,
6363
"OPTIONS": {
6464
"context_processors": [

example/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ celery = "*"
1313
django-author = "*"
1414
redis = "*"
1515
psycopg2-binary = "^2.8.4"
16+
html2text = "^2020.1.16"
1617

1718
[tool.poetry.dev-dependencies]
1819
django-admin-smoke-tests = "^0.3.0"
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from django.test import TestCase, override_settings
2+
3+
from django.urls import reverse
4+
from import_export_celery.utils import (
5+
get_export_job_mail_subject,
6+
get_export_job_mail_template,
7+
get_export_job_mail_context,
8+
DEFAULT_EXPORT_JOB_COMPLETION_MAIL_SUBJECT,
9+
DEFAULT_EXPORT_JOB_COMPLETION_MAIL_TEMPLATE,
10+
)
11+
from import_export_celery.models import ExportJob
12+
13+
14+
class UtilsTestCases(TestCase):
15+
def test_get_export_job_mail_subject_by_default(self):
16+
self.assertEqual(
17+
DEFAULT_EXPORT_JOB_COMPLETION_MAIL_SUBJECT, get_export_job_mail_subject()
18+
)
19+
20+
@override_settings(EXPORT_JOB_COMPLETION_MAIL_SUBJECT="New subject")
21+
def test_get_export_job_mail_subject_overridden(self):
22+
self.assertEqual("New subject", get_export_job_mail_subject())
23+
24+
def test_get_export_job_mail_template_default(self):
25+
self.assertEqual(
26+
DEFAULT_EXPORT_JOB_COMPLETION_MAIL_TEMPLATE, get_export_job_mail_template()
27+
)
28+
29+
@override_settings(EXPORT_JOB_COMPLETION_MAIL_TEMPLATE="mytemplate.html")
30+
def test_get_export_job_mail_template_overridden(self):
31+
self.assertEqual("mytemplate.html", get_export_job_mail_template())
32+
33+
def test_get_export_job_mail_context(self):
34+
export_job = ExportJob.objects.create(
35+
app_label="winners", model="Winner", site_of_origin="http://127.0.0.1:8000"
36+
)
37+
context = get_export_job_mail_context(export_job)
38+
expected_context = {
39+
"app_label": "winners",
40+
"model": "Winner",
41+
"link": f"http://127.0.0.1:8000/adminimport_export_celery/exportjob/{export_job.id}/change/",
42+
}
43+
self.assertEqual(context, expected_context)

import_export_celery/tasks.py

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
from . import models
1919
from .model_config import ModelConfig
20+
from .utils import send_export_job_completion_mail
2021

2122
from celery.utils.log import get_task_logger
2223
import logging
@@ -234,24 +235,5 @@ def export_resource(self, *args, **kwargs):
234235
serialized = serialized.encode("utf8")
235236
export_job.file.save(filename, ContentFile(serialized))
236237
if export_job.email_on_completion:
237-
send_mail(
238-
_("Django: Export job completed"),
239-
_(
240-
"Your export job on model {app_label}.{model} has completed. You can download the file at the following link:\n\n{link}"
241-
).format(
242-
app_label=export_job.app_label,
243-
model=export_job.model,
244-
link=export_job.site_of_origin
245-
+ reverse(
246-
"admin:%s_%s_change"
247-
% (
248-
export_job._meta.app_label,
249-
export_job._meta.model_name,
250-
),
251-
args=[export_job.pk],
252-
),
253-
),
254-
settings.SERVER_EMAIL,
255-
[export_job.updated_by.email],
256-
)
238+
send_export_job_completion_mail(export_job)
257239
return
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Document</title>
8+
</head>
9+
10+
<body>
11+
<p>Your export job on model {{app_label}}.{{model}} has completed. You can download the file at the following link:</p>
12+
<a href="{{link}}" target="_blank">{{link}}</a>
13+
</body>
14+
</html>

import_export_celery/utils.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import html2text
2+
from django.core.mail import send_mail
3+
from django.template.loader import get_template
4+
from django.conf import settings
5+
from django.urls import reverse
6+
7+
DEFAULT_EXPORT_JOB_COMPLETION_MAIL_SUBJECT = "Django: Export job completed"
8+
DEFAULT_EXPORT_JOB_COMPLETION_MAIL_TEMPLATE = "email/export_job_completion.html"
9+
10+
11+
def build_html_and_text_message(template_name, context={}):
12+
"""
13+
Render the given template with the context and returns
14+
the data in html and plain text format.
15+
"""
16+
template = get_template(template_name)
17+
html_message = template.render(context)
18+
text_message = html2text.html2text(html_message)
19+
return html_message, text_message
20+
21+
22+
def get_export_job_mail_context(export_job):
23+
context = {
24+
"app_label": export_job.app_label,
25+
"model": export_job.model,
26+
"link": export_job.site_of_origin
27+
+ reverse(
28+
"admin:%s_%s_change"
29+
% (
30+
export_job._meta.app_label,
31+
export_job._meta.model_name,
32+
),
33+
args=[export_job.pk],
34+
),
35+
}
36+
return context
37+
38+
39+
def get_export_job_mail_subject():
40+
return getattr(
41+
settings,
42+
"EXPORT_JOB_COMPLETION_MAIL_SUBJECT",
43+
DEFAULT_EXPORT_JOB_COMPLETION_MAIL_SUBJECT,
44+
)
45+
46+
47+
def get_export_job_mail_template():
48+
return getattr(
49+
settings,
50+
"EXPORT_JOB_COMPLETION_MAIL_TEMPLATE",
51+
DEFAULT_EXPORT_JOB_COMPLETION_MAIL_TEMPLATE,
52+
)
53+
54+
55+
def send_export_job_completion_mail(export_job):
56+
"""
57+
Send export job completion mail
58+
"""
59+
subject = get_export_job_mail_subject()
60+
template_name = get_export_job_mail_template()
61+
context = get_export_job_mail_context(export_job)
62+
context.update({"export_job": export_job})
63+
html_message, text_message = build_html_and_text_message(template_name, context)
64+
send_mail(
65+
subject=subject,
66+
message=text_message,
67+
html_message=html_message,
68+
from_email=settings.SERVER_EMAIL,
69+
recipient_list=[export_job.updated_by.email],
70+
)

0 commit comments

Comments
 (0)