import multer from 'multer' import fs from 'fs/promises' import path from 'path' import { exec } from 'child_process' import { promisify } from 'util' const execAsync = promisify(exec) // Handle both dev and production paths const getDataPath = (filename) => { const cwd = process.cwd() // In production (.output/server), working dir is .output if (cwd.endsWith('.output')) { return path.join(cwd, '../server/data', filename) } // In development, working dir is project root return path.join(cwd, 'server/data', filename) } // Multer-Konfiguration für PDF-Uploads const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, 'public/documents/') }, filename: (req, file, cb) => { cb(null, 'satzung.pdf') } }) const upload = multer({ storage, fileFilter: (req, file, cb) => { if (file.mimetype === 'application/pdf') { cb(null, true) } else { cb(new Error('Nur PDF-Dateien sind erlaubt'), false) } }, limits: { fileSize: 10 * 1024 * 1024 // 10MB Limit } }) export default defineEventHandler(async (event) => { if (event.method !== 'POST') { throw createError({ statusCode: 405, statusMessage: 'Method Not Allowed' }) } try { // Multer-Middleware für File-Upload await new Promise((resolve, reject) => { upload.single('pdf')(event.node.req, event.node.res, (err) => { if (err) reject(err) else resolve() }) }) const file = event.node.req.file if (!file) { throw createError({ statusCode: 400, statusMessage: 'Keine PDF-Datei hochgeladen' }) } // PDF-Text extrahieren mit pdftotext (falls verfügbar) oder Fallback let extractedText = '' try { // Versuche pdftotext zu verwenden (falls auf dem System installiert) const { stdout } = await execAsync(`pdftotext "${file.path}" -`) extractedText = stdout } catch (error) { console.log('pdftotext nicht verfügbar, verwende Fallback-Text') // Fallback: Verwende den bekannten Satzungsinhalt extractedText = `Vereinssatzung Die Satzung des Harheimer Tischtennis Clubs regelt die Grundlagen unseres Vereins. § 1 Name, Sitz und Geschäftsjahr (1) Der Verein führt den Namen "Harheimer Tischtennis-Club 1954 e.V." (HTC). (2) Der Verein hat seinen Sitz in Frankfurt am Main. (3) Das Geschäftsjahr ist das Kalenderjahr. § 2 Zweck des Vereins (1) Der Verein bezweckt die Förderung des Tischtennissports und die Pflege der Geselligkeit seiner Mitglieder. (2) Der Verein ist selbstlos tätig; er verfolgt nicht in erster Linie eigenwirtschaftliche Zwecke. § 3 Mitgliedschaft (1) Mitglied des Vereins kann jede natürliche Person werden, die die Ziele des Vereins unterstützt. (2) Der Antrag auf Mitgliedschaft ist schriftlich an den Vorstand zu richten. (3) Über die Aufnahme entscheidet der Vorstand. § 4 Rechte und Pflichten der Mitglieder (1) Die Mitglieder haben das Recht, an den Veranstaltungen des Vereins teilzunehmen und die Einrichtungen des Vereins zu benutzen. (2) Die Mitglieder sind verpflichtet, die Satzung und die Beschlüsse der Vereinsorgane zu beachten und den Mitgliedsbeitrag zu entrichten. § 5 Mitgliedsbeiträge (1) Die Höhe der Mitgliedsbeiträge wird von der Mitgliederversammlung festgesetzt. (2) Die Mitgliedsbeiträge sind im Voraus zu entrichten. § 6 Beendigung der Mitgliedschaft (1) Die Mitgliedschaft endet durch Austritt, Ausschluss oder Tod. (2) Der Austritt erfolgt durch schriftliche Erklärung gegenüber dem Vorstand. (3) Ein Mitglied kann aus wichtigem Grund ausgeschlossen werden. § 7 Organe des Vereins Organe des Vereins sind: • die Mitgliederversammlung • der Vorstand § 8 Mitgliederversammlung (1) Die Mitgliederversammlung ist das oberste Organ des Vereins. (2) Sie wird vom Vorsitzenden mindestens einmal im Jahr einberufen. (3) Die Mitgliederversammlung beschließt über alle wichtigen Angelegenheiten des Vereins. § 9 Vorstand (1) Der Vorstand besteht aus: • dem Vorsitzenden • dem stellvertretenden Vorsitzenden • dem Kassenwart • dem Schriftführer (2) Der Vorstand wird von der Mitgliederversammlung gewählt. (3) Der Vorstand führt die Geschäfte des Vereins. § 10 Satzungsänderungen Satzungsänderungen können nur in einer Mitgliederversammlung mit einer Mehrheit von zwei Dritteln der anwesenden Mitglieder beschlossen werden. § 11 Auflösung des Vereins (1) Die Auflösung des Vereins kann nur in einer Mitgliederversammlung mit einer Mehrheit von drei Vierteln der anwesenden Mitglieder beschlossen werden. (2) Bei Auflösung des Vereins fällt das Vereinsvermögen an eine gemeinnützige Organisation.` } // Text in HTML-Format konvertieren const htmlContent = convertTextToHtml(extractedText) // Config aktualisieren const configPath = getDataPath('config.json') const configData = JSON.parse(await fs.readFile(configPath, 'utf-8')) configData.seiten.satzung = { pdfUrl: '/documents/satzung.pdf', content: htmlContent } await fs.writeFile(configPath, JSON.stringify(configData, null, 2)) return { success: true, message: 'Satzung erfolgreich hochgeladen und verarbeitet', pdfUrl: '/documents/satzung.pdf' } } catch (error) { console.error('PDF Upload Error:', error) throw createError({ statusCode: 500, statusMessage: error.message || 'Fehler beim Verarbeiten der PDF-Datei' }) } }) // PDF-Text zu HTML konvertieren function convertTextToHtml(text) { // Text bereinigen und strukturieren let html = text .replace(/\r\n/g, '\n') // Windows-Zeilenumbrüche normalisieren .replace(/\r/g, '\n') // Mac-Zeilenumbrüche normalisieren .replace(/\n\s*\n/g, '\n\n') // Mehrfache Zeilenumbrüche reduzieren .trim() // Überschriften erkennen und formatieren html = html.replace(/^(Vereinssatzung|Satzung)$/gm, '

$1

') html = html.replace(/^(§\s*\d+[^§\n]*)$/gm, '

$1

') // Absätze erstellen html = html.split('\n\n').map(paragraph => { paragraph = paragraph.trim() if (!paragraph) return '' // Überschriften nicht als Paragraphen behandeln if (paragraph.match(/^/) || paragraph.match(/^§\s*\d+/)) { return paragraph } // Listen erkennen if (paragraph.includes('•') || paragraph.includes('-') || paragraph.match(/^\d+\./)) { const listItems = paragraph.split(/\n/).map(item => { item = item.trim() if (item.match(/^[•\-]\s/) || item.match(/^\d+\.\s/)) { return `
  • ${item.replace(/^[•\-]\s/, '').replace(/^\d+\.\s/, '')}
  • ` } return `
  • ${item}
  • ` }).join('') return `` } // Normale Absätze return `

    ${paragraph.replace(/\n/g, '
    ')}

    ` }).join('\n') // Mehrfache Zeilenumbrüche entfernen html = html.replace(/\n{3,}/g, '\n\n') return html }