from flask import Blueprint, render_template, request, redirect, url_for, current_app from .extensions import db from .models import Adresse, Frage, Antwort from utils import generate_vcard import re # Prefer robust validators when available; fall back to simple checks. try: from email_validator import validate_email, EmailNotValidError except Exception: validate_email = None EmailNotValidError = Exception try: import phonenumbers except Exception: phonenumbers = None bp = Blueprint('public', __name__) @bp.route('/', methods=['GET', 'POST']) def index(): if request.method == 'POST': vorname = request.form.get('vorname', '').strip() nachname = request.form.get('nachname', '').strip() strasse = request.form.get('strasse', '').strip() hausnummer = request.form.get('hausnummer', '').strip() plz = request.form.get('plz', '').strip() ort = request.form.get('ort', '').strip() land = request.form.get('land', 'Deutschland').strip() telefon_vorwahl = request.form.get('telefon_vorwahl', '').strip() telefon_nummer = request.form.get('telefon_nummer', '').strip() email = request.form.get('email', '').strip() errors = {} # Email validation: use `email_validator` if present, else fallback regex if email: if validate_email: try: # disable deliverability checks (MX/DNS) to avoid rejecting # addresses like max@example.com during testing valid = validate_email(email, check_deliverability=False) email = valid.email except EmailNotValidError: errors['email'] = 'Ungültige E-Mail-Adresse' else: email_re = re.compile(r"[^@]+@[^@]+\.[^@]+") if not email_re.match(email): errors['email'] = 'Ungültige E-Mail-Adresse' # German PLZ: exactly 5 digits if plz: if not plz.isdigit() or len(plz) != 5: errors['plz'] = 'Postleitzahl muss genau 5 Ziffern haben' # Phone validation: require both country code and number when provided if telefon_vorwahl or telefon_nummer: if not (telefon_vorwahl and telefon_nummer): errors['telefon'] = 'Vorwahl und Telefonnummer müssen beide angegeben werden' else: if phonenumbers: raw = telefon_vorwahl.lstrip('+') + telefon_nummer international = '+' + raw try: parsed = phonenumbers.parse(international, None) is_valid = phonenumbers.is_valid_number(parsed) except Exception: is_valid = False # if phonenumbers says invalid, fall back to a simple heuristic if not is_valid: if not (telefon_vorwahl.lstrip('+').isdigit() and telefon_nummer.isdigit()) or len(telefon_nummer) < 3: errors['telefon'] = 'Ungültige Telefonnummer' else: # fallback: basic numeric checks if not (telefon_vorwahl.lstrip('+').isdigit() and telefon_nummer.isdigit()): errors['telefon'] = 'Ungültige Telefonnummer' elif len(telefon_nummer) < 3: errors['telefon'] = 'Ungültige Telefonnummer' if errors: fragen = Frage.query.all() form = request.form.to_dict() return render_template('index.html', fragen=fragen, errors=errors, form=form) adresse = Adresse( vorname=vorname, nachname=nachname, strasse=strasse, hausnummer=hausnummer, plz=plz, ort=ort, land=land, telefon_vorwahl=telefon_vorwahl, telefon_nummer=telefon_nummer, email=email, ) db.session.add(adresse) db.session.commit() fragen = Frage.query.all() for frage in fragen: key = f'frage_{frage.id}' antwort_text = request.form.get(key, '').strip() antwort = Antwort(adresse_id=adresse.id, frage_id=frage.id, text=antwort_text) db.session.add(antwort) db.session.commit() try: base_dir = current_app.config.get('BASE_DIR') if current_app.config.get('BASE_DIR') else getattr(current_app, 'BASE_DIR', '.') generate_vcard(adresse, base_dir) except Exception: current_app.logger.exception('Fehler beim Erzeugen der vCard for adresse id=%s', adresse.id if hasattr(adresse, 'id') else 'unknown') return redirect(url_for('public.danke', id=adresse.id)) fragen = Frage.query.all() return render_template('index.html', fragen=fragen) @bp.route('/danke') def danke(): ad_id = request.args.get('id') adresse = db.session.get(Adresse, int(ad_id)) if ad_id else None return render_template('danke.html', adresse=adresse)