diff --git a/app.js b/app.js index 4e2715f..ef1ca9b 100644 --- a/app.js +++ b/app.js @@ -84,11 +84,6 @@ app.route('/sites') makeResponse(res, sites.createSite(req)); }); -app.route('/accounts/:account_id/sites') - .get(function(req, res, next) { - makeResponse(res, sites.getSitesByAccount(req)); - }); - app.route('/sites/:site_id') .get(function(req, res, next) { makeResponse(res, sites.getSite(req)); diff --git a/lib/utils.js b/lib/utils.js index 97bd58c..29801a9 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -51,9 +51,9 @@ function getAccountID(auth0_id) { .then(function(data) { if (data.length === 1) { return data[0].acct_id; - } else { - return Promise.reject({status: 403, message: 'Invalid Auth0 ID'}); } + + return Promise.reject({status: 403, message: 'Invalid Auth0 ID'}); }); } diff --git a/routes/sites.js b/routes/sites.js index c2e695b..4483304 100644 --- a/routes/sites.js +++ b/routes/sites.js @@ -4,6 +4,7 @@ const Promise = require('bluebird'); const utils = require('../lib/utils'); const query = utils.query; const defined = utils.defined; +const getAccountID = utils.getAccountID; /** * Gets all sites. @@ -12,17 +13,24 @@ const defined = utils.defined; * @return {Promise} The promise */ function getSites(req) { - return query('SELECT * FROM Site'); + if (req.user.authorization === 'Admin' || req.user.authorization === 'Staff') { + return query('SELECT * FROM Site'); + } + + return getAccountID(req.user.auth0_id) + .then(function(data) { + return getSitesByAccount(data); + }); } /** * Gets all sites for given account. * - * @param {Object} req The given request object + * @param {Number} accountID The given account id * @return {Promise} The promise */ -function getSitesByAccount(req) { - return query('SELECT site_id, site_name, site_address FROM Acct NATURAL JOIN AcctToProgram NATURAL JOIN Program NATURAL JOIN Site WHERE acct_id = ?', [req.params.account_id]); +function getSitesByAccount(accountID) { + return query('SELECT site_id, site_name, site_address FROM Acct NATURAL JOIN AcctToProgram NATURAL JOIN Program NATURAL JOIN Site WHERE acct_id = ?', [accountID]); } /** @@ -32,6 +40,10 @@ function getSitesByAccount(req) { * @return {Promise} The promise */ function createSite(req) { + if (req.user.authorization == 'Coach' || req.user.authorization == 'Volunteer') { + return Promise.reject({status: 403, message: 'Access denied'}); + } + if (!defined(req.body) || !defined(req.body.site_name) || !defined(req.body.site_address)) { return Promise.reject({ status: 406, @@ -59,7 +71,21 @@ function createSite(req) { * @return {Promise} The promise */ function getSite(req) { - return query('SELECT * FROM Site WHERE site_id = ?', [req.params.site_id]); + var site_id = req.params.site_id; + if (req.user.authorization === 'Admin' || req.user.authorization === 'Staff') { + return query('SELECT * FROM Site WHERE site_id = ?', [site_id]); + } + + return getAccountID(req.user.auth0_id) + .then(function(data) { + return query('SELECT site_id, site_name, site_address FROM Acct NATURAL JOIN AcctToProgram NATURAL JOIN Program NATURAL JOIN Site WHERE acct_id = ? AND Site.site_id = ?', [data, site_id]); + }) + .then(function(data) { + if (data.length !== 1) { + return Promise.reject({status: 403, message: 'Access denied or site not found'}); + } + return data; + }); } /** @@ -69,6 +95,10 @@ function getSite(req) { * @return {Promise} The promise */ function updateSite(req) { + if (req.user.authorization == 'Coach' || req.user.authorization == 'Volunteer') { + return Promise.reject({status: 403, message: 'Access denied'}); + } + if (!defined(req.body) || (!defined(req.body.site_name) && !defined(req.body.site_address))) { return Promise.reject({ status: 406, @@ -96,6 +126,10 @@ function updateSite(req) { * @return {Promise} The promise */ function deleteSite(req) { + if (req.user.authorization !== 'Admin') { + return Promise.reject({status: 403, message: 'Access denied'}); + } + return query('DELETE FROM Site WHERE site_id = ?', [req.params.site_id]); } diff --git a/routes/students.js b/routes/students.js index 81798e3..c49937f 100644 --- a/routes/students.js +++ b/routes/students.js @@ -2,6 +2,7 @@ const Promise = require('bluebird'); const utils = require('../lib/utils'); +const constants = require('../lib/constants'); const query = utils.query; const defined = utils.defined; @@ -124,14 +125,8 @@ function getStudentsBySite(req) { // Check if the id is an integer > 0 if (isPositiveInteger(id)) { // Check if the id is in the related table - return sites.getSite({ - params: { - site_id: id - }, - user: { - authorization: 'Admin' - } - }) + req.user = constants.admin; + return sites.getSite(req) .then(function(data) { if (data.length > 0) { return query(queryString, [id]); diff --git a/test/app.js b/test/app.js index 7f369ee..8fa5ccc 100644 --- a/test/app.js +++ b/test/app.js @@ -176,7 +176,6 @@ describe('app.js', function() { describe('sites endpoint', function() { var getSitesStub; - var getSitesByAccountStub; var createSiteStub; var getSiteStub; var updateSiteStub; @@ -186,9 +185,6 @@ describe('app.js', function() { getSitesStub = sinon.stub(sites, 'getSites', function() { return Promise.resolve('got the sites'); }); - getSitesByAccountStub = sinon.stub(sites, 'getSitesByAccount', function() { - return Promise.resolve('got the students for an account'); - }); createSiteStub = sinon.stub(sites, 'createSite', function() { return Promise.resolve('create a site'); }); @@ -205,7 +201,6 @@ describe('app.js', function() { after(function() { sites.getSites.restore(); - sites.getSitesByAccount.restore(); sites.createSite.restore(); sites.getSite.restore(); sites.updateSite.restore(); @@ -222,16 +217,6 @@ describe('app.js', function() { }); }); - it('GET /accounts/:account_id/sites', function(done) { - request(app) - .get('/accounts/:account_id/sites') - .expect('got the sites for an account', 200) - .end(function() { - assert.isTrue(getSitesByAccountStub.called); - done(); - }); - }); - it('POST /sites', function(done) { request(app) .post('/sites') diff --git a/test/routes/sites.js b/test/routes/sites.js index a3eb439..10a56f0 100644 --- a/test/routes/sites.js +++ b/test/routes/sites.js @@ -4,6 +4,7 @@ const chai = require('chai'); const assert = chai.assert; const sites = require('../../routes/sites'); const utils = require('../../lib/utils'); +const constants = require('../../lib/constants'); const site1 = { site_id: 1, @@ -68,22 +69,31 @@ describe('Sites', function() { describe('getSites(req)', function() { it('gets all sites', function(done) { - var promise = sites.getSites({}); + var promise = sites.getSites({ + user: constants.admin + }); promise.then(function(data) { assert.deepEqual([site1, site2, site3, site4, site5, site6, site7, site8, site9, site10, site11], data); done(); }); }); + + it('gets sites on for the accont if not admin', function(done) { + var promise = sites.getSites({ + user: constants.coach + }); + + promise.then(function(data) { + assert.deepEqual([site1, site2], data); + done(); + }); + }); }); describe('getSitesByAccount(req)', function() { it('gets all sites for a given coach', function(done) { - var promise = sites.getSitesByAccount({ - params: { - account_id: 1 - } - }); + var promise = sites.getSitesByAccount(1); promise.then(function(data) { assert.deepEqual([site1, site2], data); @@ -92,11 +102,7 @@ describe('Sites', function() { }); it('it should return no sites if the given coach does not exist', function(done) { - var promise = sites.getSitesByAccount({ - params: { - account_id: 100 - } - }); + var promise = sites.getSitesByAccount(100); promise.then(function(data) { assert.deepEqual([], data); @@ -111,16 +117,21 @@ describe('Sites', function() { site_name: 'newSiteName', site_address: 'new Boston, MA' }; - sites.getSites({}) + sites.getSites({ + user: constants.admin + }) .then(function(data) { assert.deepEqual([site1, site2, site3, site4, site5, site6, site7, site8, site9, site10, site11], data); return sites.createSite({ - body: newData + body: newData, + user: constants.admin }); }) .then(function() { - return sites.getSites({}); + return sites.getSites({ + user: constants.admin + }); }) .then(function(data) { assert.deepEqual([site1, site2, site3, site4, site5, site6, site7, site8, site9, site10, site11, { @@ -132,17 +143,36 @@ describe('Sites', function() { }); }); + it('403 if you are not an admin or staff', function(done) { + var newData = { + site_name: 'newSiteName', + site_address: 'new Boston, MA' + }; + sites.createSite({ + body: newData, + user: constants.coach + }) + .catch(function(err) { + assert.equal(err.status, 403); + assert.equal(err.message, 'Access denied'); + done(); + }); + }); + it('does not create site because a site with the given name and address already exists', function(done) { sites.createSite({ body: { site_name: 'Schuyler High School', site_address: '232 Boylston Street, Boston, MA' - } + }, + user: constants.admin }) .catch(function(err) { assert.equal(err.status, 409); assert.equal(err.message, 'Unable to create site: the site is already in the database'); - return sites.getSites({}); + return sites.getSites({ + user: constants.admin + }); }) .then(function(data) { assert.deepEqual([site1, site2, site3, site4, site5, site6, site7, site8, site9, site10, site11], data); @@ -151,10 +181,14 @@ describe('Sites', function() { }); it('does not create a site because body was missing', function(done) { - sites.createSite({}).catch(function(err) { + sites.createSite({ + user: constants.admin + }).catch(function(err) { assert.equal(err.status, 406); assert.equal(err.message, 'Must provide site\'s name, and address'); - return sites.getSites({}); + return sites.getSites({ + user: constants.admin + }); }) .then(function(data) { assert.deepEqual([site1, site2, site3, site4, site5, site6, site7, site8, site9, site10, site11], data); @@ -166,12 +200,15 @@ describe('Sites', function() { sites.createSite({ body: { site_address: 'address' - } + }, + user: constants.admin }) .catch(function(err) { assert.equal(err.status, 406); assert.equal(err.message, 'Must provide site\'s name, and address'); - return sites.getSites({}); + return sites.getSites({ + user: constants.admin + }); }) .then(function(data) { assert.deepEqual([site1, site2, site3, site4, site5, site6, site7, site8, site9, site10, site11], data); @@ -183,12 +220,15 @@ describe('Sites', function() { sites.createSite({ body: { site_name: 'name' - } + }, + user: constants.admin }) .catch(function(err) { assert.equal(err.status, 406); assert.equal(err.message, 'Must provide site\'s name, and address'); - return sites.getSites({}); + return sites.getSites({ + user: constants.admin + }); }) .then(function(data) { assert.deepEqual([site1, site2, site3, site4, site5, site6, site7, site8, site9, site10, site11], data); @@ -198,11 +238,12 @@ describe('Sites', function() { }); describe('getSite(req)', function() { - it('get a site', function(done) { + it('get a site admin', function(done) { var promise = sites.getSite({ params: { site_id: 1 - } + }, + user: constants.admin }); promise.then(function(data) { @@ -211,11 +252,41 @@ describe('Sites', function() { }); }); + it('get the site if the coach can see it', function(done) { + var promise = sites.getSite({ + params: { + site_id: 1 + }, + user: constants.coach + }); + + promise.then(function(data) { + assert.deepEqual([site1], data); + done(); + }); + }); + + it('403 if the coach cannot see the sites', function(done) { + var promise = sites.getSite({ + params: { + site_id: 3 + }, + user: constants.coach + }); + + promise.catch(function(err) { + assert.equal(err.status, 403); + assert.equal(err.message, 'Access denied or site not found'); + done(); + }); + }); + it('returns an empty array when getting a site that does not exist', function(done) { var promise = sites.getSite({ params: { site_id: 124 - } + }, + user: constants.admin }); promise.then(function(data) { @@ -230,7 +301,8 @@ describe('Sites', function() { sites.getSite({ params: { site_id: 9 - } + }, + user: constants.admin }) .then(function(data) { assert.deepEqual([site9], data); @@ -242,14 +314,16 @@ describe('Sites', function() { body: { site_name: 'new name', site_address: 'new address' - } + }, + user: constants.admin }); }) .then(function() { return sites.getSite({ params: { site_id: 9 - } + }, + user: constants.admin }); }) .then(function(data) { @@ -262,8 +336,28 @@ describe('Sites', function() { }); }); + it('only admins or staff can edit a site', function(done) { + sites.updateSite({ + params: { + site_id: 9 + }, + body: { + site_name: 'new name', + site_address: 'new address' + }, + user: constants.coach + }) + .catch(function(err) { + assert.equal(err.status, 403); + assert.equal(err.message, 'Access denied'); + done(); + }); + }); + it('does not updated a site because the body was missing', function(done) { - sites.updateSite({}).catch(function(err) { + sites.updateSite({ + user: constants.admin + }).catch(function(err) { assert.equal(err.status, 406); assert.equal(err.message, 'Must provide site\'s name, or address'); done(); @@ -272,7 +366,8 @@ describe('Sites', function() { it('does not updated a site because there are no fields to be updated', function(done) { sites.updateSite({ - body: {} + body: {}, + user: constants.admin }) .catch(function(err) { assert.equal(err.status, 406); @@ -289,7 +384,8 @@ describe('Sites', function() { body: { site_name: 'new name', site_address: 'new address' - } + }, + user: constants.admin }) .then(function(data) { assert.equal(0, data.affectedRows); @@ -303,7 +399,8 @@ describe('Sites', function() { sites.getSite({ params: { site_id: 3 - } + }, + user: constants.admin }) .then(function(data) { assert.deepEqual([site3], data); @@ -311,14 +408,16 @@ describe('Sites', function() { return sites.deleteSite({ params: { site_id: 3 - } + }, + user: constants.admin }); }) .then(function() { return sites.getSite({ params: { site_id: 3 - } + }, + user: constants.admin }); }) .then(function(data) { @@ -327,18 +426,37 @@ describe('Sites', function() { }); }); + it('only admins can delete a site', function(done) { + sites.deleteSite({ + params: { + site_id: 3 + }, + user: constants.staff + }) + .catch(function(err) { + assert.equal(err.status, 403); + assert.equal(err.message, 'Access denied'); + done(); + }); + }); + it('does nothing when told to delete a site that doesn\'t exist', function(done) { - sites.getSites({}).then(function(data) { + sites.getSites({ + user: constants.admin + }).then(function(data) { assert.deepEqual([site1, site2, site3, site4, site5, site6, site7, site8, site9, site10, site11], data); return sites.deleteSite({ params: { site_id: 12414 - } + }, + user: constants.admin }); }) .then(function() { - return sites.getSites({}); + return sites.getSites({ + user: constants.admin + }); }) .then(function(data) { assert.deepEqual([site1, site2, site3, site4, site5, site6, site7, site8, site9, site10, site11], data);