Skip to content

Commit b8f09f9

Browse files
committed
πŸ§‘β€πŸ’»(admin) provider selftest views
This allows to define views available in /admin/selftest/ like an email sender testing view for instance. I'm still not sure about this...
1 parent 6b2ca88 commit b8f09f9

File tree

6 files changed

+238
-0
lines changed

6 files changed

+238
-0
lines changed

β€Žsrc/backend/admin/registry.py

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"""
2+
Registry for custom admin views.
3+
4+
It allows to automatically register all views that inherit from
5+
`BaseSelftestAdminPageView` and add them to the admin site.
6+
"""
7+
8+
import inspect
9+
10+
from . import views
11+
12+
13+
class ViewRegistry:
14+
"""Registry for custom admin views."""
15+
16+
def __init__(self):
17+
"""Initialize the registry."""
18+
self.views = []
19+
self._register_views()
20+
21+
def register(self, view_class, name, path):
22+
"""Register a view with its name and path."""
23+
self.views.append(
24+
{
25+
"view_class": view_class,
26+
"name": name,
27+
"title": view_class.title,
28+
"path": path,
29+
}
30+
)
31+
32+
def _register_views(self):
33+
"""Register all views."""
34+
35+
for name, obj in inspect.getmembers(views):
36+
if (
37+
inspect.isclass(obj)
38+
and issubclass(obj, views.BaseSelftestAdminPageView)
39+
and not obj == views.BaseSelftestAdminPageView
40+
):
41+
# Extract name and path from class name
42+
base_name = name.replace("SelftestAdminPageView", "").lower()
43+
self.register(
44+
view_class=obj,
45+
name=base_name,
46+
path=obj.path,
47+
)
48+
49+
def get_views(self):
50+
"""Get all registered views."""
51+
return self.views
52+
53+
54+
# Create a registry instance
55+
view_registry = ViewRegistry()

β€Žsrc/backend/admin/sites.py

+19
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
from django.conf import settings
44
from django.contrib import admin
5+
from django.urls import path
6+
7+
from .registry import view_registry
58

69

