Skip to content

Commit

Permalink
ordering & default subject from registry (#37)
Browse files Browse the repository at this point in the history
Co-authored-by: Łukasz Sitko <lukasz.sitko@deployed.pl>
  • Loading branch information
citos88 and Łukasz Sitko committed Oct 26, 2022
1 parent 947c82c commit 8a55156
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 34 deletions.
4 changes: 4 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ Assumptions
Changelog
=========

1.1.15
------
* ordering in email template & default subject from registry - https://github.com/deployed/django-emailtemplates/pull/37

1.1.14
------
* Additional fields for email attachment - https://github.com/deployed/django-emailtemplates/pull/36
Expand Down
1 change: 1 addition & 0 deletions emailtemplates/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class Meta:
"subject",
"content",
"language",
"ordering",
"created",
"modified",
]
Expand Down
Binary file modified emailtemplates/locale/pl/LC_MESSAGES/django.mo
Binary file not shown.
67 changes: 38 additions & 29 deletions emailtemplates/locale/pl/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,23 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-08-09 13:50+0200\n"
"POT-Creation-Date: 2022-10-26 12:24+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n"
"%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n"
"%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && "
"(n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && "
"n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"

#: emailtemplates/admin.py:19 emailtemplates/models.py:83
#: emailtemplates/admin.py:19 emailtemplates/models.py:98
msgid "Attachment"
msgstr "Załącznik"

#: emailtemplates/admin.py:20 emailtemplates/models.py:84
#: emailtemplates/admin.py:20 emailtemplates/models.py:99
msgid "Attachments"
msgstr "Załączniki"

Expand All @@ -40,94 +40,103 @@ msgstr "Akcje"
msgid "E-MAIL TEMPLATES"
msgstr "Szblony wiadomości E-mail"

#: emailtemplates/forms.py:20 emailtemplates/models.py:29
#: emailtemplates/forms.py:20 emailtemplates/models.py:31
msgid "template"
msgstr "szablon"

#: emailtemplates/models.py:27 emailtemplates/models.py:68
#: emailtemplates/models.py:101
#: emailtemplates/models.py:29 emailtemplates/models.py:83
#: emailtemplates/models.py:116
msgid "ID"
msgstr ""

#: emailtemplates/models.py:30 emailtemplates/models.py:103
#: emailtemplates/models.py:33 emailtemplates/models.py:118
msgid "subject"
msgstr "tytuł"

#: emailtemplates/models.py:31 emailtemplates/models.py:104
#: emailtemplates/models.py:36
msgid "you can use variables from table"
msgstr "możesz użyć zmiennych kontekstowych z tabeli"

#: emailtemplates/models.py:38 emailtemplates/models.py:119
msgid "content"
msgstr "zawartość"

#: emailtemplates/models.py:33
#: emailtemplates/models.py:40
msgid "language"
msgstr "język"

#: emailtemplates/models.py:39
#: emailtemplates/models.py:45
#| msgid "Ordering"
msgid "ordering"
msgstr "kolejność"

#: emailtemplates/models.py:47
msgid "attachments"
msgstr "załączniki"

#: emailtemplates/models.py:41
#: emailtemplates/models.py:49
msgid "created"
msgstr "utworzono"

#: emailtemplates/models.py:42
#: emailtemplates/models.py:50
msgid "modified"
msgstr "zmodyfikowano"

#: emailtemplates/models.py:46
#: emailtemplates/models.py:54
msgid "Email template"
msgstr "Szablon wiadomości"

#: emailtemplates/models.py:47
#: emailtemplates/models.py:55
msgid "Email templates"
msgstr "Szablony wiadomości"

#: emailtemplates/models.py:70
#: emailtemplates/models.py:85
msgid "name"
msgstr "nazwa"

#: emailtemplates/models.py:72
#: emailtemplates/models.py:87
msgid "Attachment file"
msgstr "Plik załącznika"

#: emailtemplates/models.py:75
#: emailtemplates/models.py:90
msgid "Comment"
msgstr "Komentarz"

#: emailtemplates/models.py:75
#: emailtemplates/models.py:90
msgid "visible only in admin"
msgstr "widoczne tylko w panelu administracyjnym"

#: emailtemplates/models.py:77
#: emailtemplates/models.py:92
msgid "Ordering"
msgstr "Kolejność"

