Skip to content

Commit

Permalink
Enabling return of multiple messages and more search capabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
hbeeken committed Nov 6, 2014
1 parent 2f19780 commit 26be0c8
Show file tree
Hide file tree
Showing 3 changed files with 336 additions and 31 deletions.
89 changes: 71 additions & 18 deletions foursquare/foursquare.html
Original file line number Diff line number Diff line change
Expand Up @@ -157,19 +157,34 @@
<input type="text" id="node-input-foursquare">
</div>
<div class="form-row">
<label for="node-input-section">&nbsp;<i class="fa fa-filter"></i> Get recommended</label>
<select id="node-input-section" style="width:50% !important">
<label for="node-input-section">&nbsp;<i class="fa fa-filter"></i> Explore</label>
recommended <select id="node-input-section" style="width:30% !important">
<option value="empty"></option>
<option value="food">restaurants</option>
<option value="food">food venues</option>
<option value="drinks">drink venues</option>
<option value="coffee">coffee shops</option>
<option value="shops">shops</option>
<option value="arts">cultural venues</option>
<option value="outdoors">outdoor venues</option>
<option value="sights">sights</option>
<option value="all">venues</option>
</select>&nbsp;nearby
</div>
<div class="form-row">
<label for="node-input--output">&nbsp;<i class="fa fa-filter"></i> Output</label>
<select id="node-input--output" style="width:50%">
<option value="output">1</option>
</select>&nbsp;result(s)
<label for="node-input-outputnumber"><i class="fa fa-sign-out"></i> Output</label>
<select id="node-input-outputnumber" style="width:15% !important">
<option value="1">1</option>
<option value="10">10</option>
<option value="20">20</option>
<option value="30">30</option>
<option value="40">40</option>
<option value="50">50</option>
</select>
result<span id="node-input-outputnumber-plural">s</span>
as <select id="node-input-outputas" style='width:40% !important'>
<option value="multiple">multiple messages</option>
<option value="single">a single message</option>
</select>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
Expand All @@ -187,23 +202,48 @@
<b>msg.payload.section</b> of the message input. Valid entries are:
<ul>
<li>food</li>
<li>drinks</li>
<li>coffee</li>
<li>shops</li>
<li>arts</li>
<li>outdoors</li>
<li>sights</li>
<li>all</li>
</ul>
The value set on the node will take precedence over the contents of <b>msg.payload.section</b>.
</p>
<p>The node sets <b>msg.payload</b> to be the JSON of the first in an ordered list
of recommended venues near the provided latitude and longitude. The properties of the
<a href="https://foursquare.com/">Foursquare</a> venues explore API are documented at
<a href="https://developer.foursquare.com/docs/venues/explore">Explore Recommended and Popular Venues</a>.</p>
<p>
The node also sets the following properties:
<p>The number of results to return from the query and how to return them (either as a single message
or as multiple messages) are settings on the node.</p>
<p>The node sets the following properties
<ul>
<li><b>payload</b> - the JSON of the recommended venue</li>
<li><b>title</b> - the name of the recommended venue</li>
<li><b>location.lat</b> - the latitude of the recommended venue</li>
<li><b>location.lon</b> - the longitude of the recommended venue</li>
<li><b>location.city</b> - the city where the recommended venue is</li>
<li><b>location.country</b> - the country where the recommended venue is</li>
<li><b>location.name</b> - the name of the recommended venue</li>
</ul>
The exact location of these properties depends on the number of results chosen to be returned along
with how to return them:
<ul>
<li><b>msg.title</b> - the name of the recommended venue</li>
<li><b>msg.location.lat</b> - the latitude of the recommended venue</li>
<li><b>msg.location.lon</b> - the longitude of the recommended venue</li>
<li>If the node output value is set to one then for both returning as a single message and as multiple
messages, the node returns a msg for the first in an ordered list of recommended venues near the provided
latitude and longitude. The returned msg has the payload, location and name properties.
</li>
<li>If the node output value is set to more than one to be returned as a single message
the node sets <b>msg.payload</b>
to be an array of <b>msg</b>'s, each one corresponding to a recommended venue and ordered according to the
<a href="https://foursquare.com/">Foursquare</a> venues explore API. The first element in the array is
the most highly recommended venue and the length of the array is the output value set on the node or the
number of venues found, whichever is smaller. Each element in this array has the payload,
title, location and name properties.
</li>
<li>If the node output value is set to more than one but to be returned as a multiple then the node sends
multiple msgs, each one representing a recommended venue.
</ul>
</p>
For further information about the Foursquare API see
<a href="https://developer.foursquare.com/docs/venues/explore">Explore Recommended and Popular Venues</a>.</p>
<p>Data provided by <a href="https://foursquare.com/">Foursquare</a>.</p>
</script>

