dda5c746ce
- 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>
149 lines
5.5 KiB
Python
149 lines
5.5 KiB
Python
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)
|