const express = require('express'); const fs = require('fs'); const path = require('path'); const { createReport } = require('docx-templates'); const cors = require('cors'); const auth = require('basic-auth'); const app = express(); const PORT = process.env.PORT || 3000; // Middleware app.use(cors()); app.use(express.json()); app.use(express.static('public')); // Template-Ordner erstellen falls nicht vorhanden const templatesDir = path.join(__dirname, 'templates'); const outputDir = path.join(__dirname, 'output'); if (!fs.existsSync(templatesDir)) { fs.mkdirSync(templatesDir, { recursive: true }); } if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } // WebDAV-ähnliche Routen für Dateizugriff (ohne Authentifizierung) app.use('/webdav/output', express.static(outputDir)); app.use('/webdav/templates', express.static(templatesDir)); // Output-Dateien über WebDAV-ähnliche URL bereitstellen app.use('/webdav/output', express.static(outputDir, { setHeaders: (res, path) => { res.set('DAV', '1, 2'); res.set('MS-Author-Via', 'DAV'); } })); // Templates über WebDAV-ähnliche URL bereitstellen app.use('/webdav/templates', express.static(templatesDir, { setHeaders: (res, path) => { res.set('DAV', '1, 2'); res.set('MS-Author-Via', 'DAV'); } })); // WebDAV PROPFIND Support (vereinfacht) app.propfind('/webdav/*', (req, res) => { const requestPath = req.path.replace('/webdav/', ''); const isOutput = requestPath.startsWith('output'); const dirPath = isOutput ? outputDir : templatesDir; try { const files = fs.readdirSync(dirPath); const xml = ` ${files.map(file => { const filePath = path.join(dirPath, file); const stats = fs.statSync(filePath); return ` /webdav/${requestPath}/${file} ${file} ${stats.size} ${stats.mtime.toUTCString()} ${stats.isDirectory() ? '' : ''} HTTP/1.1 200 OK `; }).join('')} `; res.set('Content-Type', 'application/xml; charset=utf-8'); res.send(xml); } catch (error) { res.status(404).send('Not found'); } }); // Route: Template hochladen app.post('/upload-template', (req, res) => { // Hier würde normalerweise multer für File-Upload verwendet res.json({ message: 'Template-Upload-Endpoint bereit' }); }); // Route: DOCX mit Daten befüllen app.post('/generate-document', async (req, res) => { try { const { templateName, data } = req.body; if (!templateName || !data) { return res.status(400).json({ error: 'Template-Name und Daten sind erforderlich' }); } const templatePath = path.join(templatesDir, templateName); if (!fs.existsSync(templatePath)) { return res.status(404).json({ error: 'Template nicht gefunden' }); } // Template laden const template = fs.readFileSync(templatePath); // Dokument mit Daten befüllen const buffer = await createReport({ template, data: data, cmdDelimiter: ['{{', '}}'], // Template-Syntax }); // Eindeutigen Dateinamen erstellen const timestamp = Date.now(); const outputFileName = `document_${timestamp}.docx`; const outputPath = path.join(outputDir, outputFileName); // Befülltes Dokument speichern fs.writeFileSync(outputPath, buffer); // Download-Link zurückgeben res.json({ success: true, downloadUrl: `/download/${outputFileName}`, message: 'Dokument erfolgreich erstellt' }); } catch (error) { console.error('Fehler beim Erstellen des Dokuments:', error); res.status(500).json({ error: 'Fehler beim Erstellen des Dokuments', details: error.message }); } }); // Route: Dokument herunterladen app.get('/download/:filename', (req, res) => { const filename = req.params.filename; const filePath = path.join(outputDir, filename); if (!fs.existsSync(filePath)) { return res.status(404).json({ error: 'Datei nicht gefunden' }); } res.download(filePath, filename, (err) => { if (err) { console.error('Download-Fehler:', err); res.status(500).json({ error: 'Download-Fehler' }); } }); }); // Route: Verfügbare Templates auflisten app.get('/templates', (req, res) => { try { const templates = fs.readdirSync(templatesDir) .filter(file => file.endsWith('.docx')) .map(file => ({ name: file, path: `/templates/${file}` })); res.json(templates); } catch (error) { res.status(500).json({ error: 'Fehler beim Auflisten der Templates' }); } }); // Beispiel-Route: Daten von externem Service abrufen app.get('/external-data/:id', async (req, res) => { try { const id = req.params.id; // Hier würden Sie normalerweise Daten von einem externen API abrufen // Beispiel mit fetch oder axios // Beispiel-Daten für Demonstration const exampleData = { id: id, name: 'Max Mustermann', email: 'max@beispiel.de', date: new Date().toLocaleDateString('de-DE'), items: [ { product: 'Produkt A', quantity: 2, price: 29.99 }, { product: 'Produkt B', quantity: 1, price: 49.99 }, { product: 'Produkt C', quantity: 3, price: 19.99 } ], total: 129.95 }; res.json(exampleData); } catch (error) { res.status(500).json({ error: 'Fehler beim Abrufen der externen Daten' }); } }); // Kombinierte Route: Externe Daten abrufen und Dokument erstellen app.post('/generate-from-external/:id', async (req, res) => { try { const id = req.params.id; const { templateName } = req.body; // Externe Daten abrufen (simulation) const externalData = { id: id, name: 'Max Mustermann', email: 'max@beispiel.de', date: new Date().toLocaleDateString('de-DE'), items: [ { product: 'Produkt A', quantity: 2, price: 29.99 }, { product: 'Produkt B', quantity: 1, price: 49.99 }, { product: 'Produkt C', quantity: 3, price: 19.99 } ], total: 129.95 }; // Template-Pfad const templatePath = path.join(templatesDir, templateName); if (!fs.existsSync(templatePath)) { return res.status(404).json({ error: 'Template nicht gefunden' }); } // Template laden und befüllen const template = fs.readFileSync(templatePath); const buffer = await createReport({ template, data: externalData, cmdDelimiter: ['{{', '}}'], }); // Datei speichern const timestamp = Date.now(); const outputFileName = `document_${id}_${timestamp}.docx`; const outputPath = path.join(outputDir, outputFileName); fs.writeFileSync(outputPath, buffer); res.json({ success: true, downloadUrl: `/download/${outputFileName}`, data: externalData, message: 'Dokument mit externen Daten erstellt' }); } catch (error) { console.error('Fehler:', error); res.status(500).json({ error: 'Fehler beim Erstellen des Dokuments mit externen Daten' }); } }); // Health Check app.get('/health', (req, res) => { res.json({ status: 'OK', message: 'DOCX Template Server läuft', webdav: 'WebDAV-ähnliche Endpoints auf Port 3000', timestamp: new Date().toISOString() }); }); // WebDAV Info Endpoint app.get('/webdav-info', (req, res) => { res.json({ webdav: { url: 'http://localhost:3000', endpoints: { templates: 'http://localhost:3000/webdav/templates/', output: 'http://localhost:3000/webdav/output/' }, credentials: { admin: 'password123', user: 'docx2024' }, instructions: { windows: 'Als Netzlaufwerk: http://localhost:3000/webdav/output/', macos: 'Finder > Mit Server verbinden: http://localhost:3000/webdav/output/', linux: 'dav://localhost:3000/webdav/output/ oder direkt über Browser' }, note: 'Vereinfachte WebDAV-Implementation - verwenden Sie Browser oder HTTP-Clients' } }); }); // Datei-Management Endpoints app.get('/files/output', (req, res) => { try { const files = fs.readdirSync(outputDir) .filter(file => file.endsWith('.docx')) .map(file => { const filePath = path.join(outputDir, file); const stats = fs.statSync(filePath); return { name: file, size: stats.size, created: stats.birthtime, modified: stats.mtime, webdavUrl: `http://localhost:3000/webdav/output/${file}`, downloadUrl: `/download/${file}` }; }) .sort((a, b) => b.modified - a.modified); res.json({ files, count: files.length, webdavAccess: 'http://localhost:3000/webdav/output/' }); } catch (error) { res.status(500).json({ error: 'Fehler beim Auflisten der Dateien' }); } }); app.delete('/files/output/:filename', (req, res) => { try { const filename = req.params.filename; const filePath = path.join(outputDir, filename); if (!fs.existsSync(filePath)) { return res.status(404).json({ error: 'Datei nicht gefunden' }); } fs.unlinkSync(filePath); res.json({ success: true, message: `Datei ${filename} gelöscht` }); } catch (error) { res.status(500).json({ error: 'Fehler beim Löschen der Datei' }); } }); // Server starten app.listen(PORT, () => { console.log(`🚀 DOCX Template Server läuft auf Port ${PORT}`); console.log(`📁 Templates-Ordner: ${templatesDir}`); console.log(`📄 Output-Ordner: ${outputDir}`); console.log(`🌐 Health Check: http://localhost:${PORT}/health`); console.log(`🗂️ WebDAV-ähnliche Endpoints:`); console.log(` Templates: http://localhost:${PORT}/webdav/templates/`); console.log(` Output: http://localhost:${PORT}/webdav/output/`); console.log(`👤 Login: admin/password123 oder user/docx2024`); }); module.exports = app;