Skip to content

Commit

Permalink
Code changes and tests for read only fields
Browse files Browse the repository at this point in the history
  • Loading branch information
pallavi2209 committed Mar 22, 2017
1 parent 5c75891 commit edec116
Show file tree
Hide file tree
Showing 19 changed files with 694 additions and 85 deletions.
11 changes: 0 additions & 11 deletions api/v1/apiErrors.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,6 @@ apiErrors.create({
fields: [],
});

apiErrors.create({
code: 11101,
status: 400,
name: 'SubjectValidationError',
parent: apiErrors.ValidationError,
fields: [],
defaultMessage: 'You are not allowed to set the subject\'s absolutePath ' +
'attribute directly--it is generated based on the subject\'s name and ' +
'parent.',
});

apiErrors.create({
code: 11102,
status: 400,
Expand Down
16 changes: 13 additions & 3 deletions api/v1/controllers/aspects.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ function validateTags(requestBody, params) {
}
}

/**
* Validates the aspect request coming in and throws an error if the request
* does not pass the validation.
* @param {Object} req - The request object
*/
function validateRequest(req) {
utils.noReadOnlyFieldsInReq(req, helper);
validateTags(req.body);
} // validateRequest

module.exports = {

/**
Expand Down Expand Up @@ -184,7 +194,7 @@ module.exports = {
* @param {Function} next - The next middleware function in the stack
*/
patchAspect(req, res, next) {
validateTags(req.body);
validateRequest(req);
doPatch(req, res, next, helper);
},

Expand All @@ -198,7 +208,7 @@ module.exports = {
* @param {Function} next - The next middleware function in the stack
*/
postAspect(req, res, next) {
validateTags(req.body);
validateRequest(req);
doPost(req, res, next, helper);
},

Expand All @@ -213,7 +223,7 @@ module.exports = {
* @param {Function} next - The next middleware function in the stack
*/
putAspect(req, res, next) {
validateTags(req.body);
validateRequest(req);
doPut(req, res, next, helper);
},

Expand Down
7 changes: 6 additions & 1 deletion api/v1/controllers/samples.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ const httpStatus = require('../constants').httpStatus;
const sampleStore = require('../../../cache/sampleStore');
const constants = sampleStore.constants;
const redisModelSample = require('../../../cache/models/samples');
const utils = require('./utils');
const publisher = u.publisher;
const event = u.realtimeEvents;
module.exports = {

/**
Expand Down Expand Up @@ -98,6 +98,7 @@ module.exports = {
* @param {Function} next - The next middleware function in the stack
*/
patchSample(req, res, next) {
utils.noReadOnlyFieldsInReq(req, helper);
doPatch(req, res, next, helper);
},

Expand All @@ -111,6 +112,7 @@ module.exports = {
* @param {Function} next - The next middleware function in the stack
*/
postSample(req, res, next) {
utils.noReadOnlyFieldsInReq(req, helper);
doPost(req, res, next, helper);
},

Expand All @@ -125,6 +127,7 @@ module.exports = {
* @param {Function} next - The next middleware function in the stack
*/
putSample(req, res, next) {
utils.noReadOnlyFieldsInReq(req, helper);
doPut(req, res, next, helper);
},

Expand All @@ -140,6 +143,7 @@ module.exports = {
* @param {Function} next - The next middleware function in the stack
*/
upsertSample(req, res, next) {
utils.noReadOnlyFieldsInReq(req, helper);
const resultObj = { reqStartTime: new Date() };
const sampleQueryBody = req.swagger.params.queryBody.value;

Expand Down Expand Up @@ -193,6 +197,7 @@ module.exports = {
* bulk upsert request has been received.
*/
bulkUpsertSample(req, res/* , next */) {
utils.noReadOnlyFieldsInReq(req, helper);
const resultObj = { reqStartTime: new Date() };
const reqStartTime = Date.now();
const value = req.swagger.params.queryBody.value;
Expand Down
23 changes: 1 addition & 22 deletions api/v1/controllers/subjects.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,41 +70,20 @@ function validateTags(requestBody, params) {
tags = params.tags.value ? params.tags.value.split(',') : [];
}

if (absolutePath) {
throw new apiErrors.SubjectValidationError();
}

if (tags && tags.length) {
if (utils.hasDuplicates(tags)) {
throw new apiErrors.DuplicateFieldError();
}
}
} // validateTags

/**
* Throws a validation error if the read-only fields are found in the request.
* @param {Object} req - The request object
*/
function noReadOnlyFieldsInReq(req) {
const requestBody = req.body;
if (helper.readOnlyFields) {
helper.readOnlyFields.forEach((field) => {
if (requestBody[field]) {
throw new apiErrors.ValidationError(
{ explanation: `You cannot modify the read-only field: ${field}` }
);
}
});
}
} // noReadOnlyFieldsInReq

/**
* Validates the subject request coming in and throws an error if the request
* does not pass the validation.
* @param {Object} req - The request object
*/
function validateRequest(req) {
noReadOnlyFieldsInReq(req);
utils.noReadOnlyFieldsInReq(req, helper);
validateTags(req.body);
} // validateRequest

Expand Down
39 changes: 39 additions & 0 deletions api/v1/controllers/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/**
* api/v1/controllers/utils.js
*/
const apiErrors = require('../apiErrors');
const ZERO = 0;
const ONE = 1;

Expand Down Expand Up @@ -44,6 +45,44 @@ function hasDuplicates(tagsArr) {
return false;
}

/**
* Check if read only field exists in given object
* @param {String} field - Field name
* @param {Object} obj - Request object
* @throws {Object} - Throws validation error is field exists
*/
function checkReadOnlyFieldInObj(field, obj) {
if (obj.hasOwnProperty(field)) {
throw new apiErrors.ValidationError(
{ explanation: `You cannot modify the read-only field: ${field}` }
);
}
}

/**
* Throws a validation error if the read-only fields are found in the request.
* @param {Object} req - The request object
* @param {Object} props - The module containing the properties of the
* resource type.
*/
function noReadOnlyFieldsInReq(req, props) {
const requestBody = req.body;
if (props.readOnlyFields) {
props.readOnlyFields.forEach((field) => {
// if request body is an array, check each object in array.
if (typeof requestBody !== 'undefined' &&
requestBody && requestBody.constructor === Array) {
requestBody.forEach((reqObj) => {
checkReadOnlyFieldInObj(field, reqObj);
});
} else {
checkReadOnlyFieldInObj(field, requestBody);
}
});
}
} // noReadOnlyFieldsInReq

module.exports = {
hasDuplicates,
noReadOnlyFieldsInReq,
};
1 change: 1 addition & 0 deletions api/v1/helpers/nouns/aspects.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ module.exports = {
fieldsWithJsonArrayType,
fieldsWithEnum,
tagFilterName: 'tags',
readOnlyFields: ['id', 'isDeleted'],
}; // exports
4 changes: 4 additions & 0 deletions api/v1/helpers/nouns/samples.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,8 @@ module.exports = {
fieldsWithJsonArrayType,
fieldsWithEnum,
fieldsToExclude,
readOnlyFields: [
'id', 'isDeleted', 'status', 'previousStatus',
'statusChangedAt', 'createdAt', 'updatedAt',
],
}; // exports
4 changes: 3 additions & 1 deletion api/v1/helpers/nouns/subjects.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,5 +173,7 @@ module.exports = {
fieldsWithJsonArrayType,
fieldsWithArrayType,
tagFilterName: 'tags',
readOnlyFields: ['hierarchyLevel'],
readOnlyFields: [
'hierarchyLevel', 'absolutePath', 'childCount', 'id', 'isDeleted',
],
}; // exports
34 changes: 33 additions & 1 deletion tests/api/v1/aspects/patch.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/**
* tests/api/v1/aspects/patch.js
*/
'use strict';
'use strict'; // eslint-disable-line strict

const supertest = require('supertest');
const api = supertest(require('../../../../index').app);
Expand Down Expand Up @@ -166,6 +166,38 @@ describe(`api: PATCH ${path}`, () => {
done();
});
});

it('patching with readOnly field isDeleted should fail', (done) => {
api.patch(`${path}/${i}`)
.set('Authorization', token)
.send({ isDeleted: 0 })
.expect(constants.httpStatus.BAD_REQUEST)
.end((err, res) => {
if (err) {
return done(err);
}

expect(res.body.errors[0].description).to
.contain('You cannot modify the read-only field: isDeleted');
return done();
});
});

it('patching with readOnly field id should fail', (done) => {
api.patch(`${path}/${i}`)
.set('Authorization', token)
.send({ id: 'abcdefgh' })
.expect(constants.httpStatus.BAD_REQUEST)
.end((err, res) => {
if (err) {
return done(err);
}

expect(res.body.errors[0].description).to
.contain('You cannot modify the read-only field: id');
return done();
});
});
});

describe(`api: PATCH ${path} isPublished`, () => {
Expand Down
44 changes: 43 additions & 1 deletion tests/api/v1/aspects/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/**
* tests/api/v1/aspects/post.js
*/
'use strict';
'use strict'; // eslint-disable-line strict

const supertest = require('supertest');
const api = supertest(require('../../../../index').app);
Expand Down Expand Up @@ -49,6 +49,48 @@ describe(`api: POST ${path}`, () => {
});
});

it('posting with readOnly field id should fail', (done) => {
api.post(path)
.set('Authorization', token)
.send({
name: `${tu.namePrefix}ASPECTNAME`,
isPublished: true,
timeout: '110s',
id: 'abcd1234',
})
.expect(constants.httpStatus.BAD_REQUEST)
.end((err, res) => {
if (err) {
return done(err);
}

expect(res.body.errors[0].description).to
.contain('You cannot modify the read-only field: id');
return done();
});
});

it('posting with readOnly field isDeleted should fail', (done) => {
api.post(path)
.set('Authorization', token)
.send({
name: `${tu.namePrefix}ASPECTNAME`,
isPublished: true,
timeout: '110s',
isDeleted: 0,
})
.expect(constants.httpStatus.BAD_REQUEST)
.end((err, res) => {
if (err) {
return done(err);
}

expect(res.body.errors[0].description).to
.contain('You cannot modify the read-only field: isDeleted');
return done();
});
});

describe('post duplicate fails', () => {
beforeEach((done) => {
Aspect.create(u.toCreate)
Expand Down
42 changes: 41 additions & 1 deletion tests/api/v1/aspects/put.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/**
* tests/api/v1/aspects/put.js
*/
'use strict';
'use strict'; // eslint-disable-line strict

const supertest = require('supertest');
const api = supertest(require('../../../../index').app);
Expand Down Expand Up @@ -184,6 +184,46 @@ describe(`api: PUT ${path}`, () => {
});
});

it('put with readOnly field id should fail', (done) => {
api.put(`${path}/${aspectId}`)
.set('Authorization', token)
.send({
name: `${tu.namePrefix}newName`,
timeout: '220s',
id: 'abcd1234',
})
.expect(constants.httpStatus.BAD_REQUEST)
.end((err, res) => {
if (err) {
return done(err);
}

expect(res.body.errors[0].description).to
.contain('You cannot modify the read-only field: id');
return done();
});
});

it('put with readOnly field isDeleted should fail', (done) => {
api.put(`${path}/${aspectId}`)
.set('Authorization', token)
.send({
name: `${tu.namePrefix}newName`,
timeout: '220s',
isDeleted: 0,
})
.expect(constants.httpStatus.BAD_REQUEST)
.end((err, res) => {
if (err) {
return done(err);
}

expect(res.body.errors[0].description).to
.contain('You cannot modify the read-only field: isDeleted');
return done();
});
});

describe('with tags', () => {
it('update to add tags', (done) => {
const toPut = {
Expand Down

0 comments on commit edec116

Please sign in to comment.