710
class PeopleAdminSite(admin.AdminSite):
@@ -13,3 +16,19 @@ def each_context(self, request):
1316
"ADMIN_HEADER_BACKGROUND": settings.ADMIN_HEADER_BACKGROUND,
1417
"ADMIN_HEADER_COLOR": settings.ADMIN_HEADER_COLOR,
1518
}
19+
20+
def get_urls(self):
21+
"""Add custom URLs to the admin site."""
22+
urls = super().get_urls()
23+
24+
# Add all registered views from the registry
25+
selftest_urls = [
26+
path(
27+
f"selftest/{view_info['path']}",
28+
self.admin_view(view_info["view_class"].as_view()),
29+
name=f"selftest_{view_info['name']}",
30+
)
31+
for view_info in view_registry.get_views()
32+
]
33+
34+
return selftest_urls + urls
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{% extends "admin/base_site.html" %}
2+
{% load i18n %}
3+
4+
{% block breadcrumbs %}
5+
<div class="breadcrumbs">
6+
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
7+
&rsaquo;
8+
<a href="{% url 'admin:selftest_index' %}">{% trans 'Selftest' %}</a>
9+
{% if not is_index %} &rsaquo; {{ title }} {% endif %}
10+
</div>
11+
{% endblock %}
12+
13+
{% block content %}
14+
<div id="content-main">
15+
<div id="change-history" class="app-selftest module">
16+
{% block selftest_content %}{% endblock %}
17+
</div>
18+
</div>
19+
{% endblock %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{% extends "selftest/base.html" %}
2+
3+
{% block breadcrumbs %}
4+
<div class="breadcrumbs">
5+
<a href="{% url 'admin:index' %}">Home</a>
6+
&rsaquo; <a href="{% url 'admin:selftest_index' %}">Selftest</a>
7+
&rsaquo; {{ title }}
8+
</div>
9+
{% endblock %}
10+
11+
{% block selftest_content %}
12+
<form method="post">
13+
{% csrf_token %}
14+
<div class="form-row">
15+
<label for="id_email">Recipient Email:</label>
16+
<input type="email" name="email" id="id_email" required>
17+
</div>
18+
<div class="submit-row">
19+
<input type="submit" value="Send Test Email" class="default">
20+
</div>
21+
</form>
22+
{% endblock %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{% extends "selftest/base.html" %}
2+
{% load i18n %}
3+
4+
{% block breadcrumbs %}
5+
<div class="breadcrumbs">
6+
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
7+
&rsaquo;
8+
<a href="{% url 'admin:selftest_index' %}">{% trans 'Selftest' %}</a>
9+
</div>
10+
{% endblock %}
11+
12+
{% block selftest_content %}
13+
14+
<table>
15+
<caption>
16+
{% trans 'Available Selftest Pages' %}
17+
</caption>
18+
<tbody>
19+
{% for page in pages %}
20+
<tr>
21+
<th scope="row">
22+
<a href="{% url 'admin:selftest_'|add:page.url_name %}"
23+
>{{ page.title }}</a
24+
>
25+
</th>
26+
</tr>
27+
{% endfor %}
28+
</tbody>
29+
</table>
30+
31+
{% endblock %}
32+

β€Žsrc/backend/admin/views.py

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""Custom admin views for the People app."""
2+
3+
from smtplib import SMTPException
4+
5+
from django.views.generic import TemplateView
6+
7+
8+
class BaseSelftestAdminPageView(TemplateView):
9+
"""Base class for selftest admin pages."""
10+
11+
is_index = False
12+
template_name = "selftest/base.html"
13+
title = "Selftest Admin Page" # should be overridden in subclasses
14+
path = None
15+
16+
def get_context_data(self, **kwargs):
17+
"""Add the title to the context."""
18+
context = super().get_context_data(**kwargs)
19+
20+
context["title"] = self.title
21+
return context
22+
23+
24+
class IndexSelftestAdminPageView(BaseSelftestAdminPageView):
25+
"""View for the selftest index page."""
26+
27+
template_name = "selftest/index.html"
28+
is_index = True
29+
title = "Selftest Admin Index Page"
30+
path = ""
31+
32+
def get_context_data(self, **kwargs):
33+
"""Add all registered views to the context."""
34+
from .registry import view_registry # pylint: disable=import-outside-toplevel
35+
36+
context = super().get_context_data(**kwargs)
37+
context["pages"] = [
38+
{
39+
"title": view["title"],
40+
"url_name": view["name"],
41+
}
42+
for view in sorted(
43+
[
44+
view
45+
for view in view_registry.get_views()
46+
if not view["view_class"].is_index
47+
],
48+
key=lambda x: x["name"],
49+
)
50+
]
51+
return context
52+
53+
54+
class EmailSelftestAdminPageView(BaseSelftestAdminPageView):
55+
"""View for testing email functionality."""
56+
57+
title = "Send test email"
58+
template_name = "selftest/email.html"
59+
path = "email/"
60+
61+
def get(self, request, *args, **kwargs):
62+
"""Handle GET request."""
63+
context = self.get_context_data(**kwargs)
64+
context["form"] = {"email": ""}
65+
return self.render_to_response(context)
66+
67+
def post(self, request, *args, **kwargs):
68+
"""Handle POST request to send test email."""
69+
from django.contrib import messages
70+
from django.core.mail import send_mail
71+
72+
context = self.get_context_data(**kwargs)
73+
email = request.POST.get("email", "")
74+
75+
if email:
76+
try:
77+
send_mail(
78+
subject="Test Email from People Admin",
79+
message="This is a test email from the People Admin site.",
80+
from_email=None, # Use DEFAULT_FROM_EMAIL
81+
recipient_list=[email],
82+
fail_silently=False,
83+
)
84+
messages.success(request, f"Test email sent successfully to {email}")
85+
except SMTPException as e:
86+
messages.error(request, f"Failed to send email: {str(e)}")
87+
else:
88+
messages.error(request, "Please provide an email address")
89+
90+
context["form"] = {"email": email}
91+
return self.render_to_response(context)

0 commit comments

Comments
Β (0)