This commit is contained in:
Iliyan Angelov
2025-11-26 22:32:20 +02:00
commit ed94dd22dd
150 changed files with 14058 additions and 0 deletions

123
reports/email_backend.py Normal file
View File

@@ -0,0 +1,123 @@
"""
Custom email backend that uses SiteSettings for configuration.
"""
from django.core.mail.backends.smtp import EmailBackend as SMTPEmailBackend
from django.core.mail.backends.console import EmailBackend as ConsoleEmailBackend
from django.core.mail.backends.base import BaseEmailBackend
from django.conf import settings
from .models import SiteSettings
class SiteSettingsEmailBackend(BaseEmailBackend):
"""
Email backend that dynamically loads settings from SiteSettings model.
Falls back to Django settings if SiteSettings are not configured.
"""
def __init__(self, fail_silently=False, **kwargs):
super().__init__(fail_silently=fail_silently)
self._backend = None
self._backend_instance = None
self._load_backend()
def _load_backend(self):
"""Load the appropriate email backend based on SiteSettings."""
import logging
logger = logging.getLogger(__name__)
try:
site_settings = SiteSettings.get_settings()
backend_class = site_settings.email_backend
logger.info(f"Loading email backend: {backend_class}")
# If using SMTP, configure it with SiteSettings
if backend_class == 'django.core.mail.backends.smtp.EmailBackend':
# Get decrypted password
email_password = site_settings.get_email_password() if hasattr(site_settings, 'get_email_password') else site_settings.email_host_password
# Check if SMTP is properly configured
email_host = site_settings.email_host or getattr(settings, 'EMAIL_HOST', '')
# If no host is configured, fall back to console backend
if not email_host:
logger.warning("Email host not configured, using console backend")
self._backend = ConsoleEmailBackend(fail_silently=self.fail_silently)
else:
# Ensure TLS and SSL are mutually exclusive
use_tls = site_settings.email_use_tls
use_ssl = site_settings.email_use_ssl
# If both are True, prioritize TLS (common case)
if use_tls and use_ssl:
use_ssl = False
logger.warning("Both TLS and SSL were enabled. Disabling SSL and using TLS only.")
logger.info(f"Configuring SMTP: host={email_host}, port={site_settings.email_port}, user={site_settings.email_host_user}, tls={use_tls}, ssl={use_ssl}")
self._backend = SMTPEmailBackend(
host=email_host,
port=site_settings.email_port or getattr(settings, 'EMAIL_PORT', 587),
username=site_settings.email_host_user or getattr(settings, 'EMAIL_HOST_USER', ''),
password=email_password or getattr(settings, 'EMAIL_HOST_PASSWORD', ''),
use_tls=use_tls,
use_ssl=use_ssl,
timeout=site_settings.email_timeout or getattr(settings, 'EMAIL_TIMEOUT', 10),
fail_silently=self.fail_silently,
)
logger.info("SMTP backend configured successfully")
elif backend_class == 'django.core.mail.backends.console.EmailBackend':
logger.info("Using console email backend")
self._backend = ConsoleEmailBackend(fail_silently=self.fail_silently)
else:
# For other backends, try to import and instantiate
from django.utils.module_loading import import_string
backend_class_obj = import_string(backend_class)
self._backend = backend_class_obj(fail_silently=self.fail_silently)
logger.info(f"Loaded custom backend: {backend_class}")
except Exception as e:
# Fallback to console backend if there's an error
logger.exception(f"Error loading email backend from SiteSettings: {e}. Using console backend.")
self._backend = ConsoleEmailBackend(fail_silently=self.fail_silently)
def open(self):
"""Open a network connection."""
if self._backend:
return self._backend.open()
return False
def close(self):
"""Close the network connection."""
if self._backend:
return self._backend.close()
def send_messages(self, email_messages):
"""Send one or more EmailMessage objects and return the number sent."""
import logging
logger = logging.getLogger(__name__)
# Reload backend before sending to get latest settings
# This ensures settings changes take effect immediately
self._load_backend()
if self._backend:
try:
# Log email details for debugging
for msg in email_messages:
logger.info(f"Sending email: To={msg.to}, Subject={msg.subject}, From={msg.from_email}")
result = self._backend.send_messages(email_messages)
logger.info(f"Successfully sent {result} email message(s)")
return result
except Exception as e:
error_msg = str(e)
logger.exception(f"Error sending email messages: {error_msg}")
# Log more details about the error
if hasattr(self._backend, 'host'):
logger.error(f"SMTP Host: {self._backend.host}, Port: {getattr(self._backend, 'port', 'N/A')}")
if not self.fail_silently:
raise
return 0
logger.warning("No email backend available, cannot send messages")
return 0