diff --git a/foursquare/foursquare.html b/foursquare/foursquare.html
new file mode 100644
index 00000000..8156f682
--- /dev/null
+++ b/foursquare/foursquare.html
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
+
+
diff --git a/swarm/swarm.js b/foursquare/foursquare.js
similarity index 56%
rename from swarm/swarm.js
rename to foursquare/foursquare.js
index 6a4c4328..51246ae4 100644
--- a/swarm/swarm.js
+++ b/foursquare/foursquare.js
@@ -32,12 +32,11 @@ module.exports = function(RED) {
);
}
-
- function SwarmNode(n) {
+ function FoursquareNode(n) {
RED.nodes.createNode(this,n);
}
- RED.nodes.registerType("swarm-credentials", SwarmNode, {
+ RED.nodes.registerType("foursquare-credentials", FoursquareNode, {
credentials: {
displayname: {type: "text"},
clientid: {type: "password"},
@@ -45,113 +44,8 @@ module.exports = function(RED) {
accesstoken: {type: "password"}
}
});
-
- /**
- * Swarm input node - will return the most recent check-in since
- * the node has been initialized. The node will only populate msg.payload
- * with the JSON of the check-in if a new check-in has been made within
- * the polling interval.
- */
- function SwarmInNode(n) {
- RED.nodes.createNode(this, n);
- var credentials = RED.nodes.getCredentials(n.swarm);
- var node = this;
- var credentialsOk = checkCredentials(node, credentials);
- if (credentialsOk) {
- var repeat = 900000; // 15 mins
- var now = Math.floor(((new Date()).getTime())/1000); // time now in seconds since epoch
- var afterTimestamp = now;
- var lastcheckin = null;
-
- var interval = setInterval(function() {
- node.emit("input", {});
- }, repeat );
-
- this.on("input", function(msg) {
- getCheckinsAfterTimestamp(node, "self", afterTimestamp, credentials, msg, function(msg) {
- var latestcheckin = JSON.stringify(msg);
- if (latestcheckin != lastcheckin) {
- lastcheckin = latestcheckin;
- afterTimestamp = msg.payload.createdAt;
- node.send(msg);
- }
- });
- });
-
- this.on("close", function() {
- if (interval != null) {
- clearInterval(interval);
- }
- });
-
- }
- }
-
- RED.nodes.registerType("swarm in", SwarmInNode);
-
- /**
- * Swarm query node - will return the most recent check-in since
- * the node has been initialized. If a check-in exists the node will always return
- * the most recent even if no new check-ins have happened since the previous query.
- * The node only populates msg.payload when a check-in is found.
- */
- function SwarmQueryNode(n) {
- RED.nodes.createNode(this, n);
- var node = this;
- this.request = n.request || "get-most-recent-checkin";
- var credentials = RED.nodes.getCredentials(n.swarm);
- var credentialsOk = checkCredentials(node, credentials);
- if (credentialsOk) {
- var now = Math.floor(((new Date()).getTime())/1000); // time now in seconds since epoch (rounded down)
- var afterTimestamp = now;
-
- this.on("input", function(msg) {
- if (node.request === "get-most-recent-checkin") {
- getCheckinsAfterTimestamp(node, "self", afterTimestamp, credentials, msg, function(msg) {
- afterTimestamp = msg.payload.createdAt - 2;
- node.send(msg);
- });
- }
- });
- }
- }
-
- RED.nodes.registerType("swarm", SwarmQueryNode);
-
- function checkCredentials(node, credentials) {
- if (credentials && credentials.clientid && credentials.clientsecret && credentials.accesstoken) {
- return true;
- } else {
- node.error("problem with credentials being set: " + credentials + ", ");
- node.status({fill:"red",shape:"ring",text:"failed"});
- return false;
- }
- }
-
- function getCheckinsAfterTimestamp(node, userid, afterTimestamp, credentials, msg, callback) {
- var apiUrl = "https://api.foursquare.com/v2/users/" + userid + "/checkins?oauth_token=" + credentials.accesstoken + "&v=20141016&afterTimestamp=" + afterTimestamp+"&sort=newestfirst";
- request.get(apiUrl,function(err, httpResponse, body) {
- if (err) {
- node.error(err.toString());
- node.status({fill:"red",shape:"ring",text:"failed"});
- } else {
- var result = JSON.parse(body);
- if (result.meta.code != 200) {
- node.error("Error code: " + result.meta.code + ", errorDetail: " + result.meta.errorDetail);
- node.status({fill:"red",shape:"ring",text:"failed"});
- } else {
- if (result.response.checkins.items.length !== 0) {
- var latest = result.response.checkins.items[0];
- msg.payload = {};
- msg.payload = latest;
- callback(msg);
- }
- }
- }
- });
- }
- RED.httpAdmin.get('/swarm-credentials/auth', function(req, res){
+ RED.httpAdmin.get('/foursquare-credentials/auth', function(req, res){
if (!req.query.clientid || !req.query.clientsecret || !req.query.id || !req.query.callback) {
return res.status(400).send('ERROR: request does not contain the required parameters');
}
@@ -175,7 +69,7 @@ module.exports = function(RED) {
res.redirect(url);
});
- RED.httpAdmin.get('/swarm-credentials/auth/callback', function(req, res){
+ RED.httpAdmin.get('/foursquare-credentials/auth/callback', function(req, res){
if (req.query.error) {
return res.send("ERROR: " + req.query.error + ": " + req.query.error_description);
}
diff --git a/swarm/icons/swarm.png b/foursquare/icons/swarm.png
similarity index 100%
rename from swarm/icons/swarm.png
rename to foursquare/icons/swarm.png
diff --git a/foursquare/swarm.html b/foursquare/swarm.html
new file mode 100644
index 00000000..dbf4b353
--- /dev/null
+++ b/foursquare/swarm.html
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/foursquare/swarm.js b/foursquare/swarm.js
new file mode 100644
index 00000000..c9380cd6
--- /dev/null
+++ b/foursquare/swarm.js
@@ -0,0 +1,130 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+
+ "use strict";
+ var request = require('request');
+
+ /**
+ * Swarm input node - will return the most recent check-in since
+ * the node has been initialized. The node will only populate msg.payload
+ * with the JSON of the check-in if a new check-in has been made within
+ * the polling interval.
+ */
+ function SwarmInNode(n) {
+ RED.nodes.createNode(this, n);
+ var credentials = RED.nodes.getCredentials(n.foursquare);
+ var node = this;
+ var credentialsOk = checkCredentials(node, credentials);
+ if (credentialsOk) {
+ var repeat = 900000; // 15 mins
+ var now = Math.floor(((new Date()).getTime())/1000); // time now in seconds since epoch
+ var afterTimestamp = now;
+ var lastcheckin = null;
+
+ var interval = setInterval(function() {
+ node.emit("input", {});
+ }, repeat );
+
+ this.on("input", function(msg) {
+ getCheckinsAfterTimestamp(node, "self", afterTimestamp, credentials, msg, function(msg) {
+ var latestcheckin = JSON.stringify(msg);
+ if (latestcheckin != lastcheckin) {
+ lastcheckin = latestcheckin;
+ afterTimestamp = msg.payload.createdAt;
+ node.send(msg);
+ }
+ });
+ });
+
+ this.on("close", function() {
+ if (interval != null) {
+ clearInterval(interval);
+ }
+ });
+
+ }
+ }
+
+ RED.nodes.registerType("swarm in", SwarmInNode);
+
+ /**
+ * Swarm query node - will return the most recent check-in since
+ * the node has been initialized. If a check-in exists the node will always return
+ * the most recent even if no new check-ins have happened since the previous query.
+ * The node only populates msg.payload when a check-in is found.
+ */
+ function SwarmQueryNode(n) {
+ RED.nodes.createNode(this, n);
+ var node = this;
+ this.request = n.request || "get-most-recent-checkin";
+ var credentials = RED.nodes.getCredentials(n.foursquare);
+ var c = RED.nodes.getCredentials(n.swarm);
+ var credentialsOk = checkCredentials(node, credentials);
+ if (credentialsOk) {
+ var now = Math.floor(((new Date()).getTime())/1000); // time now in seconds since epoch (rounded down)
+ var afterTimestamp = now;
+
+ this.on("input", function(msg) {
+ if (node.request === "get-most-recent-checkin") {
+ getCheckinsAfterTimestamp(node, "self", afterTimestamp, credentials, msg, function(msg) {
+ afterTimestamp = msg.payload.createdAt - 2;
+ node.send(msg);
+ });
+ }
+ });
+ }
+ }
+
+ RED.nodes.registerType("swarm", SwarmQueryNode);
+
+ function checkCredentials(node, credentials) {
+ if (credentials && credentials.clientid && credentials.clientsecret && credentials.accesstoken) {
+ return true;
+ } else {
+ node.error("problem with credentials being set: " + credentials + ", ");
+ node.status({fill:"red",shape:"ring",text:"failed"});
+ return false;
+ }
+ }
+
+ function getCheckinsAfterTimestamp(node, userid, afterTimestamp, credentials, msg, callback) {
+ var apiUrl = "https://api.foursquare.com/v2/users/" + userid + "/checkins?oauth_token=" + credentials.accesstoken + "&v=20141016&afterTimestamp=" + afterTimestamp+"&sort=newestfirst&m=swarm";
+ request.get(apiUrl,function(err, httpResponse, body) {
+ if (err) {
+ node.error(err.toString());
+ node.status({fill:"red",shape:"ring",text:"failed"});
+ } else {
+ var result = JSON.parse(body);
+ if (result.meta.code != 200) {
+ node.error("Error code: " + result.meta.code + ", errorDetail: " + result.meta.errorDetail);
+ node.status({fill:"red",shape:"ring",text:"failed"});
+ } else {
+ if (result.response.checkins.items.length !== 0) {
+ var latest = result.response.checkins.items[0];
+ msg.payload = {};
+ msg.payload = latest;
+ callback(msg);
+ }
+ }
+ }
+ });
+ }
+
+
+
+}
diff --git a/package.json b/package.json
index 86d8934b..52436d2e 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,8 @@
"fitbit": "fitbit/fitbit.js",
"flickr": "flickr/flickr.js",
"dropbox": "dropbox/dropbox.js",
- "swarm":"swarm/swarm.js",
+ "foursquare":"foursquare/foursquare.js",
+ "swarm":"foursquare/swarm.js",
"instagram" : "instagram/instagram.js",
"google": "google/google.js",
"googlecalendar": "google/calendar.js"
diff --git a/swarm/swarm.html b/swarm/swarm.html
deleted file mode 100644
index d257750a..00000000
--- a/swarm/swarm.html
+++ /dev/null
@@ -1,251 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/test/foursquare/foursquare_spec.js b/test/foursquare/foursquare_spec.js
new file mode 100644
index 00000000..c035d575
--- /dev/null
+++ b/test/foursquare/foursquare_spec.js
@@ -0,0 +1,175 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var foursquareNode = require("../../foursquare/foursquare.js");
+var helper = require('../helper.js');
+var nock = helper.nock;
+
+describe('foursquare nodes', function() {
+
+ before(function(done) {
+ helper.startServer(done);
+ });
+
+ afterEach(function() {
+ helper.unload();
+ });
+
+ describe('oauth2 authentication', function() {
+
+ if (nock) {
+
+ it('can do oauth dance', function(done) {
+ helper.load(foursquareNode,
+ [{id:"n4", type:"foursquare-credentials"}],
+ function() {
+
+ var scope = nock('https://foursquare.com:443')
+ .filteringRequestBody(/redirect_uri=[^&]*/g, 'redirect_uri=XXX')
+ .post('/oauth2/access_token', "redirect_uri=XXX&" +
+ "grant_type=authorization_code&client_id=abcdefg&client_secret=mnopqrs&code=123456")
+ .reply(200, {"access_token":"2468abc"});
+
+ var apiscope = nock('https://api.foursquare.com:443')
+ .get('/v2/users/self?oauth_token=2468abc&v=20141016')
+ .reply(200, {"meta":{"code":200},"response":{"user":{"id":"987654321","firstName":"John","lastName":"Smith"}}});
+
+ helper.request()
+ .get('/foursquare-credentials/auth?id=n4&clientid=abcdefg&clientsecret=mnopqrs&response_type=code&callback=http://localhost:1880:/foursquare-credentials')
+ .expect(302)
+ .end(function(err, res) {
+ if (err) return done(err);
+ var state = res.text.split("state=n4%253A");
+ helper.request()
+ .get('/foursquare-credentials/auth/callback?code=123456&state=n4:'+state[1])
+ .expect(200)
+ .end(function(err, res) {
+ if (err) return done(err);
+ helper.credentials.get("n4")
+ .should.have.property('displayname',
+ 'John Smith');
+ done();
+ });
+ });
+ });
+ });
+
+
+ it(' fails oauth dance if request is missing required parameter', function(done) {
+ helper.load(foursquareNode,
+ [{id:"n4", type:"foursquare-credentials"}],
+ function() {
+ helper.request()
+ .get('/foursquare-credentials/auth?id=n4&clientsecret=mnopqrs&response_type=code&callback=http://localhost:1880:/foursquare-credentials')
+ .expect(400, 'ERROR: request does not contain the required parameters')
+ .end(function(err, res) {
+ done();
+ });
+ });
+ });
+
+
+ it('fails oauth dance if client id is invalid', function(done) {
+ helper.load(foursquareNode,
+ [{id:"n4", type:"foursquare-credentials"}],
+ function() {
+ var scope = nock('https://foursquare.com:443')
+ .post('/oauth/access_token')
+ .reply(401, '{"errors":[{"errorType":"oauth","fieldName":"oauth_consumer_key","message":"Cause of error: Value abcdefg is invalid for consumer key"}],"success":false}');
+ helper.request()
+ .get('/foursquare-credentials/auth?id=n4&clientid=abcdefg&clientsecret=mnopqrs&response_type=code&callback=http://localhost:1880:/foursquare-credentials')
+ .expect(302)
+ .end(function(err, res) {
+ if (err) return done(err);
+ var state = res.text.split("state=n4%253A");
+ helper.request()
+ .get('/foursquare-credentials/auth/callback?code=123456&state=n4:'+state[1])
+ .expect(200)
+ .end(function(err, res) {
+ if (err) return done(err);
+ res.text.should.containEql('Oh no');
+ done();
+ });
+ });
+ });
+ });
+
+ it(' fails if profile can\'t be retrieved', function(done) {
+ helper.load(foursquareNode,
+ [{id:"n4", type:"foursquare-credentials"}],
+ function() {
+
+ var scope = nock('https://foursquare.com:443')
+ .filteringRequestBody(/redirect_uri=[^&]*/g, 'redirect_uri=XXX')
+ .post('/oauth2/access_token', "redirect_uri=XXX&" +
+ "grant_type=authorization_code&client_id=abcdefg&client_secret=mnopqrs&code=123456")
+ .reply(200, {"access_token":"2468abc"});
+
+ var apiscope = nock('https://api.foursquare.com:443')
+ .get('/v2/users/self?oauth_token=2468abc&v=20141016')
+ .reply(401, '{"meta":[{"code":"401"}]}');
+
+ helper.request()
+ .get('/foursquare-credentials/auth?id=n4&clientid=abcdefg&clientsecret=mnopqrs&response_type=code&callback=http://localhost:1880:/foursquare-credentials')
+ .expect(302)
+ .end(function(err, res) {
+ if (err) return done(err);
+ var state = res.text.split("state=n4%253A");
+ helper.request()
+ .get('/foursquare-credentials/auth/callback?code=123456&state=n4:'+state[1])
+ .expect(200)
+ .end(function(err, res) {
+ if (err) return done(err);
+ res.text.should.containEql('Http return code');
+ done();
+ });
+ });
+ });
+ });
+
+ it(' fails if CSRF token mismatch', function(done) {
+ helper.load(foursquareNode,
+ [{id:"n4", type:"foursquare-credentials"}],
+ function() {
+
+ var scope = nock('https://foursquare.com:443')
+ .filteringRequestBody(/redirect_uri=[^&]*/g, 'redirect_uri=XXX')
+ .post('/oauth2/access_token', "redirect_uri=XXX&" +
+ "grant_type=authorization_code&client_id=abcdefg&client_secret=mnopqrs&code=123456")
+ .reply(200, {"access_token":"2468abc"});
+
+ helper.request()
+ .get('/foursquare-credentials/auth?id=n4&clientid=abcdefg&clientsecret=mnopqrs&response_type=code&callback=http://localhost:1880:/foursquare-credentials')
+ .expect(302)
+ .end(function(err, res) {
+ if (err) return done(err);
+ helper.request()
+ .get('/foursquare-credentials/auth/callback?code=123456&state=n4:13579')
+ .expect(401)
+ .end(function(err, res) {
+ if (err) return done(err);
+ res.text.should.containEql('CSRF token mismatch, possible cross-site request forgery attempt');
+ done();
+ });
+ });
+ });
+ });
+
+ }
+
+ });
+
+});
diff --git a/test/foursquare/swarm_spec.js b/test/foursquare/swarm_spec.js
new file mode 100644
index 00000000..11eae4a2
--- /dev/null
+++ b/test/foursquare/swarm_spec.js
@@ -0,0 +1,151 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var swarmNode = require("../../foursquare/swarm.js");
+var foursquareNode = require("../../foursquare/foursquare.js");
+var helper = require('../helper.js');
+var sinon = require('sinon');
+var nock = helper.nock;
+
+describe('swarm nodes', function() {
+
+ before(function(done) {
+ helper.startServer(done);
+ });
+
+ afterEach(function() {
+ helper.unload();
+ });
+
+ describe('query node', function() {
+
+ if (nock) {
+
+ it(' can fetch check-in information', function(done) {
+ helper.load([foursquareNode, swarmNode],
+ [ {id:"n1", type:"helper", wires:[["n2"]]},
+ {id:"n4", type:"foursquare-credentials"},
+ {id:"n2", type:"swarm", foursquare: "n4", wires:[["n3"]]},
+ {id:"n3", type:"helper"}],
+ {
+ "n4": {
+ displayname : "John",
+ clientid: "987654321",
+ clientsecret:"123456789",
+ accesstoken:"abcd1234",
+ },
+ },
+ function() {
+ var scope = nock('https://api.foursquare.com:443')
+ .filteringPath(/afterTimestamp=[^&]*/g, 'afterTimestamp=foo')
+ .get('/v2/users/self/checkins?oauth_token=abcd1234&v=20141016&afterTimestamp=foo&sort=newestfirst&m=swarm')
+ .reply(200, {"meta":{"code":200},"response":{"checkins":{"count":1, "items":[{"id":"b695edf5ewc2","createdAt":1412861751,"type":"checkin","timeZoneOffset":60,"venue":{"id":"49a8b774","name":"Bobs House"}}]}}});
+
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ var n3 = helper.getNode("n3");
+ n2.should.have.property('id','n2');
+ n1.send({payload:"foo"});
+ n3.on('input', function(msg){
+ var venue = msg.payload.venue;
+ venue.should.have.property('name', "Bobs House");
+ done();
+ });
+ });
+ });
+
+ it(' fails if error fetching check-in information', function(done) {
+ helper.load([foursquareNode, swarmNode],
+ [ {id:"n1", type:"helper", wires:[["n2"]]},
+ {id:"n4", type:"foursquare-credentials"},
+ {id:"n2", type:"swarm", foursquare: "n4", wires:[["n3"]]},
+ {id:"n3", type:"helper"}],
+ {
+ "n4": {
+ displayname : "John",
+ clientid: "987654321",
+ clientsecret:"123456789",
+ accesstoken:"abcd1234",
+ },
+ },
+ function() {
+ var scope = nock('https://api.foursquare.com:443')
+ .filteringPath(/afterTimestamp=[^&]*/g, 'afterTimestamp=foo')
+ .get('/v2/users/self/checkins?oauth_token=abcd1234&v=20141016&afterTimestamp=foo&sort=newestfirst&m=swarm')
+ .reply(200, {"meta":{"code":400, "errorDetail":'test forced failure'}});
+
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ var n3 = helper.getNode("n3");
+ n2.should.have.property('id','n2');
+
+ sinon.stub(n2, 'status', function(status){
+ var expected = {fill:"red",shape:"ring",text:"failed"};
+ should.deepEqual(status, expected);
+ done();
+ });
+
+ n1.send({payload:"foo"});
+ });
+ });
+
+ }}
+ );
+
+
+ describe('in node', function() {
+
+ if (nock) {
+
+ it(' can fetch check-in information', function(done) {
+ helper.load([foursquareNode, swarmNode],
+ [ {id:"n1", type:"helper", wires:[["n2"]]},
+ {id:"n4", type:"foursquare-credentials"},
+ {id:"n2", type:"swarm", foursquare: "n4", wires:[["n3"]]},
+ {id:"n3", type:"helper"}],
+ {
+ "n4": {
+ displayname : "John",
+ clientid: "987654321",
+ clientsecret:"123456789",
+ accesstoken:"abcd1234",
+ },
+ },
+ function() {
+ var scope = nock('https://api.foursquare.com:443')
+ .filteringPath(/afterTimestamp=[^&]*/g, 'afterTimestamp=foo')
+ .get('/v2/users/self/checkins?oauth_token=abcd1234&v=20141016&afterTimestamp=foo&sort=newestfirst&m=swarm')
+ .reply(200, {"meta":{"code":200},"response":{"checkins":{"count":1, "items":[{"id":"b695edf5ewc2","createdAt":1412861751,"type":"checkin","timeZoneOffset":60,"venue":{"id":"49a8b774","name":"Bobs House"}}]}}});
+
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ var n3 = helper.getNode("n3");
+ n2.should.have.property('id','n2');
+ n2.emit("input", {});
+ n3.on('input', function(msg){
+ var venue = msg.payload.venue;
+ venue.should.have.property('name', "Bobs House");
+ done();
+ });
+ });
+ });
+
+ }
+
+ });
+
+});
diff --git a/test/swarm/swarm_spec.js b/test/swarm/swarm_spec.js
deleted file mode 100644
index 8f27a661..00000000
--- a/test/swarm/swarm_spec.js
+++ /dev/null
@@ -1,301 +0,0 @@
-/**
- * Copyright 2014 IBM Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- **/
-
-var should = require("should");
-var swarmNode = require("../../swarm/swarm.js");
-var helper = require('../helper.js');
-var sinon = require('sinon');
-var nock = helper.nock;
-
-describe('swarm nodes', function() {
-
- before(function(done) {
- helper.startServer(done);
- });
-
- afterEach(function() {
- helper.unload();
- });
-
- describe('query node', function() {
-
- if (nock) {
-
- it('can do oauth dance', function(done) {
- helper.load(swarmNode,
- [ {id:"n1", type:"helper", wires:[["n2"]]},
- {id:"n4", type:"swarm-credentials"},
- {id:"n2", type:"swarm", swarm: "n4", wires:[["n3"]]},
- {id:"n3", type:"helper"}],
- function() {
-
- var scope = nock('https://foursquare.com:443')
- .filteringRequestBody(/redirect_uri=[^&]*/g, 'redirect_uri=XXX')
- .post('/oauth2/access_token', "redirect_uri=XXX&" +
- "grant_type=authorization_code&client_id=abcdefg&client_secret=mnopqrs&code=123456")
- .reply(200, {"access_token":"2468abc"});
-
- var apiscope = nock('https://api.foursquare.com:443')
- .get('/v2/users/self?oauth_token=2468abc&v=20141016')
- .reply(200, {"meta":{"code":200},"response":{"user":{"id":"987654321","firstName":"John","lastName":"Smith"}}});
-
- helper.request()
- .get('/swarm-credentials/auth?id=n4&clientid=abcdefg&clientsecret=mnopqrs&response_type=code&callback=http://localhost:1880:/swarm-credentials')
- .expect(302)
- .end(function(err, res) {
- if (err) return done(err);
- var state = res.text.split("state=n4%253A");
- helper.request()
- .get('/swarm-credentials/auth/callback?code=123456&state=n4:'+state[1])
- .expect(200)
- .end(function(err, res) {
- if (err) return done(err);
- helper.credentials.get("n4")
- .should.have.property('displayname',
- 'John Smith');
- done();
- });
- });
- });
- });
-
- it(' fails oauth dance if request is missing required parameter', function(done) {
- helper.load(swarmNode,
- [ {id:"n1", type:"helper", wires:[["n2"]]},
- {id:"n4", type:"swarm-credentials"},
- {id:"n2", type:"swarm", swarm: "n4", wires:[["n3"]]},
- {id:"n3", type:"helper"}],
- function() {
- helper.request()
- .get('/swarm-credentials/auth?id=n4&clientsecret=mnopqrs&response_type=code&callback=http://localhost:1880:/swarm-credentials')
- .expect(400, 'ERROR: request does not contain the required parameters')
- .end(function(err, res) {
- done();
- });
- });
- });
-
-
- it('fails oauth dance if client id is invalid', function(done) {
- helper.load(swarmNode,
- [ {id:"n1", type:"helper", wires:[["n2"]]},
- {id:"n4", type:"swarm-credentials"},
- {id:"n2", type:"swarm", swarm: "n4", wires:[["n3"]]},
- {id:"n3", type:"helper"}],
- function() {
- var scope = nock('https://foursquare.com:443')
- .post('/oauth/access_token')
- .reply(401, '{"errors":[{"errorType":"oauth","fieldName":"oauth_consumer_key","message":"Cause of error: Value abcdefg is invalid for consumer key"}],"success":false}');
- helper.request()
- .get('/swarm-credentials/auth?id=n4&clientid=abcdefg&clientsecret=mnopqrs&response_type=code&callback=http://localhost:1880:/swarm-credentials')
- .expect(302)
- .end(function(err, res) {
- if (err) return done(err);
- var state = res.text.split("state=n4%253A");
- helper.request()
- .get('/swarm-credentials/auth/callback?code=123456&state=n4:'+state[1])
- .expect(200)
- .end(function(err, res) {
- if (err) return done(err);
- res.text.should.containEql('Oh no');
- done();
- });
- });
- });
- });
-
- it(' fails if profile can\'t be retrieved', function(done) {
- helper.load(swarmNode,
- [ {id:"n1", type:"helper", wires:[["n2"]]},
- {id:"n4", type:"swarm-credentials"},
- {id:"n2", type:"swarm", swarm: "n4", wires:[["n3"]]},
- {id:"n3", type:"helper"}],
- function() {
-
- var scope = nock('https://foursquare.com:443')
- .filteringRequestBody(/redirect_uri=[^&]*/g, 'redirect_uri=XXX')
- .post('/oauth2/access_token', "redirect_uri=XXX&" +
- "grant_type=authorization_code&client_id=abcdefg&client_secret=mnopqrs&code=123456")
- .reply(200, {"access_token":"2468abc"});
-
- var apiscope = nock('https://api.foursquare.com:443')
- .get('/v2/users/self?oauth_token=2468abc&v=20141016')
- .reply(401, '{"meta":[{"code":"401"}]}');
-
- helper.request()
- .get('/swarm-credentials/auth?id=n4&clientid=abcdefg&clientsecret=mnopqrs&response_type=code&callback=http://localhost:1880:/swarm-credentials')
- .expect(302)
- .end(function(err, res) {
- if (err) return done(err);
- var state = res.text.split("state=n4%253A");
- helper.request()
- .get('/swarm-credentials/auth/callback?code=123456&state=n4:'+state[1])
- .expect(200)
- .end(function(err, res) {
- if (err) return done(err);
- res.text.should.containEql('Http return code');
- done();
- });
- });
- });
- });
-
- it(' fails if CSRF token mismatch', function(done) {
- helper.load(swarmNode,
- [ {id:"n1", type:"helper", wires:[["n2"]]},
- {id:"n4", type:"swarm-credentials"},
- {id:"n2", type:"swarm", swarm: "n4", wires:[["n3"]]},
- {id:"n3", type:"helper"}],
- function() {
-
- var scope = nock('https://foursquare.com:443')
- .filteringRequestBody(/redirect_uri=[^&]*/g, 'redirect_uri=XXX')
- .post('/oauth2/access_token', "redirect_uri=XXX&" +
- "grant_type=authorization_code&client_id=abcdefg&client_secret=mnopqrs&code=123456")
- .reply(200, {"access_token":"2468abc"});
-
- helper.request()
- .get('/swarm-credentials/auth?id=n4&clientid=abcdefg&clientsecret=mnopqrs&response_type=code&callback=http://localhost:1880:/swarm-credentials')
- .expect(302)
- .end(function(err, res) {
- if (err) return done(err);
- helper.request()
- .get('/swarm-credentials/auth/callback?code=123456&state=n4:13579')
- .expect(401)
- .end(function(err, res) {
- if (err) return done(err);
- res.text.should.containEql('CSRF token mismatch, possible cross-site request forgery attempt');
- done();
- });
- });
- });
- });
-
- it(' can fetch check-in information', function(done) {
- helper.load(swarmNode,
- [ {id:"n1", type:"helper", wires:[["n2"]]},
- {id:"n4", type:"swarm-credentials"},
- {id:"n2", type:"swarm", swarm: "n4", wires:[["n3"]]},
- {id:"n3", type:"helper"}],
- {
- "n4": {
- displayname : "John",
- clientid: "987654321",
- clientsecret:"123456789",
- accesstoken:"abcd1234",
- },
- },
- function() {
- var scope = nock('https://api.foursquare.com:443')
- .filteringPath(/afterTimestamp=[^&]*/g, 'afterTimestamp=foo')
- .get('/v2/users/self/checkins?oauth_token=abcd1234&v=20141016&afterTimestamp=foo&sort=newestfirst')
- .reply(200, {"meta":{"code":200},"response":{"checkins":{"count":1, "items":[{"id":"b695edf5ewc2","createdAt":1412861751,"type":"checkin","timeZoneOffset":60,"venue":{"id":"49a8b774","name":"Bobs House"}}]}}});
-
- var n1 = helper.getNode("n1");
- var n2 = helper.getNode("n2");
- var n3 = helper.getNode("n3");
- n2.should.have.property('id','n2');
- n1.send({payload:"foo"});
- n3.on('input', function(msg){
- var venue = msg.payload.venue;
- venue.should.have.property('name', "Bobs House");
- done();
- });
-
- });
- });
-
- it(' fails if error fetching check-in information', function(done) {
- helper.load(swarmNode,
- [ {id:"n1", type:"helper", wires:[["n2"]]},
- {id:"n4", type:"swarm-credentials"},
- {id:"n2", type:"swarm", swarm: "n4", wires:[["n3"]]},
- {id:"n3", type:"helper"}],
- {
- "n4": {
- displayname : "John",
- clientid: "987654321",
- clientsecret:"123456789",
- accesstoken:"abcd1234",
- },
- },
- function() {
- var scope = nock('https://api.foursquare.com:443')
- .filteringPath(/afterTimestamp=[^&]*/g, 'afterTimestamp=foo')
- .get('/v2/users/self/checkins?oauth_token=abcd1234&v=20141016&afterTimestamp=foo&sort=newestfirst')
- .reply(200, {"meta":{"code":400, "errorDetail":'test forced failure'}});
-
- var n1 = helper.getNode("n1");
- var n2 = helper.getNode("n2");
- var n3 = helper.getNode("n3");
- n2.should.have.property('id','n2');
-
- sinon.stub(n2, 'status', function(status){
- var expected = {fill:"red",shape:"ring",text:"failed"};
- should.deepEqual(status, expected);
- done();
- });
-
- n1.send({payload:"foo"});
- });
- });
-
- }}
- );
-
-
- describe('in node', function() {
-
- if (nock) {
-
- it(' can fetch check-in information', function(done) {
- helper.load(swarmNode,
- [ {id:"n1", type:"helper", wires:[["n2"]]},
- {id:"n4", type:"swarm-credentials"},
- {id:"n2", type:"swarm in", swarm: "n4", wires:[["n3"]]},
- {id:"n3", type:"helper"}],
- {
- "n4": {
- displayname : "John",
- clientid: "987654321",
- clientsecret:"123456789",
- accesstoken:"abcd1234",
- },
- },
- function() {
- var scope = nock('https://api.foursquare.com:443')
- .filteringPath(/afterTimestamp=[^&]*/g, 'afterTimestamp=foo')
- .get('/v2/users/self/checkins?oauth_token=abcd1234&v=20141016&afterTimestamp=foo&sort=newestfirst')
- .reply(200, {"meta":{"code":200},"response":{"checkins":{"count":1, "items":[{"id":"b695edf5ewc2","createdAt":1412861751,"type":"checkin","timeZoneOffset":60,"venue":{"id":"49a8b774","name":"Bobs House"}}]}}});
-
- var n1 = helper.getNode("n1");
- var n2 = helper.getNode("n2");
- var n3 = helper.getNode("n3");
- n2.should.have.property('id','n2');
- n2.emit("input", {});
- n3.on('input', function(msg){
- var venue = msg.payload.venue;
- venue.should.have.property('name', "Bobs House");
- done();
- });
- });
- });
-
- }
-
- });
-
-});