diff --git a/server/brew.api.js b/server/brew.api.js index d7e30bf..d0565b4 100644 --- a/server/brew.api.js +++ b/server/brew.api.js @@ -6,10 +6,25 @@ const mw = require('./middleware.js'); //Search router.get('/api/brew', (req, res, next) => { + const opts = _.pick(req.query, ['limit', 'sort', 'page']); - //TODO + BrewData.termSearch(req.query.terms, opts, req.admin) + .then((result) => { + return res.status(200).json(result); + }) + .catch(next); +}); +//User +router.get('/api/user/:username', (req, res, next) => { + const fullAccess = req.admin || + !!(req.account && req.params.username == req.account.username); + BrewData.userSearch(req.params.username, fullAccess) + .then((result) => { + return res.status(200).json(result); + }) + .catch(next); }); //Get diff --git a/server/brew.search.js b/server/brew.search.js index 611b1bc..a75b768 100644 --- a/server/brew.search.js +++ b/server/brew.search.js @@ -3,30 +3,35 @@ const _ = require('lodash'); module.exports = (Brew) => { const cmds = { termSearch : (terms='', opts, fullAccess) => { - const query = {$text: { - //Wrap terms in quotes to perform an AND operation - $search: _.map(terms.split(' '), (term)=>{ - return `\"${term}\"`; - }).join(' '), - $caseSensitive : false - }}; + let query = {}; + if(terms){ + query = {$text: { + //Wrap terms in quotes to perform an AND operation + $search: _.map(terms.split(' '), (term)=>{ + return `\"${term}\"`; + }).join(' '), + $caseSensitive : false + }}; + } return cmds.search(query, opts, fullAccess); }, - userSearch : (username, opts, fullAccess) => { + userSearch : (username, fullAccess) => { const query = { authors : username }; - return cmds.search(query, opts, fullAccess); + return cmds.search(query, {}, fullAccess); }, search : (queryObj={}, options={}, fullAccess = true) => { const opts = _.merge({ limit : 25, page : 0, - sort : {} + sort : {} }, options); + opts.limit = _.toNumber(opts.limit); + opts.page = _.toNumber(opts.page); let filter = { text : 0 diff --git a/server/middleware.js b/server/middleware.js index fb19fb1..fb4c424 100644 --- a/server/middleware.js +++ b/server/middleware.js @@ -16,6 +16,7 @@ const Middleware = { return next(); }, admin : (req, res, next) => { + req.admin = false; if(req.headers['x-homebrew-admin'] === config.get('admin:key')){ req.admin = true; } @@ -44,6 +45,7 @@ const Middleware = { }, + //TODO: REMOVE //Loaders loadBrew : (req, res, next) => { BrewData.getByEdit(req.params.editId) diff --git a/test/api.test.js b/test/api.test.js index 8017c8c..0ba5fdb 100644 --- a/test/api.test.js +++ b/test/api.test.js @@ -1,4 +1,5 @@ const Test = require('./test.init.js'); +const _ = require('lodash'); const request = require('supertest-as-promised'); const config = require('nconf'); @@ -6,132 +7,241 @@ const config = require('nconf'); const app = require('app.js'); const DB = require('db.js'); const BrewData = require('brew.data.js'); +const BrewGen = require('./brew.gen.js'); const Error = require('error.js'); -const apiPath = '/api/brew'; -let session_token; -const test_user = { - username : 'cool guy' -}; -let storedBrew = { - title : 'good title', - text : 'original text', - authors : ['your_dm'] -}; +const UserX = { username : 'userX' }; +const UserA = { username : 'userA' }; +let UserXToken, UserAToken; describe('Brew API', () => { - before('Connect DB', DB.connect); - before('Clear DB', BrewData.removeAll); before('Create session token', () => { - session_token = Test.getSessionToken(test_user); - }); - before('Create brew', ()=>{ - return BrewData.create(storedBrew) - .then((brew)=>{ storedBrew = brew; }); + UserXToken = Test.getSessionToken(UserX); + UserAToken = Test.getSessionToken(UserA); }); + describe('CRUD', ()=>{ + before('Connect DB', DB.connect); + before('Clear DB', BrewData.removeAll); + before('Populate brews', ()=>{ + return BrewGen.populateDB(BrewGen.static()); + }); + describe('Create', () => { + it('creates a new brew', () => { + return request(app) + .post(`/api/brew`) + .send({ text : 'Brew Text' }) + .expect(200) + .then((res) => { + const brew = res.body; + brew.should.have.property('editId').that.is.a('string'); + brew.should.have.property('shareId').that.is.a('string'); + brew.should.have.property('text').equal('Brew Text'); + brew.should.not.have.property('_id'); + }); + }); - describe('Create', () => { - it('creates a new brew', () => { - return request(app) - .post(apiPath) - .send({ text : 'Brew Text' }) - .expect(200) - .then((res) => { - const brew = res.body; - brew.should.have.property('editId').that.is.a('string'); - brew.should.have.property('shareId').that.is.a('string'); - brew.should.have.property('text').equal('Brew Text'); - brew.should.not.have.property('_id'); - }); + it('creates a new brew with a session author', () => { + return request(app) + .post(`/api/brew`) + .set('Cookie', `nc_session=${UserXToken}`) + .send({ text : 'Brew Text' }) + .expect(200) + .then((res) => { + const brew = res.body; + brew.should.have.property('authors').include(UserX.username); + }); + }); }); - it('creates a new brew with a session author', () => { - return request(app) - .post(apiPath) - .set('Cookie', `nc_session=${session_token}`) - .send({ text : 'Brew Text' }) - .expect(200) - .then((res) => { - const brew = res.body; - brew.should.have.property('authors').include(test_user.username); - }); - }); - }); + describe('Update', () => { + it('updates an existing brew', () => { + const storedBrew = BrewGen.get('BrewA'); + return request(app) + .put(`/api/brew/${storedBrew.editId}`) + .send({ text : 'New Text' }) + .expect(200) + .then((res) => { + const brew = res.body; + brew.should.have.property('editId').equal(storedBrew.editId); + brew.should.have.property('text').equal('New Text'); + brew.should.have.property('authors').include(storedBrew.authors[0]); + brew.should.not.have.property('_id'); + }); + }); - describe('Update', () => { - it('updates an existing brew', () => { - return request(app) - .put(`${apiPath}/${storedBrew.editId}`) - .send({ text : 'New Text' }) - .expect(200) - .then((res) => { - const brew = res.body; - brew.should.have.property('editId').equal(storedBrew.editId); - brew.should.have.property('text').equal('New Text'); - brew.should.have.property('authors').include('your_dm'); - brew.should.not.have.property('_id'); - }); + it('adds the user as author', () => { + const storedBrew = BrewGen.get('BrewA'); + return request(app) + .put(`/api/brew/${storedBrew.editId}`) + .set('Cookie', `nc_session=${UserXToken}`) + .send({ text : 'New Text' }) + .expect(200) + .then((res) => { + const brew = res.body; + brew.should.have.property('authors').include(UserX.username); + brew.should.have.property('authors').include(storedBrew.authors[0]); + }); + }); + it('should throw error on bad edit id', ()=>{ + const storedBrew = BrewGen.get('BrewA'); + return request(app) + .put(`/api/brew/BADEDITID`) + .send({ text : 'New Text' }) + .expect(404) + }); }); - it('adds the user as author', () => { - return request(app) - .put(`${apiPath}/${storedBrew.editId}`) - .set('Cookie', `nc_session=${session_token}`) - .send({ text : 'New Text' }) - .expect(200) - .then((res) => { - const brew = res.body; - brew.should.have.property('authors').include(test_user.username); - brew.should.have.property('authors').include('your_dm'); - }); + describe('Remove', () => { + it('should removes a brew', ()=>{ + const storedBrew = BrewGen.get('BrewA'); + return request(app) + .del(`/api/brew/${storedBrew.editId}`) + .send() + .expect(200) + .then(() => { + BrewData.getByEdit(storedBrew.editId) + .then(() => { throw 'Brew found when one should not have been'; }) + .catch((err) => { + err.should.be.instanceof(Error.noBrew); + }) + }); + }); }); - it('should throw error on bad edit id', ()=>{ - return request(app) - .put(`${apiPath}/BADEDITID`) - .send({ text : 'New Text' }) - .expect(404) - }); - }); + }) - describe('Remove', () => { - it('should removes a brew', ()=>{ - return request(app) - .del(`${apiPath}/${storedBrew.editId}`) - .send() - .expect(200) - .then(() => { - BrewData.getByEdit(storedBrew.editId) - .then(() => { throw 'Brew found when one should not have been'; }) - .catch((err) => { - err.should.be.instanceof(Error.noBrew); - }) - }); - }); - }); describe('Search', () => { - it.skip('should be able to search for brews with given terms', ()=>{ - + before('Connect DB', DB.connect); + before('Clear DB', BrewData.removeAll); + before('Populate brews', ()=>{ + return BrewGen.populateDB(BrewGen.static()); }); - it.skip('should exclude unpublished brews and have no editIdsh', ()=>{ + it('should be able to search for all published brews', ()=>{ + return request(app) + .get(`/api/brew`) + .query({}) + .send() + .expect(200) + .then((res) => { + const result = res.body; + result.total.should.be.equal(2); + result.brews.should.have.brews('BrewB','BrewD'); + result.brews[0].should.not.have.property('editId'); + }); }); - it.skip('should sort the search', ()=>{ + it('should be able to search for brews with given terms', ()=>{ + return request(app) + .get(`/api/brew`) + .query({ + terms : '5e ranger' + }) + .send() + .expect(200) + .then((res) => { + const result = res.body; + result.total.should.be.equal(1); + result.brews.should.have.brews('BrewD'); + }); }); - it.skip('should use pagniation on the search', ()=>{ - + it('should be able to sort the search', ()=>{ + return request(app) + .get(`/api/brew`) + .query({ + sort : { views : 1} + }) + .send() + .expect(200) + .then((res) => { + const result = res.body; + result.total.should.be.equal(2); + result.brews[0].should.be.brew('BrewD'); + result.brews[1].should.be.brew('BrewB'); + }); + }); + it('should use pagniation on the search', ()=>{ + return request(app) + .get(`/api/brew`) + .query({ + limit : 1, + page : 1, + sort : { views : -1} + }) + .send() + .expect(200) + .then((res) => { + const result = res.body; + result.total.should.be.equal(2); + result.brews[0].should.be.brew('BrewD'); + }) + }); + it('should return all brews and editIds if admin', ()=>{ + return request(app) + .get(`/api/brew`) + .query({}) + .set('x-homebrew-admin', config.get('admin:key')) + .send() + .expect(200) + .then((res) => { + const result = res.body; + const brewCount = _.size(BrewGen.static()); + result.total.should.be.equal(brewCount); + result.brews.length.should.be.equal(brewCount); + result.brews[0].should.have.property('editId'); + }); }); }); describe('User', () => { - it.skip('should be able to query brews for a specific user', ()=>{ - + before('Connect DB', DB.connect); + before('Clear DB', BrewData.removeAll); + before('Populate brews', ()=>{ + return BrewGen.populateDB(BrewGen.static()); }); - it.skip('should return full access to brews if loggedin user is queried user', ()=>{ + it('should be able to query brews for a specific user', ()=>{ + return request(app) + .get(`/api/user/userA`) + .send() + .expect(200) + .then((res) => { + const result = res.body; + result.total.should.be.equal(1); + result.brews.length.should.be.equal(1); + result.brews.should.have.brews('BrewB'); + result.brews[0].should.not.have.property('editId'); + }); + }); + it('should have full access if loggedin user is queried user', ()=>{ + return request(app) + .get(`/api/user/userA`) + .set('Cookie', `nc_session=${UserAToken}`) + .send() + .expect(200) + .then((res) => { + const result = res.body; + result.total.should.be.equal(3); + result.brews.length.should.be.equal(3); + result.brews.should.have.brews('BrewA', 'BrewB', 'BrewC'); + result.brews[0].should.have.property('editId'); + }); + }); + it('should have full access if admin', ()=>{ + return request(app) + .get(`/api/user/userA`) + .set('x-homebrew-admin', config.get('admin:key')) + .send() + .expect(200) + .then((res) => { + const result = res.body; + result.total.should.be.equal(3); + result.brews.length.should.be.equal(3); + result.brews.should.have.brews('BrewA', 'BrewB', 'BrewC'); + result.brews[0].should.have.property('editId'); + }); }); }); diff --git a/test/brew.gen.js b/test/brew.gen.js index 0d1fc13..c7d59b3 100644 --- a/test/brew.gen.js +++ b/test/brew.gen.js @@ -4,6 +4,8 @@ const BrewData = require('../server/brew.data.js'); let PopulatedBrews = {}; module.exports = { + //TODO: Add in a generator for old brews to test the old rendering code + random : (num = 20)=>{ return _.times(num, ()=>{ //TODO: Build better generator @@ -66,6 +68,10 @@ module.exports = { ); }, + get : (brewId) => { + return PopulatedBrews[brewId] + }, + chaiPlugin : (chai, utils) => { chai.Assertion.addMethod('brews', function(...brewIds){ new chai.Assertion(this._obj).to.be.instanceof(Array); @@ -84,5 +90,22 @@ module.exports = { `expect #{this} to not have brews ${brewIds.join(', ')}` ) }); + + chai.Assertion.addMethod('brew', function(brewId){ + new chai.Assertion(this._obj).to.be.instanceof(Object); + const brew = this._obj; + const storedBrew = PopulatedBrews[brewId]; + + const valid = storedBrew && + brew.shareId == storedBrew.shareId && + brew.title == storedBrew.title && + brew.views == storedBrew.views; + + this.assert( + valid, + `expect #{this} to be brew ${brewId}`, + `expect #{this} to not be brew ${brewId}` + ) + }); } }; \ No newline at end of file diff --git a/test/search.test.js b/test/search.test.js index 04c30d9..6649500 100644 --- a/test/search.test.js +++ b/test/search.test.js @@ -70,14 +70,27 @@ describe('Brew Search', () => { }); describe('Sorting', ()=>{ - it.skip('should sort ASC', () => { - + it('should sort ASC', () => { + return BrewData.search({}, { + sort : { views : 1 } + }) + .then((result) => { + result.brews[0].should.be.brew('BrewC'); + result.brews[1].should.be.brew('BrewD'); + result.brews[2].should.be.brew('BrewB'); + result.brews[3].should.be.brew('BrewA'); + }) }); - it.skip('should sort DESC', () => { - - }); - it.skip('should sort based on multiple fields', () => { - + it('should sort DESC', () => { + return BrewData.search({}, { + sort : { views : -1 } + }) + .then((result) => { + result.brews[0].should.be.brew('BrewA'); + result.brews[1].should.be.brew('BrewB'); + result.brews[2].should.be.brew('BrewD'); + result.brews[3].should.be.brew('BrewC'); + }) }); }); @@ -146,8 +159,12 @@ describe('Brew Search', () => { result.brews.should.have.brews('BrewB'); }); }); - it.skip('should not worry about the case of the terms', () => { - + it('should not worry about the case of the terms', () => { + return BrewData.termSearch('FANCY') + .then((result) => { + result.total.should.be.equal(2); + result.brews.should.have.brews('BrewA', 'BrewB'); + }); }); });