Compare commits

...

1 Commits
main ... dev

Author SHA1 Message Date
Kim Diallo 042d00292b frontend mvp 2026-02-13 15:46:55 +01:00
6 changed files with 148 additions and 5 deletions

View File

@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "forgejo-blog-manager" name = "forgejo-blog-manager"
version = "0.1.4" version = "0.1.5"
description = "Blog-Manager für Uberspace 8 mit Marvin API und Pelican sowie DOCX-Konvertierung" description = "Blog-Manager für Uberspace 8 mit Marvin API, Pelican und DOCX-Konvertierung"
authors = [{name = "Ihre Autorin", email = "autorin@example.com"}] authors = [{name = "Ihre Autorin", email = "autorin@example.com"}]
license = {text = "MIT"} license = {text = "MIT"}
readme = "README.md" readme = "README.md"
@ -30,4 +30,7 @@ package-dir = {"" = "src"}
packages = ["dlw"] packages = ["dlw"]
[tool.setuptools.package-data] [tool.setuptools.package-data]
"dlw" = ["ssg_config/*", "ssg_config/templates/*"] "dlw" = [
"ssg_config/*",
"templates/**/*.j2"
]

75
src/dlw/app.py Normal file
View File

@ -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)

View File

@ -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' AUTHOR = 'Ihre Autorin'
SITENAME = 'Forgejo Blog' SITENAME = 'Forgejo Blog'
SITEURL = '' SITEURL = ''
@ -5,15 +16,16 @@ PATH = 'content'
TIMEZONE = 'Europe/Berlin' TIMEZONE = 'Europe/Berlin'
DEFAULT_LANG = 'de' DEFAULT_LANG = 'de'
# --- URL-Struktur ---
ARTICLE_URL = 'blog/{slug}/' ARTICLE_URL = 'blog/{slug}/'
ARTICLE_SAVE_AS = 'blog/{slug}/index.html' ARTICLE_SAVE_AS = 'blog/{slug}/index.html'
STATIC_PATHS = ['downloads', 'images'] STATIC_PATHS = ['downloads', 'images']
THEME = 'ssg_config/templates'
# --- Markdown-Konfiguration ---
MARKDOWN = { MARKDOWN = {
'extension_configs': { 'extension_configs': {
'markdown.extensions.extra': {}, 'markdown.extensions.extra': {},
'markdown.extensions.meta': {}, 'markdown.extensions.meta': {},
}, },
'output_format': 'html5', 'output_format': 'html5',
} }

View File

@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DLW - DOCX zu PDF</title>
<style>
body {
font-family: -apple-system, system-ui, sans-serif;
max-width: 500px;
margin: 100px auto;
background: #f4f7f6;
color: #2c3e50;
}
.container {
background: white;
padding: 40px;
border-radius: 12px;
box-shadow: 0 10px 25px rgba(0,0,0,0.05);
}
h1 { font-size: 1.25rem; margin-bottom: 20px; text-align: center; }
.upload-area {
border: 2px dashed #cbd5e0;
padding: 20px;
text-align: center;
border-radius: 8px;
margin-bottom: 20px;
}
button {
width: 100%;
background: #4a90e2;
color: white;
border: none;
padding: 12px;
border-radius: 6px;
font-weight: bold;
cursor: pointer;
}
button:hover { background: #357abd; }
</style>
</head>
<body>
<div class="container">
<h1>Word-Konverter für Autorinnen</h1>
<form method="post" enctype="multipart/form-data">
<div class="upload-area">
<input type="file" name="file" accept=".docx" required>
</div>
<button type="submit">PDF generieren</button>
</form>
</div>
</body>
</html>