120 lines
4.3 KiB
Python
120 lines
4.3 KiB
Python
from datetime import datetime
|
|
|
|
from celery import shared_task
|
|
from celery.utils.log import get_task_logger
|
|
|
|
from django.core.mail import send_mail, EmailMultiAlternatives
|
|
|
|
logger = get_task_logger(__name__)
|
|
|
|
from account.models import CustomUser
|
|
from django.conf import settings
|
|
from django.template.loader import render_to_string
|
|
|
|
|
|
@shared_task
|
|
def send_notification_email_task(recipient_email, subject, template_path, context=None, attachments=None):
|
|
send_email_with_context(
|
|
recipients=recipient_email,
|
|
subject=subject,
|
|
template_path=template_path,
|
|
context=context or {},
|
|
attachments=attachments,
|
|
)
|
|
|
|
|
|
|
|
def send_email_with_context(recipients, subject, template_path=None, context=None, message: str | None = None, attachments=None):
|
|
"""
|
|
Send email using component-based template system.
|
|
Uses base.html with header/footer components and includes the specified content template.
|
|
"""
|
|
if isinstance(recipients, str):
|
|
recipients = [recipients]
|
|
|
|
if not recipients:
|
|
logger.warning("No recipients provided for email. Skipping sending email.")
|
|
return "No recipients provided for email."
|
|
|
|
ctx = dict(context or {})
|
|
|
|
# Add current_year to context if not present
|
|
if "current_year" not in ctx:
|
|
ctx["current_year"] = datetime.now().year
|
|
|
|
# Add AppConfig data for footer if not already present
|
|
if "company_name" not in ctx:
|
|
try:
|
|
from configuration.models import AppConfig
|
|
config = AppConfig.objects.first()
|
|
if config:
|
|
ctx["company_name"] = config.company_name
|
|
ctx["company_address"] = config.company_address
|
|
ctx["company_ico"] = config.company_ico
|
|
ctx["company_dic"] = config.company_dic
|
|
ctx["contact_email"] = config.contact_email
|
|
ctx["contact_phone"] = config.contact_phone
|
|
except Exception:
|
|
pass # Gracefully skip if AppConfig not available
|
|
|
|
# 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"] = {}
|
|
|
|
# Render HTML using base template with content include
|
|
html_message = None
|
|
if template_path:
|
|
ctx["content_template"] = template_path
|
|
html_message = render_to_string("email/components/base.html", ctx)
|
|
|
|
try:
|
|
email = EmailMultiAlternatives(
|
|
subject=subject,
|
|
body=message or "Tento e-mail vyžaduje HTML podporu.",
|
|
from_email=None,
|
|
to=recipients if len(recipients) == 1 else [],
|
|
bcc=recipients if len(recipients) > 1 else [],
|
|
)
|
|
|
|
if html_message:
|
|
email.attach_alternative(html_message, "text/html")
|
|
|
|
if attachments:
|
|
for filename, content, mimetype in attachments:
|
|
email.attach(filename, content, mimetype)
|
|
|
|
email.send(fail_silently=False)
|
|
|
|
logger.info(f"Sent email to {recipients} with subject '{subject}'")
|
|
|
|
if settings.EMAIL_BACKEND == 'django.core.mail.backends.console.EmailBackend':
|
|
logger.debug(f"\nEMAIL HTML:\n{html_message}\nKONEC OBSAHU")
|
|
return "Successfully sent email."
|
|
except Exception as e:
|
|
logger.error(f"E-mail se neodeslal: {e}")
|
|
raise # Re-raise so Celery marks the task as FAILED and can retry
|
|
|
|
|
|
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 "",
|
|
"username": getattr(user, "username", "") or "",
|
|
"first_name": first_name,
|
|
"firstname": first_name,
|
|
"last_name": last_name,
|
|
"lastname": last_name,
|
|
"full_name": full_name,
|
|
"get_full_name": full_name,
|
|
} |