@5minds/node-red-contrib-processcube-tools 1.1.0-feature-6eab97-mg0ov11s → 1.1.0-feature-f07d0c-mg6np5rk

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.
@@ -6,7 +6,17 @@
6
6
  name: { value: '' },
7
7
  provider: { value: 'fs' },
8
8
  baseDir: { value: '' },
9
- pgConnectionString: { value: '' },
9
+ usernameType: { value: 'str' },
10
+ username: { value: '', required: true, validate: RED.validators.typedInput('usernameType') },
11
+ passwordType: { value: 'str' },
12
+ password: { value: '', required: true, validate: RED.validators.typedInput('passwordType') },
13
+ hostType: { value: 'str' },
14
+ host: { value: '', required: true, validate: RED.validators.typedInput('hostType') },
15
+ portType: { value: 'str' },
16
+ port: { value: '', required: true, validate: RED.validators.typedInput('portType') },
17
+ databaseType: { value: 'str' },
18
+ database: { value: '', required: true, validate: RED.validators.typedInput('databaseType') },
19
+
10
20
  pgSchema: { value: 'public' },
11
21
  pgTable: { value: 'files' },
12
22
  outputAs: { value: 'stream' },
@@ -18,6 +28,34 @@
18
28
  label: function () {
19
29
  return this.name || 'file-storage';
20
30
  },
31
+ oneditprepare: function () {
32
+ // postgres fields user, password, host, port, database
33
+ $('#node-input-username').typedInput({
34
+ default: 'str',
35
+ types: ['str', 'env'],
36
+ typeField: '#node-input-usernameType',
37
+ });
38
+ $('#node-input-password').typedInput({
39
+ default: 'str',
40
+ types: ['str', 'env'],
41
+ typeField: '#node-input-passwordType',
42
+ });
43
+ $('#node-input-host').typedInput({
44
+ default: 'str',
45
+ types: ['str', 'env'],
46
+ typeField: '#node-input-hostType',
47
+ });
48
+ $('#node-input-port').typedInput({
49
+ default: 'str',
50
+ types: ['str', 'env'],
51
+ typeField: '#node-input-portType',
52
+ });
53
+ $('#node-input-database').typedInput({
54
+ default: 'str',
55
+ types: ['str', 'env'],
56
+ typeField: '#node-input-databaseType',
57
+ });
58
+ },
21
59
  });
22
60
  </script>
23
61
 
@@ -50,15 +88,36 @@
50
88
  <hr />
51
89
  <div class="form-tips">PostgreSQL</div>
52
90
  <div class="form-row">
53
- <label for="node-input-pgConnectionString"><i class="fa fa-plug"></i> Connection</label>
54
- <input type="text" id="node-input-pgConnectionString" placeholder="postgres://user:pass@host:5432/db" />
91
+ <label for="node-input-username"><i class="fa fa-user"></i> Username</label>
92
+ <input type="text" id="node-input-username" placeholder="postgres" />
93
+ <input type="hidden" id="node-input-usernameType" />
94
+ </div>
95
+ <div class="form-row">
96
+ <label for="node-input-password"><i class="fa fa-key"></i> Password</label>
97
+ <input type="text" id="node-input-password" placeholder="postgres" />
98
+ <input type="hidden" id="node-input-passwordType" />
99
+ </div>
100
+ <div class="form-row">
101
+ <label for="node-input-host"><i class="fa fa-server"></i> Host</label>
102
+ <input type="text" id="node-input-host" placeholder="localhost" />
103
+ <input type="hidden" id="node-input-hostType" />
104
+ </div>
105
+ <div class="form-row">
106
+ <label for="node-input-port"><i class="fa fa-plug"></i> Port</label>
107
+ <input type="text" id="node-input-port" placeholder="5432" />
108
+ <input type="hidden" id="node-input-portType" />
109
+ </div>
110
+ <div class="form-row">
111
+ <label for="node-input-database"><i class="fa fa-database"></i> Database</label>
112
+ <input type="text" id="node-input-database" placeholder="postgres" />
113
+ <input type="hidden" id="node-input-databaseType" />
55
114
  </div>
