Files
deploy-email-plesk-kerio-ne…/pdf.py
T
duffyduck dda5c746ce add manual/api/ssh Plesk-Backends, Minimal-PDF, --pdf-only und GUI-Verbesserungen
- PLESK_BACKEND={manual,api,ssh}: manual als Default für Shared Hosts,
  api unverändert, ssh ruft `plesk bin mail` per paramiko auf.
- POP3_PORT default 995, POP3_SSL mit Auto-Erkennung anhand Port.
- Kerio: User wird mit mayChangePassword=False angelegt.
- Zusätzliche Minimal-PDF (nur Email + Cloud) pro Konto + Sammel-Variante,
  IMAP-Port konfigurierbar.
- CLI-Flag --pdf-only und entsprechender GUI-Button "📄 Nur PDF".
- GUI: Lösch-Button "✕ löschen" sichtbarer, letzte Zeile löschbar.
- PDFs sind kunden-tauglich (kein Status-Block, kein ACHTUNG-Hinweis);
  Anlage-Status separat in _admin_report_<ts>.txt.
- README dokumentiert die Skip-Logik pro Dienst und ihre Caveats.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 12:15:39 +02:00

149 lines
5.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 typing import List
from reportlab.lib import colors
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import cm
from reportlab.platypus import (
PageBreak, Paragraph, SimpleDocTemplate, Spacer, Table, TableStyle,
)
from models import Account
def _section(title: str, rows, col_widths=(5 * cm, 11 * cm)):
styles = getSampleStyleSheet()
elements = [Paragraph(title, styles["Heading2"])]
data = [[k, v] for k, v in rows]
t = Table(data, colWidths=list(col_widths))
t.setStyle(TableStyle([
("BOX", (0, 0), (-1, -1), 0.5, colors.grey),
("INNERGRID", (0, 0), (-1, -1), 0.25, colors.lightgrey),
("BACKGROUND", (0, 0), (0, -1), colors.whitesmoke),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("FONT", (0, 0), (-1, -1), "Helvetica", 10),
("LEFTPADDING", (0, 0), (-1, -1), 4),
("RIGHTPADDING", (0, 0), (-1, -1), 4),
]))
elements.append(t)
elements.append(Spacer(1, 0.4 * cm))
return elements
def _build_user_section(account: Account, smtp_port: int,
pop_port: int, pop_ssl: bool):
styles = getSampleStyleSheet()
elements = [
Paragraph(f"Zugangsdaten {account.vollname}", styles["Title"]),
Spacer(1, 0.3 * cm),
Paragraph(f"Hauptemail: <b>{account.emailadresse}</b>", styles["Normal"]),
Spacer(1, 0.4 * cm),
]
elements += _section("Plesk Mailpostfach (Backend, eingehend für POP3-Sammler)", [
("Mailserver", account.pleskhost),
("Benutzername", account.emailadresse),
("Passwort", account.pleskemailkennwort),
("Hinweis", "Anmeldung nur am Mailserver keine Plesk-Webinterface-Anmeldung."),
])
pop_proto = "SSL" if pop_ssl else "unverschlüsselt"
elements += _section("Kerio Connect (Hauptmailkonto)", [
("Webmail", f"https://{account.keriohost}/webmail/"),
("Benutzername", account.emailadresse),
("Passwort", account.kerioemailkennwort),
("SMTP-Server (Versand)", f"{account.keriohost}:{smtp_port} (SSL)"),
("IMAP/POP-Server", f"{account.keriohost}"),
("POP3-Sammler",
f"holt automatisch von {account.pleskhost}:{pop_port} ({pop_proto}), "
f"behält 14 Tage auf dem Server"),
])
quota = f"{account.nextcloudspeicher} GB" if account.nextcloudspeicher else "unlimitiert"
elements += _section("Nextcloud", [
("URL", f"https://{account.nextcloudhost}"),
("Benutzername", account.nextcloud_username),
("Passwort", account.nextcloudkennwort),
("Email (hinterlegt)", account.emailadresse),
("Gruppe", account.nextcloudgruppe or ""),
("Speicher", quota),
])
return elements
def write_user_pdf(path: Path, account: Account,
smtp_port: int, pop_port: int, pop_ssl: bool) -> None:
doc = SimpleDocTemplate(
str(path), pagesize=A4,
leftMargin=2 * cm, rightMargin=2 * cm,
topMargin=2 * cm, bottomMargin=2 * cm,
title=f"Zugangsdaten {account.vollname}",
)
doc.build(_build_user_section(account, smtp_port, pop_port, pop_ssl))
def write_combined_pdf(path: Path, accounts: List[Account],
smtp_port: int, pop_port: int, pop_ssl: bool) -> None:
doc = SimpleDocTemplate(
str(path), pagesize=A4,
leftMargin=2 * cm, rightMargin=2 * cm,
topMargin=2 * cm, bottomMargin=2 * cm,
title="Zugangsdaten (Sammel-PDF)",
)
flow = []
for i, acc in enumerate(accounts):
flow += _build_user_section(acc, smtp_port, pop_port, pop_ssl)
if i < len(accounts) - 1:
flow.append(PageBreak())
doc.build(flow)
# ---------- Minimal-PDF (nur Email + Cloud, ohne Plesk/POP3-Sammler) ----------
def _build_minimal_section(account: Account, smtp_port: int, imap_port: int):
styles = getSampleStyleSheet()
elements = [
Paragraph(f"Zugangsdaten {account.vollname}", styles["Title"]),
Spacer(1, 0.4 * cm),
]
elements += _section("Email", [
("Emailadresse", account.emailadresse),
("Kennwort", account.kerioemailkennwort),
("SMTP-Server", f"{account.keriohost}:{smtp_port} (SSL)"),
("IMAP-Server", f"{account.keriohost}:{imap_port} (SSL)"),
])
elements += _section("Cloud", [
("Cloud URL", f"https://{account.nextcloudhost}"),
("Benutzername", account.nextcloud_username),
("Kennwort", account.nextcloudkennwort),
])
return elements
def write_user_minimal_pdf(path: Path, account: Account,
smtp_port: int, imap_port: int) -> None:
doc = SimpleDocTemplate(
str(path), pagesize=A4,
leftMargin=2 * cm, rightMargin=2 * cm,
topMargin=2 * cm, bottomMargin=2 * cm,
title=f"Zugangsdaten {account.vollname}",
)
doc.build(_build_minimal_section(account, smtp_port, imap_port))
def write_combined_minimal_pdf(path: Path, accounts: List[Account],
smtp_port: int, imap_port: int) -> None:
doc = SimpleDocTemplate(
str(path), pagesize=A4,
leftMargin=2 * cm, rightMargin=2 * cm,
topMargin=2 * cm, bottomMargin=2 * cm,
title="Zugangsdaten minimal (Sammel-PDF)",
)
flow = []
for i, acc in enumerate(accounts):
flow += _build_minimal_section(acc, smtp_port, imap_port)
if i < len(accounts) - 1:
flow.append(PageBreak())
doc.build(flow)