Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/microservice/register.json
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,14 @@
"method": "GET",
"path": "/api/v1/area/:id/alerts"
}
},{
"path": "/v1/area/find/:id",
"method": "GET",
"authenticated": true,
"redirect": {
"method": "GET",
"path": "/api/v1/area/find/:id"
}
},{
"path": "/v1/download-tiles/:geostoreId/:minZoom/:maxZoom",
"method": "GET",
Expand Down
3 changes: 2 additions & 1 deletion app/src/models/area.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ const Area = new Schema({
datasets: [Dataset],
createdAt: { type: Date, required: true, default: Date.now },
image: { type: String, required: false, trim: true },
templateId: { type: String, trim: true, required: false }
templateId: { type: String, trim: true, required: false },
templateIds: { type: Array, required: false, default: [] }
});


Expand Down
38 changes: 37 additions & 1 deletion app/src/routes/api/v1/area.router.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const AreaValidator = require('validators/area.validator');
const AlertsService = require('services/alerts.service');
const TeamService = require('services/team.service');
const s3Service = require('services/s3.service');
const config = require('config');

const router = new Router({
prefix: '/area',
Expand Down Expand Up @@ -83,11 +84,22 @@ class AreaRouter {
await AreaRouter.saveArea(ctx, ctx.params.userId);
}

// returns all area ID's which include the templateID given
static async getAOIs(ctx) {
const area = await AreaModel.find({ $or: [{ templateIds: ctx.params.id }, { templateId: ctx.params.id }] }, {
_id: 1
});
ctx.body = AreaSerializer.serialize(area);
}


static async saveArea(ctx, userId) {
logger.info('Saving area');
let image = '';
if (ctx.request.files && ctx.request.files.image) {
image = await s3Service.uploadFile(ctx.request.files.image.path, ctx.request.files.image.name);
} else {
image = config.get('image.PLACEHOLDER');
}
let datasets = [];
if (ctx.request.body.datasets) {
Expand Down Expand Up @@ -152,11 +164,34 @@ class AreaRouter {
if (ctx.request.body.datasets) {
area.datasets = JSON.parse(ctx.request.body.datasets);
}
// image fall back
if (files && files.image) {
area.image = await s3Service.uploadFile(files.image.path, files.image.name);
} else {
area.image = config.get('image.PLACEHOLDER');
}
if (typeof ctx.request.body.templateId !== 'undefined') {
area.templateId = ctx.request.body.templateId;

if (ctx.request.body.override === true) {
logger.debug('debug', ctx.request.body.templateId);

const { templateId } = ctx.request.body;
await AreaModel.findOneAndUpdate(
{ _id: ctx.params.id },
{ $pull: { templateIds: templateId.toString() } }
);
} else {
// backward compatibility - templateIds is the new version
// templateId is for backward compatibility
const templateIds = ctx.request.body.templateId;
if (templateIds.constructor === Array) {
// eslint-disable-next-line prefer-destructuring
area.templateId = ctx.request.body.templateId[0];
} else {
area.templateId = ctx.request.body.templateId;
}
area.templateIds.addToSet(ctx.request.body.templateId);
}
}
area.updatedDate = Date.now;

Expand Down Expand Up @@ -276,6 +311,7 @@ async function unwrapJSONStrings(ctx, next) {

router.post('/', loggedUserToState, unwrapJSONStrings, AreaValidator.create, AreaRouter.save);
router.patch('/:id', loggedUserToState, checkPermission, unwrapJSONStrings, AreaValidator.update, AreaRouter.update);
router.get('/find/:id', loggedUserToState, AreaRouter.getAOIs);
router.get('/', loggedUserToState, AreaRouter.getAll);
router.get('/fw', loggedUserToState, AreaRouter.getFWAreas);
router.post('/fw/:userId', loggedUserToState, AreaValidator.create, AreaRouter.saveByUserId);
Expand Down
3 changes: 2 additions & 1 deletion app/src/serializers/area.serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ const areaSerializer = new JSONAPISerializer('area', {
'datasets',
'use',
'iso',
'templateId'
'templateId',
'templateIds'
],
resource: {
attributes: ['type', 'content']
Expand Down
14 changes: 12 additions & 2 deletions app/src/services/download.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,21 @@ class DownloadService {
}
}
if (promises.length > 0) {
await Promise.all(promises);
// map the promises which error to the error promise array, retry those requests.
// If they fail then catch them as null
// This will result in missing tiles however will not fall over
const errors = [];
await Promise.all(promises.map((p) => p.catch(() => errors.push(p))));
if (errors.length > 0) {
await Promise.all(errors.map((p) => p.catch(() => null)));
logger.debug(errors);
}
promises = null;
}
// eslint-disable-next-line no-empty
} catch (err) {}
} catch (err) {
logger.debug(err);
}
await DownloadService.zipFolder(tmpobj.name, `${tmpDownload.name}/download.zip`);
logger.info('Removing file ', tmpobj.name);
await DownloadService.removeFolder(tmpobj.name);
Expand Down
1 change: 1 addition & 0 deletions app/test/e2e/utils/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const createArea = (anotherData = {}) => ({
image: '',
createdAt: new Date(),
wdpaid: 1,
templateId: 'updatedTemplateId',
...anotherData
});

Expand Down
58 changes: 58 additions & 0 deletions app/test/e2e/v1/update-area.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,64 @@ describe('Update area - V1', () => {
});
});

it('Update area with multiple template ids who is logged in', async () => {
const testArea = await new Area(createArea({ userId: USERS.USER.id })).save();

const response = await requester
.patch(`/api/v1/area/${testArea.id}`)
.send({
loggedUser: USERS.USER,
name: 'Portugal area',
application: 'rw',
geostore: '713899292fc118a915741728ef84a2a7',
wdpaid: 3,
use: {
id: 'bbb',
name: 'updated name'
},
iso: {
country: 'updatedCountryIso',
region: 'updatedRegionIso'
},
datasets: '[{"slug":"viirs","name":"VIIRS","startDate":"7","endDate":"1","lastUpdate":1513793462776.0,"_id":"5a3aa9eb98b5910011731f66","active":true,"cache":true}]',
templateId: 'firstUpdatedID'
});

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').and.equal(testArea.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(testArea.userId);
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: 'updated name'
});
response.body.data.attributes.should.have.property('iso').and.deep.equal({
country: 'updatedCountryIso',
region: 'updatedRegionIso'
});
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',
lastUpdate: 1513793462776
});
response.body.data.attributes.should.have.property('templateId').and.equal('firstUpdatedID');
response.body.data.attributes.should.have.property('templateIds').and.be.an('array');
});