56
115
  <div class="form-row">
57
116
  <label for="node-input-pgSchema"><i class="fa fa-sitemap"></i> Schema</label>
58
117
  <input type="text" id="node-input-pgSchema" placeholder="public" />
59
118
  </div>
60
119
  <div class="form-row">
61
- <label for="node-input-pgTable"><i class="fa fa-table"></i> Tabelle</label>
120
+ <label for="node-input-pgTable"><i class="fa fa-table"></i> Table</label>
62
121
  <input type="text" id="node-input-pgTable" placeholder="files" />
63
122
  </div>
64
123
  <hr />
@@ -73,25 +132,72 @@
73
132
  </script>
74
133
 
75
134
  <script type="text/html" data-help-name="file-storage">
135
+ <h2>File Storage Node</h2>
76
136
  <p>
77
- File-Storage-Node zum Speichern/Abrufen/Löschen von Dateien inkl. Metadaten. Provider: Filesystem (Datei + JSON)
78
- oder PostgreSQL (Large Objects + Metadaten-Tabelle).
137
+ A Node-RED node for storing, retrieving, and deleting files (including metadata) using either the local filesystem or PostgreSQL (Large Objects + metadata table) as a backend.
79
138
  </p>
139
+ <h3>Features</h3>
140
+ <ul>
141
+ <li><b>Providers:</b>
142
+ <ul>
143
+ <li>Filesystem (stores file and metadata as JSON)</li>
144
+ <li>PostgreSQL (stores file as Large Object and metadata in a table)</li>
145
+ </ul>
146
+ </li>
147
+ <li><b>Actions:</b> Store, Retrieve, Delete files</li>
148
+ <li><b>Flexible output:</b> Stream, Buffer, or Path (filesystem only)</li>
149
+ </ul>
150
+ <h3>Node Properties</h3>
151
+ <ul>
152
+ <li><b>Name:</b> Optional node label.</li>
153
+ <li><b>Provider:</b> Select between Filesystem and PostgreSQL.</li>
154
+ <li><b>Output:</b> Choose the output type for retrieval: Stream, Buffer, or Path (Path only for filesystem).</li>
155
+ <li><b>Base Dir:</b> (Filesystem) Directory where files are stored.</li>
156
+ <li><b>Schema:</b> (PostgreSQL) Database schema (default: public).</li>
157
+ <li><b>Table:</b> (PostgreSQL) Table for metadata (default: files).</li>
158
+ <li><b>Default Action:</b> Default action if not specified in the message (store, get, or delete).</li>
159
+ </ul>
80
160
  <h3>Input</h3>
81
161
  <pre>
82
- msg.action = "store" | "get" | "delete"
83
- msg.payload = Buffer | Readable | String (bei store)
84
- msg.file = {
85
- id?: string (bei get/delete),
86
- filename?: string,
87
- contentType?: string,
88
- metadata?: object
89
- }
90
- </pre
91
- >
162
+ msg.action = "store" | "get" | "delete" // Optional, overrides defaultAction
163
+ msg.payload = Buffer | ReadableStream | String // For "store"
164
+ msg.file = {
165
+ id?: string, // For "get" or "delete"
166
+ filename?: string, // For "store"
167
+ contentType?: string,// For "store"
168
+ metadata?: object // For "store"
169
+ }
170
+ </pre>
92
171
  <h3>Output</h3>
