-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a dashboard with email previews (#92)
Introducing a way to access a dashboard with all available email classes used in the project. --------- Co-authored-by: Johannes Maron <[email protected]>
- Loading branch information
Showing
15 changed files
with
318 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
"""This module is used to register the email classes for the emark dashboard. | ||
The following is an example of how to use this module: | ||
```python | ||
from emark.messages import MarkdownEmail | ||
from emark.contrib import dashboard | ||
@dashboard.register | ||
class MyEmail(MarkdownEmail): | ||
template = "my_app/emails/my_email.md" | ||
``` | ||
""" | ||
|
||
from emark.message import MarkdownEmail | ||
|
||
_registry: dict[str, type[MarkdownEmail]] = {} | ||
|
||
|
||
__all__ = ["register"] | ||
|
||
|
||
def register(cls: type[MarkdownEmail], key: str = None) -> type[MarkdownEmail]: | ||
"""Register a MarkdownEmail with the registry.""" | ||
_registry[key or f"{cls.__module__}{cls.__qualname__}"] = cls | ||
return cls |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class EmarkDashboardAppConfig(AppConfig): | ||
name = "emark.contrib.dashboard" | ||
label = "emark_dashboard" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{% extends "admin/base_site.html" %} | ||
{% block branding %} | ||
{{ block.super }} | ||
{% url 'emark-dashboard:dashboard' as dashboard_url %} | ||
{% if request.path != dashboard_url %} | ||
<a href="{% url 'emark-dashboard:dashboard' %}" | ||
style="align-self: center">eMark</a> | ||
{% endif %} | ||
{% endblock %} |
16 changes: 16 additions & 0 deletions
16
emark/contrib/dashboard/templates/emark/dashboard/dashboard.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{% extends "admin/base_site.html" %} | ||
{% block content %} | ||
<h2>eMark Dashboard</h2> | ||
{% regroup emails by app_label as emails_by_app_label %} | ||
{% for app_label in emails_by_app_label %} | ||
<h3>{{ app_label.grouper }}</h3> | ||
<ul> | ||
{% for email in app_label.list %} | ||
<li> | ||
<a href="{{ email.detail_url }}">{{ email.name }}</a> | ||
{% if email.doc %}-- {{ email.doc }}{% endif %} | ||
</li> | ||
{% endfor %} | ||
</ul> | ||
{% endfor %} | ||
{% endblock %} |
18 changes: 18 additions & 0 deletions
18
emark/contrib/dashboard/templates/emark/dashboard/preview.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{% extends "admin/base_site.html" %} | ||
{% load i18n %} | ||
{% block breadcrumbs %} | ||
<div class="breadcrumbs"> | ||
<a href="{% url 'admin:index' %}">{% translate 'Home' %}</a> | ||
› | ||
<a href="{% url 'emark-dashboard:dashboard' %}">{{ title }}</a> | ||
› {{ subtitle }} | ||
</div> | ||
{% endblock %} | ||
{% block content %} | ||
<div id="preview"></div> | ||
<script> | ||
const iFrame = document.getElementById('preview'); | ||
const shadow = iFrame.attachShadow({ mode: "open" }); | ||
shadow.innerHTML = `{{ email.preview|safe }}`; | ||
</script> | ||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
from django.contrib.admin.views.decorators import staff_member_required | ||
from django.urls import include, path | ||
|
||
from . import views | ||
|
||
app_name = "emark-dashboard" | ||
|
||
urlpatterns = [ | ||
path("", staff_member_required(views.DashboardView.as_view()), name="dashboard"), | ||
path( | ||
"<str:email_class>/", | ||
include( | ||
[ | ||
path( | ||
"preview", | ||
staff_member_required(views.EmailPreviewView.as_view()), | ||
name="email-preview", | ||
) | ||
] | ||
), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
from django.http import Http404 | ||
from django.urls import reverse | ||
from django.views.generic import TemplateView | ||
|
||
from ...message import MarkdownEmail | ||
from . import _registry | ||
|
||
|
||
def serialize_email_class(email_class: type[MarkdownEmail], path: str) -> {str: str}: | ||
return { | ||
"app_label": email_class.__module__.split(".")[0], | ||
"class": email_class, | ||
"name": email_class.__name__, | ||
"doc": email_class.__doc__ or "", | ||
"detail_url": reverse("emark-dashboard:email-preview", args=[path]), | ||
"preview": email_class.render_preview, | ||
} | ||
|
||
|
||
class DashboardView(TemplateView): | ||
"""Show a dashboard of registered email classes.""" | ||
|
||
template_name = "emark/dashboard/dashboard.html" | ||
|
||
def get_context_data(self, **kwargs): | ||
return super().get_context_data(**kwargs) | { | ||
"site_header": "eMark", | ||
"site_title": "eMark", | ||
"title": "Dashboard", | ||
"emails": [ | ||
serialize_email_class(klass, path) for path, klass in _registry.items() | ||
], | ||
} | ||
|
||
|
||
class EmailPreviewView(TemplateView): | ||
"""Render a preview of a single email template.""" | ||
|
||
template_name = "emark/dashboard/preview.html" | ||
|
||
def get(self, request, *args, **kwargs): | ||
key = kwargs["email_class"] | ||
try: | ||
self.email_class = _registry[key] | ||
except KeyError as e: | ||
raise Http404() from e | ||
return super().get(request, *args, **kwargs) | ||
|
||
def get_context_data(self, **kwargs): | ||
return super().get_context_data(**kwargs) | { | ||
"site_header": "eMark", | ||
"site_title": "eMark", | ||
"title": "Dashboard", | ||
"subtitle": self.email_class.__name__, | ||
"email": serialize_email_class( | ||
self.email_class, self.kwargs["email_class"] | ||
), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import pytest | ||
from django.http import Http404 | ||
from emark.contrib.dashboard import _registry, views | ||
from emark.message import MarkdownEmail | ||
|
||
|
||
class MarkdownEmailTest(MarkdownEmail): | ||
template = "template.md" | ||
|
||
|
||
def test_serialize_email_class(): | ||
assert views.serialize_email_class(email_class=MarkdownEmailTest, path="path") == { | ||
"app_label": "tests", | ||
"class": MarkdownEmailTest, | ||
"detail_url": "/emark/dashboard/path/preview", | ||
"doc": "", | ||
"name": "MarkdownEmailTest", | ||
"preview": MarkdownEmailTest.render_preview, | ||
} | ||
|
||
|
||
class TestDashboardView: | ||
|
||
def test_get_context_data(self, rf): | ||
request = rf.get("/emark/dashboard/") | ||
view = views.DashboardView() | ||
view.setup(request) | ||
context = view.get_context_data() | ||
assert context == { | ||
"site_header": "eMark", | ||
"site_title": "eMark", | ||
"title": "Dashboard", | ||
"emails": [], | ||
"view": view, | ||
} | ||
|
||
def test_render(self, admin_client): | ||
response = admin_client.get("/emark/dashboard/") | ||
assert response.status_code == 200 | ||
|
||
|
||
class TestEmailPreviewView: | ||
|
||
def test_get__404(self, rf): | ||
request = rf.get("/emark/dashboard/path/preview") | ||
view = views.EmailPreviewView() | ||
with pytest.raises(Http404): | ||
view.dispatch(request, email_class="path") | ||
|
||
def test_get(self, rf): | ||
view = views.EmailPreviewView() | ||
view.request = rf.get("/emark/dashboard/tests.MarkdownEmailTest/preview") | ||
view.kwargs = {"email_class": "tests.MarkdownEmailTest"} | ||
_registry["MarkdownEmailTest"] = MarkdownEmailTest | ||
view.get(view.request, email_class="MarkdownEmailTest") | ||
assert view.email_class == MarkdownEmailTest | ||
del _registry["MarkdownEmailTest"] | ||
|
||
def test_get_context_data(self): | ||
view = views.EmailPreviewView() | ||
view.kwargs = {"email_class": "MarkdownEmailTest"} | ||
view.email_class = MarkdownEmailTest | ||
context = view.get_context_data() | ||
_registry["MarkdownEmailTest"] = MarkdownEmailTest | ||
assert context == { | ||
"view": view, | ||
"site_header": "eMark", | ||
"site_title": "eMark", | ||
"title": "Dashboard", | ||
"subtitle": "MarkdownEmailTest", | ||
"email": { | ||
"app_label": "tests", | ||
"class": MarkdownEmailTest, | ||
"name": "MarkdownEmailTest", | ||
"doc": "", | ||
"detail_url": "/emark/dashboard/MarkdownEmailTest/preview", | ||
"preview": MarkdownEmailTest.render_preview, | ||
}, | ||
} | ||
|
||
del _registry["MarkdownEmailTest"] | ||
|
||
def test_render(self, admin_client): | ||
_registry["MarkdownEmailTest"] = MarkdownEmailTest | ||
response = admin_client.get("/emark/dashboard/MarkdownEmailTest/preview") | ||
assert response.status_code == 200 | ||
del _registry["MarkdownEmailTest"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters