Refactor email system and add contact form backend
Refactored email sending to use a single HTML template with a base layout, removed plain text email templates, and updated all related backend logic. Introduced a new ContactMe model, serializer, Celery task, and API endpoints for handling contact form submissions, including email notifications. Renamed ShopConfiguration to SiteConfiguration throughout the backend for consistency. Updated frontend to remove unused components, add a new Services section, and adjust navigation and contact form integration.
This commit is contained in:
@@ -10,34 +10,25 @@ from .models import CustomUser
|
||||
|
||||
logger = get_task_logger(__name__)
|
||||
|
||||
# TODO: předělat funkci ať funguje s base.html šablonou na emaily !!!
|
||||
def send_email_with_context(recipients, subject, message=None, template_name=None, html_template_name=None, context=None):
|
||||
def send_email_with_context(recipients, subject, template_path=None, context=None, message: str | None = None):
|
||||
"""
|
||||
General function to send emails with a specific context.
|
||||
Supports rendering plain text and HTML templates.
|
||||
Converts `user` in context to a plain dict to avoid template access to the model.
|
||||
Send emails rendering a single HTML template.
|
||||
- `template_name` is a simple base name without extension, e.g. "email/test".
|
||||
- Renders only HTML (".html"), no ".txt" support.
|
||||
- Converts `user` in context to a plain dict to avoid passing models to templates.
|
||||
"""
|
||||
if isinstance(recipients, str):
|
||||
recipients = [recipients]
|
||||
|
||||
html_message = None
|
||||
if template_name or html_template_name:
|
||||
# Best effort to resolve both templates if only one provided
|
||||
if not template_name and html_template_name:
|
||||
template_name = html_template_name.replace(".html", ".txt")
|
||||
if not html_template_name and template_name:
|
||||
html_template_name = template_name.replace(".txt", ".html")
|
||||
|
||||
if template_path:
|
||||
ctx = dict(context or {})
|
||||
# Sanitize user if someone passes the model by mistake
|
||||
if "user" in ctx and not isinstance(ctx["user"], dict):
|
||||
try:
|
||||
ctx["user"] = _build_user_template_ctx(ctx["user"])
|
||||
except Exception:
|
||||
ctx["user"] = {}
|
||||
|
||||
message = render_to_string(template_name, ctx)
|
||||
html_message = render_to_string(html_template_name, ctx)
|
||||
# Render base layout and include the provided template as the main content.
|
||||
# The included template receives the same context as the base.
|
||||
html_message = render_to_string(
|
||||
"email/components/base.html",
|
||||
{"content_template": template_path, **ctx},
|
||||
)
|
||||
|
||||
try:
|
||||
send_mail(
|
||||
@@ -48,33 +39,13 @@ def send_email_with_context(recipients, subject, message=None, template_name=Non
|
||||
fail_silently=False,
|
||||
html_message=html_message,
|
||||
)
|
||||
if settings.EMAIL_BACKEND == 'django.core.mail.backends.console.EmailBackend':
|
||||
if settings.EMAIL_BACKEND == 'django.core.mail.backends.console.EmailBackend' and message:
|
||||
logger.debug(f"\nEMAIL OBSAH:\n{message}\nKONEC OBSAHU")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"E-mail se neodeslal: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def _build_user_template_ctx(user: CustomUser) -> dict:
|
||||
"""
|
||||
Return a plain dict for templates instead of passing the DB model.
|
||||
Provides aliases to avoid template errors (firstname vs first_name).
|
||||
Adds a backward-compatible key 'get_full_name' for templates using `user.get_full_name`.
|
||||
"""
|
||||
first_name = getattr(user, "first_name", "") or ""
|
||||
last_name = getattr(user, "last_name", "") or ""
|
||||
full_name = f"{first_name} {last_name}".strip()
|
||||
return {
|
||||
"id": user.pk,
|
||||
"email": getattr(user, "email", "") or "",
|
||||
"first_name": first_name,
|
||||
"firstname": first_name, # alias for templates using `firstname`
|
||||
"last_name": last_name,
|
||||
"lastname": last_name, # alias for templates using `lastname`
|
||||
"full_name": full_name,
|
||||
"get_full_name": full_name, # compatibility for templates using method-style access
|
||||
}
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -93,7 +64,7 @@ def send_email_verification_task(user_id):
|
||||
verify_url = f"{settings.FRONTEND_URL}/email-verification/?uidb64={uid}&token={token}"
|
||||
|
||||
context = {
|
||||
"user": _build_user_template_ctx(user),
|
||||
"user": user,
|
||||
"action_url": verify_url,
|
||||
"frontend_url": settings.FRONTEND_URL,
|
||||
"cta_label": "Ověřit e‑mail",
|
||||
@@ -102,8 +73,7 @@ def send_email_verification_task(user_id):
|
||||
send_email_with_context(
|
||||
recipients=user.email,
|
||||
subject="Ověření e‑mailu",
|
||||
template_name="email/email_verification.txt",
|
||||
html_template_name="email/email_verification.html",
|
||||
template_path="email/email_verification.html",
|
||||
context=context,
|
||||
)
|
||||
|
||||
@@ -119,8 +89,7 @@ def send_email_test_task(email):
|
||||
send_email_with_context(
|
||||
recipients=email,
|
||||
subject="Testovací e‑mail",
|
||||
template_name="email/test.txt",
|
||||
html_template_name="email/test.html",
|
||||
template_path="email/test.html",
|
||||
context=context,
|
||||
)
|
||||
|
||||
@@ -138,7 +107,7 @@ def send_password_reset_email_task(user_id):
|
||||
reset_url = f"{settings.FRONTEND_URL}/reset-password/{uid}/{token}"
|
||||
|
||||
context = {
|
||||
"user": _build_user_template_ctx(user),
|
||||
"user": user,
|
||||
"action_url": reset_url,
|
||||
"frontend_url": settings.FRONTEND_URL,
|
||||
"cta_label": "Obnovit heslo",
|
||||
@@ -147,7 +116,6 @@ def send_password_reset_email_task(user_id):
|
||||
send_email_with_context(
|
||||
recipients=user.email,
|
||||
subject="Obnova hesla",
|
||||
template_name="email/password_reset.txt",
|
||||
html_template_name="email/password_reset.html",
|
||||
template_path="email/password_reset.html",
|
||||
context=context,
|
||||
)
|
||||
@@ -1,46 +1,21 @@
|
||||
<!doctype html>
|
||||
<html lang="cs">
|
||||
<body style="margin:0; padding:0; background-color:#f5f7fb;">
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="background-color:#f5f7fb;">
|
||||
<tr>
|
||||
<td align="center" style="padding:24px;">
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="600" style="width:600px; max-width:100%; background-color:#ffffff; border:1px solid #e5e7eb;">
|
||||
<tr>
|
||||
<td style="background-color:#111827; color:#ffffff; font-family:Arial, Helvetica, sans-serif; font-size:18px; font-weight:bold; padding:16px 20px;">
|
||||
Ověření e‑mailu
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding:20px; font-family:Arial, Helvetica, sans-serif; font-size:14px; color:#1f2937; line-height:1.6;">
|
||||
{% with name=user.first_name|default:user.firstname|default:user.get_full_name %}
|
||||
<p style="margin:0 0 12px 0;">Dobrý den{% if name %} {{ name }}{% endif %},</p>
|
||||
{% endwith %}
|
||||
<p style="margin:0 0 16px 0;">Děkujeme za registraci. Prosíme, ověřte svou e‑mailovou adresu kliknutím na tlačítko níže.</p>
|
||||
<h1 style="background-color:#111827; color:#ffffff; font-family:Arial, Helvetica, sans-serif; font-size:18px; font-weight:bold; padding:16px 20px; margin:0;">Ověření e‑mailu</h1>
|
||||
|
||||
{% if action_url and cta_label %}
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="margin:16px 0;">
|
||||
<tr>
|
||||
<td bgcolor="#2563eb" style="border-radius:6px;">
|
||||
<a href="{{ action_url }}" target="_blank" style="display:inline-block; padding:10px 16px; font-family:Arial, Helvetica, sans-serif; font-size:14px; color:#ffffff; text-decoration:none; font-weight:bold;">
|
||||
{{ cta_label }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p style="margin:0; color:#6b7280; font-size:12px;">Pokud tlačítko nefunguje, zkopírujte do prohlížeče tento odkaz:<br><span style="word-break:break-all;">{{ action_url }}</span></p>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="600" style="width:600px; max-width:100%; margin-top:12px;">
|
||||
<tr>
|
||||
<td align="center" style="font-family:Arial, Helvetica, sans-serif; font-size:12px; color:#6b7280;">
|
||||
Tento e‑mail byl odeslán z aplikace e‑tržnice.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
<div style="padding:20px; font-family:Arial, Helvetica, sans-serif; font-size:14px; color:#1f2937; line-height:1.6;">
|
||||
{% with name=user.first_name|default:user.firstname|default:user.get_full_name %}
|
||||
<p style="margin:0 0 12px 0;">Dobrý den{% if name %} {{ name }}{% endif %},</p>
|
||||
{% endwith %}
|
||||
<p style="margin:0 0 16px 0;">Děkujeme za registraci. Prosíme, ověřte svou e‑mailovou adresu kliknutím na tlačítko níže.</p>
|
||||
|
||||
{% if action_url and cta_label %}
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="margin:16px 0;">
|
||||
<tr>
|
||||
<td bgcolor="#2563eb" style="border-radius:6px;">
|
||||
<a href="{{ action_url }}" target="_blank" style="display:inline-block; padding:10px 16px; font-family:Arial, Helvetica, sans-serif; font-size:14px; color:#ffffff; text-decoration:none; font-weight:bold;">
|
||||
{{ cta_label }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p style="margin:0; color:#6b7280; font-size:12px;">Pokud tlačítko nefunguje, zkopírujte do prohlížeče tento odkaz:<br><span style="word-break:break-all;">{{ action_url }}</span></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{% with name=user.first_name|default:user.firstname|default:user.get_full_name %}Dobrý den{% if name %} {{ name }}{% endif %},{% endwith %}
|
||||
|
||||
Děkujeme za registraci. Prosíme, ověřte svou e‑mailovou adresu kliknutím na následující odkaz:
|
||||
|
||||
{{ action_url }}
|
||||
|
||||
Pokud jste účet nevytvořili vy, tento e‑mail ignorujte.
|
||||
@@ -1,46 +1,21 @@
|
||||
<!doctype html>
|
||||
<html lang="cs">
|
||||
<body style="margin:0; padding:0; background-color:#f5f7fb;">
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="background-color:#f5f7fb;">
|
||||
<tr>
|
||||
<td align="center" style="padding:24px;">
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="600" style="width:600px; max-width:100%; background-color:#ffffff; border:1px solid #e5e7eb;">
|
||||
<tr>
|
||||
<td style="background-color:#111827; color:#ffffff; font-family:Arial, Helvetica, sans-serif; font-size:18px; font-weight:bold; padding:16px 20px;">
|
||||
Obnova hesla
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding:20px; font-family:Arial, Helvetica, sans-serif; font-size:14px; color:#1f2937; line-height:1.6;">
|
||||
{% with name=user.first_name|default:user.firstname|default:user.get_full_name %}
|
||||
<p style="margin:0 0 12px 0;">Dobrý den{% if name %} {{ name }}{% endif %},</p>
|
||||
{% endwith %}
|
||||
<p style="margin:0 0 12px 0;">Obdrželi jste tento e‑mail, protože byla požádána obnova hesla k vašemu účtu. Pokud jste o změnu nepožádali, tento e‑mail ignorujte.</p>
|
||||
<h1 style="background-color:#111827; color:#ffffff; font-family:Arial, Helvetica, sans-serif; font-size:18px; font-weight:bold; padding:16px 20px; margin:0;">Obnova hesla</h1>
|
||||
|
||||
{% if action_url and cta_label %}
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="margin:16px 0;">
|
||||
<tr>
|
||||
<td bgcolor="#2563eb" style="border-radius:6px;">
|
||||
<a href="{{ action_url }}" target="_blank" style="display:inline-block; padding:10px 16px; font-family:Arial, Helvetica, sans-serif; font-size:14px; color:#ffffff; text-decoration:none; font-weight:bold;">
|
||||
{{ cta_label }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p style="margin:0; color:#6b7280; font-size:12px;">Pokud tlačítko nefunguje, zkopírujte do prohlížeče tento odkaz:<br><span style="word-break:break-all;">{{ action_url }}</span></p>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="600" style="width:600px; max-width:100%; margin-top:12px;">
|
||||
<tr>
|
||||
<td align="center" style="font-family:Arial, Helvetica, sans-serif; font-size:12px; color:#6b7280;">
|
||||
Tento e‑mail byl odeslán z aplikace e‑tržnice.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
<div style="padding:20px; font-family:Arial, Helvetica, sans-serif; font-size:14px; color:#1f2937; line-height:1.6;">
|
||||
{% with name=user.first_name|default:user.firstname|default:user.get_full_name %}
|
||||
<p style="margin:0 0 12px 0;">Dobrý den{% if name %} {{ name }}{% endif %},</p>
|
||||
{% endwith %}
|
||||
<p style="margin:0 0 12px 0;">Obdrželi jste tento e‑mail, protože byla požádána obnova hesla k vašemu účtu. Pokud jste o změnu nepožádali, tento e‑mail ignorujte.</p>
|
||||
|
||||
{% if action_url and cta_label %}
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="margin:16px 0;">
|
||||
<tr>
|
||||
<td bgcolor="#2563eb" style="border-radius:6px;">
|
||||
<a href="{{ action_url }}" target="_blank" style="display:inline-block; padding:10px 16px; font-family:Arial, Helvetica, sans-serif; font-size:14px; color:#ffffff; text-decoration:none; font-weight:bold;">
|
||||
{{ cta_label }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p style="margin:0; color:#6b7280; font-size:12px;">Pokud tlačítko nefunguje, zkopírujte do prohlížeče tento odkaz:<br><span style="word-break:break-all;">{{ action_url }}</span></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{% with name=user.first_name|default:user.firstname|default:user.get_full_name %}Dobrý den{% if name %} {{ name }}{% endif %},{% endwith %}
|
||||
|
||||
Obdrželi jste tento e‑mail, protože byla požádána obnova hesla k vašemu účtu.
|
||||
Pokud jste o změnu nepožádali, tento e‑mail ignorujte.
|
||||
|
||||
Pro nastavení nového hesla použijte tento odkaz:
|
||||
{{ action_url }}
|
||||
@@ -1,44 +1,19 @@
|
||||
<!doctype html>
|
||||
<html lang="cs">
|
||||
<body style="margin:0; padding:0; background-color:#f5f7fb;">
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="background-color:#f5f7fb;">
|
||||
<tr>
|
||||
<td align="center" style="padding:24px;">
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="600" style="width:600px; max-width:100%; background-color:#ffffff; border:1px solid #e5e7eb;">
|
||||
<tr>
|
||||
<td style="background-color:#111827; color:#ffffff; font-family:Arial, Helvetica, sans-serif; font-size:18px; font-weight:bold; padding:16px 20px;">
|
||||
Testovací e‑mail
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding:20px; font-family:Arial, Helvetica, sans-serif; font-size:14px; color:#1f2937; line-height:1.6;">
|
||||
<p style="margin:0 0 12px 0;">Dobrý den,</p>
|
||||
<p style="margin:0 0 16px 0;">Toto je testovací e‑mail z aplikace e‑tržnice.</p>
|
||||
<h1 style="background-color:#111827; color:#ffffff; font-family:Arial, Helvetica, sans-serif; font-size:18px; font-weight:bold; padding:16px 20px; margin:0;">Testovací e‑mail</h1>
|
||||
|
||||
{% if action_url and cta_label %}
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="margin:16px 0;">
|
||||
<tr>
|
||||
<td bgcolor="#2563eb" style="border-radius:6px;">
|
||||
<a href="{{ action_url }}" target="_blank" style="display:inline-block; padding:10px 16px; font-family:Arial, Helvetica, sans-serif; font-size:14px; color:#ffffff; text-decoration:none; font-weight:bold;">
|
||||
{{ cta_label }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p style="margin:0; color:#6b7280; font-size:12px;">Pokud tlačítko nefunguje, zkopírujte do prohlížeče tento odkaz:<br><span style="word-break:break-all;">{{ action_url }}</span></p>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="600" style="width:600px; max-width:100%; margin-top:12px;">
|
||||
<tr>
|
||||
<td align="center" style="font-family:Arial, Helvetica, sans-serif; font-size:12px; color:#6b7280;">
|
||||
Tento e‑mail byl odeslán z aplikace e‑tržnice.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
<div style="padding:20px; font-family:Arial, Helvetica, sans-serif; font-size:14px; color:#1f2937; line-height:1.6;">
|
||||
<p style="margin:0 0 12px 0;">Dobrý den,</p>
|
||||
<p style="margin:0 0 16px 0;">Toto je testovací e‑mail z aplikace e‑tržnice.</p>
|
||||
|
||||
{% if action_url and cta_label %}
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="margin:16px 0;">
|
||||
<tr>
|
||||
<td bgcolor="#2563eb" style="border-radius:6px;">
|
||||
<a href="{{ action_url }}" target="_blank" style="display:inline-block; padding:10px 16px; font-family:Arial, Helvetica, sans-serif; font-size:14px; color:#ffffff; text-decoration:none; font-weight:bold;">
|
||||
{{ cta_label }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p style="margin:0; color:#6b7280; font-size:12px;">Pokud tlačítko nefunguje, zkopírujte do prohlížeče tento odkaz:<br><span style="word-break:break-all;">{{ action_url }}</span></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
Dobrý den,
|
||||
|
||||
Toto je testovací e‑mail z aplikace e‑tržnice.
|
||||
|
||||
Odkaz na aplikaci:
|
||||
{{ action_url }}
|
||||
Reference in New Issue
Block a user