93
- <p>
94
- Bei <code>store</code>: <code>msg.payload</code> enthält Metadaten inkl. <code>id</code>. Bei <code>get</code>:
95
- <code>msg.payload</code> ist Stream/Buffer/Pfad (je nach Option), Metadaten in <code>msg.file</code>.
96
- </p>
172
+ <ul>
173
+ <li><b>store:</b> <code>msg.payload</code> contains metadata including the generated <code>id</code>. <code>msg.file</code> contains the merged file info and result.</li>
174
+ <li><b>get:</b> <code>msg.payload</code> contains the file as a Stream, Buffer, or Path (depending on output setting). <code>msg.file</code> contains the file metadata.</li>
175
+ <li><b>delete:</b> <code>msg.payload</code> contains the result of the delete operation.</li>
176
+ </ul>
177
+ <h3>Example Usage</h3>
178
+ <pre>
179
+ // Store a file:
180
+ msg.action = "store";
181
+ msg.payload = Buffer.from("Hello World");
182
+ msg.file = {
183
+ filename: "hello.txt",
184
+ contentType: "text/plain",
185
+ metadata: { author: "Alice" }
186
+ };
187
+
188
+ // Retrieve a file:
189
+ msg.action = "get";
190
+ msg.file = { id: "your-file-id" };
191
+
192
+ // Delete a file:
193
+ msg.action = "delete";
194
+ msg.file = { id: "your-file-id" };
195
+ </pre>
196
+ <h3>Notes</h3>
197
+ <ul>
198
+ <li>For PostgreSQL, ensure the connection string, schema, and table exist and the user has the necessary permissions.</li>
199
+ <li>For filesystem storage, ensure the base directory is writable by Node-RED.</li>
200
+ <li>The node is designed to handle large files efficiently using streams.</li>
201
+ </ul>
202
+ <p><b>Enjoy using the File Storage Node in your Node-RED flows!</b></p>
97
203
  </script>
