Files
SemapForm/app/main.py
WorldTeacher 51e3e2a39c
All checks were successful
Docker Build (PR) / Build Docker image (pull_request) Successful in 4m49s
feat: add elsa form with a modular addition of content type
2025-11-19 14:10:22 +01:00

349 lines
14 KiB
Python
Executable File

import os
import re
import smtplib
from email.mime.text import MIMEText
from xml.etree.ElementTree import Element, SubElement, tostring
from fastapi import FastAPI, Form, HTTPException, Request, status
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory="app/templates")
# Serve static files (CSS, images)
app.mount("/static", StaticFiles(directory="app/static"), name="static")
# add somewhere near the top-level constants
EMAIL_REGEX = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$")
# SMTP / email configuration via environment
MAIL_ENABLED = os.getenv("MAIL_ENABLED", "false").lower() == "true"
SMTP_HOST = os.getenv("SMTP_HOST", "smtp")
SMTP_PORT = int(os.getenv("SMTP_PORT", "25"))
MAIL_FROM = os.getenv("MAIL_FROM", "noreply@example.com")
MAIL_TO = os.getenv("MAIL_TO", "destination@example.com")
@app.get("/", response_class=HTMLResponse)
async def landing_page(request: Request):
"""Landing page with service selection"""
return templates.TemplateResponse("index.html", {"request": request})
@app.get("/semesterapparat", response_class=HTMLResponse)
async def semesterapparat_form(request: Request):
"""Semesterapparat form page"""
return templates.TemplateResponse("semesterapparat_form.html", {"request": request})
@app.get("/elsa", response_class=HTMLResponse)
async def elsa_form(request: Request):
"""ELSA form page"""
return templates.TemplateResponse("elsa_mono_form.html", {"request": request})
@app.post("/submit")
async def handle_form(
request: Request,
name: str = Form(...),
lastname: str = Form(...),
title: str = Form(...),
telno: str = Form(...),
mail: str = Form(...),
apparatsname: str = Form(...),
subject: str = Form(...),
semester_type: str = Form(...), # "summer" or "winter"
semester_year: str = Form(...),
authorname: list[str] = Form(...),
year: list[str] = Form(...),
booktitle: list[str] = Form(...),
signature: list[str] = Form(...),
message: str = Form(default=""),
):
# Basic email validation (server-side)
if not EMAIL_REGEX.match(mail):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Invalid email address format.",
)
# Build XML
root = Element("form_submission")
static_data = SubElement(root, "static")
SubElement(static_data, "name").text = name
SubElement(static_data, "lastname").text = lastname
SubElement(static_data, "title").text = title
SubElement(static_data, "telno").text = telno
SubElement(static_data, "mail").text = mail
SubElement(static_data, "apparatsname").text = apparatsname
SubElement(static_data, "subject").text = subject
SubElement(static_data, "semester").text = f"{semester_type} {semester_year}"
if message:
SubElement(static_data, "message").text = message
books = SubElement(root, "books")
for i in range(len(authorname)):
book = SubElement(books, "book")
SubElement(book, "authorname").text = authorname[i]
SubElement(book, "year").text = year[i]
SubElement(book, "title").text = booktitle[i]
SubElement(book, "signature").text = signature[i]
xml_data = tostring(root, encoding="unicode")
# Send mail
msg = MIMEText(xml_data, "xml")
msg["Subject"] = "New Form Submission"
msg["From"] = MAIL_FROM
msg["To"] = MAIL_TO
if MAIL_ENABLED:
with smtplib.SMTP(SMTP_HOST, SMTP_PORT) as server:
server.send_message(msg)
else:
print("=" * 80)
print("MAIL SENDING DISABLED - Would have sent:")
print(f"From: {MAIL_FROM}")
print(f"To: {MAIL_TO}")
print(f"Subject: {msg['Subject']}")
print("-" * 80)
print(xml_data)
print("=" * 80)
return RedirectResponse("/?success=true", status_code=303)
@app.post("/elsa/submit")
async def handle_elsa_form(request: Request):
"""Handle ELSA form submission with multiple media types"""
form_data = await request.form()
# Extract general information
name = str(form_data.get("name", ""))
lastname = str(form_data.get("lastname", ""))
title_field = str(form_data.get("title", ""))
mail = str(form_data.get("mail", ""))
subject = str(form_data.get("subject", ""))
classname = str(form_data.get("classname", ""))
usage_date_from = str(form_data.get("usage_date_from", ""))
usage_date_to = str(form_data.get("usage_date_to", ""))
availability_date = str(form_data.get("availability_date", ""))
message = str(form_data.get("message", ""))
# Basic email validation
if not EMAIL_REGEX.match(mail):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Invalid email address format.",
)
# Build XML structure
root = Element("elsa_submission")
# General information
general_info = SubElement(root, "general_info")
SubElement(general_info, "name").text = name
SubElement(general_info, "lastname").text = lastname
SubElement(general_info, "title").text = title_field
SubElement(general_info, "mail").text = mail
SubElement(general_info, "subject").text = subject
SubElement(general_info, "classname").text = classname
SubElement(general_info, "usage_date_from").text = usage_date_from
SubElement(general_info, "usage_date_to").text = usage_date_to
SubElement(general_info, "availability_date").text = availability_date
if message:
SubElement(general_info, "message").text = message
# Process media sections
media_root = SubElement(root, "media")
# Process Monografie entries
if "monografie_author[]" in form_data:
monografie_authors = [str(v) for v in form_data.getlist("monografie_author[]")]
monografie_years = [str(v) for v in form_data.getlist("monografie_year[]")]
monografie_editions = [
str(v) for v in form_data.getlist("monografie_edition[]")
]
monografie_titles = [str(v) for v in form_data.getlist("monografie_title[]")]
monografie_signatures = [
str(v) for v in form_data.getlist("monografie_signature[]")
]
monografie_pages_from = [
str(v) for v in form_data.getlist("monografie_pages_from[]")
]
monografie_pages_to = [
str(v) for v in form_data.getlist("monografie_pages_to[]")
]
# Get section IDs from the form (assuming they're in data-section attributes)
# Since we can't directly access data-section from form_data, we'll process sequentially
monografie_section = SubElement(media_root, "monografien")
for i in range(len(monografie_authors)):
entry = SubElement(monografie_section, "entry")
SubElement(entry, "author").text = (
monografie_authors[i] if i < len(monografie_authors) else ""
)
SubElement(entry, "year").text = (
monografie_years[i] if i < len(monografie_years) else ""
)
SubElement(entry, "edition").text = (
monografie_editions[i] if i < len(monografie_editions) else ""
)
SubElement(entry, "title").text = (
monografie_titles[i] if i < len(monografie_titles) else ""
)
SubElement(entry, "signature").text = (
monografie_signatures[i] if i < len(monografie_signatures) else ""
)
SubElement(entry, "pages_from").text = (
monografie_pages_from[i] if i < len(monografie_pages_from) else ""
)
SubElement(entry, "pages_to").text = (
monografie_pages_to[i] if i < len(monografie_pages_to) else ""
)
# Process Zeitschriftenartikel entries
if "zeitschrift_author[]" in form_data:
zeitschrift_authors = [
str(v) for v in form_data.getlist("zeitschrift_author[]")
]
zeitschrift_years = [str(v) for v in form_data.getlist("zeitschrift_year[]")]
zeitschrift_volumes = [
str(v) for v in form_data.getlist("zeitschrift_volume[]")
]
zeitschrift_article_titles = [
str(v) for v in form_data.getlist("zeitschrift_article_title[]")
]
zeitschrift_journal_titles = [
str(v) for v in form_data.getlist("zeitschrift_journal_title[]")
]
zeitschrift_signatures = [
str(v) for v in form_data.getlist("zeitschrift_signature[]")
]
zeitschrift_pages_from = [
str(v) for v in form_data.getlist("zeitschrift_pages_from[]")
]
zeitschrift_pages_to = [
str(v) for v in form_data.getlist("zeitschrift_pages_to[]")
]
zeitschrift_section = SubElement(media_root, "zeitschriftenartikel")
for i in range(len(zeitschrift_authors)):
entry = SubElement(zeitschrift_section, "entry")
SubElement(entry, "author").text = (
zeitschrift_authors[i] if i < len(zeitschrift_authors) else ""
)
SubElement(entry, "year").text = (
zeitschrift_years[i] if i < len(zeitschrift_years) else ""
)
SubElement(entry, "volume").text = (
zeitschrift_volumes[i] if i < len(zeitschrift_volumes) else ""
)
SubElement(entry, "article_title").text = (
zeitschrift_article_titles[i]
if i < len(zeitschrift_article_titles)
else ""
)
SubElement(entry, "journal_title").text = (
zeitschrift_journal_titles[i]
if i < len(zeitschrift_journal_titles)
else ""
)
SubElement(entry, "signature").text = (
zeitschrift_signatures[i] if i < len(zeitschrift_signatures) else ""
)
SubElement(entry, "pages_from").text = (
zeitschrift_pages_from[i] if i < len(zeitschrift_pages_from) else ""
)
SubElement(entry, "pages_to").text = (
zeitschrift_pages_to[i] if i < len(zeitschrift_pages_to) else ""
)
# Process Herausgeberwerk entries
if "herausgeber_publisher[]" in form_data:
herausgeber_publishers = [
str(v) for v in form_data.getlist("herausgeber_publisher[]")
]
herausgeber_work_titles = [
str(v) for v in form_data.getlist("herausgeber_work_title[]")
]
herausgeber_years = [str(v) for v in form_data.getlist("herausgeber_year[]")]
herausgeber_editions = [
str(v) for v in form_data.getlist("herausgeber_edition[]")
]
herausgeber_article_authors = [
str(v) for v in form_data.getlist("herausgeber_article_author[]")
]
herausgeber_article_titles = [
str(v) for v in form_data.getlist("herausgeber_article_title[]")
]
herausgeber_signatures = [
str(v) for v in form_data.getlist("herausgeber_signature[]")
]
herausgeber_pages_from = [
str(v) for v in form_data.getlist("herausgeber_pages_from[]")
]
herausgeber_pages_to = [
str(v) for v in form_data.getlist("herausgeber_pages_to[]")
]
herausgeber_section = SubElement(media_root, "herausgeberwerke")
for i in range(len(herausgeber_publishers)):
entry = SubElement(herausgeber_section, "entry")
SubElement(entry, "publisher").text = (
herausgeber_publishers[i] if i < len(herausgeber_publishers) else ""
)
SubElement(entry, "work_title").text = (
herausgeber_work_titles[i] if i < len(herausgeber_work_titles) else ""
)
SubElement(entry, "year").text = (
herausgeber_years[i] if i < len(herausgeber_years) else ""
)
SubElement(entry, "edition").text = (
herausgeber_editions[i] if i < len(herausgeber_editions) else ""
)
SubElement(entry, "article_author").text = (
herausgeber_article_authors[i]
if i < len(herausgeber_article_authors)
else ""
)
SubElement(entry, "article_title").text = (
herausgeber_article_titles[i]
if i < len(herausgeber_article_titles)
else ""
)
SubElement(entry, "signature").text = (
herausgeber_signatures[i] if i < len(herausgeber_signatures) else ""
)
SubElement(entry, "pages_from").text = (
herausgeber_pages_from[i] if i < len(herausgeber_pages_from) else ""
)
SubElement(entry, "pages_to").text = (
herausgeber_pages_to[i] if i < len(herausgeber_pages_to) else ""
)
xml_data = tostring(root, encoding="unicode")
# Send or print email
msg = MIMEText(xml_data, "xml")
msg["Subject"] = "New ELSA Form Submission"
msg["From"] = MAIL_FROM
msg["To"] = MAIL_TO
if MAIL_ENABLED:
with smtplib.SMTP(SMTP_HOST, SMTP_PORT) as server:
server.send_message(msg)
else:
print("=" * 80)
print("MAIL SENDING DISABLED - Would have sent:")
print(f"From: {MAIL_FROM}")
print(f"To: {MAIL_TO}")
print(f"Subject: {msg['Subject']}")
print("-" * 80)
print(xml_data)
print("=" * 80)
return RedirectResponse("/?success=true", status_code=303)