363 lines
11 KiB
JavaScript
363 lines
11 KiB
JavaScript
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 = `<?xml version="1.0" encoding="utf-8"?>
|
|
<D:multistatus xmlns:D="DAV:">
|
|
${files.map(file => {
|
|
const filePath = path.join(dirPath, file);
|
|
const stats = fs.statSync(filePath);
|
|
return `
|
|
<D:response>
|
|
<D:href>/webdav/${requestPath}/${file}</D:href>
|
|
<D:propstat>
|
|
<D:prop>
|
|
<D:displayname>${file}</D:displayname>
|
|
<D:getcontentlength>${stats.size}</D:getcontentlength>
|
|
<D:getlastmodified>${stats.mtime.toUTCString()}</D:getlastmodified>
|
|
<D:resourcetype>${stats.isDirectory() ? '<D:collection/>' : ''}</D:resourcetype>
|
|
</D:prop>
|
|
<D:status>HTTP/1.1 200 OK</D:status>
|
|
</D:propstat>
|
|
</D:response>`;
|
|
}).join('')}
|
|
</D:multistatus>`;
|
|
|
|
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; |