const express = require('express');
const Docxtemplater = require('docxtemplater');
const PizZip = require('pizzip');
const fs = require('fs');
const path = require('path');
const multer = require('multer');
const cors = require('cors');
const helmet = require('helmet');
const https = require('https');
const crypto = require('crypto');
const { faker } = require('@faker-js/faker');
const app = express();
const PORT = process.env.PORT || 80;
// Middleware
app.use(helmet());
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Verzeichnisse erstellen
const templateDir = path.join(__dirname, 'templates');
const outputDir = path.join(__dirname, 'documents');
[templateDir, outputDir].forEach(dir => {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
});
// WebDAV-Implementierung für Word/Office-Integration mit SharePoint-Kompatibilität
const webdavMethods = ['PROPFIND', 'PROPPATCH', 'MKCOL', 'COPY', 'MOVE', 'LOCK', 'UNLOCK'];
// SharePoint-spezifische Namespaces und Header
const sharePointNamespaces = {
'xmlns:D': 'DAV:',
'xmlns:S': 'http://schemas.microsoft.com/sharepoint/soap/',
'xmlns:Z': 'urn:schemas-microsoft-com:',
'xmlns:O': 'urn:schemas-microsoft-com:office:office',
'xmlns:T': 'http://schemas.microsoft.com/repl/'
};
// WebDAV PROPFIND Handler mit SharePoint-Modus
app.use('/webdav', (req, res, next) => {
// Erweiterte CORS und WebDAV-Header für Office/SharePoint
res.set({
'DAV': '1, 2, ordered-collections, versioning, extended-mkcol',
'MS-Author-Via': 'DAV',
'Server': 'Microsoft-IIS/10.0 Microsoft-HTTPAPI/2.0',
'MicrosoftSharePointTeamServices': '15.0.0.4569',
'SPRequestGuid': `{${crypto.randomUUID()}}`,
'SPIisLatency': '0',
'Allow': 'GET, HEAD, POST, PUT, DELETE, OPTIONS, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, HEAD, POST, PUT, DELETE, OPTIONS, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK',
'Access-Control-Allow-Headers': 'Content-Type, Depth, Authorization, Destination, If, Lock-Token, Overwrite, Timeout, X-Requested-With, SOAPAction',
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Pragma': 'no-cache',
'Expires': '0',
'X-SharePointHealthScore': '0',
'X-AspNet-Version': '4.0.30319',
'X-Powered-By': 'ASP.NET'
});
if (req.method === 'OPTIONS') {
return res.status(200).end();
}
if (req.method === 'PROPFIND') {
const depth = req.headers.depth || 'infinity';
const requestPath = req.path.replace('/webdav', '');
let targetDir;
if (requestPath.startsWith('/templates')) {
targetDir = path.join(templateDir, requestPath.replace('/templates', ''));
} else if (requestPath.startsWith('/documents')) {
targetDir = path.join(outputDir, requestPath.replace('/documents', ''));
} else {
targetDir = __dirname;
}
try {
let items = [];
if (fs.existsSync(targetDir)) {
const stats = fs.statSync(targetDir);
if (stats.isDirectory()) {
const files = fs.readdirSync(targetDir);
// Verzeichnis selbst
items.push({
href: req.path + (req.path.endsWith('/') ? '' : '/'),
isDirectory: true,
lastModified: stats.mtime.toUTCString(),
size: 0
});
// Dateien im Verzeichnis
files.forEach(file => {
const filePath = path.join(targetDir, file);
const fileStats = fs.statSync(filePath);
items.push({
href: req.path + (req.path.endsWith('/') ? '' : '/') + file,
isDirectory: fileStats.isDirectory(),
lastModified: fileStats.mtime.toUTCString(),
size: fileStats.size || 0,
contentType: fileStats.isDirectory() ? 'httpd/unix-directory' : 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
});
});
} else {
// Einzelne Datei
items.push({
href: req.path,
isDirectory: false,
lastModified: stats.mtime.toUTCString(),
size: stats.size,
contentType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
});
}
}
// WebDAV XML Response mit SharePoint-spezifischen Eigenschaften
const xmlResponse = `
${items.map(item => `
${item.href}
${path.basename(item.href)}
${item.lastModified}
${item.size}
${item.contentType}
${item.isDirectory ? '' : ''}
"${Date.now()}-${item.size}"
${new Date(item.lastModified).toISOString()}
${item.isDirectory ? 'true' : 'false'}
F
F
F
F
${new Date(item.lastModified).toISOString()}
${new Date().toISOString()}
${new Date(item.lastModified).toISOString()}
00000020
System Account
0
1
0x0101
0
HTTP/1.1 200 OK
`).join('')}
`;
res.set('Content-Type', 'application/xml; charset=utf-8');
res.status(207).send(xmlResponse);
} catch (error) {
res.status(404).send('Not Found');
}
return;
}
next();
});
// WebDAV PUT Handler für Dateien speichern
// PUT - File Upload (für Word Speichern)
app.put('/dav/*', (req, res) => {
const filePath = path.join(__dirname, 'uploads', req.params[0]);
const dirPath = path.dirname(filePath);
console.log(`� PUT Request: ${req.params[0]}`);
console.log(`📂 Speichere nach: ${filePath}`);
// Stelle sicher dass der Ordner existiert
fs.mkdirSync(dirPath, { recursive: true });
const writeStream = fs.createWriteStream(filePath);
req.pipe(writeStream);
writeStream.on('finish', () => {
console.log(`✅ Datei gespeichert: ${filePath}`);
res.set({
'DAV': '1, 2, ordered-collections, versioning, extended-mkcol',
'MS-Author-Via': 'DAV',
'Server': 'Microsoft-IIS/10.0 Microsoft-HTTPAPI/2.0',
'MicrosoftSharePointTeamServices': '15.0.0.4569',
'SPRequestGuid': `{${crypto.randomUUID()}}`,
'Cache-Control': 'no-cache',
'ETag': `"${Date.now()}-${req.headers['content-length'] || 0}"`,
'Last-Modified': new Date().toUTCString(),
'X-SharePoint-HealthScore': '0'
});
res.status(201).send('Created');
});
writeStream.on('error', (err) => {
console.error(`❌ Fehler beim Speichern: ${err.message}`);
res.status(500).send('Internal Server Error');
});
});
app.put('/webdav/documents/:filename', (req, res) => {
const filename = req.params.filename;
const filePath = path.join(outputDir, filename);
console.log(`📝 Word speichert Dokument: ${filename}`);
const writeStream = fs.createWriteStream(filePath);
req.pipe(writeStream);
writeStream.on('finish', () => {
// Dateirechte explizit setzen
try {
fs.chmodSync(filePath, 0o666); // Lese-/Schreibrechte für alle
} catch (error) {
console.warn('Warnung: Konnte Dateiberechtigungen nicht setzen:', error.message);
}
res.set({
'DAV': '1, 2, ordered-collections, versioning',
'MS-Author-Via': 'DAV',
'Server': 'Microsoft-IIS/10.0',
'Cache-Control': 'no-cache',
'ETag': `"${Date.now()}-${req.headers['content-length'] || 0}"`,
'Last-Modified': new Date().toUTCString()
});
res.status(201).send('Created');
console.log(`✅ Dokument gespeichert: ${filename}`);
});
writeStream.on('error', (error) => {
console.error('❌ Fehler beim Speichern:', error);
res.status(500).send('Internal Server Error');
});
});
// WebDAV GET Handler für Dateien lesen
app.get('/webdav/templates/:filename', (req, res) => {
const filename = req.params.filename;
const filePath = path.join(templateDir, filename);
if (fs.existsSync(filePath)) {
const stats = fs.statSync(filePath);
res.set({
'DAV': '1, 2, ordered-collections, versioning',
'MS-Author-Via': 'DAV',
'Server': 'Microsoft-IIS/10.0',
'Content-Type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'Content-Length': stats.size,
'Last-Modified': stats.mtime.toUTCString(),
'ETag': `"${stats.mtime.getTime()}-${stats.size}"`,
'Accept-Ranges': 'bytes',
'Cache-Control': 'no-cache'
});
console.log(`📖 Word öffnet Template: ${filename}`);
res.sendFile(filePath);
} else {
res.status(404).send('Not Found');
}
});
app.get('/webdav/documents/:filename', (req, res) => {
const filename = req.params.filename;
const filePath = path.join(outputDir, filename);
if (fs.existsSync(filePath)) {
const stats = fs.statSync(filePath);
res.set({
'DAV': '1, 2, ordered-collections, versioning',
'MS-Author-Via': 'DAV',
'Server': 'Microsoft-IIS/10.0',
'Content-Type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'Content-Length': stats.size,
'Last-Modified': stats.mtime.toUTCString(),
'ETag': `"${stats.mtime.getTime()}-${stats.size}"`,
'Accept-Ranges': 'bytes',
'Cache-Control': 'no-cache'
});
console.log(`📖 Word öffnet Dokument: ${filename}`);
res.sendFile(filePath);
} else {
res.status(404).send('Not Found');
}
});
// WebDAV LOCK/UNLOCK für Office
app.use('/webdav', (req, res, next) => {
if (req.method === 'LOCK') {
const lockToken = 'opaquelocktoken:' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
const lockResponse = `
0
Second-604800
${lockToken}
`;
res.set({
'Content-Type': 'application/xml; charset=utf-8',
'Lock-Token': `<${lockToken}>`,
'DAV': '1, 2',
'MS-Author-Via': 'DAV'
});
res.status(200).send(lockResponse);
return;
}
if (req.method === 'UNLOCK') {
res.set({
'DAV': '1, 2',
'MS-Author-Via': 'DAV'
});
res.status(204).send();
return;
}
next();
});
app.use('/webdav/documents', express.static(outputDir, {
setHeaders: (res, path) => {
res.set({
'DAV': '1, 2',
'Allow': 'GET, PUT, DELETE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, HEAD, OPTIONS',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, PUT, DELETE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, HEAD, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Depth, Authorization, If-Match, If-None-Match, Overwrite, Destination',
'MS-Author-Via': 'DAV',
'Cache-Control': 'no-cache'
});
}
}));
// WebDAV PROPFIND Support für Word
app.use('/webdav/*', (req, res, next) => {
if (req.method === 'PROPFIND') {
res.set({
'Content-Type': 'application/xml; charset=utf-8',
'DAV': '1, 2',
'MS-Author-Via': 'DAV'
});
const propfindResponse = `
${req.originalUrl}
HTTP/1.1 200 OK
httpd/unix-directory
`;
res.status(207).send(propfindResponse);
return;
}
next();
});
// SharePoint-spezifische Endpunkte
app.get('/_vti_inf.html', (req, res) => {
// SharePoint Info-Seite
res.set('Content-Type', 'text/html');
res.send(``);
});
app.post('/_vti_bin/lists.asmx', (req, res) => {
// SharePoint Lists Web Service
res.set({
'Content-Type': 'text/xml; charset=utf-8',
'SOAPAction': req.headers.soapaction || ''
});
const soapResponse = `
`;
res.send(soapResponse);
});
app.get('/_vti_bin/owssvr.dll', (req, res) => {
// SharePoint OWS Service
if (req.query.Cmd === 'Display' && req.query.List) {
res.set('Content-Type', 'text/xml');
res.send(`
`);
} else {
res.status(404).send('Not Found');
}
});
// SharePoint-kompatible WebDAV-Root
app.use('/sharepoint', (req, res, next) => {
// SharePoint-spezifische Header
res.set({
'MicrosoftSharePointTeamServices': '15.0.0.4569',
'SharePointHealthScore': '0',
'SPRequestGuid': `{${crypto.randomUUID()}}`,
'X-SharePoint-HealthScore': '0'
});
// Weiterleitung zu WebDAV
const newPath = req.path.replace('/sharepoint', '/webdav');
req.url = newPath;
next();
});
console.log('SharePoint-Kompatibilitätsmodus aktiviert:');
console.log('SharePoint WebDAV: http://localhost:' + (process.env.PORT || 80) + '/sharepoint/templates/');
console.log('SharePoint Info: http://localhost:' + (process.env.PORT || 80) + '/_vti_inf.html');
// Multer für File Upload
const upload = multer({ dest: 'uploads/' });
// Demo-Daten Generator
class DemoDataGenerator {
static generateData(tags) {
const data = {};
tags.forEach(tag => {
const lowerTag = tag.toLowerCase();
if (lowerTag.includes('name') || lowerTag.includes('vorname')) {
data[tag] = faker.person.firstName();
} else if (lowerTag.includes('nachname') || lowerTag.includes('surname')) {
data[tag] = faker.person.lastName();
} else if (lowerTag.includes('email') || lowerTag.includes('mail')) {
data[tag] = faker.internet.email();
} else if (lowerTag.includes('telefon') || lowerTag.includes('phone')) {
data[tag] = faker.phone.number();
} else if (lowerTag.includes('adresse') || lowerTag.includes('address')) {
data[tag] = faker.location.streetAddress();
} else if (lowerTag.includes('stadt') || lowerTag.includes('city')) {
data[tag] = faker.location.city();
} else if (lowerTag.includes('plz') || lowerTag.includes('postal')) {
data[tag] = faker.location.zipCode();
} else if (lowerTag.includes('land') || lowerTag.includes('country')) {
data[tag] = faker.location.country();
} else if (lowerTag.includes('datum') || lowerTag.includes('date')) {
data[tag] = faker.date.recent().toLocaleDateString('de-DE');
} else if (lowerTag.includes('betrag') || lowerTag.includes('preis') || lowerTag.includes('amount')) {
data[tag] = faker.commerce.price();
} else if (lowerTag.includes('firma') || lowerTag.includes('company')) {
data[tag] = faker.company.name();
} else if (lowerTag.includes('produkt') || lowerTag.includes('product')) {
data[tag] = faker.commerce.productName();
} else if (lowerTag.includes('beschreibung') || lowerTag.includes('description')) {
data[tag] = faker.lorem.paragraph();
} else if (lowerTag.includes('nummer') || lowerTag.includes('number') || lowerTag.includes('id')) {
data[tag] = faker.string.numeric(6);
} else {
// Fallback für unbekannte Tags
data[tag] = faker.lorem.words(2);
}
});
return data;
}
static generateTableData(tableStructure) {
const rows = Math.floor(Math.random() * 5) + 2; // 2-6 Zeilen
const tableData = [];
for (let i = 0; i < rows; i++) {
const row = {};
tableStructure.forEach(column => {
if (column.includes('position')) {
row[column] = (i + 1).toString(); // Fortlaufende Positionsnummer
} else {
row[column] = this.generateData([column])[column];
}
});
tableData.push(row);
}
return tableData;
}
}
// Template Tag Extractor
class TemplateTagExtractor {
static extractTags(docxBuffer) {
try {
const zip = new PizZip(docxBuffer);
const doc = new Docxtemplater(zip, {
paragraphLoop: true,
linebreaks: true,
});
// Alle Tags aus dem Template extrahieren
const tags = new Set();
const content = zip.file('word/document.xml').asText();
// Einfache Tags: {tag}
const simpleTagRegex = /{([^{}]+)}/g;
let match;
while ((match = simpleTagRegex.exec(content)) !== null) {
const tag = match[1].trim();
if (!tag.includes('#') && !tag.includes('/')) {
tags.add(tag);
}
}
// Loop Tags für Tabellen: {#items}...{/items}
const loopTagRegex = /{#(\w+)}/g;
const loopTags = [];
while ((match = loopTagRegex.exec(content)) !== null) {
loopTags.push(match[1]);
}
return {
simpleTags: Array.from(tags),
loopTags: loopTags
};
} catch (error) {
console.error('Fehler beim Extrahieren der Tags:', error);
return { simpleTags: [], loopTags: [] };
}
}
}
// Template Processor
class TemplateProcessor {
static async processTemplate(templatePath, outputPath, customData = null) {
try {
const content = fs.readFileSync(templatePath, 'binary');
const zip = new PizZip(content);
// Tags extrahieren
const { simpleTags, loopTags } = TemplateTagExtractor.extractTags(Buffer.from(content, 'binary'));
// Daten generieren oder verwenden
let data = customData || {};
if (!customData) {
// Demo-Daten für einfache Tags generieren
data = DemoDataGenerator.generateData(simpleTags);
// Demo-Daten für Loop Tags (Tabellen) generieren
loopTags.forEach(loopTag => {
// Erweiterte Tabellen-Spalten für professionelle Rechnung
const tableColumns = [`${loopTag}_position`, `${loopTag}_name`, `${loopTag}_value`, `${loopTag}_date`];
data[loopTag] = DemoDataGenerator.generateTableData(tableColumns);
});
}
const doc = new Docxtemplater(zip, {
paragraphLoop: true,
linebreaks: true,
});
doc.render(data);
const buf = doc.getZip().generate({
type: 'nodebuffer',
compression: 'DEFLATE',
});
fs.writeFileSync(outputPath, buf);
return {
success: true,
data: data,
extractedTags: { simpleTags, loopTags }
};
} catch (error) {
console.error('Template Verarbeitung fehlgeschlagen:', error);
return {
success: false,
error: error.message
};
}
}
}
// Routes
// Hauptseite
app.get('/', (req, res) => {
res.send(`
DOCX Template Server
DOCX Template Server
📄 Template hochladen und verarbeiten
📁 Office-Integration
Office-Integration: Öffnen Sie in Word/Excel: Datei → Öffnen → Netzwerk hinzufügen → WebDAV → http://localhost:${PORT}/webdav/templates/
Direkt speichern: Word speichert automatisch auf dem Server wenn über WebDAV geöffnet.
🔧 API Endpunkte
Word-Integration: Die API liefert spezielle Links für Microsoft Word:
wordWebdavUrl - Direkt in Word öffnen (ms-word: Protocol)
wordDirectUrl - Alternative Word-Integration
webdavDirect - Windows UNC-Pfad für Netzlaufwerk
`);
});
// Template Upload und Verarbeitung
app.post('/upload-template', upload.single('template'), async (req, res) => {
try {
if (!req.file) {
return res.status(400).json({ error: 'Keine Datei hochgeladen' });
}
const templateName = req.file.originalname;
const templatePath = path.join(templateDir, templateName);
const outputName = templateName.replace('.docx', '_ausgefuellt.docx');
const outputPath = path.join(outputDir, outputName);
// Template in Templates-Verzeichnis kopieren
fs.copyFileSync(req.file.path, templatePath);
// Template verarbeiten
const result = await TemplateProcessor.processTemplate(templatePath, outputPath);
// Upload-Datei löschen
fs.unlinkSync(req.file.path);
if (result.success) {
const protocol = req.secure ? 'https' : 'http';
const host = req.get('host') || `localhost:${PORT}`;
res.json({
message: 'Template erfolgreich verarbeitet',
templateName: templateName,
outputName: outputName,
extractedTags: result.extractedTags,
generatedData: result.data,
fileUrls: {
template: `${protocol}://${host}/webdav/templates/${templateName}`,
document: `${protocol}://${host}/webdav/documents/${outputName}`,
wordWebdavTemplate: `ms-word:ofe|u|${protocol}://${host}/webdav/templates/${encodeURIComponent(templateName)}`,
wordWebdavDocument: `ms-word:ofe|u|${protocol}://${host}/webdav/documents/${encodeURIComponent(outputName)}`,
wordDirectTemplate: `word:ofe|u|${protocol}://${host}/webdav/templates/${encodeURIComponent(templateName)}`,
wordDirectDocument: `word:ofe|u|${protocol}://${host}/webdav/documents/${encodeURIComponent(outputName)}`
}
});
} else {
res.status(500).json({ error: result.error });
}
} catch (error) {
console.error('Upload Fehler:', error);
res.status(500).json({ error: 'Server Fehler beim Upload' });
}
});
// Test Template erstellen
app.get('/create-test-template', (req, res) => {
const PizZip = require('pizzip');
// Minimales DOCX Template erstellen
const testContent = `
Firmenname: {firma}
Ansprechpartner: {vorname} {nachname}
E-Mail: {email}
Telefon: {telefon}
Adresse: {adresse}, {plz} {stadt}
Datum: {datum}
Rechnungsnummer: {nummer}
Positionen:
{#items}
- {items_name}: {items_value} EUR ({items_date})
{/items}
Gesamtbetrag: {betrag} EUR
Beschreibung:
{beschreibung}
`;
try {
// Minimal DOCX Struktur
const zip = new PizZip();
// document.xml
zip.file('word/document.xml', testContent);
// [Content_Types].xml
zip.file('[Content_Types].xml', `
`);
// _rels/.rels
zip.file('_rels/.rels', `
`);
// word/_rels/document.xml.rels
zip.file('word/_rels/document.xml.rels', `
`);
const buffer = zip.generate({ type: 'nodebuffer' });
const testTemplatePath = path.join(templateDir, 'test_template.docx');
fs.writeFileSync(testTemplatePath, buffer);
res.json({
message: 'Test Template erstellt',
templatePath: 'test_template.docx',
fileUrl: `http://localhost:${PORT}/webdav/templates/test_template.docx`,
info: 'Sie können das Template jetzt über den Datei-Server herunterladen, bearbeiten und wieder hochladen.'
});
} catch (error) {
console.error('Fehler beim Erstellen des Test Templates:', error);
res.status(500).json({ error: 'Fehler beim Erstellen des Test Templates' });
}
});
// API Endpunkte
app.get('/api/templates', (req, res) => {
try {
const files = fs.readdirSync(templateDir).filter(file => file.endsWith('.docx'));
const protocol = req.secure ? 'https' : 'http';
const host = req.get('host') || `localhost:${PORT}`;
res.json({
templates: files.map(file => ({
name: file,
fileUrl: `${protocol}://${host}/webdav/templates/${file}`,
wordWebdavUrl: `ms-word:ofe|u|${protocol}://${host}/webdav/templates/${encodeURIComponent(file)}`,
wordDirectUrl: `word:ofe|u|${protocol}://${host}/webdav/templates/${encodeURIComponent(file)}`,
downloadUrl: `${protocol}://${host}/webdav/templates/${file}`,
webdavDirect: `\\\\${host.split(':')[0]}@${PORT}\\webdav\\templates\\${file}`
}))
});
} catch (error) {
res.status(500).json({ error: 'Fehler beim Auflisten der Templates' });
}
});
app.get('/api/documents', (req, res) => {
try {
const files = fs.readdirSync(outputDir).filter(file => file.endsWith('.docx'));
const protocol = req.secure ? 'https' : 'http';
const host = req.get('host') || `localhost:${PORT}`;
res.json({
documents: files.map(file => ({
name: file,
fileUrl: `${protocol}://${host}/webdav/documents/${file}`,
wordWebdavUrl: `ms-word:ofe|u|${protocol}://${host}/webdav/documents/${encodeURIComponent(file)}`,
wordDirectUrl: `word:ofe|u|${protocol}://${host}/webdav/documents/${encodeURIComponent(file)}`,
downloadUrl: `${protocol}://${host}/webdav/documents/${file}`,
webdavDirect: `\\\\${host.split(':')[0]}@${PORT}\\webdav\\documents\\${file}`,
createdAt: fs.statSync(path.join(outputDir, file)).mtime
}))
});
} catch (error) {
res.status(500).json({ error: 'Fehler beim Auflisten der Dokumente' });
}
});
// Template mit benutzerdefinierten Daten verarbeiten
app.post('/api/process-template/:templateName', (req, res) => {
try {
const templateName = req.params.templateName;
const templatePath = path.join(templateDir, templateName);
if (!fs.existsSync(templatePath)) {
return res.status(404).json({ error: 'Template nicht gefunden' });
}
const outputName = templateName.replace('.docx', '_custom.docx');
const outputPath = path.join(outputDir, outputName);
TemplateProcessor.processTemplate(templatePath, outputPath, req.body).then(result => {
if (result.success) {
res.json({
message: 'Template mit benutzerdefinierten Daten verarbeitet',
outputName: outputName,
fileUrl: `http://localhost:${PORT}/webdav/documents/${outputName}`
});
} else {
res.status(500).json({ error: result.error });
}
});
} catch (error) {
res.status(500).json({ error: 'Fehler beim Verarbeiten des Templates' });
}
});
// SSL Konfiguration
const certPath = path.join(__dirname, '203_cert.pem');
const keyPath = path.join(__dirname, '203_key.pem');
if (fs.existsSync(keyPath) && fs.existsSync(certPath)) {
try {
const sslOptions = {
key: fs.readFileSync(keyPath),
cert: fs.readFileSync(certPath)
};
https.createServer(sslOptions, app).listen(443, () => {
console.log('🔒 HTTPS Server läuft auf Port 443');
console.log('🌐 HTTPS Zugang: https://localhost:443');
});
} catch (error) {
console.warn('⚠️ SSL-Zertifikate gefunden, aber Fehler beim Laden:', error.message);
console.log('ℹ️ Server läuft nur mit HTTP');
}
} else {
console.log('ℹ️ SSL-Zertifikate nicht gefunden - Server läuft nur mit HTTP');
console.log('💡 Für HTTPS: Platzieren Sie 203_cert.pem und 203_key.pem in /home/OfficeServerJS/');
}
// Server starten
app.listen(PORT, () => {
console.log(`\n🚀 DOCX Template Server gestartet!`);
console.log(`📍 HTTP Server: http://localhost:${PORT}`);
console.log(`📁 Templates: http://localhost:${PORT}/webdav/templates/`);
console.log(`📁 Documents: http://localhost:${PORT}/webdav/documents/`);
console.log(`\n💡 Tipp: Besuchen Sie http://localhost:${PORT} für die Web-Oberfläche`);
// SSL-Status anzeigen
const certPath = path.join(__dirname, '203_cert.pem');
const keyPath = path.join(__dirname, '203_key.pem');
if (fs.existsSync(keyPath) && fs.existsSync(certPath)) {
console.log(`🔒 HTTPS auch verfügbar: https://localhost:443`);
}
});
module.exports = app;