diff --git a/pyproject.toml b/pyproject.toml index f3bbe59..3360463 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta" [project] name = "forgejo-blog-manager" -version = "0.1.4" -description = "Blog-Manager für Uberspace 8 mit Marvin API und Pelican sowie DOCX-Konvertierung" +version = "0.1.5" +description = "Blog-Manager für Uberspace 8 mit Marvin API, Pelican und DOCX-Konvertierung" authors = [{name = "Ihre Autorin", email = "autorin@example.com"}] license = {text = "MIT"} readme = "README.md" @@ -30,4 +30,7 @@ package-dir = {"" = "src"} packages = ["dlw"] [tool.setuptools.package-data] -"dlw" = ["ssg_config/*", "ssg_config/templates/*"] \ No newline at end of file +"dlw" = [ + "ssg_config/*", + "templates/**/*.j2" +] diff --git a/src/dlw/app.py b/src/dlw/app.py new file mode 100644 index 0000000..a0af2cc --- /dev/null +++ b/src/dlw/app.py @@ -0,0 +1,75 @@ +""" +DLW Frontend - Web-Interface für die DOCX-zu-PDF Konvertierung. + +Dieses Modul stellt eine Flask-App bereit, die es Autorinnen ermöglicht, +Word-Dokumente hochzuladen und direkt als PDF im Browser zurückzuerhalten. +Genutzt werden dafür Mammoth (Struktur) und WeasyPrint (Layout). +""" + +from flask import Flask, render_template, request, send_file +from dlw.convert import convert_docx_to_pdf_stream +import os + +# --- Konfiguration der Verzeichnisstruktur --- +# Wir ermitteln den absoluten Pfad zum zentralen Template-Ordner, +# damit Flask die Jinja2-Dateien auch dann findet, wenn die App +# aus einem anderen Verzeichnis gestartet wird. +base_dir = os.path.dirname(__file__) +template_dir = os.path.abspath(os.path.join(base_dir, 'templates')) + +app = Flask(__name__, template_folder=template_dir) + +# Begrenzung der Upload-Größe auf 16 Megabyte, um den Server zu schützen. +app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 + +@app.route('/', methods=['GET', 'POST']) +def index(): + """ + Haupt-Route für den Konverter. + + GET: Zeigt das Upload-Formular an. + POST: Verarbeitet das hochgeladene DOCX, konvertiert es in ein PDF-Stream + und sendet dieses als Download an den Client zurück. + """ + if request.method == 'POST': + # 1. Validierung: Prüfen, ob überhaupt ein Datei-Teil im Request ist + if 'file' not in request.files: + return "Fehler: Kein Datei-Feld im Formular gefunden.", 400 + + file = request.files['file'] + + # 2. Validierung: Prüfen, ob eine Datei ausgewählt wurde + if file.filename == '': + return "Fehler: Es wurde keine Datei zum Hochladen ausgewählt.", 400 + + # 3. Verarbeitung: Nur .docx Dateien zulassen + if file and file.filename.endswith('.docx'): + try: + # Wir lesen die Datei direkt in den Arbeitsspeicher (Bytes) + docx_bytes = file.read() + + # Konvertierung via Mammoth & WeasyPrint (gibt BytesIO Stream zurück) + pdf_stream = convert_docx_to_pdf_stream(docx_bytes) + + # Dynamische Generierung des Dateinamens (aus .docx wird .pdf) + download_name = file.filename.replace('.docx', '.pdf') + + # PDF-Stream als Download an den Browser senden + return send_file( + pdf_stream, + mimetype='application/pdf', + as_attachment=True, + download_name=download_name + ) + except Exception as e: + # Grobe Fehlerbehandlung für den MVP-Status + return f"Interner Fehler bei der Konvertierung: {str(e)}", 500 + + # Falls GET-Request oder fehlerhafter Dateityp: Zeige das Formular + # Der Pfad 'app/converter.html.j2' bezieht sich auf den template_folder + return render_template('app/converter.html.j2') + +if __name__ == '__main__': + # Startet den lokalen Entwicklungs-Server. + # 'debug=True' sorgt für automatisches Neuladen bei Code-Änderungen. + app.run(debug=True, port=5000) diff --git a/src/dlw/ssg_config/pelicanconf.py b/src/dlw/ssg_config/pelicanconf.py index 85c91f7..7a28d69 100644 --- a/src/dlw/ssg_config/pelicanconf.py +++ b/src/dlw/ssg_config/pelicanconf.py @@ -1,3 +1,14 @@ +import os + +# --- Dynamische Pfadberechnung --- +# Ermittelt den absoluten Pfad zum Verzeichnis dieser Datei (src/dlw/ssg_config) +CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) + +# Setzt den Theme-Pfad auf den neuen zentralen Ort (src/dlw/templates/ssg) +# Wir gehen eine Ebene hoch (..) und dann in den templates/ssg Ordner +THEME = os.path.join(CURRENT_DIR, '..', 'templates', 'ssg') + +# --- Allgemeine Website-Einstellungen --- AUTHOR = 'Ihre Autorin' SITENAME = 'Forgejo Blog' SITEURL = '' @@ -5,15 +16,16 @@ PATH = 'content' TIMEZONE = 'Europe/Berlin' DEFAULT_LANG = 'de' +# --- URL-Struktur --- ARTICLE_URL = 'blog/{slug}/' ARTICLE_SAVE_AS = 'blog/{slug}/index.html' STATIC_PATHS = ['downloads', 'images'] -THEME = 'ssg_config/templates' +# --- Markdown-Konfiguration --- MARKDOWN = { 'extension_configs': { 'markdown.extensions.extra': {}, 'markdown.extensions.meta': {}, }, 'output_format': 'html5', -} \ No newline at end of file +} diff --git a/src/dlw/templates/app/converter.html.j2 b/src/dlw/templates/app/converter.html.j2 new file mode 100644 index 0000000..747f18e --- /dev/null +++ b/src/dlw/templates/app/converter.html.j2 @@ -0,0 +1,53 @@ + + + + + + DLW - DOCX zu PDF + + + +
+

Word-Konverter für Autorinnen

+
+
+ +
+ +
+
+ + diff --git a/src/dlw/ssg_config/templates/article.html b/src/dlw/templates/ssg/article.html.j2 similarity index 100% rename from src/dlw/ssg_config/templates/article.html rename to src/dlw/templates/ssg/article.html.j2 diff --git a/src/dlw/ssg_config/templates/base.html b/src/dlw/templates/ssg/base.html.j2 similarity index 100% rename from src/dlw/ssg_config/templates/base.html rename to src/dlw/templates/ssg/base.html.j2