Skip to content

Commit

Permalink
Initial commit of v0.2.0 overhaul; more coming.
Browse files Browse the repository at this point in the history
  • Loading branch information
clintandrewhall committed Jan 1, 2013
1 parent d5c6e7b commit 15add15
Show file tree
Hide file tree
Showing 30 changed files with 2,036 additions and 1,303 deletions.
50 changes: 34 additions & 16 deletions lib/checkins.js
Expand Up @@ -4,12 +4,9 @@
* @module node-foursquare/Checkins
*/
module.exports = function(config) {
var core = require("./core")(config),
path = require("path"),
log4js = require("log4js");

log4js.configure(config.log4js);
var logger = log4js.getLogger("node-foursquare.Tips");
var core = require('./core')(config),
path = require('path'),
logger = core.getLogger('checkins');

/**
* Retrieve a Foursquare Check-in.
Expand All @@ -19,18 +16,38 @@ module.exports = function(config) {
* on currently supported parameters.
* @param {String} accessToken The access token provided by Foursquare for the current user.
* @param {Function} callback The function to call with results, function({Error} error, {Object} results).
* @see https://developer.foursquare.com/docs/checkins/checkins.html
* @see https://developer.foursquare.com/docs/checkins/checkins
*/
function getCheckin(checkinId, params, accessToken, callback) {
logger.debug("ENTERING: Checkins.getCheckin");
logger.enter('ENTERING: Checkins.getCheckin');

if(!checkinId) {
logger.error('getCheckin: checkinId is required.');
callback(new Error('Checkins.getCheckin: checkinId is required.'));
return;
}

core.callApi(path.join('/checkins', checkinId), accessToken, params || {}, callback);
}

/**
* Retrieve the 'likes' for a Foursquare Check-in.
* @memberof module:node-foursquare/Checkins
* @param {String} checkinId The id of the check-in.
* @param {String} accessToken The access token provided by Foursquare for the current user.
* @param {Function} callback The function to call with results, function({Error} error, {Object} results).
* @see https://developer.foursquare.com/docs/checkins/checkins/likes
*/
function getLikes(checkinId, accessToken, callback) {
logger.enter('ENTERING: Checkins.getLikes');

if(!checkinId) {
logger.error("getCheckin: checkinId is required.");
callback(new Error("Checkins.getCheckin: checkinId is required."));
logger.error('getCheckin: checkinId is required.');
callback(new Error('Checkins.getCheckin: checkinId is required.'));
return;
}

core.callApi(path.join("/checkins", checkinId), accessToken, params || {}, callback);
core.callApi(path.join('/checkins', checkinId, 'likes'), accessToken, {}, callback);
}

/**
Expand All @@ -42,15 +59,16 @@ module.exports = function(config) {
* @param {String|Number} [params.lng] The longitude of the location around which to search.
* @param {String} accessToken The access token provided by Foursquare for the current user.
* @param {Function} callback The function to call with results, function({Error} error, {Object} results).
* @see https://developer.foursquare.com/docs/checkins/recent.html
* @see https://developer.foursquare.com/docs/checkins/recent
*/
function getRecentCheckins(params, accessToken, callback) {
logger.debug("ENTERING: Checkins.getRecentCheckins");
core.callApi("/checkins/recent", accessToken, params || {}, callback);
logger.enter('ENTERING: Checkins.getRecentCheckins');
core.callApi('/checkins/recent', accessToken, params || {}, callback);
}

return {
"getCheckin" : getCheckin,
"getRecentCheckins" : getRecentCheckins
'getCheckin' : getCheckin,
'getLikes' : getLikes,
'getRecentCheckins' : getRecentCheckins
}
};
72 changes: 47 additions & 25 deletions lib/config-default.js
@@ -1,36 +1,58 @@

var winston = require('winston');