#: emailtemplates/models.py:78
#: emailtemplates/models.py:93
msgid "Send as link"
msgstr "Wyślij jako link"

#: emailtemplates/models.py:87
#: emailtemplates/models.py:102
#, python-format
msgid "Attachment: %s"
msgstr "Załącznik: %s"

#: emailtemplates/models.py:105
#: emailtemplates/models.py:120
msgid "sent"
msgstr "wysłano"

#: emailtemplates/models.py:108
#: emailtemplates/models.py:123
msgid "Mass email message"
msgstr "Wiadomość grupowa"

#: emailtemplates/models.py:109
#: emailtemplates/models.py:124
msgid "Mass email messages"
msgstr "Wiadomości grupowe"

#: emailtemplates/registry.py:80
#: emailtemplates/registry.py:81
#, python-format
msgid "<b>USAGE: %s</b>"
msgstr "<b>UŻYCIE: %s</b>"

#: emailtemplates/registry.py:83
#: emailtemplates/registry.py:84
#, python-format
msgid "<b>CONTEXT:</b><br/>%s"
msgstr "<b>KONTEKST:</b><br/>%s"
Expand Down
35 changes: 35 additions & 0 deletions emailtemplates/migrations/0011_auto_20221026_0953.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Generated by Django 3.1.13 on 2022-10-26 07:53

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("emailtemplates", "0010_auto_20220803_1419"),
]

operations = [
migrations.AlterModelOptions(
name="emailtemplate",
options={
"ordering": ("ordering",),
"verbose_name": "Email template",
"verbose_name_plural": "Email templates",
},
),
migrations.AddField(
model_name="emailtemplate",
name="ordering",
field=models.PositiveIntegerField(default=1, verbose_name="ordering"),
),
migrations.AlterField(
model_name="emailtemplate",
name="subject",
field=models.CharField(
blank=True,
help_text="you can use variables from table",
max_length=255,
verbose_name="subject",
),
),
]
20 changes: 19 additions & 1 deletion emailtemplates/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

from django.conf import settings
from django.db import models
from django.utils import translation
from django.utils.translation import gettext_lazy as _

from emailtemplates.helpers import TemplateSourceLoader, mass_mailing_recipients
from emailtemplates.registry import email_templates, NotRegistered

try:
from django.utils.timezone import now
Expand All @@ -27,14 +29,20 @@ class EmailTemplate(models.Model):
auto_created=True, primary_key=True, serialize=False, verbose_name=_("ID")
)
title = models.CharField(_("template"), max_length=255)
subject = models.CharField(_("subject"), max_length=255, blank=True)
subject = models.CharField(
_("subject"),
max_length=255,
blank=True,
help_text=_("you can use variables from table"),
)
content = models.TextField(_("content"))
language = models.CharField(
_("language"),
max_length=10,
choices=settings.LANGUAGES,
default=settings.LANGUAGE_CODE,
)
ordering = models.PositiveIntegerField(verbose_name=_("ordering"), default=1)
attachments = models.ManyToManyField(
"EmailAttachment", blank=True, verbose_name=_("attachments")
)
Expand All @@ -45,6 +53,7 @@ class Meta:
unique_together = (("title", "language"),)
verbose_name = _("Email template")
verbose_name_plural = _("Email templates")
ordering = ("ordering",)

def __str__(self):
return "%s -> %s" % (self.title, self.language)
Expand All @@ -57,9 +66,18 @@ def get_default_content(self):
logger.error("Error loading template %s. Details: %s ", self.title, e)
return ""

def get_default_subject(self):
translation.activate(self.language)
try:
return email_templates.get_subject(self.title)
except NotRegistered:
return ""

def save(self, *args, **kwargs):
if not self.content:
self.content = self.get_default_content()
if not self.subject:
self.subject = self.get_default_subject()
super(EmailTemplate, self).save(*args, **kwargs)


Expand Down
11 changes: 8 additions & 3 deletions emailtemplates/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ def get_help_values(self):


class RegistrationItem(object):
def __init__(self, path, help_text="", help_context=None, name=""):
def __init__(self, path, help_text="", help_context=None, name="", subject=""):
self.name = name or path
self.path = path
self.help_text = help_text
self.subject = subject
self.help_context_obj = HelpContext(help_context)

