[WIP] working on mailing templates

pull/2/head
mtyton 2023-06-22 10:41:42 +02:00
rodzic 70991fc2ea
commit 1326b13948
10 zmienionych plików z 207 dodań i 1 usunięć

Wyświetl plik

@ -26,6 +26,7 @@ BASE_DIR = os.path.dirname(PROJECT_DIR)
INSTALLED_APPS = [
"home",
"store",
"mailings",
"blog",
"search",
"wagtail.contrib.forms",

Wyświetl plik

Wyświetl plik

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

Wyświetl plik

@ -0,0 +1,6 @@
from django.apps import AppConfig
class MailingsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'mailings'

Wyświetl plik

@ -0,0 +1,35 @@
# Generated by Django 4.1.9 on 2023-06-21 18:32
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="MailTemplate",
fields=[
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("template_name", models.CharField(max_length=255, unique=True)),
("template", models.FileField(upload_to="mail_templates")),
("subject", models.CharField(max_length=255)),
],
),
migrations.CreateModel(
name="OutgoingEmail",
fields=[
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("sender", models.EmailField(max_length=254)),
("recipient", models.EmailField(max_length=254)),
("sent", models.BooleanField(default=False)),
(
"template",
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="mailings.mailtemplate"),
),
],
),
]

Wyświetl plik

@ -0,0 +1,94 @@
from typing import Any
from dataclasses import dataclass
from django.db import models
from django.db import transaction
from django.template import (
Template,
Context
)
from django.core.mail import EmailMessage
from django.conf import settings
@dataclass
class Attachment:
name: str
content: Any
contenttype: str
def send_mail(
to: list[str],
attachments: list[Attachment],
subject: str,
body: str,
sender_email: str = settings.DEFAULT_FROM_EMAIL
):
message = EmailMessage(
subject=subject,
body=body,
from_email=sender_email,
to=to
)
for attachment in attachments:
message.attach(attachment.name, attachment.content, attachment.contenttype)
return bool(message.send())
class MailTemplate(models.Model):
template_name = models.CharField(max_length=255, unique=True)
template = models.FileField(
upload_to="mail_templates"
)
subject = models.CharField(max_length=255)
def delete(self, *args, **kwargs):
# delete file
super().delete(*args, **kwargs)
@transaction.on_commit
def remove_template_file(self):
self.template.delete()
def load_and_process_template(self, context: dict|Context):
if not self.template:
raise FileNotFoundError("Template file is missing")
if isinstance(context, dict):
context = Context(context)
with open(self.template.path, "r", encoding="utf-8") as f:
content = f.read()
template = Template(content)
return template.render(context)
class OutgoingEmailManager(models.Manager):
def send(
self, template_name: str,
recipient: str, context: dict | Context,
sender:str, attachments: list[Attachment] = None
):
template = MailTemplate.objects.get(template_name=template_name)
outgoing_email = self.create(template=template, recipient=recipient)
attachments = attachments or []
# send email
sent = send_mail(
to=[recipient], sender_email=sender,
subject=template.subject, content=template.load_and_process_template(context),
attachments=attachments
)
outgoing_email.sent = sent
outgoing_email.save()
return outgoing_email
class OutgoingEmail(models.Model):
template = models.ForeignKey(MailTemplate, on_delete=models.CASCADE)
sender = models.EmailField()
recipient = models.EmailField()
sent = models.BooleanField(default=False)
objects = OutgoingEmailManager()

Wyświetl plik

@ -0,0 +1,64 @@
from django.test import TestCase
from django.core.files.uploadedfile import SimpleUploadedFile
from mailings.models import (
MailTemplate,
OutgoingEmail,
)
class TestMailTemplate(TestCase):
def setUp(self) -> None:
super().setUp()
self.mail_template = MailTemplate.objects.create(
template_name="test_template",
template=SimpleUploadedFile(
"test_template.html", b"<html>{{test_var}}</html>"
),
subject="Test subject",
)
def test_load_and_process_template_success(self):
content = self.mail_template.load_and_process_template({"test_var": "test"})
self.assertEqual(content, "<html>test</html>")
def test_load_and_process_template_missing_var_failure(self):
content = self.mail_template.load_and_process_template({})
self.assertEqual(content, "<html></html>")
def test_load_and_preprocess_template_no_template_file(self):
self.mail_template.template.delete()
self.mail_template.template = None
self.mail_template.save()
with self.assertRaises(FileNotFoundError):
self.mail_template.load_and_process_template({})
class TestOutgoingEmail(TestCase):
def setUp(self) -> None:
super().setUp()
self.mail_template = MailTemplate.objects.create(
template_name="test_template",
template=SimpleUploadedFile(
"test_template.html", b"<html>{{test_var}}</html>"
),
subject="Test subject",
)
def test_send_success(self):
mail = OutgoingEmail.objects.send(
template_name="test_template",
recipient="test@stardust.io", context={},
sender="sklep-test@stardust.io"
)
self.assertEqual(mail.sent, True)
# TODO outbox
def test_send_missing_template_failure(self):
with self.assertRaises(MailTemplate.DoesNotExist):
OutgoingEmail.objects.send(
template_name="missing_template",
recipient="", sender="", context={}\
)

Wyświetl plik

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

Wyświetl plik

@ -1,7 +1,7 @@
Django>=4.1,<4.2
wagtail>=4.2,<4.3
wagtailmenus>=3.1.5,<=3.1.7
psycopg2>=2.9.5,<=2.9.6
psycopg2-binary>=2.9.5,<=2.9.6
dj-database-url<=2.0.0
djangorestframework==3.14.0
phonenumbers==8.13.13