@5minds/node-red-contrib-processcube-tools 1.0.1-develop-c7d5e6-mfffb5w1 → 1.0.1-develop-4412ca-mfm8hzs3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.template ADDED
@@ -0,0 +1,4 @@
1
+ EMAIL_SEND_PORT=
2
+ EMAIL_SEND_HOST=
3
+ EMAIL_SEND_USER=
4
+ EMAIL_SEND_PASSWORD=
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Some Nodes to efficent with the ProcessCube LowCode component (Node-RED)
2
2
 
3
- This repository contains some nodes to efficent with the ProcessCube LowCode component (Node-RED).
3
+ This repository contains nodes for working efficiently with the ProcessCube Low-Code component (Node-RED).
4
4
 
5
5
  Details see @ [ProcessCub.io - LowCode Integration Nodes](https://processcube.io/docs/node-red/integration-nodes) and [ProcessCub.io - LowCode Event Nodes](https://processcube.io/docs/node-red/event-nodes).
@@ -1,131 +1,142 @@
1
1
  <script type="text/javascript">
2
2
  RED.nodes.registerType('email-receiver', {
3
- category: 'ProcessCube Tools',
4
- color: '#02AFD6',
5
- defaults: {
6
- name: { value: "" },
7
- host: { value: "", required: true, validate: RED.validators.typedInput("hostType") },
8
- hostType: { value: "str" },
9
- port: { value: "", required: true, validate: RED.validators.typedInput("portType") },
10
- portType: { value: "num" },
11
- tls: { value: true, required: true, validate: RED.validators.typedInput("tlsType") },
12
- tlsType: { value: "bool" },
13
- user: { value: "", required: true, validate: RED.validators.typedInput("userType") },
14
- userType: { value: "str" },
15
- password: { value: "", required: true, type: "password" },
16
- passwordType: { value: "env", required: true },
17
- folder: { value: "", required: true, validate: RED.validators.typedInput("folderType") },
18
- folderType: { value: "json" },
19
- markseen: { value: true, validate: RED.validators.typedInput("markseenType") },
20
- markseenType: { value: "bool" }
21
- },
22
- inputs: 1,
23
- outputs: 1,
24
- icon: "font-awesome/fa-inbox",
25
- label: function() {
26
- return this.name || "E-Mail Receiver";
27
- },
28
- oneditprepare: function() {
29
- $('#node-input-host').typedInput({
30
- default: 'str',
31
- types: ['str', 'msg', 'flow', 'global', 'env'],
32
- typeField: '#node-input-hostType'
33
- });
34
-
35
- $('#node-input-port').typedInput({
36
- default: 'num',
37
- types: ['num', 'msg', 'flow', 'global', 'env'],
38
- typeField: '#node-input-portType'
39
- });
40
-
41
- $('#node-input-tls').typedInput({
42
- default: 'bool',
43
- types: ['bool', 'msg', 'flow', 'global', 'env'],
44
- typeField: '#node-input-tlsType'
45
- });
46
-
47
- $('#node-input-user').typedInput({
48
- default: 'str',
49
- types: ['str', 'msg', 'flow', 'global', 'env'],
50
- typeField: '#node-input-userType'
51
- });
52
-
53
- $('#node-input-password').typedInput({
54
- default: 'env',
55
- types: ['msg', 'flow', 'global', 'env'],
56
- typeField: '#node-input-passwordType'
57
- });
58
-
59
- $('#node-input-folder').typedInput({
60
- default: 'json',
61
- types: ['msg', 'flow', 'global', 'json', 'jsonata', 'env'],
62
- typeField: '#node-input-folderType'
63
- });
64
-
65
- $('#node-input-markseen').typedInput({
66
- default: 'bool',
67
- types: ['bool', 'msg', 'flow', 'global', 'env'],
68
- typeField: '#node-input-markseenType'
69
- });
70
- }
3
+ category: 'ProcessCube Tools',
4
+ color: '#02AFD6',
5
+ defaults: {
6
+ name: { value: '' },
7
+ host: { value: '', required: true, validate: RED.validators.typedInput('hostType') },
8
+ hostType: { value: 'str' },
9
+ port: { value: '', required: true, validate: RED.validators.typedInput('portType') },
10
+ portType: { value: 'num' },
11
+ tls: { value: true, required: true, validate: RED.validators.typedInput('tlsType') },
12
+ tlsType: { value: 'bool' },
13
+ user: { value: '', required: true, validate: RED.validators.typedInput('userType') },
14
+ userType: { value: 'str' },
15
+ password: { value: '', required: true, type: 'password' },
16
+ passwordType: { value: 'env', required: true },
17
+ folder: { value: '', required: true, validate: RED.validators.typedInput('folderType') },
18
+ folderType: { value: 'json' },
19
+ markseen: { value: true, validate: RED.validators.typedInput('markseenType') },
20
+ markseenType: { value: 'bool' },
21
+ },
22
+ inputs: 1,
23
+ outputs: 1,
24
+ icon: 'font-awesome/fa-inbox',
25
+ label: function () {
26
+ return this.name || 'E-Mail Receiver';
27
+ },
28
+ oneditprepare: function () {
29
+ $('#node-input-host').typedInput({
30
+ default: 'str',
31
+ types: ['str', 'msg', 'flow', 'global', 'env'],
32
+ typeField: '#node-input-hostType',
33
+ });
34
+
35
+ $('#node-input-port').typedInput({
36
+ default: 'num',
37
+ types: ['num', 'msg', 'flow', 'global', 'env'],
38
+ typeField: '#node-input-portType',
39
+ });
40
+
41
+ $('#node-input-tls').typedInput({
42
+ default: 'bool',
43
+ types: ['bool', 'msg', 'flow', 'global', 'env'],
44
+ typeField: '#node-input-tlsType',
45
+ });
46
+
47
+ $('#node-input-user').typedInput({
48
+ default: 'str',
49
+ types: ['str', 'msg', 'flow', 'global', 'env'],
50
+ typeField: '#node-input-userType',
51
+ });
52
+
53
+ $('#node-input-password').typedInput({
54
+ default: 'env',
55
+ types: ['msg', 'flow', 'global', 'env'],
56
+ typeField: '#node-input-passwordType',
57
+ });
58
+
59
+ $('#node-input-folder').typedInput({
60
+ default: 'json',
61
+ types: ['msg', 'flow', 'global', 'json', 'jsonata', 'env'],
62
+ typeField: '#node-input-folderType',
63
+ });
64
+
65
+ $('#node-input-markseen').typedInput({
66
+ default: 'bool',
67
+ types: ['bool', 'msg', 'flow', 'global', 'env'],
68
+ typeField: '#node-input-markseenType',
69
+ });
70
+ },
71
71
  });
72
- </script>
72
+ </script>
73
73
 
74
- <script type="text/html" data-template-name="email-receiver">
74
+ <script type="text/html" data-template-name="email-receiver">
75
75
  <div class="form-row">
76
- <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
77
- <input type="text" id="node-input-name" placeholder="Name">
76
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
77
+ <input type="text" id="node-input-name" placeholder="Name" />
78
78
  </div>
79
79
 
80
80
  <div class="form-row">
81
- <label for="node-input-host"><i class="fa fa-server"></i> IMAP Host</label>
82
- <input type="text" id="node-input-host" placeholder="imap.gmail.com">
83
- <input type="hidden" id="node-input-hostType">
81
+ <label for="node-input-host"><i class="fa fa-server"></i> IMAP Host</label>
82
+ <input type="text" id="node-input-host" placeholder="imap.gmail.com" />
83
+ <input type="hidden" id="node-input-hostType" />
84
84
  </div>
85
85
 
86
86
  <div class="form-row">
87
- <label for="node-input-port"><i class="fa fa-terminal"></i> Port</label>
88
- <input type="text" id="node-input-port" placeholder="993">
89
- <input type="hidden" id="node-input-portType">
87
+ <label for="node-input-port"><i class="fa fa-terminal"></i> Port</label>
88
+ <input type="text" id="node-input-port" placeholder="993" />
89
+ <input type="hidden" id="node-input-portType" />
90
90
  </div>
91
91
 
92
92
  <div class="form-row">
93
- <label for="node-input-tls"><i class="fa fa-lock"></i> Use TLS</label>
94
- <input type="text" id="node-input-tls">
95
- <input type="hidden" id="node-input-tlsType">
93
+ <label for="node-input-tls"><i class="fa fa-lock"></i> Use TLS</label>
94
+ <input type="text" id="node-input-tls" />
95
+ <input type="hidden" id="node-input-tlsType" />
96
96
  </div>
97
97
 
98
98
  <div class="form-row">
99
- <label for="node-input-user"><i class="fa fa-user"></i> User</label>
100
- <input type="text" id="node-input-user">
101
- <input type="hidden" id="node-input-userType">
99
+ <label for="node-input-user"><i class="fa fa-user"></i> User</label>
100
+ <input type="text" id="node-input-user" />
101
+ <input type="hidden" id="node-input-userType" />
102
102
  </div>
103
103
 
104
104
  <div class="form-row">
105
- <label for="node-input-password"><i class="fa fa-key"></i> Password</label>
106
- <input type="text" id="node-input-password">
107
- <input type="hidden" id="node-input-passwordType">
105
+ <label for="node-input-password"><i class="fa fa-key"></i> Password</label>
106
+ <input type="text" id="node-input-password" />
107
+ <input type="hidden" id="node-input-passwordType" />
108
108
  </div>
109
109
 
110
110
  <div class="form-row">
111
- <label for="node-input-folder"><i class="fa fa-folder-open"></i> Folder(s)</label>
112
- <input type="text" id="node-input-folder" placeholder="[INBOX]">
113
- <input type="hidden" id="node-input-folderType">
111
+ <label for="node-input-folder"><i class="fa fa-folder-open"></i> Folder(s)</label>
112
+ <input type="text" id="node-input-folder" placeholder="[INBOX]" />
113
+ <input type="hidden" id="node-input-folderType" />
114
114
  </div>
115
115
 
116
116
  <div class="form-row">
117
- <label for="node-input-markseen"><i class="fa fa-eye"></i> Mark as seen</label>
118
- <input type="text" id="node-input-markseen">
119
- <input type="hidden" id="node-input-markseenType">
117
+ <label for="node-input-markseen"><i class="fa fa-eye"></i> Mark as seen</label>
118
+ <input type="text" id="node-input-markseen" />
119
+ <input type="hidden" id="node-input-markseenType" />
120
120
  </div>
121
- </script>
122
-
123
- <script type="text/html" data-help-name="email-receiver">
124
- <p>A Node-RED node that fetches unseen emails from a specified IMAP server. Each fetched email is sent as a separate message on the output.</p>
125
-
126
- <p>All fields can be configured as a <strong>string</strong>, from a <strong>message property (msg)</strong>, <strong>flow</strong> or <strong>global</strong> context, or an <strong>environment variable</strong>.</p>
127
-
128
- <p><strong>Security Tip:</strong> It's a best practice to avoid storing sensitive information like passwords directly in your Node-RED flow. This prevents them from being exposed in your flow file. Instead, use an <strong>environment variable</strong>. You can define these variables in a <code>.env</code> file, which is especially useful when deploying your application with Docker.</p>
121
+ </script>
122
+
123
+ <script type="text/html" data-help-name="email-receiver">
124
+ <p>
125
+ A Node-RED node that fetches unseen emails from a specified IMAP server. Each fetched email is sent as a
126
+ separate message on the output.
127
+ </p>
128
+
129
+ <p>
130
+ All fields can be configured as a <strong>string</strong>, from a <strong>message property (msg)</strong>,
131
+ <strong>flow</strong> or <strong>global</strong> context, or an <strong>environment variable</strong>.
132
+ </p>
133
+
134
+ <p>
135
+ <strong>Security Tip:</strong> It's a best practice to avoid storing sensitive information like passwords
136
+ directly in your Node-RED flow. This prevents them from being exposed in your flow file. Instead, use an
137
+ <strong>environment variable</strong>. You can define these variables in a <code>.env</code> file, which is
138
+ especially useful when deploying your application with Docker.
139
+ </p>
129
140
 
130
141
  <p>A <code>.env</code> file should look like this:</p>
131
142
  <pre>
@@ -133,55 +144,76 @@
133
144
  EMAIL_SEND_HOST=smtp.gmail.com
134
145
  EMAIL_SEND_USER=myTestMail@company.com
135
146
  EMAIL_SEND_PASSWORD=mySecretPassword
136
- </pre>
147
+ </pre
148
+ >
137
149
 
138
- <p>To ensure Docker loads these variables from the <code>.env</code> file, you need to add the following line to your <code>docker-compose.yaml</code> file:</p>
150
+ <p>
151
+ To ensure Docker loads these variables from the <code>.env</code> file, you need to add the following line to
152
+ your <code>docker-compose.yaml</code> file:
153
+ </p>
139
154
  <pre>
140
155
  services:
141
156
  your_service_name:
142
157
  ...
143
158
  env_file:
144
159
  - .env
145
- </pre>
160
+ </pre
161
+ >
146
162
 
147
- <p>In your flow, you can then access the password using the environment variable <code>EMAIL_SEND_PASSWORD</code>.</p>
163
+ <p>
164
+ In your flow, you can then access the password using the environment variable <code>EMAIL_SEND_PASSWORD</code>.
165
+ </p>
148
166
 
149
167
  Inputs
150
168
  <dl class="message-properties">
151
- <dt>payload</dt>
152
- <dd>The node is triggered by any incoming message. The node's configuration can be overridden by properties of the incoming <code>msg</code> object.</dd>
169
+ <dt>payload</dt>
170
+ <dd>
171
+ The node is triggered by any incoming message. The node's configuration can be overridden by properties of
172
+ the incoming <code>msg</code> object.
173
+ </dd>
153
174
  </dl>
154
175
 
155
176
  Outputs
156
177
  <dl class="message-properties">
157
- <dt>payload
158
- <span class="property-type">string</span>
159
- </dt>
160
- <dd>The text body of the email.</dd>
178
+ <dt>
179
+ payload
180
+ <span class="property-type">string</span>
181
+ </dt>
182
+ <dd>The text body of the email.</dd>
161
183
  </dl>
162
184
 
163
185
  Optional Message Properties
164
- <p>You can override default settings by passing the following properties in the incoming <code>msg</code> object:</p>
186
+ <p>
187
+ You can override default settings by passing the following properties in the incoming <code>msg</code> object:
188
+ </p>
165
189
  <dl class="message-properties">
166
- <dt>msg.imap_connTimeout
167
- <span class="property-type">number</span>
168
- </dt>
169
- <dd>The connection timeout in milliseconds (default: 10000).</dd>
170
- <dt>msg.imap_authTimeout
171
- <span class="property-type">number</span>
172
- </dt>
173
- <dd>The authentication timeout in milliseconds (default: 5000).</dd>
174
- <dt>msg.imap_keepalive
175
- <span class="property-type">boolean</span>
176
- </dt>
177
- <dd>If set to <code>true</code>, a periodic NOOP command is sent to keep the connection alive (default: <code>true</code>).</dd>
178
- <dt>msg.imap_autotls
179
- <span class="property-type">string</span>
180
- </dt>
181
- <dd>Controls STARTTLS behavior. Set to <code>never</code> to disable it (default: <code>never</code>).</dd>
182
- <dt>msg.imap_tlsOptions
183
- <span class="property-type">object</span>
184
- </dt>
185
- <dd>An object containing TLS options for the connection.</dd>
190
+ <dt>
191
+ msg.imap_connTimeout
192
+ <span class="property-type">number</span>
193
+ </dt>
194
+ <dd>The connection timeout in milliseconds (default: 10000).</dd>
195
+ <dt>
196
+ msg.imap_authTimeout
197
+ <span class="property-type">number</span>
198
+ </dt>
199
+ <dd>The authentication timeout in milliseconds (default: 5000).</dd>
200
+ <dt>
201
+ msg.imap_keepalive
202
+ <span class="property-type">boolean</span>
203
+ </dt>
204
+ <dd>
205
+ If set to <code>true</code>, a periodic NOOP command is sent to keep the connection alive (default:
206
+ <code>true</code>).
207
+ </dd>
208
+ <dt>
209
+ msg.imap_autotls
210
+ <span class="property-type">string</span>
211
+ </dt>
212
+ <dd>Controls STARTTLS behavior. Set to <code>never</code> to disable it (default: <code>never</code>).</dd>
213
+ <dt>
214
+ msg.imap_tlsOptions
215
+ <span class="property-type">object</span>
216
+ </dt>
217
+ <dd>An object containing TLS options for the connection.</dd>
186
218
  </dl>
187
- </script>
219
+ </script>
@@ -1,4 +1,4 @@
1
- module.exports = function(RED) {
1
+ module.exports = function (RED) {
2
2
  const Imap = require('node-imap');
3
3
  const mailparser = require('mailparser');
4
4
 
@@ -6,7 +6,7 @@ module.exports = function(RED) {
6
6
  RED.nodes.createNode(this, config);
7
7
  const node = this;
8
8
 
9
- node.on('input', function(msg) {
9
+ node.on('input', function (msg) {
10
10
  // Retrieve and validate configuration values
11
11
  const imap_host = RED.util.evaluateNodeProperty(config.host, config.hostType, node, msg);
12
12
  const imap_port = RED.util.evaluateNodeProperty(config.port, config.portType, node, msg);
@@ -29,20 +29,31 @@ module.exports = function(RED) {
29
29
 
30
30
  const finalConfig = {
31
31
  host: imap_host,
32
- port: (typeof imap_port === 'string') ? parseInt(imap_port, 10) : imap_port,
32
+ port: typeof imap_port === 'string' ? parseInt(imap_port, 10) : imap_port,
33
33
  tls: imap_tls,
34
34
  user: imap_user,
35
35
  password: imap_password,
36
- folders: (Array.isArray(imap_folder)) ? imap_folder : imap_folder.split(',').map(f => f.trim()).filter(f => f.length > 0),
36
+ folders: Array.isArray(imap_folder)
37
+ ? imap_folder
38
+ : imap_folder
39
+ .split(',')
40
+ .map((f) => f.trim())
41
+ .filter((f) => f.length > 0),
37
42
  markSeen: imap_markSeen,
38
43
  connTimeout: msg.imap_connTimeout || 10000,
39
44
  authTimeout: msg.imap_authTimeout || 5000,
40
45
  keepalive: msg.imap_keepalive !== undefined ? msg.imap_keepalive : true,
41
46
  autotls: msg.imap_autotls || 'never',
42
- tlsOptions: msg.imap_tlsOptions || { rejectUnauthorized: false }
47
+ tlsOptions: msg.imap_tlsOptions || { rejectUnauthorized: false },
43
48
  };
44
49
 
45
- if (!finalConfig.user || !finalConfig.password || !finalConfig.port || !finalConfig.host || !finalConfig.folders) {
50
+ if (
51
+ !finalConfig.user ||
52
+ !finalConfig.password ||
53
+ !finalConfig.port ||
54
+ !finalConfig.host ||
55
+ !finalConfig.folders
56
+ ) {
46
57
  const missingFields = [];
47
58
  if (!finalConfig.user) missingFields.push('user');
48
59
  if (!finalConfig.password) missingFields.push('password');
@@ -56,20 +67,23 @@ module.exports = function(RED) {
56
67
  return;
57
68
  }
58
69
 
59
- const fetchEmails = ({
60
- host,
61
- port,
62
- tls,
63
- user,
64
- password,
65
- folders,
66
- markSeen = true,
67
- connTimeout = 10000,
68
- authTimeout = 5000,
69
- keepalive = true,
70
- autotls = 'never',
71
- tlsOptions = { rejectUnauthorized: false }
72
- }, onMail) => {
70
+ const fetchEmails = (
71
+ {
72
+ host,
73
+ port,
74
+ tls,
75
+ user,
76
+ password,
77
+ folders,
78
+ markSeen = true,
79
+ connTimeout = 10000,
80
+ authTimeout = 5000,
81
+ keepalive = true,
82
+ autotls = 'never',
83
+ tlsOptions = { rejectUnauthorized: false },
84
+ },
85
+ onMail,
86
+ ) => {
73
87
  const imap = new Imap({
74
88
  user,
75
89
  password,
@@ -80,7 +94,7 @@ module.exports = function(RED) {
80
94
  authTimeout,
81
95
  keepalive,
82
96
  autotls,
83
- tlsOptions
97
+ tlsOptions,
84
98
  });
85
99
 
86
100
  const state = {
@@ -106,13 +120,13 @@ module.exports = function(RED) {
106
120
  node.status({
107
121
  fill: 'red',
108
122
  shape: 'dot',
109
- text: `Done, ${state.totalMails} mails from ${state.successes}/${state.totalFolders} folders. ${state.failures} failed.`
123
+ text: `Done, ${state.totalMails} mails from ${state.successes}/${state.totalFolders} folders. ${state.failures} failed.`,
110
124
  });
111
125
  } else {
112
126
  node.status({
113
127
  fill: 'green',
114
128
  shape: 'dot',
115
- text: `Done, fetched ${state.totalMails} mails from ${folders.join(', ')}.`
129
+ text: `Done, fetched ${state.totalMails} mails from ${folders.join(', ')}.`,
116
130
  });
117
131
  }
118
132
  if (imap && imap.state !== 'disconnected') {
@@ -149,8 +163,8 @@ module.exports = function(RED) {
149
163
 
150
164
  const fetch = imap.fetch(results, { bodies: '' });
151
165
 
152
- fetch.on('message', msg => {
153
- msg.on('body', stream => {
166
+ fetch.on('message', (msg) => {
167
+ msg.on('body', (stream) => {
154
168
  mailparser.simpleParser(stream, (err, parsed) => {
155
169
  if (err) {
156
170
  node.error(`Parse error for email from folder "${folder}": ${err.message}`);
@@ -165,7 +179,7 @@ module.exports = function(RED) {
165
179
  date: parsed.date,
166
180
  folder,
167
181
  header: parsed.headers,
168
- attachments: parsed.attachments.map(att => ({
182
+ attachments: parsed.attachments.map((att) => ({
169
183
  contentType: att.contentType,
170
184
  fileName: att.filename,
171
185
  transferEncoding: att.transferEncoding,
@@ -174,15 +188,15 @@ module.exports = function(RED) {
174
188
  contentId: att.cid,
175
189
  checksum: att.checksum,
176
190
  length: att.size,
177
- content: att.content
178
- }))
191
+ content: att.content,
192
+ })),
179
193
  };
180
194
  onMail(outMsg);
181
195
  });
182
196
  });
183
197
  });
184
198
 
185
- fetch.once('error', err => {
199
+ fetch.once('error', (err) => {
186
200
  node.error(`Fetch error in folder "${folder}": ${err.message}`);
187
201
  });
188
202
 
@@ -210,7 +224,7 @@ module.exports = function(RED) {
210
224
  startNextFolder();
211
225
  });
212
226
 
213
- imap.once('error', err => {
227
+ imap.once('error', (err) => {
214
228
  finalizeSession(err);
215
229
  });
216
230
 
@@ -222,15 +236,15 @@ module.exports = function(RED) {
222
236
  imap.connect();
223
237
  };
224
238
 
225
- fetchEmails(finalConfig, mail => {
239
+ fetchEmails(finalConfig, (mail) => {
226
240
  node.send(mail);
227
241
  });
228
242
  });
229
243
  }
230
244
 
231
- RED.nodes.registerType("email-receiver", EmailReceiverNode, {
245
+ RED.nodes.registerType('email-receiver', EmailReceiverNode, {
232
246
  credentials: {
233
- password: { type: "password" }
234
- }
247
+ password: { type: 'password' },
248
+ },
235
249
  });
236
- };
250
+ };