diff --git a/README.rst b/README.rst index 71762fb..cc3f36f 100644 --- a/README.rst +++ b/README.rst @@ -16,6 +16,10 @@ Assumptions Changelog ========= +1.1.14 +------ +* Additional fields for email attachment - https://github.com/deployed/django-emailtemplates/pull/36 + 1.1.13 ------ * Change default auto field to BigAutoField - https://github.com/deployed/django-emailtemplates/pull/35 diff --git a/emailtemplates/__init__.py b/emailtemplates/__init__.py index 0020d13..1948f91 100644 --- a/emailtemplates/__init__.py +++ b/emailtemplates/__init__.py @@ -1,6 +1,6 @@ -default_app_config = 'emailtemplates.apps.EmailtempatesConfig' +default_app_config = "emailtemplates.apps.EmailtempatesConfig" -VERSION = (1, 1, 13) +VERSION = (1, 1, 14) # Dynamically calculate the version based on VERSION tuple if len(VERSION) > 2 and VERSION[2] is not None: diff --git a/emailtemplates/admin.py b/emailtemplates/admin.py index 68a129e..a0b05a8 100644 --- a/emailtemplates/admin.py +++ b/emailtemplates/admin.py @@ -5,7 +5,12 @@ from django.utils.translation import gettext_lazy as _ from .forms import EmailTemplateAdminForm, MassEmailMessageForm, MassEmailAttachmentForm -from .models import EmailTemplate, MassEmailMessage, MassEmailAttachment, EmailAttachment +from .models import ( + EmailTemplate, + MassEmailMessage, + MassEmailAttachment, + EmailAttachment, +) class EmailTemplateAttachmentInline(admin.TabularInline): @@ -19,33 +24,42 @@ class EmailTemplateAdmin(admin.ModelAdmin): """ Admin view of EmailTemplate """ - list_display = ('title', 'language', 'subject',) - list_display_links = ('title',) - list_filter = ('title', 'language',) - search_fields = ('title', 'subject') + + list_display = ( + "title", + "language", + "subject", + ) + list_display_links = ("title",) + list_filter = ( + "title", + "language", + ) + search_fields = ("title", "subject") form = EmailTemplateAdminForm save_on_top = True save_as = True - readonly_fields = ['show_links', 'created', 'modified'] + readonly_fields = ["show_links", "created", "modified"] inlines = [EmailTemplateAttachmentInline] def show_links(self, obj): if not obj.pk: - return '' - return mark_safe(u'%s' % ( - reverse('email_preview', kwargs={'pk': obj.pk}), _('Show email preview') - )) + return "" + return mark_safe( + '%s' + % (reverse("email_preview", kwargs={"pk": obj.pk}), _("Show email preview")) + ) show_links.allow_tags = True - show_links.short_description = _('Actions') + show_links.short_description = _("Actions") admin.site.register(EmailTemplate, EmailTemplateAdmin) class EmailAttachmentAdmin(admin.ModelAdmin): - list_display = ["name"] - search_fields = ["name"] + list_display = ["name", "comment", "ordering"] + search_fields = ["name", "comment"] admin.site.register(EmailAttachment, EmailAttachmentAdmin) @@ -57,8 +71,8 @@ class MassEmailAttachmentInline(admin.TabularInline): class MassEmailMessageAdmin(admin.ModelAdmin): - list_display = ('subject', 'date_sent') - readonly_fields = ['date_sent'] + list_display = ("subject", "date_sent") + readonly_fields = ["date_sent"] form = MassEmailMessageForm inlines = [MassEmailAttachmentInline] diff --git a/emailtemplates/apps.py b/emailtemplates/apps.py index bcee402..29ff5a2 100644 --- a/emailtemplates/apps.py +++ b/emailtemplates/apps.py @@ -4,6 +4,6 @@ class EmailtempatesConfig(AppConfig): - name = 'emailtemplates' - verbose_name = _('E-MAIL TEMPLATES') - default_auto_field = 'django.db.models.BigAutoField' + name = "emailtemplates" + verbose_name = _("E-MAIL TEMPLATES") + default_auto_field = "django.db.models.BigAutoField" diff --git a/emailtemplates/email.py b/emailtemplates/email.py index 46d2dd3..8d74408 100644 --- a/emailtemplates/email.py +++ b/emailtemplates/email.py @@ -1,7 +1,9 @@ # coding=utf-8 import logging import os +import re from smtplib import SMTPException +from urllib.parse import urljoin from django.conf import settings from django.core.exceptions import ObjectDoesNotExist @@ -11,8 +13,6 @@ from .models import now, EmailTemplate from .registry import email_templates -import re -from urllib.parse import urljoin logger = logging.getLogger(__name__) @@ -28,9 +28,17 @@ class EmailFromTemplate(object): Site Admins should be familiar with Django Template System. """ - def __init__(self, name="", from_email=settings.DEFAULT_FROM_EMAIL, base_url="", - language=settings.LANGUAGE_CODE, subject="", template_class=EmailTemplate, - registry_validation=True, template_object=None): + def __init__( + self, + name="", + from_email=settings.DEFAULT_FROM_EMAIL, + base_url="", + language=settings.LANGUAGE_CODE, + subject="", + template_class=EmailTemplate, + registry_validation=True, + template_object=None, + ): """ Class constructor @@ -55,18 +63,18 @@ def __init__(self, name="", from_email=settings.DEFAULT_FROM_EMAIL, base_url="", self.template = None self.compiled_template = None # for storing compiled template - self.context = {'date': now()} # default context + self.context = {"date": now()} # default context self.sent = 0 # number of messages sent self.message = "" - self.content_subtype = 'html' - self._template_source = 'default' + self.content_subtype = "html" + self._template_source = "default" @property def template_source(self): """Source of the template. One of the following: - * default - * filesystem - * database + * default + * filesystem + * database """ return self._template_source @@ -78,9 +86,12 @@ def __get_template_from_file(self): try: self.compiled_template = get_template(path) except (TemplateDoesNotExist, IOError): - logger.warning("Can't find %s template in the filesystem, will use very default one.", path) + logger.warning( + "Can't find %s template in the filesystem, will use very default one.", + path, + ) else: - self._template_source = 'filesystem' + self._template_source = "filesystem" def build_absolute_uri(self, url: str): """ @@ -106,17 +117,20 @@ def get_object(self): try: tmp = self.get_template_object() except ObjectDoesNotExist: - logger.warning("Can't find EmailTemplate object in database, using default file template.") + logger.warning( + "Can't find EmailTemplate object in database, using default file template." + ) break except UnicodeError: logger.warning( - "Can't convert to unicode EmailTemplate object from database, using default file template.") + "Can't convert to unicode EmailTemplate object from database, using default file template." + ) break else: self.template = str(tmp.content) self.subject = self.get_subject(tmp) - self._template_source = 'database' - logger.debug(u"Got template %s from database", self.name) + self._template_source = "database" + logger.debug("Got template %s from database", self.name) return # fallback self.__get_template_from_file() @@ -126,9 +140,9 @@ def __compile_template(self): self.compiled_template = Template(self.template) def get_context(self): - self.context.update({ - "default_attachments": self.get_default_attachments(as_links=True) - }) + self.context.update( + {"default_attachments": self.get_default_attachments(as_links=True)} + ) return self.context def render_message(self): @@ -141,18 +155,22 @@ def render_message(self): self.message = message def get_message_object(self, send_to, attachment_paths, *args, **kwargs): - if kwargs.get('reply_to') is None: - defaut_reply_to_email = getattr(settings, 'DEFAULT_REPLY_TO_EMAIL', None) + if kwargs.get("reply_to") is None: + defaut_reply_to_email = getattr(settings, "DEFAULT_REPLY_TO_EMAIL", None) if defaut_reply_to_email: - kwargs['reply_to'] = [defaut_reply_to_email] + kwargs["reply_to"] = [defaut_reply_to_email] - msg = EmailMessage(self.subject, self.message, self.from_email, send_to, *args, **kwargs) + msg = EmailMessage( + self.subject, self.message, self.from_email, send_to, *args, **kwargs + ) if attachment_paths: for path in attachment_paths: msg.attach_file(path) return msg - def send_email(self, send_to, attachment_paths=None, fail_silently=True, *args, **kwargs): + def send_email( + self, send_to, attachment_paths=None, fail_silently=True, *args, **kwargs + ): """ Sends email to recipient based on self object parameters. @@ -160,7 +178,7 @@ def send_email(self, send_to, attachment_paths=None, fail_silently=True, *args, @param send_to: recipient email @param args: additional args passed to EmailMessage @param kwargs: kwargs passed to EmailMessage - @param attachment_paths: paths to attachments as received by django EmailMessage.attach_file(path) method + @param attachment_paths: paths to attachments as received by django EmailMessage.attach_file(path) method @return: number of sent messages """ msg = self.get_message_object(send_to, attachment_paths, *args, **kwargs) @@ -171,7 +189,7 @@ def send_email(self, send_to, attachment_paths=None, fail_silently=True, *args, except SMTPException as e: if not fail_silently: raise - logger.error(u'Problem sending email to %s: %s', send_to, e) + logger.error("Problem sending email to %s: %s", send_to, e) return self.sent @@ -188,29 +206,35 @@ def get_default_attachments(self, as_links=False): for attachment in tmp.attachments.filter(send_as_link=as_links): if as_links: attachments.append( - (attachment.get_name(), self.build_absolute_uri(attachment.attachment_file.url)) + ( + attachment.get_name(), + self.build_absolute_uri(attachment.attachment_file.url), + ) ) else: attachments.append( - (os.path.basename(attachment.attachment_file.name), attachment.attachment_file.read()) + ( + os.path.basename(attachment.attachment_file.name), + attachment.attachment_file.read(), + ) ) return attachments def send(self, to, attachment_paths=None, *args, **kwargs): """This function does all the operations on eft object, that are necessary to send email. - Usually one would use eft object like this: - eft = EmailFromTemplate(name='sth/sth.html') - eft.get_object() - eft.render_message() - eft.send_email(['email@example.com']) - return eft.sent + Usually one would use eft object like this: + eft = EmailFromTemplate(name='sth/sth.html') + eft.get_object() + eft.render_message() + eft.send_email(['email@example.com']) + return eft.sent """ attachments = self.get_default_attachments(as_links=False) - attachments.extend(kwargs.pop('attachments', [])) + attachments.extend(kwargs.pop("attachments", [])) self.get_object() self.render_message() self.send_email(to, attachment_paths, attachments=attachments, *args, **kwargs) if self.sent: - logger.info(u"Mail has been sent to: %s ", to) + logger.info("Mail has been sent to: %s ", to) return self.sent diff --git a/emailtemplates/forms.py b/emailtemplates/forms.py index e7127bb..e1fa494 100644 --- a/emailtemplates/forms.py +++ b/emailtemplates/forms.py @@ -16,49 +16,55 @@ class EmailTemplateAdminForm(forms.ModelForm): - title = forms.ChoiceField(choices=lazy(email_templates.email_template_choices, list), label=_("template")) + title = forms.ChoiceField( + choices=lazy(email_templates.email_template_choices, list), label=_("template") + ) class Meta: model = EmailTemplate fields = [ - 'title', - 'subject', - 'content', - 'language', - 'created', - 'modified', + "title", + "subject", + "content", + "language", + "created", + "modified", ] def __init__(self, *args, **kwargs): super(EmailTemplateAdminForm, self).__init__(*args, **kwargs) - self.fields['title'].help_text = mark_safe(email_templates.get_form_help_text(self.initial.get('title'))) + self.fields["title"].help_text = mark_safe( + email_templates.get_form_help_text(self.initial.get("title")) + ) if self.instance.pk: - self.fields['title'].widget = forms.TextInput(attrs={'readonly': 'readonly', 'style': 'width:480px'}) + self.fields["title"].widget = forms.TextInput( + attrs={"readonly": "readonly", "style": "width:480px"} + ) else: - self.fields['content'].widget = forms.HiddenInput() - self.fields['content'].required = False - self.fields['subject'].widget = forms.HiddenInput() + self.fields["content"].widget = forms.HiddenInput() + self.fields["content"].required = False + self.fields["subject"].widget = forms.HiddenInput() def clean_content(self): - content = self.cleaned_data['content'] + content = self.cleaned_data["content"] try: Template(content) except TemplateSyntaxError as e: - raise ValidationError(u"Syntax error in custom email template: %s" % e) + raise ValidationError("Syntax error in custom email template: %s" % e) return content class MassEmailAttachmentForm(forms.ModelForm): class Meta: model = MassEmailAttachment - fields = ['attachment_file'] + fields = ["attachment_file"] class MassEmailMessageForm(forms.ModelForm): class Meta: model = MassEmailMessage fields = [ - 'subject', - 'content', - 'date_sent', + "subject", + "content", + "date_sent", ] diff --git a/emailtemplates/helpers.py b/emailtemplates/helpers.py index 8a30796..40f0704 100644 --- a/emailtemplates/helpers.py +++ b/emailtemplates/helpers.py @@ -36,7 +36,7 @@ def __unicode__(self): return 'a string containing "%s"' % self.containing def __str__(self): - return unicode(self).encode('utf-8') + return unicode(self).encode("utf-8") __repr__ = __unicode__ @@ -60,15 +60,19 @@ def mass_mailing_recipients(): :rtype iterable """ - if hasattr(settings, 'MASS_EMAIL_RECIPIENTS'): - callback_name = settings.MASS_EMAIL_RECIPIENTS.split('.') - module_name = '.'.join(callback_name[:-1]) + if hasattr(settings, "MASS_EMAIL_RECIPIENTS"): + callback_name = settings.MASS_EMAIL_RECIPIENTS.split(".") + module_name = ".".join(callback_name[:-1]) func_name = callback_name[-1] module = import_module(module_name) func = getattr(module, func_name, lambda: []) return func() User = get_user_model() - if hasattr(User, 'is_active') and hasattr(User, 'email'): - filtered_users = User.objects.filter(is_active=True).exclude(email__isnull=True).exclude(email__exact='') - return filtered_users.values_list('email', flat=True).distinct() + if hasattr(User, "is_active") and hasattr(User, "email"): + filtered_users = ( + User.objects.filter(is_active=True) + .exclude(email__isnull=True) + .exclude(email__exact="") + ) + return filtered_users.values_list("email", flat=True).distinct() return [] diff --git a/emailtemplates/locale/de/LC_MESSAGES/django.mo b/emailtemplates/locale/de/LC_MESSAGES/django.mo index 28e33d9..b0eba4d 100644 Binary files a/emailtemplates/locale/de/LC_MESSAGES/django.mo and b/emailtemplates/locale/de/LC_MESSAGES/django.mo differ diff --git a/emailtemplates/locale/de/LC_MESSAGES/django.po b/emailtemplates/locale/de/LC_MESSAGES/django.po index 223444c..ed7e94c 100644 --- a/emailtemplates/locale/de/LC_MESSAGES/django.po +++ b/emailtemplates/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-13 12:08+0100\n" +"POT-Creation-Date: 2022-08-09 13:50+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -20,96 +20,114 @@ msgstr "" "%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:34 +#: emailtemplates/admin.py:19 emailtemplates/models.py:83 +msgid "Attachment" +msgstr "Anlage" + +#: emailtemplates/admin.py:20 emailtemplates/models.py:84 +msgid "Attachments" +msgstr "Anhänge" + +#: emailtemplates/admin.py:50 msgid "Show email preview" msgstr "E-Mail-Vorschau anzeigen" -#: emailtemplates/admin.py:38 +#: emailtemplates/admin.py:54 msgid "Actions" msgstr "Aktionen" -msgid "Send as link" -msgstr "Als Link versenden" - #: emailtemplates/apps.py:8 msgid "E-MAIL TEMPLATES" msgstr "E-Mail Templates" -#: emailtemplates/forms.py:19 emailtemplates/models.py:25 +#: emailtemplates/forms.py:20 emailtemplates/models.py:29 msgid "template" msgstr "Vorlage" -#: emailtemplates/models.py:26 emailtemplates/models.py:76 +#: emailtemplates/models.py:27 emailtemplates/models.py:68 +#: emailtemplates/models.py:101 +msgid "ID" +msgstr "" + +#: emailtemplates/models.py:30 emailtemplates/models.py:103 msgid "subject" msgstr "Thema" -#: emailtemplates/models.py:27 emailtemplates/models.py:77 +#: emailtemplates/models.py:31 emailtemplates/models.py:104 msgid "content" msgstr "Inhalt" -#: emailtemplates/models.py:28 +#: emailtemplates/models.py:33 msgid "language" msgstr "Sprache" -#: emailtemplates/models.py:30 +#: emailtemplates/models.py:39 +msgid "attachments" +msgstr "anhänge" + +#: emailtemplates/models.py:41 msgid "created" msgstr "erstellt" -#: emailtemplates/models.py:31 +#: emailtemplates/models.py:42 msgid "modified" msgstr "geändert" -#: emailtemplates/models.py:35 +#: emailtemplates/models.py:46 msgid "Email template" msgstr "E-Mail Template" -#: emailtemplates/models.py:36 +#: emailtemplates/models.py:47 msgid "Email templates" msgstr "E-Mail Templates" -#: emailtemplates/models.py:56 +#: emailtemplates/models.py:70 msgid "name" msgstr "Name" -#: emailtemplates/models.py:57 +#: emailtemplates/models.py:72 msgid "Attachment file" msgstr "Datei anhängen" -#: emailtemplates/models.py:61 -msgid "Attachment" -msgstr "Anlage" +#: emailtemplates/models.py:75 +msgid "Comment" +msgstr "Kommentar" -#: emailtemplates/models.py:62 -msgid "Attachments" -msgstr "Anhänge" +#: emailtemplates/models.py:75 +msgid "visible only in admin" +msgstr "nur im Administrationsbereich sichtbar" + +#: emailtemplates/models.py:77 +msgid "Ordering" +msgstr "Bestellung" + +#: emailtemplates/models.py:78 +msgid "Send as link" +msgstr "Als Link versenden" -#: emailtemplates/models.py:65 +#: emailtemplates/models.py:87 #, python-format msgid "Attachment: %s" msgstr "Anlage: %s" -#: emailtemplates/models.py:72 -msgid "email template" -msgstr "E-Mail-Vorlage" - -#: emailtemplates/models.py:78 +#: emailtemplates/models.py:105 msgid "sent" msgstr "gesendet" -#: emailtemplates/models.py:81 +#: emailtemplates/models.py:108 msgid "Mass email message" msgstr "Massen E-Mail" -#: emailtemplates/models.py:82 +#: emailtemplates/models.py:109 msgid "Mass email messages" msgstr "Massen E-Mails" -#: emailtemplates/registry.py:68 +#: emailtemplates/registry.py:80 #, python-format msgid "USAGE: %s" msgstr "ANWENDUNG: %s" -#: emailtemplates/registry.py:69 +#: emailtemplates/registry.py:83 #, python-format msgid "CONTEXT:
%s" msgstr "KONTEXT:
%s" @@ -118,18 +136,31 @@ msgstr "KONTEXT:
%s" msgid "Send to all users" msgstr "An alle Benutzer senden" -#: emailtemplates/views.py:51 +#: emailtemplates/tests/test_template_registry.py:60 +msgid "USAGE" +msgstr "ANWENDUNG" + +#: emailtemplates/tests/test_template_registry.py:61 +msgid "CONTEXT" +msgstr "KONTEXT" + +#: emailtemplates/views.py:55 msgid "" "Mass email was already sent. Create new mail message or force sending from " "shell." msgstr "" -"Die Massen-E-Mail wurde bereits gesendet. Neue E-Mail-Nachricht erstellen oder " -"Senden aus der Shell erzwingen" +"Die Massen-E-Mail wurde bereits gesendet. Neue E-Mail-Nachricht erstellen " +"oder Senden aus der Shell erzwingen" -#: emailtemplates/views.py:56 +#: emailtemplates/views.py:62 msgid "Mass email sent successfully" msgstr "Massen-E-Mail erfolgreich gesendet" -#: emailtemplates/views.py:58 +#: emailtemplates/views.py:65 msgid "Error occurred when trying to send mass email message." -msgstr "Beim Versuch, eine Massen-E-Mail-Nachricht zu senden, ist ein Fehler aufgetreten" +msgstr "" +"Beim Versuch, eine Massen-E-Mail-Nachricht zu senden, ist ein Fehler " +"aufgetreten" + +#~ msgid "email template" +#~ msgstr "E-Mail-Vorlage" diff --git a/emailtemplates/locale/pl/LC_MESSAGES/django.mo b/emailtemplates/locale/pl/LC_MESSAGES/django.mo index 95ddb56..faff1a1 100644 Binary files a/emailtemplates/locale/pl/LC_MESSAGES/django.mo and b/emailtemplates/locale/pl/LC_MESSAGES/django.mo differ diff --git a/emailtemplates/locale/pl/LC_MESSAGES/django.po b/emailtemplates/locale/pl/LC_MESSAGES/django.po index 2f05833..bfd7766 100644 --- a/emailtemplates/locale/pl/LC_MESSAGES/django.po +++ b/emailtemplates/locale/pl/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-13 12:08+0100\n" +"POT-Creation-Date: 2022-08-09 13:50+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -20,96 +20,114 @@ msgstr "" "%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:34 +#: emailtemplates/admin.py:19 emailtemplates/models.py:83 +msgid "Attachment" +msgstr "Załącznik" + +#: emailtemplates/admin.py:20 emailtemplates/models.py:84 +msgid "Attachments" +msgstr "Załączniki" + +#: emailtemplates/admin.py:50 msgid "Show email preview" msgstr "Pokaż podgląd wiadomości" -#: emailtemplates/admin.py:38 +#: emailtemplates/admin.py:54 msgid "Actions" msgstr "Akcje" -msgid "Send as link" -msgstr "Wyślij jako link" - #: emailtemplates/apps.py:8 msgid "E-MAIL TEMPLATES" msgstr "Szblony wiadomości E-mail" -#: emailtemplates/forms.py:19 emailtemplates/models.py:25 +#: emailtemplates/forms.py:20 emailtemplates/models.py:29 msgid "template" msgstr "szablon" -#: emailtemplates/models.py:26 emailtemplates/models.py:76 +#: emailtemplates/models.py:27 emailtemplates/models.py:68 +#: emailtemplates/models.py:101 +msgid "ID" +msgstr "" + +#: emailtemplates/models.py:30 emailtemplates/models.py:103 msgid "subject" msgstr "tytuł" -#: emailtemplates/models.py:27 emailtemplates/models.py:77 +#: emailtemplates/models.py:31 emailtemplates/models.py:104 msgid "content" msgstr "zawartość" -#: emailtemplates/models.py:28 +#: emailtemplates/models.py:33 msgid "language" msgstr "język" -#: emailtemplates/models.py:30 +#: emailtemplates/models.py:39 +msgid "attachments" +msgstr "załączniki" + +#: emailtemplates/models.py:41 msgid "created" msgstr "utworzono" -#: emailtemplates/models.py:31 +#: emailtemplates/models.py:42 msgid "modified" msgstr "zmodyfikowano" -#: emailtemplates/models.py:35 +#: emailtemplates/models.py:46 msgid "Email template" msgstr "Szablon wiadomości" -#: emailtemplates/models.py:36 +#: emailtemplates/models.py:47 msgid "Email templates" msgstr "Szablony wiadomości" -#: emailtemplates/models.py:56 +#: emailtemplates/models.py:70 msgid "name" msgstr "nazwa" -#: emailtemplates/models.py:57 +#: emailtemplates/models.py:72 msgid "Attachment file" msgstr "Plik załącznika" -#: emailtemplates/models.py:61 -msgid "Attachment" -msgstr "Załącznik" +#: emailtemplates/models.py:75 +msgid "Comment" +msgstr "Komentarz" -#: emailtemplates/models.py:62 -msgid "Attachments" -msgstr "Załączniki" +#: emailtemplates/models.py:75 +msgid "visible only in admin" +msgstr "widoczne tylko w panelu administracyjnym" + +#: emailtemplates/models.py:77 +msgid "Ordering" +msgstr "Kolejność" + +#: emailtemplates/models.py:78 +msgid "Send as link" +msgstr "Wyślij jako link" -#: emailtemplates/models.py:65 +#: emailtemplates/models.py:87 #, python-format msgid "Attachment: %s" msgstr "Załącznik: %s" -#: emailtemplates/models.py:72 -msgid "email template" -msgstr "szablon email" - -#: emailtemplates/models.py:78 +#: emailtemplates/models.py:105 msgid "sent" msgstr "wysłano" -#: emailtemplates/models.py:81 +#: emailtemplates/models.py:108 msgid "Mass email message" msgstr "Wiadomość grupowa" -#: emailtemplates/models.py:82 +#: emailtemplates/models.py:109 msgid "Mass email messages" msgstr "Wiadomości grupowe" -#: emailtemplates/registry.py:68 +#: emailtemplates/registry.py:80 #, python-format msgid "USAGE: %s" msgstr "UŻYCIE: %s" -#: emailtemplates/registry.py:69 +#: emailtemplates/registry.py:83 #, python-format msgid "CONTEXT:
%s" msgstr "KONTEKST:
%s" @@ -118,7 +136,15 @@ msgstr "KONTEKST:
%s" msgid "Send to all users" msgstr "Wyślij do wszystkich użytkowników" -#: emailtemplates/views.py:51 +#: emailtemplates/tests/test_template_registry.py:60 +msgid "USAGE" +msgstr "UŻYCIE" + +#: emailtemplates/tests/test_template_registry.py:61 +msgid "CONTEXT" +msgstr "KONTEKST" + +#: emailtemplates/views.py:55 msgid "" "Mass email was already sent. Create new mail message or force sending from " "shell." @@ -126,10 +152,13 @@ msgstr "" "Wiadomość grupowa została już wysłana. Utwórz nową lub wymuś wysłanie z " "konsoli shell." -#: emailtemplates/views.py:56 +#: emailtemplates/views.py:62 msgid "Mass email sent successfully" msgstr "Wiadomość grupowa wysłana pomyślnie" -#: emailtemplates/views.py:58 +#: emailtemplates/views.py:65 msgid "Error occurred when trying to send mass email message." msgstr "Wystąpił błąd podczas próby wysłania wiadomości grupowej." + +#~ msgid "email template" +#~ msgstr "szablon email" diff --git a/emailtemplates/migrations/0001_initial.py b/emailtemplates/migrations/0001_initial.py index 867c720..45b95b1 100644 --- a/emailtemplates/migrations/0001_initial.py +++ b/emailtemplates/migrations/0001_initial.py @@ -10,24 +10,164 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='EmailTemplate', + name="EmailTemplate", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('title', models.CharField(choices=[(b'accounts/activation.html', b'accounts/activation.html'), (b'project/introduction_project_mail_1d.html', b'project/introduction_project_mail_1d.html'), (b'project/notice_original_deletion_3days.html', b'project/notice_original_deletion_3days.html'), (b'accounts/password_reset_email.html', b'accounts/password_reset_email.html'), (b'accounts/email_verification.html', b'accounts/email_verification.html'), (b'share/invitation.html', b'share/invitation.html'), (b'orders/cancelled_payment.html', b'orders/cancelled_payment.html'), (b'project/new_template_available.html', b'project/new_template_available.html'), (b'supports/feedback_email.html', b'supports/feedback_email.html'), (b'invitations/invite_friend.html', b'invitations/invite_friend.html'), (b'project/introduction_project_mail_2d.html', b'project/introduction_project_mail_2d.html'), (b'share/invitation_subject.html', b'share/invitation_subject.html'), (b'orders/delivered.html', b'orders/delivered.html'), (b'project/project_action_notification.html', b'project/project_action_notification.html'), (b'project/notice_original_deletion_1week.html', b'project/notice_original_deletion_1week.html'), (b'accounts/welcome.html', b'accounts/welcome.html'), (b'project/download_zip.html', b'project/download_zip.html'), (b'orders/in_production.html', b'orders/in_production.html'), (b'project/notice_original_deletion_1month.html', b'project/notice_original_deletion_1month.html'), (b'accounts/introducing_email_4d.html', b'accounts/introducing_email_4d.html'), (b'orders/reorder_incentive_mail.html', b'orders/reorder_incentive_mail.html'), (b'project/project_action_like_comment_notification.html', b'project/project_action_like_comment_notification.html'), (b'accounts/introducing_email_2d.html', b'accounts/introducing_email_2d.html'), (b'project/package_expired.html', b'project/package_expired.html'), (b'project/package_upgrade.html', b'project/package_upgrade.html'), (b'project/introduction_project_mail_7d.html', b'project/introduction_project_mail_7d.html'), (b'subscriptions/subscription_email.html', b'subscriptions/subscription_email.html'), (b'accounts/introducing_email_3d.html', b'accounts/introducing_email_3d.html'), (b'accounts/introducing_email_1d.html', b'accounts/introducing_email_1d.html'), (b'supports/support_request.html', b'supports/support_request.html'), (b'supports/support_confirm.html', b'supports/support_confirm.html')], max_length=255, verbose_name='template')), - ('subject', models.CharField(blank=True, max_length=255, verbose_name='subject')), - ('content', models.TextField(verbose_name='content')), - ('language', models.CharField(choices=[(b'de', b'German')], default=b'de', max_length=10, verbose_name='language')), - ('created', models.DateTimeField(default=django.utils.timezone.now)), - ('modified', models.DateTimeField(default=django.utils.timezone.now)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "title", + models.CharField( + choices=[ + (b"accounts/activation.html", b"accounts/activation.html"), + ( + b"project/introduction_project_mail_1d.html", + b"project/introduction_project_mail_1d.html", + ), + ( + b"project/notice_original_deletion_3days.html", + b"project/notice_original_deletion_3days.html", + ), + ( + b"accounts/password_reset_email.html", + b"accounts/password_reset_email.html", + ), + ( + b"accounts/email_verification.html", + b"accounts/email_verification.html", + ), + (b"share/invitation.html", b"share/invitation.html"), + ( + b"orders/cancelled_payment.html", + b"orders/cancelled_payment.html", + ), + ( + b"project/new_template_available.html", + b"project/new_template_available.html", + ), + ( + b"supports/feedback_email.html", + b"supports/feedback_email.html", + ), + ( + b"invitations/invite_friend.html", + b"invitations/invite_friend.html", + ), + ( + b"project/introduction_project_mail_2d.html", + b"project/introduction_project_mail_2d.html", + ), + ( + b"share/invitation_subject.html", + b"share/invitation_subject.html", + ), + (b"orders/delivered.html", b"orders/delivered.html"), + ( + b"project/project_action_notification.html", + b"project/project_action_notification.html", + ), + ( + b"project/notice_original_deletion_1week.html", + b"project/notice_original_deletion_1week.html", + ), + (b"accounts/welcome.html", b"accounts/welcome.html"), + ( + b"project/download_zip.html", + b"project/download_zip.html", + ), + ( + b"orders/in_production.html", + b"orders/in_production.html", + ), + ( + b"project/notice_original_deletion_1month.html", + b"project/notice_original_deletion_1month.html", + ), + ( + b"accounts/introducing_email_4d.html", + b"accounts/introducing_email_4d.html", + ), + ( + b"orders/reorder_incentive_mail.html", + b"orders/reorder_incentive_mail.html", + ), + ( + b"project/project_action_like_comment_notification.html", + b"project/project_action_like_comment_notification.html", + ), + ( + b"accounts/introducing_email_2d.html", + b"accounts/introducing_email_2d.html", + ), + ( + b"project/package_expired.html", + b"project/package_expired.html", + ), + ( + b"project/package_upgrade.html", + b"project/package_upgrade.html", + ), + ( + b"project/introduction_project_mail_7d.html", + b"project/introduction_project_mail_7d.html", + ), + ( + b"subscriptions/subscription_email.html", + b"subscriptions/subscription_email.html", + ), + ( + b"accounts/introducing_email_3d.html", + b"accounts/introducing_email_3d.html", + ), + ( + b"accounts/introducing_email_1d.html", + b"accounts/introducing_email_1d.html", + ), + ( + b"supports/support_request.html", + b"supports/support_request.html", + ), + ( + b"supports/support_confirm.html", + b"supports/support_confirm.html", + ), + ], + max_length=255, + verbose_name="template", + ), + ), + ( + "subject", + models.CharField( + blank=True, max_length=255, verbose_name="subject" + ), + ), + ("content", models.TextField(verbose_name="content")), + ( + "language", + models.CharField( + choices=[(b"de", b"German")], + default=b"de", + max_length=10, + verbose_name="language", + ), + ), + ("created", models.DateTimeField(default=django.utils.timezone.now)), + ("modified", models.DateTimeField(default=django.utils.timezone.now)), ], ), migrations.AlterUniqueTogether( - name='emailtemplate', - unique_together=set([('title', 'language')]), + name="emailtemplate", + unique_together=set([("title", "language")]), ), ] diff --git a/emailtemplates/migrations/0002_auto_20170428_1442.py b/emailtemplates/migrations/0002_auto_20170428_1442.py index 7d62a38..7af84e3 100644 --- a/emailtemplates/migrations/0002_auto_20170428_1442.py +++ b/emailtemplates/migrations/0002_auto_20170428_1442.py @@ -8,13 +8,115 @@ class Migration(migrations.Migration): dependencies = [ - ('emailtemplates', '0001_initial'), + ("emailtemplates", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='emailtemplate', - name='title', - field=models.CharField(choices=[(b'accounts/activation.html', b'accounts/activation.html'), (b'project/introduction_project_mail_1d.html', b'project/introduction_project_mail_1d.html'), (b'project/notice_original_deletion_3days.html', b'project/notice_original_deletion_3days.html'), (b'supports/feedback_email.html', b'supports/feedback_email.html'), (b'accounts/email_verification.html', b'accounts/email_verification.html'), (b'share/invitation.html', b'share/invitation.html'), (b'orders/cancelled_payment.html', b'orders/cancelled_payment.html'), (b'project/new_template_available.html', b'project/new_template_available.html'), (b'invitations/invite_friend.html', b'invitations/invite_friend.html'), (b'project/introduction_project_mail_2d.html', b'project/introduction_project_mail_2d.html'), (b'share/invitation_subject.html', b'share/invitation_subject.html'), (b'orders/delivered.html', b'orders/delivered.html'), (b'subscriptions/subscription_email.html', b'subscriptions/subscription_email.html'), (b'project/notice_original_deletion_1week.html', b'project/notice_original_deletion_1week.html'), (b'accounts/welcome.html', b'accounts/welcome.html'), (b'project/download_zip.html', b'project/download_zip.html'), (b'orders/in_production.html', b'orders/in_production.html'), (b'project/notice_original_deletion_1month.html', b'project/notice_original_deletion_1month.html'), (b'accounts/introducing_email_4d.html', b'accounts/introducing_email_4d.html'), (b'orders/reorder_incentive_mail.html', b'orders/reorder_incentive_mail.html'), (b'project/project_action_like_comment_notification.html', b'project/project_action_like_comment_notification.html'), (b'accounts/introducing_email_2d.html', b'accounts/introducing_email_2d.html'), (b'accounts/password_reset_email.html', b'accounts/password_reset_email.html'), (b'project/package_expired.html', b'project/package_expired.html'), (b'project/package_upgrade.html', b'project/package_upgrade.html'), (b'project/introduction_project_mail_7d.html', b'project/introduction_project_mail_7d.html'), (b'project/project_action_notification.html', b'project/project_action_notification.html'), (b'accounts/introducing_email_3d.html', b'accounts/introducing_email_3d.html'), (b'accounts/introducing_email_1d.html', b'accounts/introducing_email_1d.html'), (b'supports/support_request.html', b'supports/support_request.html'), (b'supports/support_confirm.html', b'supports/support_confirm.html')], max_length=255, verbose_name='template'), + model_name="emailtemplate", + name="title", + field=models.CharField( + choices=[ + (b"accounts/activation.html", b"accounts/activation.html"), + ( + b"project/introduction_project_mail_1d.html", + b"project/introduction_project_mail_1d.html", + ), + ( + b"project/notice_original_deletion_3days.html", + b"project/notice_original_deletion_3days.html", + ), + (b"supports/feedback_email.html", b"supports/feedback_email.html"), + ( + b"accounts/email_verification.html", + b"accounts/email_verification.html", + ), + (b"share/invitation.html", b"share/invitation.html"), + ( + b"orders/cancelled_payment.html", + b"orders/cancelled_payment.html", + ), + ( + b"project/new_template_available.html", + b"project/new_template_available.html", + ), + ( + b"invitations/invite_friend.html", + b"invitations/invite_friend.html", + ), + ( + b"project/introduction_project_mail_2d.html", + b"project/introduction_project_mail_2d.html", + ), + ( + b"share/invitation_subject.html", + b"share/invitation_subject.html", + ), + (b"orders/delivered.html", b"orders/delivered.html"), + ( + b"subscriptions/subscription_email.html", + b"subscriptions/subscription_email.html", + ), + ( + b"project/notice_original_deletion_1week.html", + b"project/notice_original_deletion_1week.html", + ), + (b"accounts/welcome.html", b"accounts/welcome.html"), + (b"project/download_zip.html", b"project/download_zip.html"), + (b"orders/in_production.html", b"orders/in_production.html"), + ( + b"project/notice_original_deletion_1month.html", + b"project/notice_original_deletion_1month.html", + ), + ( + b"accounts/introducing_email_4d.html", + b"accounts/introducing_email_4d.html", + ), + ( + b"orders/reorder_incentive_mail.html", + b"orders/reorder_incentive_mail.html", + ), + ( + b"project/project_action_like_comment_notification.html", + b"project/project_action_like_comment_notification.html", + ), + ( + b"accounts/introducing_email_2d.html", + b"accounts/introducing_email_2d.html", + ), + ( + b"accounts/password_reset_email.html", + b"accounts/password_reset_email.html", + ), + (b"project/package_expired.html", b"project/package_expired.html"), + (b"project/package_upgrade.html", b"project/package_upgrade.html"), + ( + b"project/introduction_project_mail_7d.html", + b"project/introduction_project_mail_7d.html", + ), + ( + b"project/project_action_notification.html", + b"project/project_action_notification.html", + ), + ( + b"accounts/introducing_email_3d.html", + b"accounts/introducing_email_3d.html", + ), + ( + b"accounts/introducing_email_1d.html", + b"accounts/introducing_email_1d.html", + ), + ( + b"supports/support_request.html", + b"supports/support_request.html", + ), + ( + b"supports/support_confirm.html", + b"supports/support_confirm.html", + ), + ], + max_length=255, + verbose_name="template", + ), ), ] diff --git a/emailtemplates/migrations/0003_auto_20180523_1027.py b/emailtemplates/migrations/0003_auto_20180523_1027.py index e4ec1d9..4d40744 100644 --- a/emailtemplates/migrations/0003_auto_20180523_1027.py +++ b/emailtemplates/migrations/0003_auto_20180523_1027.py @@ -8,17 +8,28 @@ class Migration(migrations.Migration): dependencies = [ - ('emailtemplates', '0002_auto_20170428_1442'), + ("emailtemplates", "0002_auto_20170428_1442"), ] operations = [ migrations.CreateModel( - name='MassEmailMessage', + name="MassEmailMessage", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('subject', models.CharField(max_length=255, verbose_name='subject')), - ('content', models.TextField(verbose_name='content')), - ('date_sent', models.DateTimeField(blank=True, null=True, verbose_name='sent')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("subject", models.CharField(max_length=255, verbose_name="subject")), + ("content", models.TextField(verbose_name="content")), + ( + "date_sent", + models.DateTimeField(blank=True, null=True, verbose_name="sent"), + ), ], ), ] diff --git a/emailtemplates/migrations/0004_auto_20180523_1608.py b/emailtemplates/migrations/0004_auto_20180523_1608.py index 0941d67..7784b80 100644 --- a/emailtemplates/migrations/0004_auto_20180523_1608.py +++ b/emailtemplates/migrations/0004_auto_20180523_1608.py @@ -9,28 +9,48 @@ class Migration(migrations.Migration): dependencies = [ - ('emailtemplates', '0003_auto_20180523_1027'), + ("emailtemplates", "0003_auto_20180523_1027"), ] operations = [ migrations.CreateModel( - name='MassEmailAttachment', + name="MassEmailAttachment", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('attachment_file', models.FileField(upload_to=b'', verbose_name='Attachment file')), - ('mass_email_message', - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='emailtemplates.MassEmailMessage')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "attachment_file", + models.FileField(upload_to=b"", verbose_name="Attachment file"), + ), + ( + "mass_email_message", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="emailtemplates.MassEmailMessage", + ), + ), ], ), migrations.AlterField( - model_name='emailtemplate', - name='language', - field=models.CharField(choices=settings.LANGUAGES, default=settings.LANGUAGE_CODE, max_length=10, - verbose_name='language'), + model_name="emailtemplate", + name="language", + field=models.CharField( + choices=settings.LANGUAGES, + default=settings.LANGUAGE_CODE, + max_length=10, + verbose_name="language", + ), ), migrations.AlterField( - model_name='emailtemplate', - name='title', - field=models.CharField(max_length=255, verbose_name='template'), + model_name="emailtemplate", + name="title", + field=models.CharField(max_length=255, verbose_name="template"), ), ] diff --git a/emailtemplates/migrations/0005_auto_20201110_1115.py b/emailtemplates/migrations/0005_auto_20201110_1115.py index bc41e16..c7e48b6 100644 --- a/emailtemplates/migrations/0005_auto_20201110_1115.py +++ b/emailtemplates/migrations/0005_auto_20201110_1115.py @@ -6,27 +6,36 @@ class Migration(migrations.Migration): dependencies = [ - ('emailtemplates', '0004_auto_20180523_1608'), + ("emailtemplates", "0004_auto_20180523_1608"), ] operations = [ migrations.AlterModelOptions( - name='emailtemplate', - options={'verbose_name': 'Email template', 'verbose_name_plural': 'Email templates'}, + name="emailtemplate", + options={ + "verbose_name": "Email template", + "verbose_name_plural": "Email templates", + }, ), migrations.AlterModelOptions( - name='massemailmessage', - options={'verbose_name': 'Mass email message', 'verbose_name_plural': 'Mass email messages'}, + name="massemailmessage", + options={ + "verbose_name": "Mass email message", + "verbose_name_plural": "Mass email messages", + }, ), migrations.AlterField( - model_name='massemailattachment', - name='attachment_file', - field=models.FileField(upload_to='', verbose_name='Attachment file'), + model_name="massemailattachment", + name="attachment_file", + field=models.FileField(upload_to="", verbose_name="Attachment file"), ), migrations.AlterField( - model_name='massemailattachment', - name='mass_email_message', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attachments', - to='emailtemplates.massemailmessage'), + model_name="massemailattachment", + name="mass_email_message", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="attachments", + to="emailtemplates.massemailmessage", + ), ), ] diff --git a/emailtemplates/migrations/0006_auto_20201110_1151.py b/emailtemplates/migrations/0006_auto_20201110_1151.py index 3f43306..b82a6a8 100644 --- a/emailtemplates/migrations/0006_auto_20201110_1151.py +++ b/emailtemplates/migrations/0006_auto_20201110_1151.py @@ -7,18 +7,22 @@ class Migration(migrations.Migration): dependencies = [ - ('emailtemplates', '0005_auto_20201110_1115'), + ("emailtemplates", "0005_auto_20201110_1115"), ] operations = [ migrations.AlterField( - model_name='emailtemplate', - name='created', - field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='created'), + model_name="emailtemplate", + name="created", + field=models.DateTimeField( + default=django.utils.timezone.now, verbose_name="created" + ), ), migrations.AlterField( - model_name='emailtemplate', - name='modified', - field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='modified'), + model_name="emailtemplate", + name="modified", + field=models.DateTimeField( + default=django.utils.timezone.now, verbose_name="modified" + ), ), ] diff --git a/emailtemplates/migrations/0007_auto_20201113_1354.py b/emailtemplates/migrations/0007_auto_20201113_1354.py index a92948f..6e9ac3a 100644 --- a/emailtemplates/migrations/0007_auto_20201113_1354.py +++ b/emailtemplates/migrations/0007_auto_20201113_1354.py @@ -6,40 +6,65 @@ class Migration(migrations.Migration): dependencies = [ - ('emailtemplates', '0006_auto_20201110_1151'), + ("emailtemplates", "0006_auto_20201110_1151"), ] operations = [ migrations.CreateModel( - name='EmailAttachment', + name="EmailAttachment", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(blank=True, max_length=50, verbose_name='name')), - ('attachment_file', models.FileField(upload_to='emails/attachments/', verbose_name='Attachment file')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "name", + models.CharField(blank=True, max_length=50, verbose_name="name"), + ), + ( + "attachment_file", + models.FileField( + upload_to="emails/attachments/", verbose_name="Attachment file" + ), + ), ], options={ - 'verbose_name': 'Attachment', - 'verbose_name_plural': 'Attachments', - 'abstract': False, + "verbose_name": "Attachment", + "verbose_name_plural": "Attachments", + "abstract": False, }, ), migrations.AlterModelOptions( - name='massemailattachment', - options={'verbose_name': 'Attachment', 'verbose_name_plural': 'Attachments'}, + name="massemailattachment", + options={ + "verbose_name": "Attachment", + "verbose_name_plural": "Attachments", + }, ), migrations.AddField( - model_name='massemailattachment', - name='name', - field=models.CharField(blank=True, max_length=50, verbose_name='name'), + model_name="massemailattachment", + name="name", + field=models.CharField(blank=True, max_length=50, verbose_name="name"), ), migrations.AlterField( - model_name='massemailattachment', - name='attachment_file', - field=models.FileField(upload_to='emails/attachments/', verbose_name='Attachment file'), + model_name="massemailattachment", + name="attachment_file", + field=models.FileField( + upload_to="emails/attachments/", verbose_name="Attachment file" + ), ), migrations.AddField( - model_name='emailtemplate', - name='attachments', - field=models.ManyToManyField(blank=True, to='emailtemplates.EmailAttachment', verbose_name='attachments'), + model_name="emailtemplate", + name="attachments", + field=models.ManyToManyField( + blank=True, + to="emailtemplates.EmailAttachment", + verbose_name="attachments", + ), ), ] diff --git a/emailtemplates/migrations/0008_auto_20201120_1056.py b/emailtemplates/migrations/0008_auto_20201120_1056.py index bc6932c..5f4e712 100644 --- a/emailtemplates/migrations/0008_auto_20201120_1056.py +++ b/emailtemplates/migrations/0008_auto_20201120_1056.py @@ -6,18 +6,18 @@ class Migration(migrations.Migration): dependencies = [ - ('emailtemplates', '0007_auto_20201113_1354'), + ("emailtemplates", "0007_auto_20201113_1354"), ] operations = [ migrations.AddField( - model_name='emailattachment', - name='send_as_link', - field=models.BooleanField(default=True, verbose_name='Send as link'), + model_name="emailattachment", + name="send_as_link", + field=models.BooleanField(default=True, verbose_name="Send as link"), ), migrations.AddField( - model_name='massemailattachment', - name='send_as_link', - field=models.BooleanField(default=True, verbose_name='Send as link'), + model_name="massemailattachment", + name="send_as_link", + field=models.BooleanField(default=True, verbose_name="Send as link"), ), ] diff --git a/emailtemplates/migrations/0010_auto_20220803_1419.py b/emailtemplates/migrations/0010_auto_20220803_1419.py new file mode 100644 index 0000000..e879af4 --- /dev/null +++ b/emailtemplates/migrations/0010_auto_20220803_1419.py @@ -0,0 +1,53 @@ +# Generated by Django 3.1.13 on 2022-08-03 12:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("emailtemplates", "0009_auto_20220111_1011"), + ] + + operations = [ + migrations.AlterModelOptions( + name="emailattachment", + options={ + "ordering": ["ordering"], + "verbose_name": "Attachment", + "verbose_name_plural": "Attachments", + }, + ), + migrations.AlterModelOptions( + name="massemailattachment", + options={ + "ordering": ["ordering"], + "verbose_name": "Attachment", + "verbose_name_plural": "Attachments", + }, + ), + migrations.AddField( + model_name="emailattachment", + name="comment", + field=models.TextField( + blank=True, verbose_name="Comment", help_text="visible only in admin" + ), + ), + migrations.AddField( + model_name="emailattachment", + name="ordering", + field=models.PositiveIntegerField(default=0, verbose_name="Ordering"), + ), + migrations.AddField( + model_name="massemailattachment", + name="comment", + field=models.TextField( + blank=True, verbose_name="Comment", help_text="visible only in admin" + ), + ), + migrations.AddField( + model_name="massemailattachment", + name="ordering", + field=models.PositiveIntegerField(default=0, verbose_name="Ordering"), + ), + ] diff --git a/emailtemplates/models.py b/emailtemplates/models.py index d675346..ec4dcf4 100644 --- a/emailtemplates/models.py +++ b/emailtemplates/models.py @@ -22,30 +22,40 @@ class EmailTemplate(models.Model): """ Model to store email template. """ - title = models.CharField(_(u'template'), max_length=255) - subject = models.CharField(_(u'subject'), max_length=255, blank=True) - content = models.TextField(_(u'content')) - language = models.CharField(_(u'language'), max_length=10, choices=settings.LANGUAGES, - default=settings.LANGUAGE_CODE) - attachments = models.ManyToManyField("EmailAttachment", blank=True, verbose_name=_("attachments")) + + id = models.BigAutoField( + 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) + content = models.TextField(_("content")) + language = models.CharField( + _("language"), + max_length=10, + choices=settings.LANGUAGES, + default=settings.LANGUAGE_CODE, + ) + attachments = models.ManyToManyField( + "EmailAttachment", blank=True, verbose_name=_("attachments") + ) created = models.DateTimeField(default=now, verbose_name=_("created")) modified = models.DateTimeField(default=now, verbose_name=_("modified")) class Meta: - unique_together = (('title', 'language'),) - verbose_name = _('Email template') - verbose_name_plural = _('Email templates') + unique_together = (("title", "language"),) + verbose_name = _("Email template") + verbose_name_plural = _("Email templates") def __str__(self): - return '%s -> %s' % (self.title, self.language) + return "%s -> %s" % (self.title, self.language) def get_default_content(self): loader = TemplateSourceLoader() try: return loader.get_source(self.title) except Exception as e: - logger.error('Error loading template %s. Details: %s ', self.title, e) - return '' + logger.error("Error loading template %s. Details: %s ", self.title, e) + return "" def save(self, *args, **kwargs): if not self.content: @@ -54,12 +64,22 @@ def save(self, *args, **kwargs): class BaseEmailAttachment(models.Model): + id = models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name=_("ID") + ) name = models.CharField(_("name"), blank=True, max_length=50) - attachment_file = models.FileField(_(u"Attachment file"), upload_to="emails/attachments/") + attachment_file = models.FileField( + _("Attachment file"), upload_to="emails/attachments/" + ) + comment = models.TextField( + verbose_name=_("Comment"), blank=True, help_text=_("visible only in admin") + ) + ordering = models.PositiveIntegerField(verbose_name=_("Ordering"), default=0) send_as_link = models.BooleanField(verbose_name=_("Send as link"), default=True) class Meta: abstract = True + ordering = ["ordering"] verbose_name = _("Attachment") verbose_name_plural = _("Attachments") @@ -77,13 +97,16 @@ class EmailAttachment(BaseEmailAttachment): class MassEmailMessage(models.Model): - subject = models.CharField(_(u'subject'), max_length=255) - content = models.TextField(_(u'content')) - date_sent = models.DateTimeField(_(u'sent'), null=True, blank=True) + id = models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name=_("ID") + ) + subject = models.CharField(_("subject"), max_length=255) + content = models.TextField(_("content")) + date_sent = models.DateTimeField(_("sent"), null=True, blank=True) class Meta: - verbose_name = _('Mass email message') - verbose_name_plural = _('Mass email messages') + verbose_name = _("Mass email message") + verbose_name_plural = _("Mass email messages") def __str__(self): return self.subject @@ -94,26 +117,35 @@ def sent(self): def send(self, recipients=None, force=False): from emailtemplates.email import EmailFromTemplate + recipients = recipients or mass_mailing_recipients() if self.sent and not force: return False eft = EmailFromTemplate( - name="emailtemplates/mass_email.html", subject=self.subject, - template_object=self, registry_validation=False, + name="emailtemplates/mass_email.html", + subject=self.subject, + template_object=self, + registry_validation=False, ) - attachment_paths = [attachment.attachment_file.path for attachment in self.attachments.all()] + attachment_paths = [ + attachment.attachment_file.path for attachment in self.attachments.all() + ] sent_count = 0 for recipient in recipients: sent = eft.send(to=[recipient], attachment_paths=attachment_paths) if sent: sent_count += 1 - logger.info(u"Successfully sent mass email message to user %s", recipient) + logger.info( + "Successfully sent mass email message to user %s", recipient + ) else: - logger.warning(u"Error sending mass email message to user %s", recipient) + logger.warning("Error sending mass email message to user %s", recipient) self.date_sent = now() self.save() return sent_count == len(recipients) class MassEmailAttachment(BaseEmailAttachment): - mass_email_message = models.ForeignKey(MassEmailMessage, related_name="attachments", on_delete=models.CASCADE) + mass_email_message = models.ForeignKey( + MassEmailMessage, related_name="attachments", on_delete=models.CASCADE + ) diff --git a/emailtemplates/registry.py b/emailtemplates/registry.py index 2d06503..9bb58cc 100644 --- a/emailtemplates/registry.py +++ b/emailtemplates/registry.py @@ -4,7 +4,6 @@ from django.template.loader import render_to_string from django.utils.translation import gettext_lazy as _ - logger = logging.getLogger(__name__) @@ -20,6 +19,7 @@ class HelpContext(object): """ Provides helpers methods for displaying help context keys (descriptions) and values (examples). """ + def __init__(self, help_context): self.help_context = help_context or {} @@ -44,13 +44,12 @@ def get_help_values(self): if isinstance(v, tuple) and len(v) == 2: help_values[k] = v[1] else: - help_values[k] = u"<%s>" % k + help_values[k] = "<%s>" % k return help_values class RegistrationItem(object): - - def __init__(self, path, help_text=u"", help_context=None, name=""): + def __init__(self, path, help_text="", help_context=None, name=""): self.name = name or path self.path = path self.help_text = help_text @@ -61,16 +60,31 @@ def help_context(self): return self.help_context_obj.get_help_keys() def _context_key(self, key): - return u"{{ %s }}" % key + return "{{ %s }}" % key def context_description(self): - help_text_item = lambda k, v: u"%s - %s" % (self._context_key(k), v) if v else u"%s" % self._context_key(k) - return u"
".join([help_text_item(k, v) for (k, v) in sorted(self.help_context_obj.get_help_keys().items())]) + help_text_item = ( + lambda k, v: "%s - %s" % (self._context_key(k), v) + if v + else "%s" % self._context_key(k) + ) + return "
".join( + [ + help_text_item(k, v) + for (k, v) in sorted(self.help_context_obj.get_help_keys().items()) + ] + ) def as_form_help_text(self): - item_help_text = _(u"USAGE: %s") % self.help_text if self.help_text else u"" - item_help_context = _(u"CONTEXT:
%s") % self.context_description() if self.help_context_obj.get_help_keys() else u"" - return u"
".join((item_help_text, item_help_context)) + item_help_text = ( + _("USAGE: %s") % self.help_text if self.help_text else "" + ) + item_help_context = ( + _("CONTEXT:
%s") % self.context_description() + if self.help_context_obj.get_help_keys() + else "" + ) + return "
".join((item_help_text, item_help_context)) def as_form_choice(self): return self.path, self.name @@ -80,7 +94,6 @@ def get_help_content(self): class EmailTemplateRegistry(object): - def __init__(self): self._registry = {} @@ -89,8 +102,8 @@ def register(self, path, name="", help_text=None, help_context=None): Registers email template. Example usage: - email_templates.register('hello_template.html', help_text=u'Hello template', - help_context={'username': u'Name of user in hello expression'}) + email_templates.register('hello_template.html', help_text='Hello template', + help_context={'username': 'Name of user in hello expression'}) :param name: Template name [optional] :param path: Template file path. It will become immutable registry lookup key. @@ -103,8 +116,10 @@ def register(self, path, name="", help_text=None, help_context=None): If an email template is already registered, this will raise AlreadyRegistered. """ 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) + raise AlreadyRegistered("The template %s is already registered" % path) + self._registry[path] = RegistrationItem( + path, help_text, help_context, name=name + ) logger.debug("Registered email template %s", path) def is_registered(self, path): @@ -146,11 +161,12 @@ def get_form_help_text(self, path): Returns text that can be used as form help text for creating email templates. """ try: - form_help_text = render_to_string("admin/emailtemplates/_helptext.html", context={ - 'registration_item': self.get_registration(path) - }) + form_help_text = render_to_string( + "admin/emailtemplates/_helptext.html", + context={"registration_item": self.get_registration(path)}, + ) except NotRegistered: - form_help_text = u"" + form_help_text = "" return form_help_text diff --git a/emailtemplates/shortcuts.py b/emailtemplates/shortcuts.py index 25d4068..3a36af8 100644 --- a/emailtemplates/shortcuts.py +++ b/emailtemplates/shortcuts.py @@ -2,7 +2,7 @@ from .email import EmailFromTemplate -def send_email(name, ctx_dict, send_to=None, subject=u'Subject', **kwargs): +def send_email(name, ctx_dict, send_to=None, subject="Subject", **kwargs): """ Shortcut function for EmailFromTemplate class diff --git a/emailtemplates/tests/test_email.py b/emailtemplates/tests/test_email.py index 27eb923..58041f0 100644 --- a/emailtemplates/tests/test_email.py +++ b/emailtemplates/tests/test_email.py @@ -1,7 +1,7 @@ # coding=utf-8 -import mock import os +import mock from django.conf import settings from django.core import mail from django.test import TestCase, override_settings @@ -10,8 +10,7 @@ from ..email import EmailFromTemplate from ..email import logger as email_logger -from ..helpers import substr -from ..models import EmailTemplate +from ..models import EmailTemplate, EmailAttachment from ..registry import email_templates, NotRegistered, EmailTemplateRegistry @@ -23,10 +22,10 @@ def check_email_was_sent(self, eft, to, reply_to=None): self.assertTrue(len(mail.outbox) > 0) msg = mail.outbox[0] self.assertTrue(settings.DEFAULT_FROM_EMAIL in msg.from_email) - self.assertEqual(msg.content_subtype, 'html') + self.assertEqual(msg.content_subtype, "html") self.assertEqual(msg.subject, eft.subject) self.assertEqual(msg.body, eft.message) - self.assertTrue('Message-Id' in msg.message()) + self.assertTrue("Message-Id" in msg.message()) self.assertEqual(msg.to, to) self.assertEqual(msg.reply_to, reply_to) @@ -35,37 +34,61 @@ class EmailFromTemplateTest(CheckEmail): def setUp(self): mail.outbox = [] email_templates = EmailTemplateRegistry() - email_logger.warning = Mock() - self.attachment_filepath = os.path.join(os.path.dirname(__file__), 'data', 'example_file.txt') + self.attachment_filepath = os.path.join( + os.path.dirname(__file__), "data", "example_file.txt" + ) - @override_settings(DEFAULT_REPLY_TO_EMAIL='hello@hello.pl') + @override_settings(DEFAULT_REPLY_TO_EMAIL="hello@hello.pl") def test_empty_object(self): eft = EmailFromTemplate(registry_validation=False) self.assertTrue(isinstance(eft, object)) eft.render_message() - to = ['to@example.com'] + to = ["to@example.com"] eft.send_email(to) - self.check_email_was_sent(eft, to, reply_to=['hello@hello.pl']) + self.check_email_was_sent(eft, to, reply_to=["hello@hello.pl"]) @override_settings(DEFAULT_REPLY_TO_EMAIL=None) def test_empty_object_with_empty_reply_to(self): eft = EmailFromTemplate(registry_validation=False) self.assertTrue(isinstance(eft, object)) eft.render_message() - to = ['to@example.com'] + to = ["to@example.com"] eft.send_email(to) self.check_email_was_sent(eft, to) - def test_with_empty_db_object(self): - eft = EmailFromTemplate(registry_validation=False) + @mock.patch("emailtemplates.email.logger") + def test_with_empty_db_object(self, mock_logger): + eft = EmailFromTemplate(registry_validation=False, name="template.html") eft.get_object() - email_logger.warning.assert_has_calls(substr("Can't find EmailTemplate object in database")) - email_logger.warning.assert_has_calls(substr("template in the filesystem, will use very default one")) + mock_logger.warning.assert_called_with( + "Can't find %s template in the filesystem, will use very default one.", + "template.html", + ) eft.render_message() - to = ['to@example.com'] + to = ["to@example.com"] eft.send_email(to) self.check_email_was_sent(eft, to) + def test_get_default_attachments_ordering(self): + email_template = EmailTemplate.objects.create(title="template.html") + attachment1 = EmailAttachment.objects.create( + name="file1", + attachment_file="test/file1.pdf", + ordering=10, + send_as_link=True, + ) + attachment2 = EmailAttachment.objects.create( + name="file2", + attachment_file="test/file2.pdf", + ordering=1, + send_as_link=True, + ) + email_template.attachments.add(attachment1, attachment2) + eft = EmailFromTemplate(registry_validation=False, name="template.html") + result = eft.get_default_attachments(as_links=True) + self.assertEqual(result[0][0], attachment2.name) + self.assertEqual(result[1][0], attachment1.name) + def test_init_check_email_templates_registry(self): with self.assertRaises(NotRegistered): email_template = EmailFromTemplate("some_template.html") @@ -75,63 +98,73 @@ def test_init_check_email_templates_registry(self): def test_send_attachment_paths(self): eft = EmailFromTemplate(registry_validation=False) - to = ['to@example.com'] + to = ["to@example.com"] eft.send(to, attachment_paths=[self.attachment_filepath]) self.check_email_was_sent(eft, to) self.assertEqual( - mail.outbox[0].attachments, - [('example_file.txt', u'Some content of example file.', 'text/plain')], + mail.outbox[0].attachments, + [("example_file.txt", "Some content of example file.", "text/plain")], ) class EmailFromTemplateWithFixturesTest(CheckEmail): def setUp(self): - self.language = 'pl' + self.language = "pl" email_templates = EmailTemplateRegistry() self.support_template = EmailTemplate.objects.create( language=self.language, - title='support_respond.html', + title="support_respond.html", subject="Hi {{ user_name }}", - content="Support: {{ user_name }}" + content="Support: {{ user_name }}", ) mail.outbox = [] email_logger.debug = Mock() def test_support_database_template(self): - template_name = 'support_respond.html' - eft = EmailFromTemplate(name=template_name, language=self.language, registry_validation=False) + template_name = "support_respond.html" + eft = EmailFromTemplate( + name=template_name, language=self.language, registry_validation=False + ) eft.context = {"user_name": "Lucas"} eft.get_object() - email_logger.debug.assert_called_with('Got template %s from database', template_name) - self.assertEqual(eft.template_source, 'database') + email_logger.debug.assert_called_with( + "Got template %s from database", template_name + ) + self.assertEqual(eft.template_source, "database") eft.render_message() - to = ['tester1@example.com', 'tester2@example.com'] + to = ["tester1@example.com", "tester2@example.com"] eft.send_email(to) self.check_email_was_sent(eft, to) def test_support_database_template_without_title(self): - self.support_template.subject = '' - self.support_template.save(update_fields=['subject']) + self.support_template.subject = "" + self.support_template.save(update_fields=["subject"]) eft = EmailFromTemplate( - name='support_respond.html', - subject='default email title - hi {{ user_name }}', + name="support_respond.html", + subject="default email title - hi {{ user_name }}", language=self.language, - registry_validation=False + registry_validation=False, ) eft.context = {"user_name": "Lucas"} eft.get_object() - self.assertEqual(eft.subject, 'default email title - hi Lucas') + self.assertEqual(eft.subject, "default email title - hi Lucas") def test_friends_invitation_no_database_or_filesystem_template(self): eft = EmailFromTemplate(registry_validation=False) - eft.context = {'user_name': 'Alibaba', - 'personal_message': "I'd like you te be site member!", - 'landing_url': 'http://example.com/followers/612/'} + eft.context = { + "user_name": "Alibaba", + "personal_message": "I'd like you te be site member!", + "landing_url": "http://example.com/followers/612/", + } eft.template = "{{ user_name }}, {{ personal_message }} {{ landing_url }}" eft.render_message() - self.assertEqual(eft.message, - escape(u"Alibaba, I'd like you te be site member! http://example.com/followers/612/")) - to = ['tester@example.com'] - self.assertEqual(eft.template_source, 'default') + self.assertEqual( + eft.message, + escape( + "Alibaba, I'd like you te be site member! http://example.com/followers/612/" + ), + ) + to = ["tester@example.com"] + self.assertEqual(eft.template_source, "default") eft.send_email(to) self.check_email_was_sent(eft, to) diff --git a/emailtemplates/tests/test_helpers.py b/emailtemplates/tests/test_helpers.py index 4993b87..d81600f 100644 --- a/emailtemplates/tests/test_helpers.py +++ b/emailtemplates/tests/test_helpers.py @@ -5,17 +5,21 @@ def recipients_test_function(): - return ['user@example.com', 'another@example.com'] + return ["user@example.com", "another@example.com"] -class HelpersTest(TestCase): +class HelpersTest(TestCase): def test_mass_mailing_recipients(self): User = get_user_model() User.objects.create(username="mike", email="mike@example.com", is_active=True) User.objects.create(username="john", email="john@example.com", is_active=False) User.objects.create(username="paul", is_active=True) self.assertEqual(list(mass_mailing_recipients()), ["mike@example.com"]) - - @override_settings(MASS_EMAIL_RECIPIENTS='emailtemplates.tests.test_helpers.recipients_test_function') + + @override_settings( + MASS_EMAIL_RECIPIENTS="emailtemplates.tests.test_helpers.recipients_test_function" + ) def test_mass_mailing_recipients_from_settings(self): - self.assertEqual(mass_mailing_recipients(), ['user@example.com', 'another@example.com']) + self.assertEqual( + mass_mailing_recipients(), ["user@example.com", "another@example.com"] + ) diff --git a/emailtemplates/tests/test_models.py b/emailtemplates/tests/test_models.py index 352c801..beee1f0 100644 --- a/emailtemplates/tests/test_models.py +++ b/emailtemplates/tests/test_models.py @@ -1,8 +1,9 @@ # encoding: utf-8 from __future__ import unicode_literals -import mock + import os +import mock from django.core import mail from django.core.files import File from django.test import TestCase @@ -13,38 +14,46 @@ class EmailTemplateTest(TestCase): def setUp(self): - self.default_content = '

