From ad82da75c9de4d2078967edd8204adc291770adb Mon Sep 17 00:00:00 2001 From: logenet Date: Mon, 6 Nov 2017 16:59:50 -0500 Subject: [PATCH 1/5] Refactor of the entire plugin. It now uses ES6 Classes and now uses Node6/8 features. Reduced and simplified code paths. --- controllers/feed.js | 62 +++++++++++------------- services/oauth_service.js | 78 +++++++++++++----------------- services/posts_service.js | 58 +++++++++------------- test/helpers/oauth_service_mock.js | 4 +- test/helpers/posts_service_mock.js | 4 +- test/oauth_service_spec.js | 28 ++++++----- test/posts_service_spec.js | 21 ++++---- 7 files changed, 114 insertions(+), 141 deletions(-) diff --git a/controllers/feed.js b/controllers/feed.js index 0c0f913..1e17b65 100644 --- a/controllers/feed.js +++ b/controllers/feed.js @@ -15,37 +15,33 @@ along with this program. If not, see . */ -module.exports = function FeedControllerModule(pb){ - var util = pb.util; - - - function FeedController(){} - - util.inherits(FeedController, pb.BaseController); - - FeedController.prototype.getPagePosts = function(cb){ - var OauthService = pb.PluginService.getService("oauthService", "pencilblue_facebook", this.site); - var PostsService = pb.PluginService.getService("postsService", "pencilblue_facebook", this.site); - var oauthService = new OauthService({"site":this.site}); - var postsService = new PostsService({"site":this.site}); - oauthService.getAccessToken(function(accessToken){ - postsService.getPagePosts(accessToken, cb); - }); - }; - - FeedController.getRoutes = function(cb){ - var routes = [ - { - method: 'get', - path: '/action/facebook/posts', - auth_required: false, - content_type: 'application/json', - handler: 'getPagePosts', - localization: true - } - ]; - cb(null, routes); - }; - - return FeedController; +module.exports = function FeedControllerModule(pb) { + + class FeedController extends pb.BaseController { + getPagePosts(cb) { + const oauthService = new (pb.PluginService.getService('oauthService', 'pencilblue_facebook', this.site))({site: this.site}); + const postService = new (pb.PluginService.getService('postsService', 'pencilblue_facebook', this.site))({site: this.site}); + let pluginService = new pb.PluginService({site: this.site}); + pluginService.getSettingsKV('pencilblue_facebook', (err, settings) => { + oauthService.getAccessToken(settings, (accessToken) => { + postService.getPagePosts(accessToken, settings, cb); + }); + }); + } + + static getRoutes(cb) { + cb(null, [ + { + method: 'get', + path: '/action/facebook/posts', + auth_required: false, + content_type: 'application/json', + handler: 'getPagePosts', + localization: true + } + ]); + } + } + + return FeedController; }; diff --git a/services/oauth_service.js b/services/oauth_service.js index 9463c42..0c77858 100644 --- a/services/oauth_service.js +++ b/services/oauth_service.js @@ -14,53 +14,41 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +const FB = require('fb'); module.exports = function OauthServiceModule(pb) { - var FB = require('fb'); - function OauthService(options) { - if (options){ - this.site = options.site ? options.site : ''; - }else { - this.site = ''; + class OauthService { + constructor(context = {}) { + this.site = context.site || ''; + } + + static init(cb) { + cb(null, true); + } + + static getName() { + return 'oauthService'; + } + + getAccessToken(settings, cb) { + let route = 'oauth/access_token'; + let params = { + client_id: settings.app_id, + client_secret: settings.app_secret, + grant_type: 'client_credentials' + }; + + FB.api(route, params, (response) => { + if (!response || response.error) { + let message = !response ? 'Did not get an response body while trying to get FB Access Token' : `FB Access Token failure: ${response.error}`; + pb.log.error(message); + response = {}; + } + FB.setAccessToken(response.access_token || ''); + cb(response.access_token || ''); + }); + } } - } - OauthService.init = function(cb){ - pb.log.debug("OauthService: Initialized"); - cb(null, true); - }; - - OauthService.getName = function(){ - return "oauthService"; - }; - - OauthService.prototype.getAccessToken = function(cb){ - var self = this; - var pluginService = new pb.PluginService({site: self.site}); - pluginService.getSettingsKV('pencilblue_facebook', function(err, settings){ - self.callApi('oauth/access_token', { - client_id: settings.app_id, - client_secret: settings.app_secret, - grant_type: 'client_credentials' - }, cb); - }); - }; - - OauthService.prototype.callApi = function(route, params, cb){ - FB.api(route, params, function (res) { - var accessToken = ''; - if(!res || res.error) { - pb.log.error(!res ? 'error occurred' : res.error); - } - else{ - accessToken = res.access_token; - } - FB.setAccessToken(accessToken); - if(cb){ - cb(accessToken); - } - }); - }; - - return OauthService; + return OauthService; }; diff --git a/services/posts_service.js b/services/posts_service.js index cfda380..1da4efd 100644 --- a/services/posts_service.js +++ b/services/posts_service.js @@ -14,43 +14,29 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +const FB = require('fb'); module.exports = function PostsServiceModule(pb){ - var FB = require('fb'); - - function PostsService(options) { - if (options) { - this.site = options.site ? options.site : ''; - } else { - this.site = ''; + + class PostsService { + constructor(context = {}) { + this.site = context.site || ''; + } + static init(cb) { + cb(null, true); + } + static getName () { + return 'postsService'; + } + + getPagePosts(accessToken, settings, cb) { + let route = `/v2.3/${settings.facebook_page_id}/posts`; + FB.api(route, {'access_token': accessToken}, (response) => { + response.siteLink = `https://facebook.com/${settings.facebook_page_id}`; + cb({content: JSON.stringify(response)}); + }); + } } - } - - PostsService.init = function(cb){ - pb.log.debug("PostsService: Initialized"); - cb(null, true); - }; - - PostsService.getName = function(){ - return "postsService"; - }; - - PostsService.prototype.getPagePosts = function(accessToken, cb){ - var self = this; - var pluginService = new pb.PluginService({site: self.site}); - pluginService.getSettingsKV('pencilblue_facebook', function(err, settings){ - self.callApi(accessToken, '/v2.3/' + settings.facebook_page_id + '/posts', cb); - }); - }; - - PostsService.prototype.callApi = function(accessToken, route, cb){ - FB.api(route, {"access_token":accessToken},function(response){ - cb({ - status:200, - content:JSON.stringify(response) - }); - }); - }; - + return PostsService; -}; \ No newline at end of file +}; diff --git a/test/helpers/oauth_service_mock.js b/test/helpers/oauth_service_mock.js index 86d67ea..76ffd6a 100644 --- a/test/helpers/oauth_service_mock.js +++ b/test/helpers/oauth_service_mock.js @@ -21,8 +21,8 @@ OauthService.getName = function(){ return "oauthService"; }; -OauthService.prototype.getAccessToken = function(cb){ +OauthService.prototype.getAccessToken = function(setting, cb){ cb('mockaccesstoken'); }; -module.exports = OauthService; \ No newline at end of file +module.exports = OauthService; diff --git a/test/helpers/posts_service_mock.js b/test/helpers/posts_service_mock.js index 4eca43c..77e3b3d 100644 --- a/test/helpers/posts_service_mock.js +++ b/test/helpers/posts_service_mock.js @@ -21,8 +21,8 @@ PostsService.getName = function(){ return "postsService"; }; -PostsService.prototype.getPagePosts = function(accessToken, cb){ +PostsService.prototype.getPagePosts = function(accessToken, settings, cb){ cb(null, '{data:[{id:"mockid",message:"Mock Message", created_time:"2015-04-09T16:00:04+0000"}]}'); }; -module.exports = PostsService; \ No newline at end of file +module.exports = PostsService; diff --git a/test/oauth_service_spec.js b/test/oauth_service_spec.js index 9252910..4658af3 100644 --- a/test/oauth_service_spec.js +++ b/test/oauth_service_spec.js @@ -43,26 +43,26 @@ describe('When using the OauthService', function(){ apiStub = sinon.stub(FB, 'api'); apiStub.onCall(0).yields({access_token: 'mockaccesstoken'}); apiStub.onCall(1).yields({access_token: '', error: 'mockError'}); - apiSpy = sinon.spy(oauthService, 'callApi'); + apiSpy = sinon.spy(oauthService, 'getAccessToken'); }); - + }); - + after(function(){ FB.api.restore(); }); - + it('getName should return "oauthService"', function(end){ expect(OauthService.getName()).to.equal('oauthService'); end(); }); - + it('instantiation should take in an options object', function(end){ var tmpOauthService = new OauthService({'site':'8675309'}); expect(tmpOauthService.site).to.equal('8675309'); end(); }); - + it('service should contain an init function that yields a null err and a result of true', function(end){ OauthService.init(function(err, result){ expect(err).to.equal(null); @@ -70,11 +70,15 @@ describe('When using the OauthService', function(){ end(); }); }); - + it('the service should return an access token from the facebook api module', function(end){ - oauthService.getAccessToken(function(accessToken){ + let settings = { + app_id: 'mockappid', + app_secret: 'mockappsecret' + }; + oauthService.getAccessToken(settings, function(accessToken){ expect(accessToken).to.equal('mockaccesstoken'); - var args = apiSpy.getCall(0).args; + var args = apiStub.getCall(0).args; expect(args[0]).to.equal('oauth/access_token'); expect(args[1].client_id).to.equal(apiCredentials.client_id); expect(args[1].client_secret).to.equal(apiCredentials.client_secret); @@ -83,12 +87,12 @@ describe('When using the OauthService', function(){ end(); }); }); - + it('should log an errorbut return empty token when api bombs', function(end){ - oauthService.getAccessToken(function(accessToken){ + oauthService.getAccessToken({}, function(accessToken){ expect(accessToken).to.equal(''); end(); }); }); - + }); diff --git a/test/posts_service_spec.js b/test/posts_service_spec.js index 35c2f6b..8e925b3 100644 --- a/test/posts_service_spec.js +++ b/test/posts_service_spec.js @@ -44,14 +44,14 @@ describe('When using the PostsService', function(){ postsService = new PostsService(); apiStub = sinon.stub(FB, 'api'); apiStub.onCall(0).yields(expectedJSON); - apiSpy = sinon.spy(postsService, 'callApi'); + apiSpy = sinon.spy(postsService, 'getPagePosts'); }); }); - + after(function(){ FB.api.restore(); }); - + it('getName should return "postsService"', function(end){ expect(PostsService.getName()).to.equal('postsService'); end(); @@ -62,7 +62,7 @@ describe('When using the PostsService', function(){ expect(tmpPostsService.site).to.equal('8675309'); end(); }); - + it('service should contain an init function that yields a null err and a result of true', function(end){ PostsService.init(function(err, result){ expect(err).to.equal(null); @@ -70,18 +70,17 @@ describe('When using the PostsService', function(){ end(); }); }); - + it('the service should return an access token from the facebook api module', function(end){ var accessToken = 'mockaccesstoken'; - postsService.getPagePosts(accessToken, function(content){ - expect(content.status).to.equal(200); + postsService.getPagePosts(accessToken, {'facebook_page_id': 'mockpageid'}, function(content){ expect(content.content).to.equal(JSON.stringify(expectedJSON)); - var args = apiSpy.getCall(0).args; - expect(args[0]).to.equal(accessToken); - expect(args[1]).to.equal('/v2.3/mockpageid/posts'); + var args = apiStub.getCall(0).args; + expect(args[0]).to.equal('/v2.3/mockpageid/posts'); + expect(args[1]).to.deep.equal({access_token: accessToken}); expect(typeof args[2]).to.equal('function'); end(); }); }); - + }); From c0ecd39960b6fa4d86acc020248b6ad76cccc190 Mon Sep 17 00:00:00 2001 From: logenet Date: Tue, 7 Nov 2017 09:47:38 -0500 Subject: [PATCH 2/5] Changed the api version to correctly ID 2.10 instead of being forced up to 2.10 instead of 2.3 (which is gone) Defaulted the settings param so not to crash the system on a bad request. --- controllers/feed.js | 2 +- services/posts_service.js | 2 +- test/posts_service_spec.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/controllers/feed.js b/controllers/feed.js index 1e17b65..a5dc7f1 100644 --- a/controllers/feed.js +++ b/controllers/feed.js @@ -22,7 +22,7 @@ module.exports = function FeedControllerModule(pb) { const oauthService = new (pb.PluginService.getService('oauthService', 'pencilblue_facebook', this.site))({site: this.site}); const postService = new (pb.PluginService.getService('postsService', 'pencilblue_facebook', this.site))({site: this.site}); let pluginService = new pb.PluginService({site: this.site}); - pluginService.getSettingsKV('pencilblue_facebook', (err, settings) => { + pluginService.getSettingsKV('pencilblue_facebook', (err, settings = {}) => { oauthService.getAccessToken(settings, (accessToken) => { postService.getPagePosts(accessToken, settings, cb); }); diff --git a/services/posts_service.js b/services/posts_service.js index 1da4efd..5cfff4d 100644 --- a/services/posts_service.js +++ b/services/posts_service.js @@ -30,7 +30,7 @@ module.exports = function PostsServiceModule(pb){ } getPagePosts(accessToken, settings, cb) { - let route = `/v2.3/${settings.facebook_page_id}/posts`; + let route = `/v2.10/${settings.facebook_page_id}/posts`; FB.api(route, {'access_token': accessToken}, (response) => { response.siteLink = `https://facebook.com/${settings.facebook_page_id}`; cb({content: JSON.stringify(response)}); diff --git a/test/posts_service_spec.js b/test/posts_service_spec.js index 8e925b3..8e80ea5 100644 --- a/test/posts_service_spec.js +++ b/test/posts_service_spec.js @@ -76,7 +76,7 @@ describe('When using the PostsService', function(){ postsService.getPagePosts(accessToken, {'facebook_page_id': 'mockpageid'}, function(content){ expect(content.content).to.equal(JSON.stringify(expectedJSON)); var args = apiStub.getCall(0).args; - expect(args[0]).to.equal('/v2.3/mockpageid/posts'); + expect(args[0]).to.equal('/v2.10/mockpageid/posts'); expect(args[1]).to.deep.equal({access_token: accessToken}); expect(typeof args[2]).to.equal('function'); end(); From 0df99153705b31af5f40c51f81aaf5cd1251796c Mon Sep 17 00:00:00 2001 From: Jacob Robertson Date: Mon, 13 Nov 2017 17:03:48 -0500 Subject: [PATCH 3/5] return single post with url --- package-lock.json | 1169 +++++++++++++++++++++++++++++++++++++ package.json | 2 +- services/posts_service.js | 24 +- 3 files changed, 1189 insertions(+), 6 deletions(-) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..1c8054e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1169 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "dev": true + }, + "ajv": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.3.0.tgz", + "integrity": "sha1-RBT/dKUIecII7l/cgm4ywwNUnto=", + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "assertion-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", + "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=", + "dev": true + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "2.5.1", + "regenerator-runtime": "0.11.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "requires": { + "hoek": "4.2.0" + } + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true, + "optional": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "optional": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, + "chai": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", + "dev": true, + "requires": { + "assertion-error": "1.0.2", + "deep-eql": "0.1.3", + "type-detect": "1.0.0" + } + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "optional": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true, + "optional": true + } + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", + "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "core-decorators": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/core-decorators/-/core-decorators-0.17.0.tgz", + "integrity": "sha1-P0MYCobSqwzFEGn0ah7D5J5869Y=" + }, + "core-js": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz", + "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "requires": { + "hoek": "4.2.0" + } + } + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "optional": true + }, + "deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "dev": true, + "requires": { + "type-detect": "0.1.1" + }, + "dependencies": { + "type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", + "dev": true + } + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "escape-string-regexp": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", + "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", + "dev": true + }, + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "dev": true, + "requires": { + "esprima": "2.7.3", + "estraverse": "1.9.3", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.2.0" + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fb": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fb/-/fb-2.0.0.tgz", + "integrity": "sha1-kf1AMl2jTsQcaLJVMPw6Pg2s+mo=", + "requires": { + "any-promise": "1.3.0", + "babel-runtime": "6.26.0", + "core-decorators": "0.17.0", + "debug": "2.6.9", + "request": "2.83.0" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "formatio": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz", + "integrity": "sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=", + "dev": true, + "requires": { + "samsam": "1.1.2" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "1.0.0" + } + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "handlebars": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", + "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", + "dev": true, + "requires": { + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "requires": { + "ajv": "5.3.0", + "har-schema": "2.0.0" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.0", + "sntp": "2.1.0" + } + }, + "hoek": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", + "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==" + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "istanbul": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", + "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "dev": true, + "requires": { + "abbrev": "1.0.9", + "async": "1.5.2", + "escodegen": "1.8.1", + "esprima": "2.7.3", + "glob": "5.0.15", + "handlebars": "4.0.11", + "js-yaml": "3.10.0", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "once": "1.4.0", + "resolve": "1.1.7", + "supports-color": "3.2.3", + "which": "1.3.0", + "wordwrap": "1.0.0" + } + }, + "jade": { + "version": "0.26.3", + "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", + "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", + "dev": true, + "requires": { + "commander": "0.6.1", + "mkdirp": "0.3.0" + }, + "dependencies": { + "commander": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", + "dev": true + }, + "mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", + "dev": true + } + } + }, + "js-yaml": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + } + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true, + "optional": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "lolex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz", + "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE=", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "mocha": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", + "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", + "dev": true, + "requires": { + "commander": "2.3.0", + "debug": "2.2.0", + "diff": "1.4.0", + "escape-string-regexp": "1.0.2", + "glob": "3.2.11", + "growl": "1.9.2", + "jade": "0.26.3", + "mkdirp": "0.5.1", + "supports-color": "1.2.0", + "to-iso-string": "0.0.2" + }, + "dependencies": { + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "minimatch": "0.3.0" + } + }, + "minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "dev": true, + "requires": { + "lru-cache": "2.7.3", + "sigmund": "1.0.1" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + }, + "supports-color": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", + "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", + "dev": true + } + } + }, + "mocha-istanbul": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/mocha-istanbul/-/mocha-istanbul-0.2.0.tgz", + "integrity": "sha1-77CwH5UxFf+mVj+c3m9O0UXUL2M=", + "dev": true, + "requires": { + "istanbul": "0.4.5" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1.0.9" + } + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "0.0.10", + "wordwrap": "0.0.3" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + } + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "regenerator-runtime": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", + "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.1", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "optional": true, + "requires": { + "align-text": "0.1.4" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "samsam": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz", + "integrity": "sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc=", + "dev": true + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, + "sinon": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz", + "integrity": "sha1-RUKk9JugxFwF6y6d2dID4rjv4L8=", + "dev": true, + "requires": { + "formatio": "1.1.1", + "lolex": "1.3.2", + "samsam": "1.1.2", + "util": "0.10.3" + } + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "requires": { + "hoek": "4.2.0" + } + }, + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "dev": true, + "optional": true, + "requires": { + "amdefine": "1.0.1" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + }, + "to-iso-string": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", + "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "type-detect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", + "dev": true + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "optional": true, + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "optional": true + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + } + } + }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + } + }, + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true, + "optional": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } + } +} diff --git a/package.json b/package.json index 931e5a2..759ea7f 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "url": "http://github.com/btidwell/pencilblue_facebook.git" }, "dependencies": { - "fb": "1.0.2" + "fb": "^2.0.0" }, "devDependencies": { "chai": "^3.5.0", diff --git a/services/posts_service.js b/services/posts_service.js index 5cfff4d..79fb73f 100644 --- a/services/posts_service.js +++ b/services/posts_service.js @@ -15,6 +15,13 @@ along with this program. If not, see . */ const FB = require('fb'); +const Promise = require('bluebird') +FB.options({ + version: 'v2.11', + Promise +}) + +const fbUrl = 'https://facebook.com/' module.exports = function PostsServiceModule(pb){ @@ -30,11 +37,18 @@ module.exports = function PostsServiceModule(pb){ } getPagePosts(accessToken, settings, cb) { - let route = `/v2.10/${settings.facebook_page_id}/posts`; - FB.api(route, {'access_token': accessToken}, (response) => { - response.siteLink = `https://facebook.com/${settings.facebook_page_id}`; - cb({content: JSON.stringify(response)}); - }); + const page = `${settings.facebook_page_id}/` + const posts = `${page}posts/` + FB.api(posts, { access_token: accessToken }).then(({data: [post]}) => { + const siteLink = `${fbUrl}${page}` + post.url = `${fbUrl}${post.id}` + return { + siteLink, + post + } + }) + .then(content => ({content})) + .then(cb, cb) } } From bc6c9bd86bc48928670fdd77a5ce6b2dcae508a7 Mon Sep 17 00:00:00 2001 From: Jacob Robertson Date: Mon, 13 Nov 2017 17:29:56 -0500 Subject: [PATCH 4/5] add bluebird --- package-lock.json | 5 +++++ package.json | 1 + 2 files changed, 6 insertions(+) diff --git a/package-lock.json b/package-lock.json index 1c8054e..6dfe32e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -111,6 +111,11 @@ "tweetnacl": "0.14.5" } }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, "boom": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", diff --git a/package.json b/package.json index 759ea7f..4377b03 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "url": "http://github.com/btidwell/pencilblue_facebook.git" }, "dependencies": { + "bluebird": "^3.5.1", "fb": "^2.0.0" }, "devDependencies": { From dc596a22d73eb34a76dd41a32aaf526ab50167f1 Mon Sep 17 00:00:00 2001 From: Jacob Robertson Date: Mon, 13 Nov 2017 17:50:04 -0500 Subject: [PATCH 5/5] get them unit tests passing --- package-lock.json | 63 ++++++++++++++++++++++++++++++++++++++ package.json | 5 +-- services/posts_service.js | 2 +- test/posts_service_spec.js | 21 +++++++------ 4 files changed, 78 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6dfe32e..0780c74 100644 --- a/package-lock.json +++ b/package-lock.json @@ -229,6 +229,16 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "create-thenable": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/create-thenable/-/create-thenable-1.0.2.tgz", + "integrity": "sha1-4gMXIMzJV12M+jH1wUbnYqgMBTQ=", + "dev": true, + "requires": { + "object.omit": "2.0.1", + "unique-concat": "0.2.2" + } + }, "cryptiles": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", @@ -388,6 +398,21 @@ "request": "2.83.0" } }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -530,6 +555,12 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -806,6 +837,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "native-promise-only": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=", + "dev": true + }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -820,6 +857,16 @@ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.1" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -973,6 +1020,16 @@ "util": "0.10.3" } }, + "sinon-as-promised": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/sinon-as-promised/-/sinon-as-promised-4.0.3.tgz", + "integrity": "sha1-wFRbFoX9gTWIpO1pcBJIftEdFRs=", + "dev": true, + "requires": { + "create-thenable": "1.0.2", + "native-promise-only": "0.8.1" + } + }, "sntp": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", @@ -1097,6 +1154,12 @@ "dev": true, "optional": true }, + "unique-concat": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/unique-concat/-/unique-concat-0.2.2.tgz", + "integrity": "sha1-khD5vcqsxeHjkpSQ18AZ35bxhxI=", + "dev": true + }, "util": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", diff --git a/package.json b/package.json index 4377b03..0df784b 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,11 @@ }, "devDependencies": { "chai": "^3.5.0", + "istanbul": "^0.4.2", "mocha": "^2.4.5", + "mocha-istanbul": "^0.2.0", "sinon": "^1.17.3", - "istanbul": "^0.4.2", - "mocha-istanbul": "^0.2.0" + "sinon-as-promised": "^4.0.3" }, "scripts": { "test": "./node_modules/.bin/mocha --recursive --reporter nyan", diff --git a/services/posts_service.js b/services/posts_service.js index 79fb73f..165b0ce 100644 --- a/services/posts_service.js +++ b/services/posts_service.js @@ -39,7 +39,7 @@ module.exports = function PostsServiceModule(pb){ getPagePosts(accessToken, settings, cb) { const page = `${settings.facebook_page_id}/` const posts = `${page}posts/` - FB.api(posts, { access_token: accessToken }).then(({data: [post]}) => { + return FB.api(posts, { access_token: accessToken }).then(({data: [post]}) => { const siteLink = `${fbUrl}${page}` post.url = `${fbUrl}${post.id}` return { diff --git a/test/posts_service_spec.js b/test/posts_service_spec.js index 8e80ea5..f708b44 100644 --- a/test/posts_service_spec.js +++ b/test/posts_service_spec.js @@ -16,6 +16,7 @@ */ var sinon = require('sinon'); +require('sinon-as-promised') var chai = require('chai'); var expect = chai.expect; var mockService = require('../test/helpers/pb_mock_service'); @@ -43,7 +44,7 @@ describe('When using the PostsService', function(){ PostsService = PostsServiceModule(pb); postsService = new PostsService(); apiStub = sinon.stub(FB, 'api'); - apiStub.onCall(0).yields(expectedJSON); + apiStub.onCall(0).resolves(expectedJSON); apiSpy = sinon.spy(postsService, 'getPagePosts'); }); }); @@ -71,16 +72,16 @@ describe('When using the PostsService', function(){ }); }); - it('the service should return an access token from the facebook api module', function(end){ + it('the service should return an access token from the facebook api module', async function(){ var accessToken = 'mockaccesstoken'; - postsService.getPagePosts(accessToken, {'facebook_page_id': 'mockpageid'}, function(content){ - expect(content.content).to.equal(JSON.stringify(expectedJSON)); - var args = apiStub.getCall(0).args; - expect(args[0]).to.equal('/v2.10/mockpageid/posts'); - expect(args[1]).to.deep.equal({access_token: accessToken}); - expect(typeof args[2]).to.equal('function'); - end(); - }); + let { content } = await postsService.getPagePosts(accessToken, {'facebook_page_id': 'mockpageid'}) + expect(content).to.deep.equal({ + siteLink: 'https://facebook.com/mockpageid/', + post: { ...expectedJSON.data[0], url: 'https://facebook.com/mockid' } + }) + var args = apiStub.getCall(0).args; + expect(args[0]).to.equal('mockpageid/posts/'); + expect(args[1]).to.deep.equal({access_token: accessToken}); }); });