This repository was archived by the owner on Jan 7, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprocesscube-google-docs-mail-template.js
More file actions
158 lines (122 loc) · 6.59 KB
/
processcube-google-docs-mail-template.js
File metadata and controls
158 lines (122 loc) · 6.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
module.exports = function (RED) {
const fs = require('fs');
const path = require('path');
const { pipeline } = require('stream');
const { promisify } = require('util');
const AdmZip = require('adm-zip');
const fetch = require('node-fetch');
const streamPipeline = promisify(pipeline);
function ProcesssCubeGoogleDocsMailTemplate(config) {
RED.nodes.createNode(this, config);
const node = this;
node.on('input', async function (msg) {
try {
async function inlineCssImport(html) {
// 1. Finde @import-Zeile
const importRegex = /@import\s+url\(([^)]+)\);?/;
const match = html.match(importRegex);
if (!match) return html; // keine @import-Zeile gefunden
const url = match[1].replace(/['"]/g, ''); // evtl. Anführungszeichen entfernen
try {
const response = await fetch(url);
if (!response.ok) throw new Error(`Fehler beim Laden von ${url}`);
const cssContent = await response.text();
// 2. Ersetze @import-Zeile durch eingebettetes CSS
const embeddedStyle = `\n/* inlined from ${url} */\n${cssContent}`;
return html.replace(importRegex, embeddedStyle);
} catch (error) {
console.error('Fehler beim Inlining der CSS-Datei:', error);
return html; // Fallback: Original belassen
}
}
function convertGoogleDriveLink(link) {
// Format 0: https://docs.google.com/document/d/FILE_ID/edit
const editMatch = link.match(/https:\/\/docs\.google\.com\/document\/d\/([^/]+)/);
if (editMatch) {
const fileId = editMatch[1];
return `https://docs.google.com/document/d/${fileId}/export?format=zip`;
}
// Format 1: https://drive.google.com/file/d/FILE_ID/view?usp=sharing
const fileMatch = link.match(/https:\/\/drive\.google\.com\/file\/d\/([^/]+)\/view/);
if (fileMatch) {
return `https://drive.google.com/uc?export=download&id=${fileMatch[1]}`;
}
// Format 2: https://drive.google.com/open?id=FILE_ID
const openMatch = link.match(/https:\/\/drive\.google\.com\/open\?id=([^&]+)/);
if (openMatch) {
return `https://drive.google.com/uc?export=download&id=${openMatch[1]}`;
}
// Anderenfalls unverändert zurückgeben
return link;
}
function renderTemplate(html, payload) {
// Ersetze {{feld}} und ///feld///
return html.replace(/({{([^}]+)}}|\/\/\/([^/]+)\/\/\/)/g, (match, _, field1, field2) => {
const key = field1 || field2;
return payload[key.trim()] ?? match; // fallback: Platzhalter bleibt bestehen
});
}
function removeGoogleRedirects(html) {
return html.replace(/https:\/\/www\.google\.com\/url\?q=([^"&]+)[^"]*/g, (match, actualUrl) => {
try {
// Google-URLs sind URL-encoded – dekodieren
return decodeURIComponent(actualUrl);
} catch {
return actualUrl;
}
});
}
const template_link = RED.util.evaluateNodeProperty(config.template_link, config.template_link_type, node, msg);
const customRoot = path.resolve(RED.settings.userDir, 'tmp/processcube-google-docs-mail-template');
fs.mkdirSync(customRoot, { recursive: true });
const tempDir = fs.mkdtempSync(path.join(customRoot, 'run-'));
const zipPath = path.join(tempDir, 'downloaded.zip');
const url = convertGoogleDriveLink(template_link);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Fehler beim Herunterladen: ${response.status} ${response.statusText}`);
}
await streamPipeline(response.body, fs.createWriteStream(zipPath));
const zip = new AdmZip(zipPath);
zip.extractAllTo(tempDir, true);
// === HTML-Datei im obersten Verzeichnis finden ===
const topLevelFiles = fs.readdirSync(tempDir, { withFileTypes: true });
const htmlEntry = topLevelFiles.find(file =>
file.isFile() && file.name.toLowerCase().endsWith('.html')
);
if (!htmlEntry) {
throw new Error('Keine HTML-Datei im ZIP-Hauptverzeichnis gefunden.');
}
const htmlPath = path.join(tempDir, htmlEntry.name);
let html = fs.readFileSync(htmlPath, 'utf8');
// === Bilder durch CID ersetzen ===
const imgRegex = /src="images\/([^"]+)"/g;
const attachments = [];
let match;
while ((match = imgRegex.exec(html)) !== null) {
const fileName = match[1];
const cidName = path.parse(fileName).name;
const imgPath = path.join(tempDir, 'images', fileName);
if (fs.existsSync(imgPath)) {
attachments.push({
filename: fileName,
path: imgPath,
cid: cidName
});
html = html.replace(`src="images/${fileName}"`, `src="cid:${cidName}"`);
}
}
html = await inlineCssImport(html);
let new_payload = renderTemplate(html, msg.payload);
// ggf. mit schalter
new_payload = removeGoogleRedirects(new_payload);
msg.payload = new_payload;
msg.attachments = attachments;
node.send(msg);
} catch (queryError) {
node.error(`Generate the content: ${queryError.message}`, msg);
}
});
}
RED.nodes.registerType('processcube-google-docs-mail-template', ProcesssCubeGoogleDocsMailTemplate);
};