afterEach(async () => {
if (!nock.isDone()) {
throw new Error(`Not all nock interceptors were used: ${nock.pendingMocks()}`);
Expand Down
3 changes: 3 additions & 0 deletions config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
"host": "127.0.0.1",
"port": 27017
},
"image": {
"PLACEHOLDER": "https://glowvarietyshow.com/wp-content/uploads/2017/03/placeholder-image.jpg"
},
"gladDataset": "f8662607-02cc-4bfb-9bb3-06b25c9ecade",
"viirsDataset": "f8662607-02cc-4bfb-9bb3-06b25c9ecade",
"viirsDatasetTableName": "vnp14imgtdl_nrt_global_7d",
Expand Down
69 changes: 48 additions & 21 deletions k8s/production/deployment.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: gfw
namespace: fw
labels:
name: {name}
app: gfw
Expand All @@ -10,9 +10,25 @@ spec:
revisionHistoryLimit: 2
template:
metadata:
annotations:
chaos.alpha.kubernetes.io/enabled: "true"
labels:
name: {name}
spec:
tolerations:
- key: "type"
operator: "Equal"
value: "gfw"
effect: "NoSchedule"
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type
operator: In
values:
- gfw
containers:
- name: {name}
image: vizzuality/{name}
Expand All @@ -28,24 +44,29 @@ spec:
- start
env:
- name: PORT
value: "4100"
value: "4400"
- name: NODE_ENV
value: prod
- name: NODE_PATH
value: app/src
- name: LOCAL_URL
value: http://{name}.gfw.svc.cluster.local:4100
- name: GLAD_DATASET
value: e663eb09-04de-4f39-b871-35c6c2ed10b5
- name: VIIRS_DATASET
value: 20cc5eca-8c63-4c41-8e8e-134dcf1e6d76
- name: VIIRS_DATASET_TABLENAME
value: vnp14imgtdl_nrt_global_7d
value: http://{name}.fw.svc.cluster.local:4400
- name: QUEUE_PROVIDER
value: redis
- name: QUEUE_NAME
value: mail_prod
- name: WRI_MAIL_RECIPIENTS
value: mweisse@wri.org
- name: MONGO_URI
valueFrom:
secretKeyRef:
name: dbsecrets
key: AREA_MONGO_URI
key: FORMS_MONGO_URI
- name: QUEUE_URL
valueFrom:
secretKeyRef:
name: dbsecrets
key: REDIS_URI
- name: CT_URL
valueFrom:
secretKeyRef:
Expand All @@ -70,42 +91,48 @@ spec:
valueFrom:
secretKeyRef:
name: mssecrets
key: AREA_S3_ACCESS_KEY_ID
key: FORMS_S3_ACCESS_KEY_ID
- name: S3_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: mssecrets
key: AREA_S3_SECRET_ACCESS_KEY
key: FORMS_S3_SECRET_ACCESS_KEY
- name: S3_BUCKET
value: forest-watcher-files
- name: AOI_DATA_S3_ACCESS_KEY_ID
- name: GOOGLE_PRIVATE_KEY
valueFrom:
secretKeyRef:
name: mssecrets
key: AREA_AOI_DATA_S3_ACCESS_KEY_ID
- name: AOI_DATA_S3_SECRET_ACCESS_KEY
key: FORMS_GOOGLE_PRIVATE_KEY
- name: GOOGLE_PROJECT_EMAIL
valueFrom:
secretKeyRef:
name: mssecrets
key: AREA_AOI_DATA_S3_SECRET_ACCESS_KEY
- name: AOI_DATA_S3_BUCKET
value: gfw-pipelines
key: FORMS_GOOGLE_PROJECT_EMAIL
- name: TARGET_SHEET_ID
value: 1oCRTDUlaaadA_xVCWTQ9BaCLxY8do0uSQYGLXu0fQ1k
- name: TARGET_SHEET_INDEX
value: "1"
- name: LEGACY_TEMPLATE_ID
value: "597b0f55856351000b087c9c"
- name: DEFAULT_TEMPLATE_ID
value: "59b6a26b138f260012e9fdeb"

ports:
- containerPort: 4100
- containerPort: 4400
readinessProbe:
httpGet:
scheme: HTTP
path: /healthcheck
port: 4100
port: 4400
initialDelaySeconds: 30
timeoutSeconds: 5
periodSeconds: 15
livenessProbe:
httpGet:
scheme: HTTP
path: /healthcheck
port: 4100
port: 4400
failureThreshold: 3
initialDelaySeconds: 30
timeoutSeconds: 5
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,11 @@
"koa-send": "^5.0.0",
"koa-simple-healthcheck": "0.0.1",
"koa-validate": "^1.0.7",
"lint": "^0.7.0",
"moment": "^2.10.6",
"mustache": "^2.3.0",
"mongoose": "^5.7.11",
"mongoose-history": "^0.8.0",
"mustache": "^2.3.0",
"ngeohash": "^0.6.0",
"request": "^2.79.0",
"request-promise": "^4.1.1",
Expand Down