import io import smtplib import ssl from email.message import EmailMessage from itsdangerous import URLSafeTimedSerializer import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt from config import Config from flask import current_app from pathlib import Path from weasyprint import HTML def generate_pdf_from_html(html_string, output_path, base_url=None): output_path = Path(output_path) output_path.parent.mkdir(parents=True, exist_ok=True) HTML(string=html_string, base_url=base_url).write_pdf(str(output_path)) return output_path serializer = URLSafeTimedSerializer(Config.SECRET_KEY) def generate_activation_token(email): return serializer.dumps(email, salt='account-activation') def verify_activation_token(token, max_age=86400): return serializer.loads(token, salt='account-activation', max_age=max_age) def send_mail(to_address, subject, body): msg = EmailMessage() msg['Subject'] = subject msg['From'] = Config.MAIL_SENDER msg['To'] = to_address msg.set_content(body) # SMTPS if Config.SMTP_PORT == 465: context = ssl.create_default_context() with smtplib.SMTP_SSL(Config.SMTP_SERVER, Config.SMTP_PORT, context=context) as server: if Config.SMTP_USERNAME: server.login(Config.SMTP_USERNAME, Config.SMTP_PASSWORD) server.send_message(msg) return # Normales SMTP, z. B. Port 25 with smtplib.SMTP(Config.SMTP_SERVER, Config.SMTP_PORT) as server: server.ehlo() if Config.MAIL_USE_TLS: server.starttls(context=ssl.create_default_context()) server.ehlo() if Config.SMTP_USERNAME and Config.SMTP_USERNAME.strip(): server.login(Config.SMTP_USERNAME, Config.SMTP_PASSWORD) server.send_message(msg) def create_assessment_chart(labels, yes_counts, output_path): fig, ax = plt.subplots(figsize=(11, 5)) x_values = list(range(len(labels))) ax.plot(x_values, yes_counts, marker='o') for x, y in zip(x_values, yes_counts): if y >= 7: color = 'green' elif y >= 4: color = 'orange' else: color = 'red' ax.scatter([x], [y], color=color, s=120) ax.set_xticks(x_values) ax.set_xticklabels(labels, rotation=20, ha='right') ax.set_ylim(0, 8) ax.set_ylabel('Anzahl JA-Antworten') ax.set_xlabel('Themen') ax.set_title('Assessment-Ergebnis') ax.grid(True, axis='y', alpha=0.3) fig.tight_layout() fig.savefig(output_path, dpi=150) plt.close(fig) def create_chart_bytes(labels, yes_counts): buffer = io.BytesIO() fig, ax = plt.subplots(figsize=(11, 5)) x_values = list(range(len(labels))) ax.plot(x_values, yes_counts, marker='o') for x, y in zip(x_values, yes_counts): if y >= 7: color = 'green' elif y >= 4: color = 'orange' else: color = 'red' ax.scatter([x], [y], color=color, s=120) ax.set_xticks(x_values) ax.set_xticklabels(labels, rotation=20, ha='right') ax.set_ylim(0, 8) ax.set_ylabel('Anzahl JA-Antworten') ax.set_xlabel('Themen') ax.set_title('Assessment-Ergebnis') ax.grid(True, axis='y', alpha=0.3) fig.tight_layout() fig.savefig(buffer, format='png', dpi=150) plt.close(fig) buffer.seek(0) return buffer def get_image_files(image_dir): allowed_extensions = {".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"} #current_app.logger.error(f"IMAGE DIR: {image_dir}") #current_app.logger.error(f"EXISTS: {image_dir.exists()}") if not image_dir.exists(): return [] files = sorted( file.name for file in image_dir.iterdir() if file.is_file() and file.suffix.lower() in allowed_extensions ) #current_app.logger.error(f"FILES: {files}") return files