Store contact form submissions in Wagtail admin
This commit is contained in:
7
contact_form/__init__.py
Normal file
7
contact_form/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
"""Project-level overrides for the Ocyan contact_form plugin.
|
||||||
|
|
||||||
|
Ocyan loads contact form handlers via module labels like `contact_form.views`.
|
||||||
|
By shipping this package in the project repository we can extend behavior
|
||||||
|
without forking the upstream plugin.
|
||||||
|
"""
|
||||||
|
|
||||||
104
contact_form/views.py
Normal file
104
contact_form/views.py
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.core.mail import EmailMultiAlternatives
|
||||||
|
from django.shortcuts import redirect
|
||||||
|
from django.template.loader import render_to_string
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
from django.views.decorators.http import require_http_methods
|
||||||
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
|
from oscar.core.utils import redirect_to_referrer
|
||||||
|
from wagtail.models import Locale, Site
|
||||||
|
|
||||||
|
from ocyan.core.fender import config
|
||||||
|
from ocyan.plugin.contact_form.forms import ContactForm
|
||||||
|
from ocyan.plugin.contact_form.utils import get_from_email, get_to_email
|
||||||
|
|
||||||
|
from mandelstudio.models import ContactMessage
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def _client_ip(request) -> str | None:
|
||||||
|
forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
|
||||||
|
if forwarded_for:
|
||||||
|
return forwarded_for.split(",")[0].strip() or None
|
||||||
|
return request.META.get("REMOTE_ADDR")
|
||||||
|
|
||||||
|
def _active_locale(request) -> Locale:
|
||||||
|
language_code = (getattr(request, "LANGUAGE_CODE", "") or "").split("-")[0]
|
||||||
|
if language_code:
|
||||||
|
locale = Locale.objects.filter(language_code=language_code).first()
|
||||||
|
if locale is not None:
|
||||||
|
return locale
|
||||||
|
return Locale.get_default()
|
||||||
|
|
||||||
|
|
||||||
|
@require_http_methods(["POST"])
|
||||||
|
def post_contact_form(request):
|
||||||
|
form = ContactForm(request.POST, request=request)
|
||||||
|
|
||||||
|
if form.is_valid():
|
||||||
|
cleaned = form.cleaned_data
|
||||||
|
site = Site.find_for_request(request) or Site.objects.order_by("id").first()
|
||||||
|
locale = _active_locale(request)
|
||||||
|
|
||||||
|
message_obj = ContactMessage.objects.create(
|
||||||
|
site=site,
|
||||||
|
locale=locale,
|
||||||
|
user=request.user if getattr(request.user, "is_authenticated", False) else None,
|
||||||
|
ip_address=_client_ip(request),
|
||||||
|
path=request.path or "",
|
||||||
|
name=str(cleaned.get("name", "")),
|
||||||
|
email=str(cleaned.get("email_from", "")),
|
||||||
|
phone_number=str(cleaned.get("phonenumber") or ""),
|
||||||
|
message=str(cleaned.get("message", "")),
|
||||||
|
)
|
||||||
|
logger.info("Saved ContactMessage id=%s email=%s", message_obj.id, message_obj.email)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
"website_url": request.build_absolute_uri(),
|
||||||
|
"form_data": cleaned,
|
||||||
|
}
|
||||||
|
|
||||||
|
html_message = render_to_string("contact_form/contact_email.html", context)
|
||||||
|
text_message = render_to_string("contact_form/contact_email.txt", context)
|
||||||
|
|
||||||
|
site_name = getattr(site, "site_name", "") or config.get("django", "name")
|
||||||
|
subject = _("Contact form email from %s") % site_name
|
||||||
|
msg = EmailMultiAlternatives(
|
||||||
|
subject,
|
||||||
|
text_message,
|
||||||
|
from_email=get_from_email(request, form),
|
||||||
|
to=get_to_email(request, form),
|
||||||
|
reply_to=[cleaned["email_from"]],
|
||||||
|
)
|
||||||
|
msg.attach_alternative(html_message, "text/html")
|
||||||
|
msg.send()
|
||||||
|
|
||||||
|
request.session["contact_form_submitted"] = True
|
||||||
|
messages.add_message(request, messages.SUCCESS, _("Message sent"))
|
||||||
|
return redirect(reverse("contact_form:contact-form-thank-you"))
|
||||||
|
|
||||||
|
request.session["contact_form_post_data"] = request.POST
|
||||||
|
messages.add_message(
|
||||||
|
request,
|
||||||
|
messages.ERROR,
|
||||||
|
_("An error occured in the contact form: %s") % form.errors.as_text(),
|
||||||
|
)
|
||||||
|
return redirect_to_referrer(request, "contact_form:contact-form-handler")
|
||||||
|
|
||||||
|
|
||||||
|
class ContactFormThankYou(TemplateView):
|
||||||
|
template_name = "contact_form/thank_you.html"
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
contact_form_submitted = request.session.pop("contact_form_submitted", False)
|
||||||
|
if contact_form_submitted:
|
||||||
|
return super().get(request, *args, **kwargs)
|
||||||
|
return redirect(getattr(settings, "CONTACT_REDIRECT_URL", "/"))
|
||||||
43
mandelstudio/migrations/0004_contact_messages.py
Normal file
43
mandelstudio/migrations/0004_contact_messages.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Generated by Django 5.2.13 on 2026-05-08 23:34
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mandelstudio', '0003_locale_audit_models'),
|
||||||
|
('wagtailcore', '0097_contact_messages'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='localizedfootercontent',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ContactMessage',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True, db_index=True)),
|
||||||
|
('ip_address', models.GenericIPAddressField(blank=True, null=True)),
|
||||||
|
('path', models.CharField(blank=True, max_length=255)),
|
||||||
|
('name', models.CharField(max_length=200)),
|
||||||
|
('email', models.EmailField(max_length=254)),
|
||||||
|
('phone_number', models.CharField(blank=True, max_length=64)),
|
||||||
|
('message', models.TextField()),
|
||||||
|
('locale', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='contact_messages', to='wagtailcore.locale')),
|
||||||
|
('site', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='contact_messages', to='wagtailcore.site')),
|
||||||
|
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='contact_messages', to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Contact message',
|
||||||
|
'verbose_name_plural': 'Contact messages',
|
||||||
|
'ordering': ['-created_at'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
@@ -102,3 +103,47 @@ class LocaleAuditIssue(models.Model):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ["locale_code", "url", "field_path"]
|
ordering = ["locale_code", "url", "field_path"]
|
||||||
|
|
||||||
|
|
||||||
|
class ContactMessage(models.Model):
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True, db_index=True)
|
||||||
|
site = models.ForeignKey(
|
||||||
|
Site, on_delete=models.PROTECT, related_name="contact_messages"
|
||||||
|
)
|
||||||
|
locale = models.ForeignKey(
|
||||||
|
Locale, on_delete=models.PROTECT, related_name="contact_messages"
|
||||||
|
)
|
||||||
|
user = models.ForeignKey(
|
||||||
|
settings.AUTH_USER_MODEL,
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
related_name="contact_messages",
|
||||||
|
)
|
||||||
|
ip_address = models.GenericIPAddressField(null=True, blank=True)
|
||||||
|
path = models.CharField(max_length=255, blank=True)
|
||||||
|
|
||||||
|
name = models.CharField(max_length=200)
|
||||||
|
email = models.EmailField()
|
||||||
|
phone_number = models.CharField(max_length=64, blank=True)
|
||||||
|
message = models.TextField()
|
||||||
|
|
||||||
|
panels = [
|
||||||
|
FieldPanel("site"),
|
||||||
|
FieldPanel("locale"),
|
||||||
|
FieldPanel("user"),
|
||||||
|
FieldPanel("ip_address"),
|
||||||
|
FieldPanel("path"),
|
||||||
|
FieldPanel("name"),
|
||||||
|
FieldPanel("email"),
|
||||||
|
FieldPanel("phone_number"),
|
||||||
|
FieldPanel("message"),
|
||||||
|
]
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ["-created_at"]
|
||||||
|
verbose_name = _("Contact message")
|
||||||
|
verbose_name_plural = _("Contact messages")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.created_at:%Y-%m-%d %H:%M} - {self.name}"
|
||||||
|
|||||||
@@ -1 +1,20 @@
|
|||||||
from mandelblog_content_guard.hooks import * # noqa: F401,F403
|
from mandelblog_content_guard.hooks import * # noqa: F401,F403
|
||||||
|
|
||||||
|
from wagtail.snippets.views.snippets import SnippetViewSet
|
||||||
|
from wagtail.snippets.models import register_snippet
|
||||||
|
|
||||||
|
from mandelstudio.models import ContactMessage
|
||||||
|
|
||||||
|
|
||||||
|
@register_snippet
|
||||||
|
class ContactMessageViewSet(SnippetViewSet):
|
||||||
|
model = ContactMessage
|
||||||
|
icon = "mail"
|
||||||
|
menu_label = "Contact messages"
|
||||||
|
menu_order = 220
|
||||||
|
add_to_admin_menu = True
|
||||||
|
|
||||||
|
list_display = ("created_at", "name", "email", "locale", "site")
|
||||||
|
list_filter = ("locale", "site")
|
||||||
|
search_fields = ("name", "email", "message", "phone_number")
|
||||||
|
ordering = ("-created_at",)
|
||||||
|
|||||||
Reference in New Issue
Block a user