diff --git a/Dockerfile b/Dockerfile index 40e253c..3758d91 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20.4-alpine3.18 +FROM node:20.5-alpine3.18 MAINTAINER info@vizzuality.com ENV NAME gfw-area diff --git a/app/src/serializers/adminSourceUtils.js b/app/src/serializers/adminSourceUtils.js new file mode 100644 index 0000000..60c0d44 --- /dev/null +++ b/app/src/serializers/adminSourceUtils.js @@ -0,0 +1,60 @@ +const GADM_VERSION_2_8 = '2.8'; +const GADM_VERSION_3_6 = '3.6'; + +let gadmVersion = GADM_VERSION_2_8; + +function isIsoDefined(area) { + return area.attributes.iso && area.attributes.iso.country; +} + +function isAdminDefined(area) { + return area.attributes.admin && area.attributes.admin.adm0; +} + +function isAdministrativeBoundary(area) { + return isIsoDefined(area) || isAdminDefined(area); +} + +function addSource(adminInfo) { + const result = { + ...adminInfo, + source: { + provider: 'gadm', + version: gadmVersion, + } + }; + return result; +} + +function addSourceToIsoAttribute(area) { + if (isIsoDefined(area)) { + area.attributes.iso = addSource(area.attributes.iso); + } +} + +function addSourceToAdminAttribute(area) { + if (isAdminDefined(area)) { + area.attributes.admin = addSource(area.attributes.admin); + } +} + +function addSourceForAdministrativeAreas(data) { + const areas = Array.isArray(data) ? data : [data]; + areas.filter(isAdministrativeBoundary).forEach((area) => { + addSourceToIsoAttribute(area); + addSourceToAdminAttribute(area); + }); + return data; +} + +const addV1SourceForAdministrativeAreas = (data) => { + gadmVersion = GADM_VERSION_2_8; + return addSourceForAdministrativeAreas(data); +}; + +const addV2SourceForAdministrativeAreas = (data) => { + gadmVersion = GADM_VERSION_3_6; + return addSourceForAdministrativeAreas(data); +}; + +module.exports = { addV1SourceForAdministrativeAreas, addV2SourceForAdministrativeAreas }; diff --git a/app/src/serializers/area.serializer.js b/app/src/serializers/area.serializer.js index da1c92b..b4410cc 100644 --- a/app/src/serializers/area.serializer.js +++ b/app/src/serializers/area.serializer.js @@ -1,4 +1,5 @@ const JSONAPISerializer = require('jsonapi-serializer').Serializer; +const { addV1SourceForAdministrativeAreas } = require('./adminSourceUtils'); const areaSerializer = new JSONAPISerializer('area', { attributes: [ @@ -35,6 +36,8 @@ class AreaSerializer { result = areaSerializer.serialize(data); } + result.data = addV1SourceForAdministrativeAreas(JSON.parse(JSON.stringify(result.data))); + if (link) { result.links = { self: `${link}page[number]=${data.page}&page[size]=${data.limit}`, @@ -52,7 +55,6 @@ class AreaSerializer { return result; } - } module.exports = AreaSerializer; diff --git a/app/src/serializers/area.serializerV2.js b/app/src/serializers/area.serializerV2.js index 4f745ce..798cc89 100644 --- a/app/src/serializers/area.serializerV2.js +++ b/app/src/serializers/area.serializerV2.js @@ -1,4 +1,5 @@ const JSONAPISerializer = require('jsonapi-serializer').Serializer; +const { addV2SourceForAdministrativeAreas } = require('./adminSourceUtils'); const areaSerializer = new JSONAPISerializer('area', { attributes: [ @@ -53,6 +54,8 @@ class AreaSerializer { }); } + serializedData.data = addV2SourceForAdministrativeAreas(JSON.parse(JSON.stringify(serializedData.data))); + if (link) { serializedData.links = { self: `${link}page[number]=${data.page}&page[size]=${data.limit}`, diff --git a/app/test/e2e/v1/create-area-fw.spec.js b/app/test/e2e/v1/create-area-fw.spec.js index 4e701bc..3d4e02c 100644 --- a/app/test/e2e/v1/create-area-fw.spec.js +++ b/app/test/e2e/v1/create-area-fw.spec.js @@ -81,7 +81,11 @@ describe('V1 - Create area FW', () => { }); response.body.data.attributes.should.have.property('iso').and.deep.equal({ country: 'createdCountryIso', - region: 'createdRegionIso' + region: 'createdRegionIso', + source: { + provider: 'gadm', + version: '2.8', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); @@ -166,7 +170,11 @@ describe('V1 - Create area FW', () => { }); response.body.data.attributes.should.have.property('iso').and.deep.equal({ country: 'createdCountryIso', - region: 'createdRegionIso' + region: 'createdRegionIso', + source: { + provider: 'gadm', + version: '2.8', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); diff --git a/app/test/e2e/v1/create-area.spec.js b/app/test/e2e/v1/create-area.spec.js index d665479..d3320c6 100644 --- a/app/test/e2e/v1/create-area.spec.js +++ b/app/test/e2e/v1/create-area.spec.js @@ -81,7 +81,11 @@ describe('V1 - Create area', () => { }); response.body.data.attributes.should.have.property('iso').and.deep.equal({ country: 'createdCountryIso', - region: 'createdRegionIso' + region: 'createdRegionIso', + source: { + provider: 'gadm', + version: '2.8', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); @@ -137,7 +141,11 @@ describe('V1 - Create area', () => { }); response.body.data.attributes.should.have.property('iso').and.deep.equal({ country: 'createdCountryIso', - region: 'createdRegionIso' + region: 'createdRegionIso', + source: { + provider: 'gadm', + version: '2.8', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); @@ -197,7 +205,11 @@ describe('V1 - Create area', () => { }); response.body.data.attributes.should.have.property('iso').and.deep.equal({ country: 'createdCountryIso', - region: 'createdRegionIso' + region: 'createdRegionIso', + source: { + provider: 'gadm', + version: '2.8', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); @@ -256,7 +268,11 @@ describe('V1 - Create area', () => { }); response.body.data.attributes.should.have.property('iso').and.deep.equal({ country: 'createdCountryIso', - region: 'createdRegionIso' + region: 'createdRegionIso', + source: { + provider: 'gadm', + version: '2.8', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); @@ -313,7 +329,11 @@ describe('V1 - Create area', () => { }); response.body.data.attributes.should.have.property('iso').and.deep.equal({ country: 'createdCountryIso', - region: 'createdRegionIso' + region: 'createdRegionIso', + source: { + provider: 'gadm', + version: '2.8', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); diff --git a/app/test/e2e/v1/update-area.spec.js b/app/test/e2e/v1/update-area.spec.js index 53c89a3..edba778 100644 --- a/app/test/e2e/v1/update-area.spec.js +++ b/app/test/e2e/v1/update-area.spec.js @@ -97,7 +97,11 @@ describe('V1 - Update area', () => { }); response.body.data.attributes.should.have.property('iso').and.deep.equal({ country: 'updatedCountryIso', - region: 'updatedRegionIso' + region: 'updatedRegionIso', + source: { + provider: 'gadm', + version: '2.8', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); @@ -156,7 +160,11 @@ describe('V1 - Update area', () => { }); response.body.data.attributes.should.have.property('iso').and.deep.equal({ country: 'updatedCountryIso', - region: 'updatedRegionIso' + region: 'updatedRegionIso', + source: { + provider: 'gadm', + version: '2.8', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); @@ -219,7 +227,11 @@ describe('V1 - Update area', () => { }); response.body.data.attributes.should.have.property('iso').and.deep.equal({ country: 'updatedCountryIso', - region: 'updatedRegionIso' + region: 'updatedRegionIso', + source: { + provider: 'gadm', + version: '2.8', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); diff --git a/app/test/e2e/v2/create-area.spec.js b/app/test/e2e/v2/create-area.spec.js index 74457ce..3b88d06 100644 --- a/app/test/e2e/v2/create-area.spec.js +++ b/app/test/e2e/v2/create-area.spec.js @@ -75,7 +75,11 @@ describe('V2 - Create area', () => { 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' + region: 'createdRegionIso', + source: { + provider: 'gadm', + version: '3.6', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); @@ -92,6 +96,60 @@ describe('V2 - Create area', () => { }); }); + it('Creating an area while being logged in as a user that owns the area and using admin instead of iso should return a 200 HTTP code and the created area object', async () => { + mockValidateRequestWithApiKeyAndUserToken({ user: USERS.USER }); + + const response = await requester + .post(`/api/v2/area`) + .set('Authorization', 'Bearer abcd') + .set('x-api-key', 'api-key-test') + .send({ + name: 'Portugal area', + application: 'rw', + geostore: '713899292fc118a915741728ef84a2a7', + wdpaid: 3, + use: { id: 'bbb', name: 'created name' }, + admin: { adm0: 'createdCountryIso', adm1: 15, adm2: 8 }, + 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('env').and.equal('production'); + response.body.data.attributes.should.have.property('use').and.deep.equal({ id: 'bbb', name: 'created name' }); + response.body.data.attributes.should.have.property('admin').and.deep.equal({ + adm0: 'createdCountryIso', + adm1: 15, + adm2: 8, + source: { + provider: 'gadm', + version: '3.6', + } + }); + response.body.data.attributes.should.have.property('iso').and.eql({}); + response.body.data.attributes.should.have.property('createdAt'); + response.body.data.attributes.should.have.property('updatedAt'); + new Date(response.body.data.attributes.updatedAt).should.closeToTime(new Date(response.body.data.attributes.createdAt), 5); + 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' + }); + }); + describe('Custom envs', () => { it('Creating an area with no env should be successful and have the default env value', async () => { @@ -128,7 +186,11 @@ describe('V2 - Create area', () => { }); response.body.data.attributes.should.have.property('iso').and.deep.equal({ country: 'createdCountryIso', - region: 'createdRegionIso' + region: 'createdRegionIso', + source: { + provider: 'gadm', + version: '3.6', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); @@ -180,7 +242,11 @@ describe('V2 - Create area', () => { }); response.body.data.attributes.should.have.property('iso').and.deep.equal({ country: 'createdCountryIso', - region: 'createdRegionIso' + region: 'createdRegionIso', + source: { + provider: 'gadm', + version: '3.6', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); @@ -238,7 +304,11 @@ describe('V2 - Create area', () => { }); response.body.data.attributes.should.have.property('iso').and.deep.equal({ country: 'createdCountryIso', - region: 'createdRegionIso' + region: 'createdRegionIso', + source: { + provider: 'gadm', + version: '3.6', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); @@ -294,7 +364,11 @@ describe('V2 - Create area', () => { 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' + region: 'createdRegionIso', + source: { + provider: 'gadm', + version: '3.6', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); diff --git a/app/test/e2e/v2/update-area.spec.js b/app/test/e2e/v2/update-area.spec.js index 93db2f7..3c9c643 100644 --- a/app/test/e2e/v2/update-area.spec.js +++ b/app/test/e2e/v2/update-area.spec.js @@ -97,7 +97,11 @@ describe('V2 - Update area', () => { }); response.body.data.attributes.should.have.property('iso').and.deep.equal({ country: 'updatedCountryIso', - region: 'updatedRegionIso' + region: 'updatedRegionIso', + source: { + provider: 'gadm', + version: '3.6', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); @@ -156,7 +160,11 @@ describe('V2 - Update area', () => { }); response.body.data.attributes.should.have.property('iso').and.deep.equal({ country: 'updatedCountryIso', - region: 'updatedRegionIso' + region: 'updatedRegionIso', + source: { + provider: 'gadm', + version: '3.6', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); @@ -211,7 +219,11 @@ describe('V2 - Update area', () => { }); response.body.data.attributes.should.have.property('iso').and.deep.equal({ country: 'updatedCountryIso', - region: 'updatedRegionIso' + region: 'updatedRegionIso', + source: { + provider: 'gadm', + version: '3.6', + } }); response.body.data.attributes.should.have.property('createdAt'); response.body.data.attributes.should.have.property('updatedAt'); diff --git a/app/test/unit/serializers/adminSourceUtils.test.js b/app/test/unit/serializers/adminSourceUtils.test.js new file mode 100644 index 0000000..f615550 --- /dev/null +++ b/app/test/unit/serializers/adminSourceUtils.test.js @@ -0,0 +1,95 @@ +const chai = require('chai'); +const { addV1SourceForAdministrativeAreas, addV2SourceForAdministrativeAreas } = require('serializers/adminSourceUtils'); + +const { expect } = chai; + +describe('adminSourceUtils', () => { + describe('Adding GADM 2.8 Source Information', () => { + const serializedAreaFragment = { + attributes: { + iso: { + country: 'HND', + region: '8', + }, + }, + }; + + it('should add GADM 2.8 source information', () => { + const result = addV1SourceForAdministrativeAreas(serializedAreaFragment); + expect(result.attributes.iso).to.deep.include({ source: { provider: 'gadm', version: '2.8' } }); + }); + + describe('An Area That Is NOT An Administrative Boundary', () => { + const serializedCustomAreaFragment = { + attributes: { + name: 'Distrito Central, Francisco Morazán, Honduras', + geostore: 'abcf7041e2fbc5e8e7774178157ababe', + iso: {}, + } + }; + + it('should not add source information to the iso attribute', () => { + const result = addV1SourceForAdministrativeAreas(serializedCustomAreaFragment); + expect(result.attributes.iso).to.not.have.property('source'); + }); + }); + }); + + describe('Adding GADM 3.6 Source Information', () => { + const serializedAreaFragment = { + attributes: { + iso: { + country: 'HND', + region: '8', + subregion: '4', + }, + }, + }; + + it('should add GADM 3.6 source information', () => { + const result = addV2SourceForAdministrativeAreas(serializedAreaFragment); + expect(result.attributes.iso).to.deep.include({ source: { provider: 'gadm', version: '3.6' } }); + }); + + describe('An Administrative Boundary Area with Both an "iso" and "admin" Property', () => { + it('should NOT add source information to an empty "iso" object', () => { + const serializedAreaFragmentWithEmptyIsoAndAdmin = { + attributes: { + iso: {}, + admin: { + adm0: 'HND', + adm1: 8, + adm2: 4 + }, + }, + }; + + const result = addV2SourceForAdministrativeAreas(serializedAreaFragmentWithEmptyIsoAndAdmin); + expect(result.attributes.iso).to.eql({}); + }); + }); + + describe('An Area That Is NOT An Administrative Boundary', () => { + const serializedCustomAreaFragment = { + attributes: { + name: 'Distrito Central, Francisco Morazán, Honduras', + geostore: 'abcf7041e2fbc5e8e7774178157ababe', + iso: {}, + admin: { + adm0: null, + } + } + }; + + it('should not add source information to the iso attribute', () => { + const result = addV1SourceForAdministrativeAreas(serializedCustomAreaFragment); + expect(result.attributes.iso).to.not.have.property('source'); + }); + + it('should not add source information to the admin attribute', () => { + const result = addV1SourceForAdministrativeAreas(serializedCustomAreaFragment); + expect(result.attributes.admin).to.not.have.property('source'); + }); + }); + }); +}); diff --git a/app/test/unit/serializers/area.serializer.test.js b/app/test/unit/serializers/area.serializer.test.js new file mode 100644 index 0000000..ce4b086 --- /dev/null +++ b/app/test/unit/serializers/area.serializer.test.js @@ -0,0 +1,53 @@ +const chai = require('chai'); +const AreaModel = require('models/area.model'); +const areaSerializer = require('serializers/area.serializer'); + +const { expect } = chai; + +describe('Area Serializer', () => { + const area = { + name: 'Distrito Central, Francisco Morazán, Honduras', + geostore: 'abcf7041e2fbc5e8e7774178157ababe', + iso: { + country: 'HND', + region: '8', + }, + }; + + it('should include the name of the Area', () => { + const result = areaSerializer.serialize(new AreaModel(area)); + expect(result.data.attributes.name).to.equal('Distrito Central, Francisco Morazán, Honduras'); + }); + + it('should include the geostore of the Area', () => { + const result = areaSerializer.serialize(new AreaModel(area)); + expect(result.data.attributes.geostore).to.equal('abcf7041e2fbc5e8e7774178157ababe'); + }); + + describe('Administrative Boundary IDs', () => { + describe('The ISO attribute', () => { + it('should include the country and region', () => { + const result = areaSerializer.serialize(new AreaModel(area)); + expect(result.data.attributes.iso).to.deep.include({ country: 'HND', region: '8', }); + }); + + it('should include the administrative ID provider and version', () => { + const result = areaSerializer.serialize(new AreaModel(area)); + expect(result.data.attributes.iso).to.deep.include({ source: { provider: 'gadm', version: '2.8' } }); + }); + }); + }); + + describe('An Area That Is NOT An Administrative Boundary', () => { + const customArea = { + name: 'Distrito Central, Francisco Morazán, Honduras', + geostore: 'abcf7041e2fbc5e8e7774178157ababe', + iso: {}, + }; + + it('should not add source information to the iso attribute', () => { + const result = areaSerializer.serialize(new AreaModel(customArea)); + expect(result.data.attributes.iso).to.not.have.property('source'); + }); + }); +}); diff --git a/app/test/unit/serializers/area.serializerV2.test.js b/app/test/unit/serializers/area.serializerV2.test.js new file mode 100644 index 0000000..9ef608d --- /dev/null +++ b/app/test/unit/serializers/area.serializerV2.test.js @@ -0,0 +1,79 @@ +const chai = require('chai'); +const AreaModel = require('models/area.modelV2'); +const areaSerializerV2 = require('serializers/area.serializerV2'); + +const { expect } = chai; + +describe('Area Serializer V2', () => { + const area = { + name: 'Distrito Central, Francisco Morazán, Honduras', + geostore: 'abcf7041e2fbc5e8e7774178157ababe', + iso: { + country: 'HND', + region: '8', + subregion: '4', + }, + admin: { + adm0: 'HND', + adm1: 8, + adm2: 4, + } + }; + + it('should include the name of the Area', () => { + const result = areaSerializerV2.serialize(new AreaModel(area)); + expect(result.data.attributes.name).to.equal('Distrito Central, Francisco Morazán, Honduras'); + }); + + it('should include the geostore of the Area', () => { + const result = areaSerializerV2.serialize(new AreaModel(area)); + expect(result.data.attributes.geostore).to.equal('abcf7041e2fbc5e8e7774178157ababe'); + }); + + describe('Administrative Boundary IDs', () => { + describe('The ISO attribute', () => { + it('should include the country, region, and subregion', () => { + const result = areaSerializerV2.serialize(new AreaModel(area)); + expect(result.data.attributes.iso).to.deep.include({ country: 'HND', region: '8', subregion: '4' }); + }); + + it('should include the administrative ID provider and version', () => { + const result = areaSerializerV2.serialize(new AreaModel(area)); + expect(result.data.attributes.iso).to.deep.include({ source: { provider: 'gadm', version: '3.6' } }); + }); + }); + + describe('The Admin attribute', () => { + it('should include the adm0, adm1, and adm2 IDs', () => { + const result = areaSerializerV2.serialize(new AreaModel(area)); + expect(result.data.attributes.admin).to.deep.include({ adm0: 'HND', adm1: 8, adm2: 4 }); + }); + + it('should include the administrative ID provider and version', () => { + const result = areaSerializerV2.serialize(new AreaModel(area)); + expect(result.data.attributes.admin).to.deep.include({ source: { provider: 'gadm', version: '3.6' } }); + }); + }); + + describe('An Area That Is NOT An Administrative Boundary', () => { + const customArea = { + name: 'Distrito Central, Francisco Morazán, Honduras', + geostore: 'abcf7041e2fbc5e8e7774178157ababe', + iso: {}, + admin: { + adm0: null, + } + }; + + it('should not add source information to the iso attribute', () => { + const result = areaSerializerV2.serialize(new AreaModel(customArea)); + expect(result.data.attributes.iso).to.not.have.property('source'); + }); + + it('should not add source information to the admin attribute', () => { + const result = areaSerializerV2.serialize(new AreaModel(customArea)); + expect(result.data.attributes.admin).to.not.have.property('source'); + }); + }); + }); +}); diff --git a/area.sh b/area.sh index b6d46e6..630de94 100755 --- a/area.sh +++ b/area.sh @@ -5,12 +5,12 @@ case "$1" in yarn start ;; develop) - type docker-compose >/dev/null 2>&1 || { echo >&2 "docker-compose is required but it's not installed. Aborting."; exit 1; } - docker-compose -f docker-compose-develop.yml build && docker-compose -f docker-compose-develop.yml up + type docker compose >/dev/null 2>&1 || { echo >&2 "docker compose is required but it's not installed. Aborting."; exit 1; } + docker compose -f docker-compose-develop.yml build && docker compose -f docker-compose-develop.yml up ;; test) - type docker-compose >/dev/null 2>&1 || { echo >&2 "docker-compose is required but it's not installed. Aborting."; exit 1; } - docker-compose -f docker-compose-test.yml build && docker-compose -f docker-compose-test.yml up --abort-on-container-exit + type docker compose >/dev/null 2>&1 || { echo >&2 "docker compose is required but it's not installed. Aborting."; exit 1; } + docker compose -f docker-compose-test.yml build && docker compose -f docker-compose-test.yml up --abort-on-container-exit ;; *) echo "Usage: area.sh {start|develop|test}" >&2 diff --git a/docker-compose-develop.yml b/docker-compose-develop.yml index eaff46f..47d93c1 100644 --- a/docker-compose-develop.yml +++ b/docker-compose-develop.yml @@ -11,12 +11,14 @@ services: PORT: 4100 NODE_ENV: dev NODE_PATH: app/src - MONGO_PORT_27017_TCP_ADDR: mongo + MONGO_PORT_27017_TCP_ADDR: gfw-areas-mongo WAIT_HOSTS: mongo:27017 FASTLY_ENABLED: "false" AWS_REGION: "us-east-1" AWS_ACCESS_KEY_ID: "test" AWS_SECRET_ACCESS_KEY: "test" + REQUIRE_API_KEY: "false" + AWS_CLOUD_WATCH_LOGGING_ENABLED: "false" command: develop depends_on: - mongo diff --git a/entrypoint.sh b/entrypoint.sh index 4cb2938..74894c1 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -4,7 +4,7 @@ set -e case "$1" in develop) echo "Running Development Server" - exec grunt --gruntfile app/Gruntfile.js | bunyan + exec npx grunt --gruntfile app/Gruntfile.js | npx bunyan ;; startDev) echo "Running Start Dev" diff --git a/package.json b/package.json index 153a9db..d3d8791 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "keywords": [], "license": "ISC", "engines": { - "node": "~20.4" + "node": "~20.5" }, "author": { "name": "Vizzuality", @@ -32,6 +32,8 @@ "eslint-plugin-react": "^7.30.0", "grunt": "^1.5.3", "grunt-cli": "^1.3.2", + "grunt-contrib-watch": "^1.1.0", + "grunt-express-server": "^0.5.4", "grunt-mocha-test": "^0.13.3", "grunt-simple-nyc": "^3.0.1", "husky": "^3.0.9", diff --git a/yarn.lock b/yarn.lock index 613c008..a315468 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1755,6 +1755,13 @@ ast-types-flow@^0.0.7: resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= +async@^2.6.0: + version "2.6.4" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== + dependencies: + lodash "^4.17.14" + async@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/async/-/async-3.1.0.tgz#42b3b12ae1b74927b5217d8c0016baaf62463772" @@ -1913,6 +1920,16 @@ bluebird@^3.5.0: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w== +body@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" + integrity sha512-chUsBxGRtuElD6fmw1gHLpvnKdVLK302peeFa9ZqAEk8TyzZ3fygLyUEDDPTJvL9+Bor0dIwn6ePOsRM2y0zQQ== + dependencies: + continuable-cache "^0.3.1" + error "^7.0.0" + raw-body "~1.1.0" + safe-json-parse "~1.0.1" + bowser@^2.11.0: version "2.11.0" resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" @@ -2009,6 +2026,11 @@ bunyan@^1.8.15: mv "~2" safe-json-stringify "~1" +bytes@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" + integrity sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ== + bytes@3.1.0, bytes@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" @@ -2390,6 +2412,11 @@ content-type@^1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== +continuable-cache@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" + integrity sha512-TF30kpKhTH8AGCG3dut0rdd/19B7Z+qCnrMoBLpyQu/2drZdNrrpcjPEoJeSVsQM+8KmWG5O56oPDjSSUsuTyA== + convert-source-map@^1.6.0: version "1.7.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" @@ -2802,6 +2829,13 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +error@^7.0.0: + version "7.2.1" + resolved "https://registry.yarnpkg.com/error/-/error-7.2.1.tgz#eab21a4689b5f684fc83da84a0e390de82d94894" + integrity sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA== + dependencies: + string-template "~0.2.1" + es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5, es-abstract@^1.20.0: version "1.20.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814" @@ -3233,6 +3267,13 @@ fastq@^1.6.0: dependencies: reusify "^1.0.0" +faye-websocket@~0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + integrity sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ== + dependencies: + websocket-driver ">=0.5.1" + figures@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" @@ -3539,6 +3580,13 @@ functions-have-names@^1.2.2: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== +gaze@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" + integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== + dependencies: + globule "^1.0.0" + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -3654,7 +3702,7 @@ glob@^6.0.1: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.3, glob@~7.1.6: +glob@^7.1.3, glob@~7.1.1, glob@~7.1.6: version "7.1.7" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== @@ -3735,6 +3783,15 @@ globby@^10.0.1: merge2 "^1.2.3" slash "^3.0.0" +globule@^1.0.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.3.4.tgz#7c11c43056055a75a6e68294453c17f2796170fb" + integrity sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg== + dependencies: + glob "~7.1.1" + lodash "^4.17.21" + minimatch "~3.0.2" + graceful-fs@^4.1.11, graceful-fs@^4.1.2: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" @@ -3772,6 +3829,21 @@ grunt-cli@~1.4.3: nopt "~4.0.1" v8flags "~3.2.0" +grunt-contrib-watch@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/grunt-contrib-watch/-/grunt-contrib-watch-1.1.0.tgz#c143ca5b824b288a024b856639a5345aedb78ed4" + integrity sha512-yGweN+0DW5yM+oo58fRu/XIRrPcn3r4tQx+nL7eMRwjpvk+rQY6R8o94BPK0i2UhTg9FN21hS+m8vR8v9vXfeg== + dependencies: + async "^2.6.0" + gaze "^1.1.0" + lodash "^4.17.10" + tiny-lr "^1.1.1" + +grunt-express-server@^0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/grunt-express-server/-/grunt-express-server-0.5.4.tgz#8ce79c335c6cbb9ef50ee1dfaa61942028f43aeb" + integrity sha512-Q9sTDOwxC46uviL1/LSXFflTMv+/WnwANtzxD7hwnEXaej79LS1AUZlWc/O5P+CWjKG69/1xJFn+CVP94fOQ6Q== + grunt-known-options@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/grunt-known-options/-/grunt-known-options-1.1.1.tgz#6cc088107bd0219dc5d3e57d91923f469059804d" @@ -4055,6 +4127,11 @@ http-errors@~1.6.2: setprototypeof "1.1.0" statuses ">= 1.4.0 < 2" +http-parser-js@>=0.5.1: + version "0.5.8" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" + integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== + http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -5094,6 +5171,11 @@ listr@^0.14.3: p-map "^2.0.0" rxjs "^6.3.3" +livereload-js@^2.3.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.4.0.tgz#447c31cf1ea9ab52fc20db615c5ddf678f78009c" + integrity sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw== + load-grunt-tasks@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/load-grunt-tasks/-/load-grunt-tasks-5.1.0.tgz#14894c27a7e34ebbef9937c39cc35c573cd04c1c" @@ -5194,16 +5276,16 @@ lodash@^3.9.3: resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y= +lodash@^4.17.10, lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.21, lodash@~4.17.19, lodash@~4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.2, lodash@^4.17.4: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== -lodash@^4.17.19, lodash@~4.17.19, lodash@~4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - log-symbols@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" @@ -5398,6 +5480,13 @@ minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@~3.0.2: + version "3.0.8" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.8.tgz#5e6a59bd11e2ab0de1cfb843eb2d82e546c321c1" + integrity sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q== + dependencies: + brace-expansion "^1.1.7" + minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" @@ -6377,6 +6466,14 @@ raw-body@^2.2.0: iconv-lite "0.4.24" unpipe "1.0.0" +raw-body@~1.1.0: + version "1.1.7" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" + integrity sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg== + dependencies: + bytes "1" + string_decoder "0.10" + react-is@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -6754,11 +6851,16 @@ safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, s resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +safe-json-parse@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" + integrity sha512-o0JmTu17WGUaUOHa1l0FPGXKBfijbxK6qoHzlkihsDXxzBHvJcA7zgviKR92Xs841rX9pK16unfphLq0/KqX7A== + safe-json-stringify@~1: version "1.2.0" resolved "https://registry.yarnpkg.com/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz#356e44bc98f1f93ce45df14bcd7c01cda86e0afd" @@ -7120,6 +7222,11 @@ string-argv@^0.3.0: resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== +string-template@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + integrity sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw== + string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -7196,6 +7303,11 @@ string.prototype.trimstart@^1.0.5: define-properties "^1.1.4" es-abstract "^1.19.5" +string_decoder@0.10: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -7390,6 +7502,18 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= +tiny-lr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" + integrity sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA== + dependencies: + body "^5.1.0" + debug "^3.1.0" + faye-websocket "~0.10.0" + livereload-js "^2.3.0" + object-assign "^4.1.0" + qs "^6.4.0" + tmp@0.0.31: version "0.0.31" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" @@ -7698,6 +7822,20 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +websocket-driver@>=0.5.1: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"