From 1bcf2803f737d8ba171c75230bdbfce5cc7aac03 Mon Sep 17 00:00:00 2001 From: Ethan Roday Date: Thu, 13 Aug 2020 10:51:05 -0700 Subject: [PATCH] For the /area/fw/:userId endpoint, automatically set pplication field to w if not set. --- CHANGELOG.md | 4 + app/src/routes/api/v1/area.router.js | 7 +- app/src/validators/area.validator.js | 1 + app/test/e2e/v1/create-area-fw.spec.js | 171 +++++++++++++++++++++++++ config/mongoose.js | 2 +- 5 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 app/test/e2e/v1/create-area-fw.spec.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 726a314..2310fec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 13/08/2020 + +- For the `/area/fw/:userId` endpoint, automatically set `application` field to `fw` if not set. + # v1.6.1 ## 20/07/2020 diff --git a/app/src/routes/api/v1/area.router.js b/app/src/routes/api/v1/area.router.js index b451e12..95a1809 100644 --- a/app/src/routes/api/v1/area.router.js +++ b/app/src/routes/api/v1/area.router.js @@ -82,6 +82,11 @@ class AreaRouter { } static async saveByUserId(ctx) { + // We are assuming here that the user has 'fw' in their application list + // To be safer, we could call the user MS and check + if (!ctx.request.body.application) { + ctx.request.body.application = 'fw'; + } await AreaRouter.saveArea(ctx, ctx.params.userId); } @@ -280,7 +285,7 @@ router.post('/', loggedUserToState, unwrapJSONStrings, AreaValidator.create, Are router.patch('/:id', loggedUserToState, checkPermission, unwrapJSONStrings, AreaValidator.update, AreaRouter.update); router.get('/', loggedUserToState, AreaRouter.getAll); router.get('/fw', loggedUserToState, AreaRouter.getFWAreas); -router.post('/fw/:userId', loggedUserToState, AreaValidator.create, AreaRouter.saveByUserId); +router.post('/fw/:userId', loggedUserToState, unwrapJSONStrings, AreaValidator.create, AreaRouter.saveByUserId); router.get('/fw/:userId', loggedUserToState, isMicroservice, AreaRouter.getFWAreasByUserId); router.get('/:id', loggedUserToState, AreaRouter.get); router.get('/:id/alerts', loggedUserToState, AreaRouter.getAlertsOfArea); diff --git a/app/src/validators/area.validator.js b/app/src/validators/area.validator.js index 23a7d42..a4c5f26 100644 --- a/app/src/validators/area.validator.js +++ b/app/src/validators/area.validator.js @@ -28,6 +28,7 @@ class AreaValidator { ctx.checkBody('use').optional().check((use) => AreaValidator.isObject(use), 'must be an object'); if (ctx.errors) { + logger.debug(`Area validation failed with error: ${JSON.stringify(ctx.errors)}`); ctx.body = ErrorSerializer.serializeValidationBodyErrors(ctx.errors); ctx.status = 400; return; diff --git a/app/test/e2e/v1/create-area-fw.spec.js b/app/test/e2e/v1/create-area-fw.spec.js new file mode 100644 index 0000000..a3460fa --- /dev/null +++ b/app/test/e2e/v1/create-area-fw.spec.js @@ -0,0 +1,171 @@ +const nock = require('nock'); +const chai = require('chai'); +const Area = require('models/area.model'); +const fs = require('fs'); +const config = require('config'); +const { USERS } = require('../utils/test.constants'); + +chai.should(); + +const { getTestServer } = require('../utils/test-server'); + +nock.disableNetConnect(); +nock.enableNetConnect(process.env.HOST_IP); + +const requester = getTestServer(); + +describe('V1 - Create area FW', () => { + before(() => { + if (process.env.NODE_ENV !== 'test') { + throw Error(`Running the test suite with NODE_ENV ${process.env.NODE_ENV} may result in permanent data loss. Please use NODE_ENV=test.`); + } + }); + + it('Creating an area without being logged in should return a 401 - "Not logged" error', async () => { + const response = await requester + .post(`/api/v1/area/fw/${USERS.USER.id}`); + + response.status.should.equal(401); + + response.body.should.have.property('errors').and.be.an('array'); + response.body.errors[0].should.have.property('detail').and.equal(`Not logged`); + }); + + it('Creating an area while being logged in as a user that owns the area should return a 200 HTTP code and the created area object', async () => { + const response = await requester + .post(`/api/v1/area/fw/${USERS.USER.id}`) + .send({ + loggedUser: USERS.USER, + name: 'Portugal area', + application: 'rw', + geostore: '713899292fc118a915741728ef84a2a7', + wdpaid: 3, + use: { + id: 'bbb', + name: 'created name' + }, + iso: { + country: 'createdCountryIso', + region: 'createdRegionIso' + }, + datasets: '[{"slug":"viirs","name":"VIIRS","startDate":"7","endDate":"1","lastCreate":1513793462776.0,"_id":"5a3aa9eb98b5910011731f66","active":true,"cache":true}]', + templateId: 'createdTemplateId' + }); + + response.status.should.equal(200); + + response.body.should.have.property('data').and.be.an('object'); + response.body.data.should.have.property('type').and.equal('area'); + response.body.data.should.have.property('id'); + response.body.data.attributes.should.have.property('name').and.equal('Portugal area'); + response.body.data.attributes.should.have.property('application').and.equal('rw'); + response.body.data.attributes.should.have.property('geostore').and.equal('713899292fc118a915741728ef84a2a7'); + response.body.data.attributes.should.have.property('userId').and.equal(USERS.USER.id); + response.body.data.attributes.should.have.property('wdpaid').and.equal(3); + response.body.data.attributes.should.have.property('use').and.deep.equal({ + id: 'bbb', + name: 'created name' + }); + response.body.data.attributes.should.have.property('iso').and.deep.equal({ + country: 'createdCountryIso', + region: 'createdRegionIso' + }); + response.body.data.attributes.should.have.property('createdAt'); + response.body.data.attributes.should.have.property('datasets').and.be.an('array').and.length(1); + response.body.data.attributes.datasets[0].should.deep.equal({ + cache: true, + active: true, + _id: '5a3aa9eb98b5910011731f66', + slug: 'viirs', + name: 'VIIRS', + startDate: '7', + endDate: '1' + }); + }); + + it('Creating an area should automatically set the application field to "fw"', async () => { + const response = await requester + .post(`/api/v1/area/fw/${USERS.USER.id}`) + .send({ + loggedUser: USERS.USER, + name: 'Portugal area', + geostore: '713899292fc118a915741728ef84a2a7', + wdpaid: 3, + use: { + id: 'bbb', + name: 'created name' + }, + iso: { + country: 'createdCountryIso', + region: 'createdRegionIso' + }, + datasets: '[{"slug":"viirs","name":"VIIRS","startDate":"7","endDate":"1","lastCreate":1513793462776.0,"_id":"5a3aa9eb98b5910011731f66","active":true,"cache":true}]', + templateId: 'createdTemplateId' + }); + + response.status.should.equal(200); + + response.body.data.attributes.should.have.property('application').and.equal('fw'); + + }); + + it('Creating an area with a file while being logged in as a user that owns the area should upload the image to S3 and return a 200 HTTP code and the created area object', async () => { + nock(`https://${config.get('s3.bucket')}.s3.amazonaws.com`) + .put(/^\/areas-dev\/(\w|-)+.png/) + .reply(200); + + const fileData = fs.readFileSync(`${__dirname}/../assets/sample.png`); + + const response = await requester + .post(`/api/v1/area/fw/${USERS.USER.id}`) + .attach('image', fileData, 'sample.png') + .field('loggedUser', JSON.stringify(USERS.USER)) + .field('name', 'Portugal area') + .field('application', 'rw') + .field('geostore', '713899292fc118a915741728ef84a2a7') + .field('wdpaid', '3') + .field('use', '{"id": "bbb", "name": "created name"}') + .field('iso', '{"country": "createdCountryIso", "region": "createdRegionIso"}') + .field('templateId', 'createdTemplateId') + .field('datasets', '[{"slug":"viirs","name":"VIIRS","startDate":"7","endDate":"1","lastCreate":1513793462776.0,"_id":"5a3aa9eb98b5910011731f66","active":true,"cache":true}]'); + + response.status.should.equal(200); + + response.body.should.have.property('data').and.be.an('object'); + response.body.data.should.have.property('type').and.equal('area'); + response.body.data.should.have.property('id'); + response.body.data.attributes.should.have.property('name').and.equal('Portugal area'); + response.body.data.attributes.should.have.property('application').and.equal('rw'); + response.body.data.attributes.should.have.property('geostore').and.equal('713899292fc118a915741728ef84a2a7'); + response.body.data.attributes.should.have.property('userId').and.equal(USERS.USER.id); + response.body.data.attributes.should.have.property('wdpaid').and.equal(3); + response.body.data.attributes.should.have.property('use').and.deep.equal({ + id: 'bbb', + name: 'created name' + }); + response.body.data.attributes.should.have.property('iso').and.deep.equal({ + country: 'createdCountryIso', + region: 'createdRegionIso' + }); + response.body.data.attributes.should.have.property('createdAt'); + response.body.data.attributes.should.have.property('datasets').and.be.an('array').and.length(1); + response.body.data.attributes.should.have.property('image').and.include(`https://s3.amazonaws.com/${config.get('s3.bucket')}/${config.get('s3.folder')}`); + response.body.data.attributes.datasets[0].should.deep.equal({ + cache: true, + active: true, + _id: '5a3aa9eb98b5910011731f66', + slug: 'viirs', + name: 'VIIRS', + startDate: '7', + endDate: '1' + }); + }); + + afterEach(async () => { + if (!nock.isDone()) { + throw new Error(`Not all nock interceptors were used: ${nock.pendingMocks()}`); + } + + await Area.deleteMany({}).exec(); + }); +}); diff --git a/config/mongoose.js b/config/mongoose.js index 0e4a159..1776a4b 100644 --- a/config/mongoose.js +++ b/config/mongoose.js @@ -8,7 +8,7 @@ const mongooseOptions = { readPreference: 'secondaryPreferred', // Has MongoDB prefer secondary servers for read operations. appname: 'area', // Displays the app name in MongoDB logs, for ease of debug serverSelectionTimeoutMS: 10000, // Number of milliseconds the underlying MongoDB driver has to pick a server - loggerLevel: config.get('logger.level') // Logger level to pass to the MongoDB driver + }; module.exports = mongooseOptions;