TEST DEFAULT CONTENT

' - self.email_template = EmailTemplate.objects.create(title='template-1.html') + self.default_content = "

TEST DEFAULT CONTENT

" + self.email_template = EmailTemplate.objects.create(title="template-1.html") - @mock.patch.object(TemplateSourceLoader, 'get_source') + @mock.patch.object(TemplateSourceLoader, "get_source") def test_get_default_content(self, mock_source): mock_source.return_value = self.default_content - self.assertEqual(self.email_template.get_default_content(), self.default_content) + self.assertEqual( + self.email_template.get_default_content(), self.default_content + ) - @mock.patch.object(TemplateSourceLoader, 'get_source', mock.Mock(side_effect=Exception('error...'))) + @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(), '') + self.assertEqual(self.email_template.get_default_content(), "") - @mock.patch.object(TemplateSourceLoader, 'get_source') + @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') + email_template = EmailTemplate.objects.create(title="template-2.html") self.assertEqual(email_template.content, self.default_content) - @mock.patch.object(TemplateSourceLoader, 'get_source') + @mock.patch.object(TemplateSourceLoader, "get_source") def test_do_not_override_existing_content(self, mock_source): mock_source.return_value = self.default_content - email_template = EmailTemplate.objects.create(title='template-2.html', content='

