Skip to content

Commit 908261f

Browse files
committed
improve error handling and allow use of api key/password
1 parent 3d8f86f commit 908261f

File tree

3 files changed

+74
-33
lines changed

3 files changed

+74
-33
lines changed

77-cloudant-cf.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616

1717
<script type="text/x-red" data-template-name="cloudant">
1818
<div class="form-row">
19-
<label for="node-config-input-hostname"><i class="fa fa-bookmark"></i> Host</label>
20-
<input class="input-append-left" type="text" id="node-config-input-hostname"
21-
placeholder="https://[username].cloudant.com">
19+
<label for="node-config-input-host"><i class="fa fa-bookmark"></i> Host</label>
20+
<input class="input-append-left" type="text" id="node-config-input-host"
21+
placeholder="[username].cloudant.com">
2222
</div>
2323

2424
<div class="form-row">
@@ -42,13 +42,13 @@
4242
category: "config",
4343
color: "rgb(114, 199, 231)",
4444
defaults: {
45-
hostname: { value: "", required: true },
45+
host: { value: "", required: true },
4646
name: { value: "" },
4747
//user -> credentials
4848
//pass -> credentials
4949
},
5050
label: function() {
51-
return this.name || this.hostname;
51+
return this.name || this.host;
5252
},
5353
oneditprepare: function() {
5454
$.getJSON("cloudant/"+this.id, function(data) {

77-cloudant-cf.js

Lines changed: 68 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -90,24 +90,23 @@ module.exports = function(RED) {
9090
function CloudantNode(n) {
9191
RED.nodes.createNode(this, n);
9292

93-
this.name = n.name;
94-
this.hostname = n.hostname;
93+
this.name = n.name;
94+
this.host = n.host;
95+
96+
// remove unnecessary parts from host value
97+
var parsedUrl = url.parse(this.host);
98+
if (parsedUrl.host) {
99+
this.host = parsedUrl.host;
100+
}
101+
102+
// extract only the account name
103+
this.account = this.host.substring(0, this.host.indexOf('.'));
95104

96105
var credentials = RED.nodes.getCredentials(n.id);
97106
if (credentials) {
98107
this.username = credentials.username;
99108
this.password = credentials.password;
100109
}
101-
102-
var parsedUrl = url.parse(this.hostname);
103-
var authUrl = parsedUrl.protocol+'//';
104-
105-
if (this.username && this.password) {
106-
authUrl += this.username + ":" + encodeURIComponent(this.password) + "@";
107-
}
108-
authUrl += parsedUrl.hostname;
109-
110-
this.url = authUrl;
111110
}
112111
RED.nodes.registerType("cloudant", CloudantNode);
113112

@@ -121,12 +120,13 @@ module.exports = function(RED) {
121120

122121
var node = this;
123122
var credentials = {
124-
account: node.cloudantConfig.credentials.username,
125-
password: node.cloudantConfig.credentials.password
123+
account: node.cloudantConfig.account,
124+
key: node.cloudantConfig.username,
125+
password: node.cloudantConfig.password
126126
};
127127

128128
Cloudant(credentials, function(err, cloudant) {
129-
if (err) { node.error(err); }
129+
if (err) { node.error(err.description, err); }
130130
else {
131131
// check if the database exists and create it if it doesn't
132132
createDatabase(cloudant, node);
@@ -139,10 +139,24 @@ module.exports = function(RED) {
139139

140140
function createDatabase(cloudant, node) {
141141
cloudant.db.list(function(err, all_dbs) {
142-
if (err) { node.error(err); }
142+
if (err) {
143+
if (err.error !== 'forbidden') {
144+
// if err.error is 'forbidden' then we are using an api
145+
// key, so we can assume the database already exists
146+
return;
147+
}
148+
node.error("Failed to list databases: " + err.description, err);
149+
}
143150
else {
144151
if (all_dbs && all_dbs.indexOf(node.database) < 0) {
145-
cloudant.db.create(node.database);
152+
cloudant.db.create(node.database, function(err, body) {
153+
if (err) {
154+
node.error(
155+
"Failed to create database: " + err.description,
156+
err
157+
);
158+
}
159+
});
146160
}
147161
}
148162
});
@@ -155,7 +169,12 @@ module.exports = function(RED) {
155169
var doc = parseMessage(msg, root);
156170

157171
insertDocument(cloudant, node, doc, MAX_ATTEMPTS, function(err, body) {
158-
if (err) { node.error(err); }
172+
if (err) {
173+
node.error(
174+
"Failed to insert document: " + err.description,
175+
err
176+
);
177+
}
159178
});
160179
}
161180
else if (node.operation === "delete") {
@@ -164,10 +183,16 @@ module.exports = function(RED) {
164183
if ("_rev" in doc && "_id" in doc) {
165184
var db = cloudant.use(node.database);
166185
db.destroy(doc._id, doc._rev, function(err, body) {
167-
if (err) { node.error(err); }
186+
if (err) {
187+
node.error(
188+
"Failed to delete document: " + err.description,
189+
err
190+
);
191+
}
168192
});
169193
} else {
170-
node.error("_rev and _id are required to delete a document");
194+
var err = new Error("_id and _rev are required to delete a document");
195+
node.error(err.message, err);
171196
}
172197
}
173198
}
@@ -249,12 +274,13 @@ module.exports = function(RED) {
249274

250275
var node = this;
251276
var credentials = {
252-
account: node.cloudantConfig.credentials.username,
253-
password: node.cloudantConfig.credentials.password
277+
account: node.cloudantConfig.account,
278+
key: node.cloudantConfig.username,
279+
password: node.cloudantConfig.password
254280
};
255281

256282
Cloudant(credentials, function(err, cloudant) {
257-
if (err) { node.error(err); }
283+
if (err) { node.error(err.description, err); }
258284
else {
259285
node.on("input", function(msg) {
260286
var db = cloudant.use(node.database);
@@ -339,10 +365,13 @@ module.exports = function(RED) {
339365
msg.payload = null;
340366

341367
if (err.description === "missing") {
342-
node.warn("Document '" + node.inputId + "' not found in database '" +
343-
node.database + "'.");
368+
node.warn(
369+
"Document '" + node.inputId +
370+
"' not found in database '" + node.database + "'.",
371+
err
372+
);
344373
} else {
345-
node.error(err.reason);
374+
node.error(err.description, err);
346375
}
347376
}
348377

@@ -351,11 +380,23 @@ module.exports = function(RED) {
351380
}
352381
RED.nodes.registerType("cloudant in", CloudantInNode);
353382

383+
// must return an object with, at least, values for account, username and
384+
// password for the Cloudant service at the top-level of the object
354385
function _getCloudantConfig(n) {
355386
if (n.service === "_ext_") {
356387
return RED.nodes.getNode(n.cloudant);
388+
357389
} else if (n.service !== "") {
358-
return appEnv.getService(n.service);
390+
var service = appEnv.getService(n.service);
391+
var cloudantConfig = { };
392+
393+
var host = service.credentials.host;
394+
395+
cloudantConfig.username = service.credentials.username;
396+
cloudantConfig.password = service.credentials.password;
397+
cloudantConfig.account = host.substring(0, host.indexOf('.'));
398+
399+
return cloudantConfig;
359400
}
360401
}
361402

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name" : "node-red-node-cf-cloudant",
3-
"version" : "0.2.12",
3+
"version" : "0.2.13",
44
"description" : "A Node-RED node to access a Cloudant database on Bluemix",
55
"dependencies" : {
66
"cfenv" : "1.0.0",

0 commit comments

Comments
 (0)