@bkmj/node-red-contrib-odbcmj 2.0.1 → 2.0.3
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/odbc.html +16 -27
- package/odbc.js +25 -12
- package/package.json +1 -1
package/odbc.html
CHANGED
|
@@ -31,15 +31,13 @@
|
|
|
31
31
|
oneditprepare: function () {
|
|
32
32
|
var node = this;
|
|
33
33
|
|
|
34
|
-
//
|
|
35
|
-
// On ajoute un écouteur de clic sur les en-têtes de section
|
|
34
|
+
// Logique pour les sections déroulantes
|
|
36
35
|
$('.form-section-header').on('click', function() {
|
|
37
36
|
$(this).toggleClass('expanded');
|
|
38
|
-
// On fait basculer le conteneur d'options qui suit immédiatement l'en-tête
|
|
39
37
|
$(this).next('.form-section-content').slideToggle();
|
|
40
38
|
});
|
|
41
39
|
|
|
42
|
-
//
|
|
40
|
+
// Logique pour le mode de connexion hybride
|
|
43
41
|
function toggleConnectionMode(mode) {
|
|
44
42
|
if (mode === 'structured') {
|
|
45
43
|
$(".config-mode-structured").show();
|
|
@@ -65,7 +63,7 @@
|
|
|
65
63
|
toggleDriverField($(this).val());
|
|
66
64
|
}).trigger("change");
|
|
67
65
|
|
|
68
|
-
//
|
|
66
|
+
// Logiques pour les cases à cocher
|
|
69
67
|
$("#node-config-input-syntaxtick").on("change", function () {
|
|
70
68
|
$(".input-syntax").toggle(this.checked);
|
|
71
69
|
}).trigger("change");
|
|
@@ -74,7 +72,7 @@
|
|
|
74
72
|
$(".retry-options").toggle(this.checked);
|
|
75
73
|
}).trigger("change");
|
|
76
74
|
|
|
77
|
-
//
|
|
75
|
+
// Logique pour le bouton de test
|
|
78
76
|
$('#node-config-test-connection').on('click', function() {
|
|
79
77
|
var button = $(this);
|
|
80
78
|
var originalText = "Test Connection";
|
|
@@ -84,11 +82,6 @@
|
|
|
84
82
|
|
|
85
83
|
var connectionMode = $("#node-config-input-connectionMode").val();
|
|
86
84
|
|
|
87
|
-
// --- CORRECTION : Récupérer le bon mot de passe selon le mode ---
|
|
88
|
-
var password = (connectionMode === 'structured')
|
|
89
|
-
? $("#node-config-input-password-structured").val()
|
|
90
|
-
: $("#node-config-input-password-string").val();
|
|
91
|
-
|
|
92
85
|
var configData = {
|
|
93
86
|
connectionMode: connectionMode,
|
|
94
87
|
dbType: $("#node-config-input-dbType").val(),
|
|
@@ -96,8 +89,9 @@
|
|
|
96
89
|
server: $("#node-config-input-server").val(),
|
|
97
90
|
database: $("#node-config-input-database").val(),
|
|
98
91
|
user: $("#node-config-input-user").val(),
|
|
99
|
-
|
|
100
|
-
|
|
92
|
+
connectionString: $("#node-config-input-connectionString").val(),
|
|
93
|
+
// Le mot de passe n'est envoyé que si on est en mode structuré
|
|
94
|
+
password: (connectionMode === 'structured') ? $("#node-config-input-password").val() : null
|
|
101
95
|
};
|
|
102
96
|
|
|
103
97
|
$.ajax({
|
|
@@ -128,6 +122,7 @@
|
|
|
128
122
|
padding: 5px;
|
|
129
123
|
border-bottom: 1px solid #ddd;
|
|
130
124
|
margin-bottom: 10px;
|
|
125
|
+
user-select: none;
|
|
131
126
|
}
|
|
132
127
|
.form-section-header i.fa-caret-right {
|
|
133
128
|
transition: transform 0.2s ease-in-out;
|
|
@@ -181,20 +176,15 @@
|
|
|
181
176
|
<input type="text" id="node-config-input-user">
|
|
182
177
|
</div>
|
|
183
178
|
<div class="form-row">
|
|
184
|
-
<label for="node-config-input-password
|
|
185
|
-
<input type="password" id="node-config-input-password
|
|
179
|
+
<label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label>
|
|
180
|
+
<input type="password" id="node-config-input-password">
|
|
186
181
|
</div>
|
|
187
182
|
</div>
|
|
188
183
|
|
|
189
184
|
<div class="config-mode-string">
|
|
190
185
|
<div class="form-row">
|
|
191
186
|
<label for="node-config-input-connectionString"><i class="fa fa-font"></i> Connection String</label>
|
|
192
|
-
<input type="text" id="node-config-input-connectionString" placeholder="DRIVER={...};PWD
|
|
193
|
-
</div>
|
|
194
|
-
<div class="form-row">
|
|
195
|
-
<label for="node-config-input-password-string"><i class="fa fa-lock"></i> Password</label>
|
|
196
|
-
<input type="password" id="node-config-input-password-string">
|
|
197
|
-
<span class="form-tips">Use <code>{{{password}}}</code> placeholder in the string above.</span>
|
|
187
|
+
<input type="text" id="node-config-input-connectionString" placeholder="DRIVER={...};SERVER=...;UID=...;PWD=...;">
|
|
198
188
|
</div>
|
|
199
189
|
</div>
|
|
200
190
|
|
|
@@ -205,8 +195,8 @@
|
|
|
205
195
|
|
|
206
196
|
<hr/>
|
|
207
197
|
|
|
208
|
-
<div class="form-section-header
|
|
209
|
-
<div class="form-section-content">
|
|
198
|
+
<div class="form-section-header"><h4><i class="fa fa-caret-right"></i> <i class="fa fa-sitemap"></i> Pool Options</h4></div>
|
|
199
|
+
<div class="form-section-content" style="display: none;">
|
|
210
200
|
<div class="form-row">
|
|
211
201
|
<label for="node-config-input-initialSize"><i class="fa fa-play"></i> Initial Size</label>
|
|
212
202
|
<input type="number" id="node-config-input-initialSize" placeholder="5" />
|
|
@@ -235,8 +225,8 @@
|
|
|
235
225
|
</div>
|
|
236
226
|
</div>
|
|
237
227
|
|
|
238
|
-
<div class="form-section-header
|
|
239
|
-
<div class="form-section-content">
|
|
228
|
+
<div class="form-section-header"><h4><i class="fa fa-caret-right"></i> <i class="fa fa-exclamation-triangle"></i> Error Handling & Retry</h4></div>
|
|
229
|
+
<div class="form-section-content" style="display: none;">
|
|
240
230
|
<div class="form-row">
|
|
241
231
|
<label for="node-config-input-retryFreshConnection" style="width: auto;"><i class="fa fa-refresh"></i> Retry with fresh connection</label>
|
|
242
232
|
<input type="checkbox" id="node-config-input-retryFreshConnection" style="display: inline-block; width: auto; vertical-align: top;" />
|
|
@@ -277,10 +267,9 @@
|
|
|
277
267
|
</div>
|
|
278
268
|
</script>
|
|
279
269
|
|
|
280
|
-
|
|
281
270
|
<script type="text/javascript">
|
|
282
271
|
RED.nodes.registerType("odbc", {
|
|
283
|
-
category: "storage
|
|
272
|
+
category: "storage",
|
|
284
273
|
color: "#89A5C0",
|
|
285
274
|
defaults: {
|
|
286
275
|
name: { value: "" },
|
package/odbc.js
CHANGED
|
@@ -120,14 +120,18 @@ module.exports = function (RED) {
|
|
|
120
120
|
}
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
+
// --- API ENDPOINT POUR LE BOUTON DE TEST (VERSION CORRIGÉE) ---
|
|
123
124
|
RED.httpAdmin.post("/odbc_config/:id/test", RED.auth.needsPermission("odbc.write"), async function(req, res) {
|
|
124
125
|
const tempConfig = req.body;
|
|
125
|
-
const tempCredentials = { password: tempConfig.password };
|
|
126
|
-
delete tempConfig.password;
|
|
127
126
|
|
|
127
|
+
// Cette fonction interne ne doit PAS interagir avec `res`.
|
|
128
|
+
// Elle retourne une chaîne ou lance une erreur.
|
|
128
129
|
const buildTestConnectionString = () => {
|
|
129
|
-
|
|
130
|
-
if (!tempConfig.dbType || !tempConfig.server)
|
|
130
|
+
if (tempConfig.connectionMode === 'structured') {
|
|
131
|
+
if (!tempConfig.dbType || !tempConfig.server) {
|
|
132
|
+
// On lance une erreur au lieu d'envoyer une réponse.
|
|
133
|
+
throw new Error("En mode structuré, le type de base de données et le serveur sont requis.");
|
|
134
|
+
}
|
|
131
135
|
let driver;
|
|
132
136
|
let parts = [];
|
|
133
137
|
switch (tempConfig.dbType) {
|
|
@@ -137,15 +141,19 @@ module.exports = function (RED) {
|
|
|
137
141
|
default: driver = tempConfig.driver || ''; break;
|
|
138
142
|
}
|
|
139
143
|
if(driver) parts.unshift(`DRIVER={${driver}}`);
|
|
140
|
-
parts.push(`SERVER=${tempConfig.server}`);
|
|
144
|
+
if (tempConfig.server) parts.push(`SERVER=${tempConfig.server}`);
|
|
141
145
|
if (tempConfig.database) parts.push(`DATABASE=${tempConfig.database}`);
|
|
142
146
|
if (tempConfig.user) parts.push(`UID=${tempConfig.user}`);
|
|
143
|
-
|
|
147
|
+
// Le mot de passe est géré dans le bloc try/catch principal
|
|
148
|
+
if (tempConfig.password) parts.push(`PWD=${tempConfig.password}`);
|
|
149
|
+
|
|
144
150
|
return parts.join(';');
|
|
145
|
-
|
|
151
|
+
|
|
152
|
+
} else { // 'string' mode
|
|
146
153
|
let connStr = tempConfig.connectionString || "";
|
|
147
|
-
|
|
148
|
-
|
|
154
|
+
// Le mot de passe est supposé être dans la chaîne ici
|
|
155
|
+
if (!connStr) {
|
|
156
|
+
throw new Error("La chaîne de connexion ne peut pas être vide.");
|
|
149
157
|
}
|
|
150
158
|
return connStr;
|
|
151
159
|
}
|
|
@@ -153,14 +161,19 @@ module.exports = function (RED) {
|
|
|
153
161
|
|
|
154
162
|
let connection;
|
|
155
163
|
try {
|
|
164
|
+
// Le bloc try/catch gère maintenant TOUTES les erreurs.
|
|
156
165
|
const testConnectionString = buildTestConnectionString();
|
|
157
|
-
|
|
166
|
+
|
|
158
167
|
connection = await odbcModule.connect(testConnectionString);
|
|
159
|
-
res.sendStatus(200);
|
|
168
|
+
res.sendStatus(200); // Succès, on envoie la seule et unique réponse.
|
|
169
|
+
|
|
160
170
|
} catch (err) {
|
|
171
|
+
// Qu'il s'agisse d'une erreur de validation ou de connexion, on l'attrape ici.
|
|
161
172
|
res.status(500).send(err.message || "Erreur inconnue durant le test.");
|
|
162
173
|
} finally {
|
|
163
|
-
if (connection)
|
|
174
|
+
if (connection) {
|
|
175
|
+
await connection.close();
|
|
176
|
+
}
|
|
164
177
|
}
|
|
165
178
|
});
|
|
166
179
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bkmj/node-red-contrib-odbcmj",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "A powerful Node-RED node to connect to any ODBC data source, with connection pooling, advanced retry logic, and result streaming.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"node-red",
|