New content

') - self.assertEqual(email_template.content, '

New content

') + email_template = EmailTemplate.objects.create( + title="template-2.html", content="

New content

" + ) + self.assertEqual(email_template.content, "

New content

") class MassEmailMessageTest(TestCase): def setUp(self): self.mass_email_message = MassEmailMessage.objects.create( - subject="Temat maila", - content="

Treść emaila

" + subject="Temat maila", content="

Treść emaila

" ) - self.attachment_filepath = os.path.join(os.path.dirname(__file__), 'data', 'example_file.txt') + self.attachment_filepath = os.path.join( + os.path.dirname(__file__), "data", "example_file.txt" + ) + mail.outbox = [] def test_send(self): recipients = ["person@example.com"] @@ -57,13 +66,15 @@ def test_send(self): def test_send_with_attachments(self): attachment = MassEmailAttachment.objects.create( - attachment_file=File(open(self.attachment_filepath, 'r'), 'example_file.txt'), + attachment_file=File( + open(self.attachment_filepath, "r"), "example_file.txt" + ), mass_email_message=self.mass_email_message, ) recipients = ["person@example.com"] sent = self.mass_email_message.send(recipients) self.assertTrue(sent) self.assertEqual( - mail.outbox[0].attachments, - [('example_file.txt', u'Some content of example file.', 'text/plain')], - ) \ No newline at end of file + mail.outbox[0].attachments, + [("example_file.txt", "Some content of example file.", "text/plain")], + ) diff --git a/emailtemplates/tests/test_template_registry.py b/emailtemplates/tests/test_template_registry.py index 942458f..6e0da11 100644 --- a/emailtemplates/tests/test_template_registry.py +++ b/emailtemplates/tests/test_template_registry.py @@ -1,121 +1,155 @@ # coding=utf-8 from django.test import TestCase +from django.utils.translation import gettext as _ from ..registry import EmailTemplateRegistry, RegistrationItem, HelpContext class HelpContextTest(TestCase): - def test_get_help_keys(self): - help_context = HelpContext({ - 'username': (u'Name of user in hello expression', u'superman_90'), - 'full_name': (u'Full user name', u'John Smith'), - 'property': u'Some other property', - }) - self.assertDictEqual(help_context.get_help_keys(), { - 'username': u'Name of user in hello expression', - 'full_name': u'Full user name', - 'property': u'Some other property', - }) + help_context = HelpContext( + { + "username": ("Name of user in hello expression", "superman_90"), + "full_name": ("Full user name", "John Smith"), + "property": "Some other property", + } + ) + self.assertDictEqual( + help_context.get_help_keys(), + { + "username": "Name of user in hello expression", + "full_name": "Full user name", + "property": "Some other property", + }, + ) def test_get_help_values(self): - help_context = HelpContext({ - 'username': (u'Name of user in hello expression', u'superman_90'), - 'full_name': (u'Full user name', u'John Smith'), - 'property': u'Some other property', - }) - self.assertDictEqual(help_context.get_help_values(), { - 'username': u'superman_90', - 'full_name': u'John Smith', - 'property': u'', - }) + help_context = HelpContext( + { + "username": ("Name of user in hello expression", "superman_90"), + "full_name": ("Full user name", "John Smith"), + "property": "Some other property", + } + ) + self.assertDictEqual( + help_context.get_help_values(), + { + "username": "superman_90", + "full_name": "John Smith", + "property": "", + }, + ) class RegistrationItemTest(TestCase): - def test_context_description(self): - item = RegistrationItem('hello_template.html', help_text=u'Hello template', - help_context={'username': u'Name of user in hello expression'}) - self.assertIn(u"{{ username }}", item.context_description()) + item = RegistrationItem( + "hello_template.html", + help_text="Hello template", + help_context={"username": "Name of user in hello expression"}, + ) + self.assertIn("{{ username }}", item.context_description()) def test_as_form_help_text(self): - item = RegistrationItem('hello_template.html', help_text=u'Hello template', - help_context={'username': u'Name of user in hello expression'}) + item = RegistrationItem( + "hello_template.html", + help_text="Hello template", + help_context={"username": "Name of user in hello expression"}, + ) self.assertEqual(str, type(item.as_form_help_text())) - self.assertIn("USAGE", item.as_form_help_text()) - self.assertIn("CONTEXT", item.as_form_help_text()) + self.assertIn(_("USAGE"), item.as_form_help_text()) + self.assertIn(_("CONTEXT"), item.as_form_help_text()) def test_as_form_choice(self): - item = RegistrationItem('hello_template.html', help_text=u'Hello template', - help_context={'username': u'Name of user in hello expression'}) + item = RegistrationItem( + "hello_template.html", + help_text="Hello template", + help_context={"username": "Name of user in hello expression"}, + ) self.assertEqual(tuple, type(item.as_form_choice())) def test_safe_defaults(self): - item = RegistrationItem('hello_template.html') + item = RegistrationItem("hello_template.html") self.assertEqual(str, type(item.help_text)) self.assertEqual(dict, type(item.help_context)) self.assertEqual(tuple, type(item.as_form_choice())) class EmailTemplateRegistryTest(TestCase): - def test_is_registered(self): registry = EmailTemplateRegistry() - registry.register('hello_template.html') - self.assertTrue(registry.is_registered('hello_template.html')) + registry.register("hello_template.html") + self.assertTrue(registry.is_registered("hello_template.html")) def test_get_help_text(self): template_registry = EmailTemplateRegistry() - template_registry.register('hello_template.html', help_text=u'Hello template', - help_context={'username': u'Name of user in hello expression'}) - help_text = template_registry.get_help_text('hello_template.html') - self.assertEqual(help_text, u'Hello template') + template_registry.register( + "hello_template.html", + help_text="Hello template", + help_context={"username": "Name of user in hello expression"}, + ) + help_text = template_registry.get_help_text("hello_template.html") + self.assertEqual(help_text, "Hello template") def test_get_help_context(self): template_registry = EmailTemplateRegistry() - template_registry.register('hello_template.html', help_text=u'Hello template', - help_context={'username': u'Name of user in hello expression'}) - help_context = template_registry.get_help_context('hello_template.html') - self.assertIn('username', help_context) + template_registry.register( + "hello_template.html", + help_text="Hello template", + help_context={"username": "Name of user in hello expression"}, + ) + help_context = template_registry.get_help_context("hello_template.html") + self.assertIn("username", help_context) def test_get_help_content(self): template_registry = EmailTemplateRegistry() - template_registry.register('hello_template.html', help_text=u'Hello template', - help_context={ - 'username': (u'Name of user in hello expression', u'superman_90'), - 'full_name': (u'Full user name', u'John Smith'), - 'property': u'Some other property', - }) - help_content = template_registry.get_help_content('hello_template.html') - self.assertDictEqual(help_content, { - 'username': u'superman_90', - 'full_name': u'John Smith', - 'property': u'', - }) + template_registry.register( + "hello_template.html", + help_text="Hello template", + help_context={ + "username": ("Name of user in hello expression", "superman_90"), + "full_name": ("Full user name", "John Smith"), + "property": "Some other property", + }, + ) + help_content = template_registry.get_help_content("hello_template.html") + self.assertDictEqual( + help_content, + { + "username": "superman_90", + "full_name": "John Smith", + "property": "", + }, + ) def test_get_email_templates(self): template_registry = EmailTemplateRegistry() - template_registry.register('hello_template.html', help_text=u'Hello template', - help_context={'username': u'Name of user in hello expression'}) - template_registry.register('simple_template.html', help_text=u'Simple template') + template_registry.register( + "hello_template.html", + help_text="Hello template", + help_context={"username": "Name of user in hello expression"}, + ) + template_registry.register("simple_template.html", help_text="Simple template") self.assertEqual(2, len(template_registry.email_template_choices())) def test_email_template_choices(self): template_registry = EmailTemplateRegistry() - template_registry.register('hello_template.html', help_text=u'Hello template', - help_context={'username': u'Name of user in hello expression'}) + template_registry.register( + "hello_template.html", + help_text="Hello template", + help_context={"username": "Name of user in hello expression"}, + ) self.assertEqual(1, len(template_registry.email_template_choices())) template, _ = template_registry.email_template_choices()[0] - self.assertEqual('hello_template.html', template) + self.assertEqual("hello_template.html", template) def test_registration_items(self): template_registry = EmailTemplateRegistry() - template_registry.register('hello_template.html', help_text=u'Hello template', - help_context={'username': u'Name of user in hello expression'}) + template_registry.register( + "hello_template.html", + help_text="Hello template", + help_context={"username": "Name of user in hello expression"}, + ) items = list(template_registry.registration_items()) self.assertEqual(1, len(items)) - self.assertEqual('hello_template.html', items[0].path) - - - - + self.assertEqual("hello_template.html", items[0].path) diff --git a/emailtemplates/urls.py b/emailtemplates/urls.py index 680bd50..040cd7f 100644 --- a/emailtemplates/urls.py +++ b/emailtemplates/urls.py @@ -3,6 +3,8 @@ from emailtemplates.views import email_preview_view, send_mass_email_view urlpatterns = [ - url(r'^email-preview/(?P\d+)/$', email_preview_view, name='email_preview'), - url(r'^send-mass-email/(?P\d+)/$', send_mass_email_view, name='send_mass_email'), + url(r"^email-preview/(?P\d+)/$", email_preview_view, name="email_preview"), + url( + r"^send-mass-email/(?P\d+)/$", send_mass_email_view, name="send_mass_email" + ), ] diff --git a/emailtemplates/views.py b/emailtemplates/views.py index 6a9a124..f7292e8 100644 --- a/emailtemplates/views.py +++ b/emailtemplates/views.py @@ -15,9 +15,8 @@ class EmailPreviewView(View): - def get_email_template(self): - return get_object_or_404(EmailTemplate, pk=self.kwargs['pk']) + return get_object_or_404(EmailTemplate, pk=self.kwargs["pk"]) def get_context_data(self): email_template = self.get_email_template() @@ -28,7 +27,7 @@ def get(self, request, *args, **kwargs): email_content = Template(email_template.content) return HttpResponse( email_content.render(Context(self.get_context_data())), - content_type='text/html; charset=utf-8' + content_type="text/html; charset=utf-8", ) @@ -36,26 +35,35 @@ def get(self, request, *args, **kwargs): class SendMassEmailView(View): - def get_mass_email_message(self): - return get_object_or_404(MassEmailMessage, pk=self.kwargs['pk']) + return get_object_or_404(MassEmailMessage, pk=self.kwargs["pk"]) def redirect_back(self): return HttpResponseRedirect( - reverse('admin:emailtemplates_massemailmessage_change', args=(self.get_mass_email_message().pk,)), + reverse( + "admin:emailtemplates_massemailmessage_change", + args=(self.get_mass_email_message().pk,), + ), ) def get(self, request, *args, **kwargs): mass_email_message = self.get_mass_email_message() if mass_email_message.sent: - messages.success(request, _("Mass email was already sent. " - "Create new mail message or force sending from shell.")) + messages.success( + request, + _( + "Mass email was already sent. " + "Create new mail message or force sending from shell." + ), + ) return self.redirect_back() sent = mass_email_message.send() if sent: messages.success(request, _("Mass email sent successfully")) else: - messages.warning(request, _("Error occurred when trying to send mass email message.")) + messages.warning( + request, _("Error occurred when trying to send mass email message.") + ) return self.redirect_back() diff --git a/setup.py b/setup.py index 1562e3f..e1e846e 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ setup( name='django-emailtemplates', - version='1.1.13', + version='1.1.14', packages=find_packages(), package_data={'emailtemplates': ['locale/*/LC_MESSAGES/*.po', 'locale/*/LC_MESSAGES/*.mo']}, include_package_data=True,