From a33838369d91a34d88dfbe08951ead4f8e98fae3 Mon Sep 17 00:00:00 2001 From: Hans Kristian Flaatten Date: Thu, 25 Aug 2016 21:27:02 +0200 Subject: [PATCH 1/9] chore(package): add mockery to dev dependencies --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 5aff06f..ec821cf 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "greenkeeper-postpublish": "^1.0.0", "istanbul": "^0.4.3", "mocha": "^3.0.0", + "mockery": "^1.7.0", "nsp": "^2.4.0", "semantic-release": "^4.3.5", "supertest": "^2.0.0", From bd69fed70df71948f1b532a0b7efcfee4d3e6ff8 Mon Sep 17 00:00:00 2001 From: Hans Kristian Flaatten Date: Thu, 25 Aug 2016 21:28:03 +0200 Subject: [PATCH 2/9] chore(test): clear mongoose model after testing --- test/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/index.js b/test/index.js index c28f12c..8c18c8d 100644 --- a/test/index.js +++ b/test/index.js @@ -19,6 +19,11 @@ before(function before(done) { } }); +after(() => { + mongo.models = {}; + mongo.modelSchemas = {}; +}); + // mongodb clean beforeEach(() => mongo.connection.db.dropDatabase()); From 1674745546765ba68e246a03bdd8296b7ad4ba51 Mon Sep 17 00:00:00 2001 From: Hans Kristian Flaatten Date: Thu, 25 Aug 2016 21:28:31 +0200 Subject: [PATCH 3/9] feat(Checkin): add static method `#getCheckinsForList()` This will query Nasjonal Turbase for the list spcified list and return all checkins belonging to places (steder) on this list. Usage: ``` Checkin.getCheckinsForList(myListId).then(checkins => { // list of checkins are here }); ``` --- models/Checkin.js | 26 +++++++++++++++++++++++++- test/acceptance/checkin.js | 10 +++++----- test/fixtures/checkins.js | 6 +++--- test/models/Checkin.js | 37 +++++++++++++++++++++++++++++++++++++ test/support/env.js | 3 +++ 5 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 test/models/Checkin.js diff --git a/models/Checkin.js b/models/Checkin.js index 5949a6f..fb9f0c4 100644 --- a/models/Checkin.js +++ b/models/Checkin.js @@ -1,8 +1,10 @@ 'use strict'; +const { Schema, Types: { ObjectId: objectId } } = require('../lib/db'); const mongoose = require('../lib/db'); -const Schema = mongoose.Schema; +const fetch = require('node-fetch'); +const HttpError = require('@starefossen/http-error'); const checkinSchema = new Schema({ timestamp: Date, @@ -18,6 +20,28 @@ const checkinSchema = new Schema({ dnt_user_id: { type: Number, ref: 'User' }, }); +checkinSchema.statics.getCheckinsForList = function getCheckinsForList(list) { + const env = process.env.NTB_API_ENV || 'api'; + const key = process.env.NTB_API_KEY; + + const headers = { + Authorization: `Token ${key}`, + }; + + return fetch(`https://${env}.nasjonalturbase.no/lister/${list}`, { headers }) + .then(res => { + if (res.status !== 200) { + throw new HttpError(`Status Code ${res.status}`, res.status); + } else { + return res; + } + }) + .then(res => res.json()) + .then(liste => liste.steder || []) + .then(steder => steder.map(id => objectId(id))) + .then(steder => this.find().where('ntb_steder_id').in(steder)); +}; + checkinSchema.index({ location: '2dsphere' }); // Fix for https://github.com/Automattic/mongoose/issues/1251 diff --git a/test/acceptance/checkin.js b/test/acceptance/checkin.js index 062abe8..4cc1136 100644 --- a/test/acceptance/checkin.js +++ b/test/acceptance/checkin.js @@ -117,7 +117,7 @@ describe('GET /steder/:sted/besok/:id', () => { coordinates: [-117.220406, 32.719464], type: 'Point', }, - ntb_steder_id: '300000000000000000000000', + ntb_steder_id: '400000000000000000000000', timestamp: '2016-07-07T23:32:49.923Z', }, }) @@ -125,7 +125,7 @@ describe('GET /steder/:sted/besok/:id', () => { }); describe('GET /steder/:sted/stats', () => { - const url = '/api/dev/steder/300000000000000000000001/stats'; + const url = '/api/dev/steder/400000000000000000000001/stats'; it('returns checkin statistics for a given place', () => ( app.get(url) @@ -135,7 +135,7 @@ describe('GET /steder/:sted/stats', () => { }); describe('GET /steder/:sted/logg', () => { - const url = '/api/dev/steder/300000000000000000000001/logg'; + const url = '/api/dev/steder/400000000000000000000001/logg'; it('returns the most recent checkins', () => ( app.get(url) @@ -145,13 +145,13 @@ describe('GET /steder/:sted/logg', () => { _id: '200000000000000000000001', timestamp: '2016-07-07T23:32:50.923Z', location: { type: 'Point', coordinates: [-117.220406, 32.719464] }, - ntb_steder_id: '300000000000000000000001', + ntb_steder_id: '400000000000000000000001', dnt_user_id: 1234, }, { _id: '200000000000000000000002', timestamp: '2016-07-06T23:32:58.923Z', location: { type: 'Point', coordinates: [-117.220406, 32.719464] }, - ntb_steder_id: '300000000000000000000001', + ntb_steder_id: '400000000000000000000001', dnt_user_id: 5678, }] }); }) diff --git a/test/fixtures/checkins.js b/test/fixtures/checkins.js index a2441c0..10150d9 100644 --- a/test/fixtures/checkins.js +++ b/test/fixtures/checkins.js @@ -6,18 +6,18 @@ module.exports = [{ _id: objectId('200000000000000000000000'), timestamp: new Date('2016-07-07T23:32:49.923Z'), location: { type: 'Point', coordinates: [-117.220406, 32.719464] }, - ntb_steder_id: objectId('300000000000000000000000'), + ntb_steder_id: objectId('400000000000000000000000'), dnt_user_id: 1234, }, { _id: objectId('200000000000000000000001'), timestamp: new Date('2016-07-07T23:32:50.923Z'), location: { type: 'Point', coordinates: [-117.220406, 32.719464] }, - ntb_steder_id: objectId('300000000000000000000001'), + ntb_steder_id: objectId('400000000000000000000001'), dnt_user_id: 1234, }, { _id: objectId('200000000000000000000002'), timestamp: new Date('2016-07-06T23:32:58.923Z'), location: { type: 'Point', coordinates: [-117.220406, 32.719464] }, - ntb_steder_id: objectId('300000000000000000000001'), + ntb_steder_id: objectId('400000000000000000000001'), dnt_user_id: 5678, }]; diff --git a/test/models/Checkin.js b/test/models/Checkin.js new file mode 100644 index 0000000..ae6b1ca --- /dev/null +++ b/test/models/Checkin.js @@ -0,0 +1,37 @@ +/* eslint import/no-extraneous-dependencies: ["error", {"devDependencies": true}] */ +'use strict'; + +const assert = require('assert'); +const mockery = require('mockery'); + +describe('Checkin', () => { + before(() => mockery.enable({ + useCleanCache: true, + warnOnReplace: false, + warnOnUnregistered: false, + })); + + afterEach(() => mockery.deregisterMock('node-fetch')); + + after(() => mockery.disable()); + + describe('#getCheckinsForList()', () => { + it('it returns existing checkins for existing list', () => { + // Mock node-fetch + mockery.registerMock('node-fetch', () => Promise.resolve({ + status: 200, + json: () => ({ + steder: ['400000000000000000000000', '400000000000000000000001'], + }), + })); + + // Require Checkin (it now uses the mock above) + const Checkin = require('../../models/Checkin'); // eslint-disable-line global-require + + return Checkin.getCheckinsForList('300000000000000000000000') + .then(checkins => { + assert.equal(checkins.length, 3); + }); + }); + }); +}); diff --git a/test/support/env.js b/test/support/env.js index 4aa3309..7362a7f 100644 --- a/test/support/env.js +++ b/test/support/env.js @@ -3,3 +3,6 @@ process.env.NODE_ENV = 'test'; process.env.MONGO_DB = 'test'; process.env.VIRTUAL_PATH = '/api/dev'; + +process.env.NTB_API_ENV = 'dev'; +process.env.NTB_API_KEY = 'fake'; From f6d5a0526bc91e9449715fcee51e5ecc6ece25df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Ranum?= Date: Mon, 29 Aug 2016 09:51:07 +0200 Subject: [PATCH 4/9] feat(list): add endpoint for list log --- index.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 578a6e4..571f627 100644 --- a/index.js +++ b/index.js @@ -57,6 +57,7 @@ router.get('/', (req, res) => { profile_view: `${req.fullUrl}/brukere/{bruker}`, list_join: `${req.fullUrl}/lister/{liste}/blimed`, list_leave: `${req.fullUrl}/lister/{liste}/meldav`, + list_log: `${req.fullUrl}/lister/{liste}/logg`, }); }); @@ -153,7 +154,14 @@ router.get('/steder/:sted/besok/:checkin', (req, res, next) => { }); router.get('/lister/:liste/stats', notImplementedYet); -router.get('/lister/:liste/logg', notImplementedYet); + +router.get('/lister/:liste/logg', (req, res) => { + Checkin.getCheckinsForList(req.params.liste) + .then(checkins => { + res.json({ checkins: checkins }); + }); +}); + router.post('/lister/:liste/blimed', requireAuth, (req, res) => { const user = req.user; user.lister.push(req.params.liste); From 1f83e723a73eb16cd6dfe0bf6cd1b510278131de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Ranum?= Date: Mon, 29 Aug 2016 09:51:20 +0200 Subject: [PATCH 5/9] test(list): add endpoint for list log --- test/acceptance/lists.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test/acceptance/lists.js b/test/acceptance/lists.js index 50609f9..03915a8 100644 --- a/test/acceptance/lists.js +++ b/test/acceptance/lists.js @@ -3,6 +3,7 @@ const assert = require('assert'); const request = require('supertest'); +const mockery = require('mockery'); const app = request(require('../../index')); const auth = require('../../lib/auth'); @@ -60,4 +61,38 @@ describe('POST /lister/:liste/*', () => { }); }); }); + + describe.only('GET /lister/:liste/logg', () => { + before(() => mockery.enable({ + useCleanCache: true, + warnOnReplace: false, + warnOnUnregistered: false, + })); + + afterEach(() => mockery.deregisterMock('node-fetch')); + + after(() => mockery.disable()); + + it('returns a log of checkins to a place in a list', done => { + // Mock node-fetch + mockery.registerMock('node-fetch', () => Promise.resolve({ + status: 200, + json: () => ({ + steder: ['400000000000000000000001'], + }), + })); + + // Require new app to apply mocked data + const appMocked = request(require('../../index')); // eslint-disable-line global-require + + appMocked.get(`${url}/logg`) + .set('X-User-Id', '1234') + .set('X-User-Token', 'abc123') + .expect(200) + .end((req, res) => { + assert.equal(res.body.checkins.length, 2); + done(); + }); + }); + }); }); From cb98658d78aa78f01598738640980296a1355104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Ranum?= Date: Mon, 29 Aug 2016 09:53:55 +0200 Subject: [PATCH 6/9] fix(list): use shorthand property --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 571f627..62d4e7a 100644 --- a/index.js +++ b/index.js @@ -158,7 +158,7 @@ router.get('/lister/:liste/stats', notImplementedYet); router.get('/lister/:liste/logg', (req, res) => { Checkin.getCheckinsForList(req.params.liste) .then(checkins => { - res.json({ checkins: checkins }); + res.json({ checkins }); }); }); From ebb7cd58dfda7d08246a9abdaa0aea1c346954dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Ranum?= Date: Mon, 29 Aug 2016 10:29:14 +0200 Subject: [PATCH 7/9] fix(list): wrap checkins in data property --- index.js | 2 +- test/acceptance/lists.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 62d4e7a..0eedd30 100644 --- a/index.js +++ b/index.js @@ -158,7 +158,7 @@ router.get('/lister/:liste/stats', notImplementedYet); router.get('/lister/:liste/logg', (req, res) => { Checkin.getCheckinsForList(req.params.liste) .then(checkins => { - res.json({ checkins }); + res.json({ data: { checkins } }); }); }); diff --git a/test/acceptance/lists.js b/test/acceptance/lists.js index 03915a8..58c2970 100644 --- a/test/acceptance/lists.js +++ b/test/acceptance/lists.js @@ -90,7 +90,7 @@ describe('POST /lister/:liste/*', () => { .set('X-User-Token', 'abc123') .expect(200) .end((req, res) => { - assert.equal(res.body.checkins.length, 2); + assert.equal(res.body.data.checkins.length, 2); done(); }); }); From d0a1aa7675a31bc2099cca4e4e35c381453852d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Ranum?= Date: Mon, 29 Aug 2016 10:40:26 +0200 Subject: [PATCH 8/9] fix(list): list checkin objects in data property --- index.js | 2 +- test/acceptance/lists.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 0eedd30..27c3e07 100644 --- a/index.js +++ b/index.js @@ -158,7 +158,7 @@ router.get('/lister/:liste/stats', notImplementedYet); router.get('/lister/:liste/logg', (req, res) => { Checkin.getCheckinsForList(req.params.liste) .then(checkins => { - res.json({ data: { checkins } }); + res.json({ data: checkins }); }); }); diff --git a/test/acceptance/lists.js b/test/acceptance/lists.js index 58c2970..baf035c 100644 --- a/test/acceptance/lists.js +++ b/test/acceptance/lists.js @@ -90,7 +90,7 @@ describe('POST /lister/:liste/*', () => { .set('X-User-Token', 'abc123') .expect(200) .end((req, res) => { - assert.equal(res.body.data.checkins.length, 2); + assert.equal(res.body.data.length, 2); done(); }); }); From fff5c523a8a432d43a6ecccf6aeeed74f08219ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Ranum?= Date: Mon, 29 Aug 2016 10:43:51 +0200 Subject: [PATCH 9/9] doc(list): add doc for lister logg endpoint --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 1d3d36e..82562db 100644 --- a/README.md +++ b/README.md @@ -229,4 +229,28 @@ Content-Type: application/json "data": {...} } ``` + +### GET /v2/lister/{liste}/logg + +**Status codes:** + +Returns `200 Ok` on successfull request. + +**Example:** + +```http +GET /v2/lister/57974036b565590001a98884/logg HTTP/1.1 +Accept: application/json + +HTTP/1.1 Ok +Content-Type: application/json + +{ + "data": [ + {...}, + {...} + ] +} +``` + ## [MIT lisenced](https://github.com/Turistforeningen/Verdandi/blob/master/LICENSE)