Expand All @@ -215,14 +255,27 @@
defaults: {
foursquare: {type:"foursquare-credentials",required:true},
section: {value:""},
output:{value:"1"},
outputnumber:{value:"1"},
outputas:{value:"single"},
name: {value:""}
},
inputs:1,
outputs:1,
icon: "foursquare.png",
label: function() {
return this.name||'foursquare';
},
oneditprepare: function() {
var updateOptions = function() {
var outputnumber = $("#node-input-outputnumber option:selected").val();
if (outputnumber == "1") {
$("#node-input-outputnumber-plural").hide();
} else {
$("#node-input-outputnumber-plural").show();
}
};
updateOptions();
$("#node-input-outputnumber").change(updateOptions);
}
});
})();
Expand Down
77 changes: 67 additions & 10 deletions foursquare/foursquare.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ module.exports = function(RED) {
var node = this;

node.section = n.section;
node.output = n.output || "1";
node.outputNumber = parseInt(n.outputnumber) || 50;
node.outputAs = n.outputas || "multiple";

var credentials = RED.nodes.getCredentials(n.foursquare);
var credentialsOk = checkCredentials(node, credentials);
Expand All @@ -64,7 +65,10 @@ module.exports = function(RED) {
// data in the node settings overwrites that in the msg
if ((!node.section || (node.section === "empty")) &&
(msg.section &&
(msg.section === "food" || msg.section ==="outdoors" || msg.section === "sights"))) {
(msg.section === "food" || msg.section ==="drinks" ||
msg.section === "coffee" || msg.section === "shops" ||
msg.section === "arts" || msg.section === "outdoors" ||
msg.section === "sights" || msg.section === "all"))) {
node.section = msg.section;
}
if (node.section && (node.section !== "empty")) {
Expand Down Expand Up @@ -97,7 +101,13 @@ module.exports = function(RED) {
}

function getRecommendedVenuesNearLocation(node, credentials, msg, callback) {
var apiUrl = "https://api.foursquare.com/v2/venues/explore?oauth_token=" + credentials.accesstoken + "&section=" + node.section + "&ll=" + msg.location.lat + "," + msg.location.lon + "&v=20141016&m=foursquare";
var apiUrl;
if (node.section === "all") {
apiUrl = "https://api.foursquare.com/v2/venues/explore?oauth_token=" + credentials.accesstoken + "&ll=" + msg.location.lat + "," + msg.location.lon + "&v=20141016&m=foursquare";
} else {
apiUrl = "https://api.foursquare.com/v2/venues/explore?oauth_token=" + credentials.accesstoken + "&section=" + node.section + "&ll=" + msg.location.lat + "," + msg.location.lon + "&v=20141016&m=foursquare";
}

request.get(apiUrl,function(err, httpResponse, body) {
if (err) {
node.error(err.toString());
Expand All @@ -109,13 +119,41 @@ module.exports = function(RED) {
node.status({fill:"red",shape:"ring",text:"failed"});
} else {
if (result.response.groups[0].items.length !== 0) {
var firstVenue = result.response.groups[0].items[0];
msg.payload = {};
msg.payload = firstVenue;
msg.location.lat = firstVenue.venue.location.lat;
msg.location.lon = firstVenue.venue.location.lng;
msg.title = firstVenue.venue.name;
callback(msg);
if (node.outputNumber === 1) {
var firstVenue = result.response.groups[0].items[0];
msg.payload = {};
msg.payload = firstVenue;
msg.location.lat = firstVenue.venue.location.lat;
msg.location.lon = firstVenue.venue.location.lng;
msg.location.name = firstVenue.venue.name;
msg.location.city = firstVenue.venue.location.city;
msg.location.country = firstVenue.venue.location.country;
msg.title = firstVenue.venue.name;
callback(msg);
} else if (node.outputAs === "single") {
// reset the location/title information as they make no sense here
msg.location = null;
msg.title = null;
// returning as a single msg sets msg.payload to be an array of venues found
msg.payload = collateVenuesFound(node, result.response.groups[0].items);
callback(msg);
} else if (node.outputAs === "multiple") {
var venues = collateVenuesFound(node, result.response.groups[0].items);
var msgs = [];
for (var i = 0; i < venues.length; i++) {
var clone = RED.util.cloneMessage(msg);
clone.payload = venues[i].payload;
clone.location = venues[i].location;
clone.title = venues[i].title;
msgs[i] = clone;
}
callback([msgs]);
} else {
// shouldn't ever get here
node.error("Incorrect number of messages to output or incorrect choice of how to output them");
node.status({fill:"red",shape:"ring",text:"failed"});
}

} else {
msg.payload = null;
callback(msg);
Expand All @@ -125,6 +163,25 @@ module.exports = function(RED) {
});
}

function collateVenuesFound(node, venuesFound) {
var venues = [];
var numberToReturn = Math.min(node.outputNumber,venuesFound.length);
for (var i = 0; i < numberToReturn; i++) {
var venue = venuesFound[i];
venues[i] = {};
venues[i].payload = venue;
venues[i].location = {};
venues[i].location.lat = venue.venue.location.lat;
venues[i].location.lon = venue.venue.location.lng;
venues[i].location.name = venue.venue.name;
venues[i].location.city = venue.venue.location.city;
venues[i].location.country = venue.venue.location.country;
venues[i].title = venue.venue.name;
}
return venues;
}


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');
Expand Down
Loading

0 comments on commit 26be0c8

Please sign in to comment.