module.exports = {
"foursquare" : {
"accessTokenUrl" : "https://foursquare.com/oauth2/access_token",
"authenticateUrl" : "https://foursquare.com/oauth2/authenticate",
"apiUrl" : "https://api.foursquare.com/v2"
'foursquare' : {
'accessTokenUrl' : 'https://foursquare.com/oauth2/access_token',
'authenticateUrl' : 'https://foursquare.com/oauth2/authenticate',
'apiUrl' : 'https://api.foursquare.com/v2'
/*
This field will indicate which version of the Foursquare API you wish to call. If not specified or set to "LATEST",
This field will indicate which version of the Foursquare API you wish to call. If not specified or set to 'LATEST',
it will use the latest version by setting the version number to today's date.
*/
//"version" : "LATEST",
//'version' : 'LATEST',
/*
This field determines how this library handles endpoints that return results along with an error, (e.g. deprecations).
- If set to "WARN" (default), log4js will write a warning to the log, (NOTE: You must raise the
"node-foursquare.core" log4js level to WARN or lower in order to see these warnings.
- If set to "ERROR", the library will behave as though it encountered an ERROR and not return results.
- If set to 'WARN' (default), log4js will write a warning to the log, (NOTE: You must raise the
'node-foursquare.core' log4js level to WARN or lower in order to see these warnings.
- If set to 'ERROR', the library will behave as though it encountered an ERROR and not return results.
*/
//"warnings" : "WARN"
//'warnings' : 'WARN'
},
"log4js" : {
"levels" : {
"node-foursquare" : "INFO",
"node-foursquare.core" : "OFF",
"node-foursquare.Users" : "OFF",
"node-foursquare.Venues" : "OFF",
"node-foursquare.Checkins" : "OFF",
"node-foursquare.Tips" : "OFF",
"node-foursquare.Lists" : "OFF",
"node-foursquare.Photos" : "OFF",
"node-foursquare.Settings" : "OFF",
"node-foursquare.Specials" : "OFF",
"node-foursquare.Updates" : "OFF",
"node-foursquare.Events" : "OFF"
'winston' : {
'transports' : [
new (winston.transports.Console)(
{
'level' : 'enter',
'colorize' : true
}
)
],
'levels': {
'detail': 0,
'trace': 1,
'debug': 2,
'enter': 3,
'info': 4,
'warn': 5,
'error': 6
},
'colors': {
'detail': 'grey',
'trace': 'white',
'debug': 'blue',
'enter': 'inverse',
'info': 'green',
'warn': 'yellow',
'error': 'red'
},
'loggers': {
'default': {
'console': {
'level': 'none'
}
}
}
},
"secrets" : { }
'secrets' : { }
};
109 changes: 72 additions & 37 deletions lib/core.js
@@ -1,8 +1,9 @@
var exports = module.exports,
qs = require('querystring'),
sys = require("util"),
util = require('util'),
https = require('https'),
urlParser = require('url'),
winston = require('winston'),
emptyCallback = function() { };

/**
Expand All @@ -11,43 +12,60 @@ var exports = module.exports,
*/
module.exports = function(config) {

var log4js = require("log4js");
var logger = getLogger('core');

log4js.configure(config.log4js);
var logger = log4js.getLogger("node-foursquare.core");
function getLoggerSettings(name) {
var settings = config.winston.loggers[name] || config.winston.loggers.default;

if(!settings) {
logger.error('No settings exist for \'' + name + '\', nor is there a default. Update your configuration.');
settings = config.winston.loggers['default'] = {
'console': {
'level': 'warn'
}
}
}

for(var setting in settings) {
settings[setting]['label'] = 'node-foursquare:' + name;
settings[setting]['colorize'] = true;
}

return settings;
}

function retrieve(url, callback) {
callback = callback || emptyCallback;

var parsedUrl = urlParser.parse(url, true), request, result = "";
var parsedUrl = urlParser.parse(url, true), request, result = '';

if(parsedUrl.protocol == "https:" && !parsedUrl.port) {
if(parsedUrl.protocol == 'https:' && !parsedUrl.port) {
parsedUrl.port = 443;
}

if(parsedUrl.query === undefined) {
parsedUrl.query = {};
}
var path = parsedUrl.pathname + "?" + qs.stringify(parsedUrl.query);
logger.debug("Requesting: " + path);
var path = parsedUrl.pathname + '?' + qs.stringify(parsedUrl.query);
logger.debug('retrieve: Request path: ' + path);
request = https.request({
"host" : parsedUrl.hostname,
"port" : parsedUrl.port,
"path" : path,
"method" : "GET",
"headers" : {
"Content-Length": 0
'host' : parsedUrl.hostname,
'port' : parsedUrl.port,
'path' : path,
'method' : 'GET',
'headers' : {
'Content-Length': 0
}
}, function(res) {
res.on("data", function(chunk) {
res.on('data', function(chunk) {
result += chunk;
});
res.on("end", function() {
res.on('end', function() {
callback(null, res.statusCode, result);
});
});
request.on("error", function(error) {
logger.error("Error calling remote host: " + error.message);
request.on('error', function(error) {
logger.error('retrieve: Error calling remote host: ' + error.message);
callback(error);
});

Expand All @@ -72,7 +90,7 @@ module.exports = function(config) {
parsedUrl.query.v = config.foursquare.version;
}

parsedUrl.search = "?" + qs.stringify(parsedUrl.query);
parsedUrl.search = '?' + qs.stringify(parsedUrl.query);
url = urlParser.format(parsedUrl);

retrieve(url,
Expand All @@ -81,7 +99,7 @@ module.exports = function(config) {
callback(error);
}
else {
logger.trace(sys.inspect(result));
logger.trace('invokeApi: Result: ' + util.inspect(result));
callback(null, status, result);
}
});
Expand All @@ -103,9 +121,10 @@ module.exports = function(config) {
if(json.meta && json.meta.code === 200) {
if(json.meta.errorType) {
var parsedUrl = urlParser.parse(url),
message = parsedUrl.pathname + " (" + json.meta.errorType + "): " + json.meta.errorDetail || "No detail provided.";
logger.debug("Warning level set to: " + config.foursquare.warnings);
if(config.foursquare.warnings === "ERROR") {
message =
parsedUrl.pathname + ' (' + json.meta.errorType + '): ' + json.meta.errorDetail || 'No detail provided.';
logger.debug('extractData: Warning level set to ' + config.foursquare.warnings);
if(config.foursquare.warnings === 'ERROR') {
logger.error(message);
callback(new Error(message));
return;
Expand All @@ -122,48 +141,64 @@ module.exports = function(config) {
}
}
else if(json.meta) {
logger.error("JSON Response had unexpected code: \"" + json.meta.code + ": " + json.meta.errorDetail + "\"");
callback(new Error(json.meta.code + ": " + json.meta.errorDetail));
logger.error('JSON Response had unexpected code: \'' + json.meta.code + ': ' + json.meta.errorDetail + '\'');
callback(new Error(json.meta.code + ': ' + json.meta.errorDetail));
}
else {
logger.error("Response had no code: " + sys.inspect(json));
callback(new Error("Response had no code: " + sys.inspect(json)));
logger.error('Response had no code: ' + util.inspect(json));
callback(new Error('Response had no code: ' + util.inspect(json)));
}
}
else {
logger.error("There was an unexpected, fatal error calling Foursquare: the response was undefined or had no status code.");
callback(new Error("Foursquare had no response or status code."));
logger.error(
'There was an unexpected, fatal error calling Foursquare: the response was undefined or had no status code.'
);
callback(new Error('Foursquare had no response or status code.'));
}
}

function callApi(path, accessToken, params, callback) {

if(!callback || typeof(callback) !== 'function') {
logger.error('callApi: callback not provided.');
throw new Error('callApi: callback not provided');
}

var url = config.foursquare.apiUrl + path;

if(params) {
if((params.lat && !params.lng) || (!params.lat && params.lng)) {
callback(new Error("parameters: if you specify a longitude or latitude, you must include BOTH."));
callback(new Error('callApi:parameters: if you specify a longitude or latitude, you must include BOTH.'));
return;
}

if(params.lat && params.lng) {
params.ll = params.lat + "," + params.lng;
params.ll = params.lat + ',' + params.lng;
delete params.lat;
delete params.lng;
}

url += "?" + qs.stringify(params);
url += '?' + qs.stringify(params);
}
logger.trace("URL: " + url);
logger.trace('callApi: Request URL: ' + url);
invokeApi(url, accessToken, function(error, status, result) {
extractData(url, status, result, callback);
});
}

function getLogger(name) {
if(!winston.loggers.has(name)) {
var logger = winston.loggers.add(name, getLoggerSettings(name));
logger.setLevels(config.winston.levels);
}
return winston.loggers.get(name);
}

return {
"retrieve" : retrieve,
"invokeApi" : invokeApi,
"extractData" : extractData,
"callApi" : callApi
'getLogger' : getLogger,
'retrieve' : retrieve,
'invokeApi' : invokeApi,
'extractData' : extractData,
'callApi' : callApi
}
};

0 comments on commit 15add15

Please sign in to comment.