@property
Expand Down Expand Up @@ -97,7 +98,7 @@ class EmailTemplateRegistry(object):
def __init__(self):
self._registry = {}

def register(self, path, name="", help_text=None, help_context=None):
def register(self, path, name="", help_text=None, help_context=None, subject=""):
"""
Registers email template.
Expand All @@ -109,6 +110,7 @@ def register(self, path, name="", help_text=None, help_context=None):
:param path: Template file path. It will become immutable registry lookup key.
:param help_text: Help text to describe template in admin site
:param help_context: Dictionary of possible keys used in the context and description of their content
:param subject: Default subject of email [optional]
`help_context` items values may be strings or tuples of two strings. If strings, then email template preview
will use variable names to fill context, otherwise the second tuple element will become example value.
Expand All @@ -118,7 +120,7 @@ def register(self, path, name="", help_text=None, help_context=None):
if path in self._registry:
raise AlreadyRegistered("The template %s is already registered" % path)
self._registry[path] = RegistrationItem(
path, help_text, help_context, name=name
path, help_text, help_context, name=name, subject=subject
)
logger.debug("Registered email template %s", path)

Expand Down Expand Up @@ -147,6 +149,9 @@ def get_help_context(self, path):
def get_help_content(self, path):
return self.get_registration(path).get_help_content()

def get_subject(self, path):
return self.get_registration(path).subject

def registration_items(self):
return self._registry.values()

Expand Down
19 changes: 19 additions & 0 deletions emailtemplates/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@

from emailtemplates.helpers import TemplateSourceLoader
from emailtemplates.models import EmailTemplate, MassEmailMessage, MassEmailAttachment
from emailtemplates.registry import email_templates, NotRegistered


class EmailTemplateTest(TestCase):
def setUp(self):
self.default_content = "<h1>TEST DEFAULT CONTENT</h1>"
self.subject = "Subject"
self.email_template = EmailTemplate.objects.create(title="template-1.html")

@mock.patch.object(TemplateSourceLoader, "get_source")
Expand All @@ -24,18 +26,35 @@ def test_get_default_content(self, mock_source):
self.email_template.get_default_content(), self.default_content
)

@mock.patch.object(email_templates, "get_subject")
def test_get_default_subject(self, mock_subject):
mock_subject.return_value = self.subject
self.assertEqual(self.email_template.get_default_subject(), self.subject)

@mock.patch.object(
TemplateSourceLoader, "get_source", mock.Mock(side_effect=Exception("error..."))
)
def test_get_empty_default_content_if_error(self):
self.assertEqual(self.email_template.get_default_content(), "")

@mock.patch.object(
email_templates, "get_subject", mock.Mock(side_effect=NotRegistered("error..."))
)
def test_get_empty_default_subject_if_error(self):
self.assertEqual(self.email_template.get_default_subject(), "")

@mock.patch.object(TemplateSourceLoader, "get_source")
def test_save_default_content(self, mock_source):
mock_source.return_value = self.default_content
email_template = EmailTemplate.objects.create(title="template-2.html")
self.assertEqual(email_template.content, self.default_content)

@mock.patch.object(email_templates, "get_subject")
def test_save_default_subject(self, mock_subject):
mock_subject.return_value = self.subject
email_template = EmailTemplate.objects.create(title="template-2.html")
self.assertEqual(email_template.subject, self.subject)

@mock.patch.object(TemplateSourceLoader, "get_source")
def test_do_not_override_existing_content(self, mock_source):
mock_source.return_value = self.default_content
Expand Down
7 changes: 7 additions & 0 deletions emailtemplates/tests/test_template_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ def test_is_registered(self):
registry.register("hello_template.html")
self.assertTrue(registry.is_registered("hello_template.html"))

def test_get_subject(self):
template_registry = EmailTemplateRegistry()
template_registry.register("hello_template.html", subject="subject")
self.assertEqual(
template_registry.get_subject("hello_template.html"), "subject"
)

def test_get_help_text(self):
template_registry = EmailTemplateRegistry()
template_registry.register(
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

setup(
name='django-emailtemplates',
version='1.1.14',
version='1.1.15',
packages=find_packages(),
package_data={'emailtemplates': ['locale/*/LC_MESSAGES/*.po', 'locale/*/LC_MESSAGES/*.mo']},
include_package_data=True,
Expand Down

0 comments on commit 8a55156

Please sign in to comment.