import time import smtplib import yaml import requests import csv import qrcode import io from email.message import EmailMessage from flask import Flask, request, jsonify, abort from jinja2 import Template from functools import wraps from datetime import datetime app = Flask(__name__) with open("config.yaml", "r") as f: config = yaml.safe_load(f) MAIL_CONFIG = config["mails"] MEALS = config["meals"] TYPES = config["types"] PRETIX = config["pretix"] AUTH_TOKEN = config.get("auth", {}).get("token") with open("template.txt", "r") as f: MAIL_TEMPLATE = Template(f.read()) def require_auth(f): @wraps(f) def decorated(*args, **kwargs): token = request.headers.get("Authorization") if not token or token != f"Bearer {AUTH_TOKEN}": abort(401, description="Unauthorized: Invalid or missing token") return f(*args, **kwargs) return decorated def send_email(to_email, subject, body, attachment_bytes, filename): print(f"[DEBUG] Sending email to {to_email} with attachment {filename}") msg = EmailMessage() msg["From"] = MAIL_CONFIG["sender"] msg["To"] = to_email msg["Subject"] = subject msg.set_content(body) msg.add_attachment(attachment_bytes, maintype="application", subtype="pdf", filename=filename) server = smtplib.SMTP(MAIL_CONFIG["server"], MAIL_CONFIG["port"]) if MAIL_CONFIG.get("starttls"): server.starttls() server.login(MAIL_CONFIG["user"], MAIL_CONFIG["password"]) server.send_message(msg) server.quit() print("[DEBUG] Email sent successfully") def get_meal_times(meal_key): if meal_key.endswith("mittag"): return "11:30 - 13:30" elif meal_key.endswith("abend"): return "17:30 - 19:30" return "" def log_printed(email, meal_key): location = email.split("@")[0] now = datetime.now() date_str = now.strftime("%Y-%m-%d") time_str = now.strftime("%H:%M:%S") with open("printed.csv", "a", newline="") as csvfile: writer = csv.writer(csvfile, delimiter=";") writer.writerow([date_str, time_str, meal_key, location]) print(f"[DEBUG] Logged printed PDF: {location} - {meal_key}") def generate_qr(secret): qr = qrcode.QRCode(box_size=10, border=4) qr.add_data(secret) qr.make(fit=True) img = qr.make_image(fill_color="black", back_color="white") buf = io.BytesIO() img.save(buf, format="PNG") buf.seek(0) return buf.getvalue() @app.route("/order", methods=["POST"]) @require_auth def order(): data = request.get_json() print(f"[DEBUG] Incoming request JSON: {data}") email = data.get("email") typ = data.get("type") meal_key = data.get("meal") if not email or not typ or not meal_key: return jsonify({"error": "Missing field"}), 400 meal_info = MEALS.get(meal_key) if not meal_info: return jsonify({"error": "Meal not found in config"}), 400 position = { "positionid": 1, "item": TYPES.get(typ), "variation": None, "price": "0", "attendee_email": None, "addon_to": None, "subevent": meal_info["subevent"] } pretix_body = { "email": "pretixfood@td00.de", "locale": "en", "sales_channel": "web", "payment_provider": "manual", "positions": [position] } url = f"{PRETIX['host']}/api/v1/organizers/{PRETIX['organizer']}/events/{PRETIX['event']}/orders/" headers = {"Authorization": f"Token {PRETIX['token']}"} print(f"[DEBUG] Sending POST to Pretix: {url} with body {pretix_body}") resp = requests.post(url, json=pretix_body, headers=headers) print(f"[DEBUG] Pretix response status: {resp.status_code}") print(f"[DEBUG] Pretix response text: {resp.text}") try: resp_json = resp.json() print(f"[DEBUG] Pretix response JSON: {resp_json}") except ValueError: print("[DEBUG] Pretix returned no JSON") return jsonify({"error": "Pretix returned no JSON", "status_code": resp.status_code, "text": resp.text}), 502 if "positions" in resp_json and "item" in resp_json["positions"][0] and isinstance(resp_json["positions"][0]["item"], list): if isinstance(resp_json["positions"][0]["item"][0], str): print("[DEBUG] Not enough quota available") return "Essen ist bereits alle", 418 try: secret = resp_json["positions"][0]["secret"] print(f"[DEBUG] Secret: {secret}") except (KeyError, IndexError): return jsonify({"error": "Secret not found in Pretix response", "resp_json": resp_json}), 500 meal_times = get_meal_times(meal_key) mail_body = MAIL_TEMPLATE.render( meal_name=meal_info["name"], meal_name_en=meal_info["name_en"], meal_date=meal_info["date"], meal_times=meal_times ) if email.endswith("@printme.local"): log_printed(email, meal_key) return secret, 200, {"Content-Type": "text/plain; charset=utf-8"} qr_bytes = generate_qr(secret) send_email(email, "Dein Engelessen / Your Angel Meal", mail_body, qr_bytes, "ticket.png") return "Token gesendet", 201 if __name__ == "__main__": app.run(host="0.0.0.0", port=8000, debug=True)