@@ -1,3 +1,77 @@
1
+ /**
2
+ * # File Storage Node
3
+ *
4
+ * A Node-RED node for storing, retrieving, and deleting files (including metadata) using either the local filesystem or PostgreSQL (Large Objects + metadata table) as a backend.
5
+ *
6
+ * ## Features
7
+ * - **Providers:**
8
+ * - Filesystem (stores file and metadata as JSON)
9
+ * - PostgreSQL (stores file as Large Object and metadata in a table)
10
+ * - **Actions:**
11
+ * - Store a file
12
+ * - Retrieve a file
13
+ * - Delete a file
14
+ * - **Flexible output:**
15
+ * - Stream, Buffer, or Path (filesystem only)
16
+ *
17
+ * ## Node Properties
18
+ * - **Name:** Optional node label.
19
+ * - **Provider:** Select between `Filesystem` and `PostgreSQL`.
20
+ * - **Output:** Choose the output type for retrieval: `Stream`, `Buffer`, or `Path` (Path only for filesystem).
21
+ * - **Base Dir:** (Filesystem) Directory where files are stored.
22
+ * - **Connection:** (PostgreSQL) Connection string for the database.
23
+ * - **Schema:** (PostgreSQL) Database schema (default: `public`).
24
+ * - **Table:** (PostgreSQL) Table for metadata (default: `files`).
25
+ * - **Default Action:** Default action if not specified in the message (`store`, `get`, or `delete`).
26
+ *
27
+ * ## Input
28
+ * The node expects the following properties in the incoming message:
29
+ * ```
30
+ * msg.action = "store" | "get" | "delete" // Optional, overrides defaultAction
31
+ * msg.payload = Buffer | ReadableStream | String // For "store"
32
+ * msg.file = {
33
+ * id?: string, // For "get" or "delete"
34
+ * filename?: string, // For "store"
35
+ * contentType?: string,// For "store"
36
+ * metadata?: object // For "store"
37
+ * }
38
+ * ```
39
+ *
40
+ * ## Output
41
+ * - For **store**:
42
+ * - `msg.payload` contains metadata including the generated `id`.
43
+ * - `msg.file` contains the merged file info and result.
44
+ * - For **get**:
45
+ * - `msg.payload` contains the file as a Stream, Buffer, or Path (depending on output setting).
46
+ * - `msg.file` contains the file metadata.
47
+ * - For **delete**:
48
+ * - `msg.payload` contains the result of the delete operation.
49
+ *
50
+ * ## Example Usage
51
+ * // Store a file:
52
+ * msg.action = "store";
53
+ * msg.payload = Buffer.from("Hello World");
54
+ * msg.file = {
55
+ * filename: "hello.txt",
56
+ * contentType: "text/plain",
57
+ * metadata: { author: "Alice" }
58
+ * };
59
+ *
60
+ * // Retrieve a file:
61
+ * msg.action = "get";
62
+ * msg.file = { id: "your-file-id" };
63
+ *
64
+ * // Delete a file:
65
+ * msg.action = "delete";
66
+ * msg.file = { id: "your-file-id" };
67
+ *
68
+ * ## Notes
69
+ * - For PostgreSQL, ensure the connection string, schema, and table exist and the user has the necessary permissions.
70
+ * - For filesystem storage, ensure the base directory is writable by Node-RED.
71
+ * - The node is designed to handle large files efficiently using streams.
72
+ *
73
+ * Enjoy using the File Storage Node in your Node-RED flows!
74
+ */
1
75
  module.exports = function (RED) {
2
76
  const StorageCore = require('../storage/storage-core');
3
77
 
@@ -9,7 +83,11 @@ module.exports = function (RED) {
9
83
  node.provider = config.provider || 'fs';
10
84
  node.baseDir = config.baseDir;
11
85
  node.pg = {
12
- connectionString: config.pgConnectionString,
86
+ username: RED.util.evaluateNodeProperty(config.username, config.usernameType, node) || 'postgres',
87
+ password: RED.util.evaluateNodeProperty(config.password, config.passwordType, node) || 'postgres',
88
+ host: RED.util.evaluateNodeProperty(config.host, config.hostType, node) || 'localhost',
89
+ port: RED.util.evaluateNodeProperty(config.port, config.portType, node) || 5432,
90
+ database: RED.util.evaluateNodeProperty(config.database, config.databaseType, node) || 'postgres',
13
91
  schema: config.pgSchema || 'public',
14
92
  table: config.pgTable || 'files',
15
93
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@5minds/node-red-contrib-processcube-tools",
3
- "version": "1.1.0-feature-6eab97-mg0ov11s",
3
+ "version": "1.1.0-feature-f07d0c-mg6np5rk",
4
4
  "license": "MIT",
5
5
  "description": "Node-RED tools nodes for ProcessCube",
6
6
  "scripts": {
@@ -7,10 +7,11 @@ const pump = promisify(pipeline);
7
7
 
8
8
  class PgProvider {
9
9
  constructor(opts = {}) {
10
- // this.connectionString = opts.connectionString || process.env.PG_URL || 'postgres://localhost/postgres';
10
+ const conString = "postgres://" + opts.username + ":" + opts.password + "@" + opts.host + ":" + opts.port + "/" + opts.database;
11
+ this.connectionString = conString
11
12
  this.schema = opts.schema || 'public';
12
13
  this.table = opts.table || 'files';
13
- // this.pool = new Pool({ connectionString: this.connectionString });
14
+ this.pool = new Pool({ connectionString: this.connectionString });
14
15
  this.pool = new Pool();
15
16
  }
16
17
 
@@ -23,7 +23,11 @@ class StorageCore {
23
23
  * @param {Object} [config.fs]
24
24
  * @param {string} [config.fs.baseDir]
25
25
  * @param {Object} [config.pg]
26
- * @param {string} [config.pg.connectionString]
26
+ * @param {string} [config.pg.username]
27
+ * @param {string} [config.pg.password]
28
+ * @param {string} [config.pg.host]
29
+ * @param {number} [config.pg.port]
30
+ * @param {string} [config.pg.database]
27
31
  * @param {string} [config.pg.schema]
28
32
  * @param {string} [config.pg.table]
29
33
  */