diff --git a/post_office/admin.py b/post_office/admin.py index 5ebff70c..9c89fbc2 100644 --- a/post_office/admin.py +++ b/post_office/admin.py @@ -1,23 +1,30 @@ import re from django import forms -from django.db import models -from django.contrib import admin from django.conf import settings -from django.conf.urls import re_path +from django.contrib import admin from django.core.exceptions import ValidationError from django.core.mail.message import SafeMIMEText +from django.db import models from django.forms import BaseInlineFormSet from django.forms.widgets import TextInput -from django.http.response import HttpResponse, HttpResponseNotFound -from django.template import Context, Template +from django.http.response import HttpResponse +from django.http.response import HttpResponseNotFound +from django.template import Context +from django.template import Template +from django.urls import re_path from django.urls import reverse from django.utils.html import format_html from django.utils.text import Truncator from django.utils.translation import gettext_lazy as _ +from . import settings as post_office_settings from .fields import CommaSeparatedEmailField -from .models import Attachment, Log, Email, EmailTemplate, STATUS +from .models import Attachment +from .models import Email +from .models import EmailTemplate +from .models import Log +from .models import STATUS from .sanitizer import clean_html @@ -249,24 +256,54 @@ def __init__(self, *args, **kwargs): self.fields['language'].disabled = True +def _create_iframe(src, height): + return format_html(''' + + ''', height=height, src=src) + + class EmailTemplateInline(admin.StackedInline): form = EmailTemplateAdminForm formset = EmailTemplateAdminFormSet model = EmailTemplate extra = 0 - fields = ('language', 'subject', 'content', 'html_content',) + fields = ('language', 'subject', 'content', 'html_content', + 'rendered_content', 'rendered_html_content',) + readonly_fields = ('rendered_content', 'rendered_html_content',) formfield_overrides = { models.CharField: {'widget': SubjectField} } + def rendered_content(self, instance): + if instance.content: + src = '?preview=text&language={}'.format(instance.language) + height = instance.content.count('\n') * 25 + return _create_iframe(src, height) + else: + return '' + + def rendered_html_content(self, instance): + if instance.html_content: + src = '?preview=text&language={}'.format(instance.language) + return _create_iframe(src, 800) + else: + return '' + def get_max_num(self, request, obj=None, **kwargs): return len(settings.LANGUAGES) class EmailTemplateAdmin(admin.ModelAdmin): form = EmailTemplateAdminForm - list_display = ('name', 'description_shortened', 'subject', 'languages_compact', 'created') + list_display = ( + 'name', 'description_shortened', 'subject', 'languages_compact', + 'created') search_fields = ('name', 'description', 'subject') + readonly_fields = ('rendered_content', 'rendered_html_content') fieldsets = [ (None, { 'fields': ('name', 'description'), @@ -274,11 +311,56 @@ class EmailTemplateAdmin(admin.ModelAdmin): (_("Default Content"), { 'fields': ('subject', 'content', 'html_content'), }), + (_("Preview"), { + 'fields': ('example_context', 'rendered_content', + 'rendered_html_content'), + }), ] inlines = (EmailTemplateInline,) if settings.USE_I18N else () formfield_overrides = { models.CharField: {'widget': SubjectField} } + change_form_template = 'admin/post_office/EmailTemplate/change_form.html' + + def change_view(self, request, object_id, form_url='', extra_context=None): + if request.GET.get('preview'): + instance = self.model.objects.get(id=object_id) + engine = post_office_settings.get_template_engine() + + if request.GET.get('language'): + template_instance = instance.translated_templates.filter( + language=request.GET.get('language'), + ).first() + else: + template_instance = instance + + if request.GET.get('preview') == 'html': + template = engine.from_string( + template_instance.html_content + .replace('inline_image', 'static') + .replace(' post_office ', ' static ')) + else: + template = engine.from_string( + '
%s
' % template_instance.content) + + return HttpResponse(clean_html(template.render( + instance.example_context))) + + return super().change_view(request, object_id, form_url, extra_context) + + def rendered_content(self, instance): + if instance.content: + src = '?preview=text' + height = instance.content.count('\n') * 25 + return _create_iframe(src, height) + else: + return '' + + def rendered_html_content(self, instance): + if instance.html_content: + return _create_iframe('?preview=html', 800) + else: + return '' def get_queryset(self, request): return self.model.objects.filter(default_template__isnull=True) diff --git a/post_office/migrations/0012_add_example_context.py b/post_office/migrations/0012_add_example_context.py new file mode 100644 index 00000000..492cb536 --- /dev/null +++ b/post_office/migrations/0012_add_example_context.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.10 on 2021-12-12 02:17 + +from django.db import migrations, models +import jsonfield.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('post_office', '0011_models_help_text'), + ] + + operations = [ + migrations.AddField( + model_name='emailtemplate', + name='example_context', + field=jsonfield.fields.JSONField(blank=True, null=True, verbose_name='Context'), + ), + ] diff --git a/post_office/models.py b/post_office/models.py index d736d48e..1033d6f0 100644 --- a/post_office/models.py +++ b/post_office/models.py @@ -269,6 +269,7 @@ class EmailTemplate(models.Model): default='', blank=True) default_template = models.ForeignKey('self', related_name='translated_templates', null=True, default=None, verbose_name=_('Default template'), on_delete=models.CASCADE) + example_context = context_field_class(_('Context'), blank=True, null=True) objects = EmailTemplateManager()