Files
serienbrief_django/serienbrief/app/mailmerge/views.py
T
2026-05-21 10:36:16 +02:00

95 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from pathlib import Path
from django.contrib.auth.decorators import login_required
from django.http import FileResponse, Http404, HttpResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.views.decorators.http import require_http_methods
from .forms import LetterTemplateForm, MailMergeJobForm
from .models import LetterTemplate, MailMergeJob
from .services.docx_renderer import extract_placeholders
from .tasks import run_mailmerge
@login_required
def dashboard(request):
templates = LetterTemplate.objects.all()[:20]
jobs = MailMergeJob.objects.select_related("template")[:20]
return render(request, "mailmerge/dashboard.html",
{"templates": templates, "jobs": jobs})
@login_required
@require_http_methods(["GET", "POST"])
def template_upload(request):
form = LetterTemplateForm(request.POST or None, request.FILES or None)
if request.method == "POST" and form.is_valid():
tpl = form.save(commit=False)
tpl.created_by = request.user
tpl.save()
# Platzhalter extrahieren Datei liegt jetzt auf Disk
tpl.placeholders = extract_placeholders(Path(tpl.file.path))
tpl.save(update_fields=["placeholders"])
return redirect(reverse("template-detail", args=[tpl.id]))
return render(request, "mailmerge/template_form.html", {"form": form})
@login_required
def template_detail(request, pk):
tpl = get_object_or_404(LetterTemplate, pk=pk)
return render(request, "mailmerge/template_detail.html", {"template": tpl})
@login_required
@require_http_methods(["GET", "POST"])
def job_create(request):
form = MailMergeJobForm(request.POST or None, request.FILES or None)
if request.method == "POST" and form.is_valid():
job = form.save(commit=False)
job.created_by = request.user
job.save()
run_mailmerge.delay(str(job.id))
return redirect(reverse("job-detail", args=[job.id]))
return render(request, "mailmerge/job_form.html", {"form": form})
@login_required
def job_detail(request, pk):
job = get_object_or_404(
MailMergeJob.objects.select_related("template"), pk=pk
)
logs = job.logs.all()
# HTMX partials: nur das Status-Fragment ausliefern
if request.headers.get("HX-Request"):
return render(request, "mailmerge/_job_status.html",
{"job": job, "logs": logs})
return render(request, "mailmerge/job_detail.html",
{"job": job, "logs": logs})
@login_required
def job_download(request, pk):
"""PDF-Download via X-Accel-Redirect in Production, direkter Stream im Dev."""
job = get_object_or_404(MailMergeJob, pk=pk)
if not job.result_pdf:
raise Http404("Kein Ergebnis-PDF vorhanden.")
# In Dev (settings.DEBUG) direkt streamen
from django.conf import settings
if settings.DEBUG:
return FileResponse(job.result_pdf.open("rb"),
as_attachment=True,
filename=Path(job.result_pdf.name).name)
# In Production: Nginx serviert die Datei via internem Mount.
response = HttpResponse()
response["Content-Type"] = "application/pdf"
response["Content-Disposition"] = (
f'attachment; filename="{Path(job.result_pdf.name).name}"'
)
# Pfad relativ zu MEDIA_ROOT, gemappt auf /protected-media/
relative = job.result_pdf.name
response["X-Accel-Redirect"] = f"/protected-media/{relative}"
return response