Refactor configuration and security features for improved development experience
- Updated the .env.example file to reflect a development environment setup with enhanced secret key requirements and local host settings. - Modified the Docker Compose configuration to enhance security with read-only settings and no-new-privileges options. - Updated requirements.txt to pin package versions for better dependency management. - Enhanced the FastAPI application to include dynamic OpenAPI and documentation URLs based on the environment. - Implemented session versioning in JWT tokens to improve security and user session management. - Added new validation for user roles and password strength in schemas. - Improved email sending logic to handle recipient lists more robustly and added logging for SMTP operations. - Updated dashboard and profile templates to reflect new features and improve user experience.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import logging
|
||||
import smtplib
|
||||
from datetime import datetime
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
@@ -7,9 +8,12 @@ from typing import Sequence
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.email_utils import parse_recipient_list
|
||||
from app.models.system import SendLog
|
||||
from app.services.config_store import get_config
|
||||
|
||||
logger = logging.getLogger("newsletter.smtp")
|
||||
|
||||
|
||||
def get_smtp_settings(db: Session) -> dict[str, str]:
|
||||
return {
|
||||
@@ -25,6 +29,7 @@ def get_smtp_settings(db: Session) -> dict[str, str]:
|
||||
"recipients": get_config(db, "smtp.recipients", ""),
|
||||
# Zeitplan
|
||||
"schedule_enabled": get_config(db, "smtp.schedule_enabled", "false"),
|
||||
"schedule_acknowledged": get_config(db, "smtp.schedule_acknowledged", "false"),
|
||||
"schedule_frequency": get_config(db, "smtp.schedule_frequency", "monthly"),
|
||||
"schedule_time": get_config(db, "smtp.schedule_time", "08:00"),
|
||||
"schedule_weekdays": get_config(db, "smtp.schedule_weekdays", "0"),
|
||||
@@ -44,6 +49,8 @@ def schedule_is_due(settings: dict[str, str], now: datetime) -> bool:
|
||||
return False
|
||||
if (settings.get("schedule_enabled") or "false").lower() != "true":
|
||||
return False
|
||||
if (settings.get("schedule_acknowledged") or "false").lower() != "true":
|
||||
return False
|
||||
freq = (settings.get("schedule_frequency") or "off").lower()
|
||||
if freq == "off":
|
||||
return False
|
||||
@@ -88,6 +95,13 @@ def send_newsletter(
|
||||
_log(db, subject, recipients, "failed", detail, scheduled)
|
||||
return "failed", detail
|
||||
|
||||
try:
|
||||
validated_recipients = parse_recipient_list(",".join(recipients))
|
||||
except ValueError as exc:
|
||||
detail = f"Ungültige Empfängerliste: {exc}"
|
||||
_log(db, subject, recipients, "failed", detail, scheduled)
|
||||
return "failed", detail
|
||||
|
||||
msg = MIMEMultipart("alternative")
|
||||
msg.attach(MIMEText(text_content, "plain", "utf-8"))
|
||||
msg.attach(MIMEText(html_content, "html", "utf-8"))
|
||||
@@ -96,7 +110,8 @@ def send_newsletter(
|
||||
msg["From"] = formataddr((settings["from_name"], settings["from_email"]))
|
||||
else:
|
||||
msg["From"] = settings["from_email"]
|
||||
msg["To"] = ", ".join(recipients)
|
||||
msg["To"] = settings["from_email"]
|
||||
msg["Bcc"] = ", ".join(validated_recipients)
|
||||
if settings.get("reply_to"):
|
||||
msg["Reply-To"] = settings["reply_to"]
|
||||
|
||||
@@ -107,13 +122,14 @@ def send_newsletter(
|
||||
server.starttls()
|
||||
if settings["username"]:
|
||||
server.login(settings["username"], settings["password"])
|
||||
server.sendmail(settings["from_email"], list(recipients), msg.as_string())
|
||||
detail = f"Versand erfolgreich an {len(recipients)} Empfänger."
|
||||
_log(db, subject, recipients, "sent", detail, scheduled)
|
||||
server.sendmail(settings["from_email"], validated_recipients, msg.as_string())
|
||||
detail = f"Versand erfolgreich an {len(validated_recipients)} Empfänger."
|
||||
_log(db, subject, validated_recipients, "sent", detail, scheduled)
|
||||
return "sent", detail
|
||||
except Exception as exc:
|
||||
detail = f"Versandfehler: {exc}"
|
||||
_log(db, subject, recipients, "failed", detail, scheduled)
|
||||
logger.exception("SMTP-Versand fehlgeschlagen")
|
||||
detail = "Versandfehler: E-Mail konnte nicht zugestellt werden. Details stehen im Server-Log."
|
||||
_log(db, subject, validated_recipients, "failed", detail, scheduled)
|
||||
return "failed", detail
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user