Compare commits

...

1 Commits

Author SHA1 Message Date
Quentin BEY de7adb221f 🧑‍💻(admin) add selftest views mechanism
This allows to define views available in /admin/selftest/ like an email
sender testing view for instance.

I'm still not sure about this...
2025-03-20 15:14:48 +01:00
6 changed files with 238 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
"""
Registry for custom admin views.
It allows to automatically register all views that inherit from
`BaseSelftestAdminPageView` and add them to the admin site.
"""
import inspect
from . import views
class ViewRegistry:
"""Registry for custom admin views."""
def __init__(self):
"""Initialize the registry."""
self.views = []
self._register_views()
def register(self, view_class, name, path):
"""Register a view with its name and path."""
self.views.append(
{
"view_class": view_class,
"name": name,
"title": view_class.title,
"path": path,
}
)
def _register_views(self):
"""Register all views."""
for name, obj in inspect.getmembers(views):
if (
inspect.isclass(obj)
and issubclass(obj, views.BaseSelftestAdminPageView)
and not obj == views.BaseSelftestAdminPageView
):
# Extract name and path from class name
base_name = name.replace("SelftestAdminPageView", "").lower()
self.register(
view_class=obj,
name=base_name,
path=obj.path,
)
def get_views(self):
"""Get all registered views."""
return self.views
# Create a registry instance
view_registry = ViewRegistry()
+19
View File
@@ -2,6 +2,9 @@
from django.conf import settings
from django.contrib import admin
from django.urls import path
from .registry import view_registry
class PeopleAdminSite(admin.AdminSite):
@@ -13,3 +16,19 @@ class PeopleAdminSite(admin.AdminSite):
"ADMIN_HEADER_BACKGROUND": settings.ADMIN_HEADER_BACKGROUND,
"ADMIN_HEADER_COLOR": settings.ADMIN_HEADER_COLOR,
}
def get_urls(self):
"""Add custom URLs to the admin site."""
urls = super().get_urls()
# Add all registered views from the registry
selftest_urls = [
path(
f"selftest/{view_info['path']}",
self.admin_view(view_info["view_class"].as_view()),
name=f"selftest_{view_info['name']}",
)
for view_info in view_registry.get_views()
]
return selftest_urls + urls
@@ -0,0 +1,19 @@
{% extends "admin/base_site.html" %}
{% load i18n %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo;
<a href="{% url 'admin:selftest_index' %}">{% trans 'Selftest' %}</a>
{% if not is_index %} &rsaquo; {{ title }} {% endif %}
</div>
{% endblock %}
{% block content %}
<div id="content-main">
<div id="change-history" class="app-selftest module">
{% block selftest_content %}{% endblock %}
</div>
</div>
{% endblock %}
@@ -0,0 +1,22 @@
{% extends "selftest/base.html" %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">Home</a>
&rsaquo; <a href="{% url 'admin:selftest_index' %}">Selftest</a>
&rsaquo; {{ title }}
</div>
{% endblock %}
{% block selftest_content %}
<form method="post">
{% csrf_token %}
<div class="form-row">
<label for="id_email">Recipient Email:</label>
<input type="email" name="email" id="id_email" required>
</div>
<div class="submit-row">
<input type="submit" value="Send Test Email" class="default">
</div>
</form>
{% endblock %}
@@ -0,0 +1,32 @@
{% extends "selftest/base.html" %}
{% load i18n %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo;
<a href="{% url 'admin:selftest_index' %}">{% trans 'Selftest' %}</a>
</div>
{% endblock %}
{% block selftest_content %}
<table>
<caption>
{% trans 'Available Selftest Pages' %}
</caption>
<tbody>
{% for page in pages %}
<tr>
<th scope="row">
<a href="{% url 'admin:selftest_'|add:page.url_name %}"
>{{ page.title }}</a
>
</th>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
+91
View File
@@ -0,0 +1,91 @@
"""Custom admin views for the People app."""
from smtplib import SMTPException
from django.views.generic import TemplateView
class BaseSelftestAdminPageView(TemplateView):
"""Base class for selftest admin pages."""
is_index = False
template_name = "selftest/base.html"
title = "Selftest Admin Page" # should be overridden in subclasses
path = None
def get_context_data(self, **kwargs):
"""Add the title to the context."""
context = super().get_context_data(**kwargs)
context["title"] = self.title
return context
class IndexSelftestAdminPageView(BaseSelftestAdminPageView):
"""View for the selftest index page."""
template_name = "selftest/index.html"
is_index = True
title = "Selftest Admin Index Page"
path = ""
def get_context_data(self, **kwargs):
"""Add all registered views to the context."""
from .registry import view_registry # pylint: disable=import-outside-toplevel
context = super().get_context_data(**kwargs)
context["pages"] = [
{
"title": view["title"],
"url_name": view["name"],
}
for view in sorted(
[
view
for view in view_registry.get_views()
if not view["view_class"].is_index
],
key=lambda x: x["name"],
)
]
return context
class EmailSelftestAdminPageView(BaseSelftestAdminPageView):
"""View for testing email functionality."""
title = "Send test email"
template_name = "selftest/email.html"
path = "email/"
def get(self, request, *args, **kwargs):
"""Handle GET request."""
context = self.get_context_data(**kwargs)
context["form"] = {"email": ""}
return self.render_to_response(context)
def post(self, request, *args, **kwargs):
"""Handle POST request to send test email."""
from django.contrib import messages
from django.core.mail import send_mail
context = self.get_context_data(**kwargs)
email = request.POST.get("email", "")
if email:
try:
send_mail(
subject="Test Email from People Admin",
message="This is a test email from the People Admin site.",
from_email=None, # Use DEFAULT_FROM_EMAIL
recipient_list=[email],
fail_silently=False,
)
messages.success(request, f"Test email sent successfully to {email}")
except SMTPException as e:
messages.error(request, f"Failed to send email: {str(e)}")
else:
messages.error(request, "Please provide an email address")
context["form"] = {"email": email}
return self.render_to_response(context)