Skip to content

Commit

Permalink
Merge branch 'master' into testforsample
Browse files Browse the repository at this point in the history
  • Loading branch information
annyhe committed Dec 28, 2016
2 parents 52bf62a + 5e85640 commit 8b37ebe
Show file tree
Hide file tree
Showing 25 changed files with 610 additions and 124 deletions.
9 changes: 9 additions & 0 deletions api/v1/apiErrors.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ apiErrors.create({
'previously revoked, and vice versa.',
});

apiErrors.create({
code: 11103,
status: 400,
name: 'DuplicateFieldError',
parent: apiErrors.ValidationError,
fields: ['tags'],
defaultMessage: 'Tags are case-insensitive. Duplicates found',
});

// ----------------------------------------------------------------------------
// Not Found
// ----------------------------------------------------------------------------
Expand Down
70 changes: 57 additions & 13 deletions api/v1/controllers/subjects.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,58 @@ const u = require('../helpers/verbs/utils');
const httpStatus = require('../constants').httpStatus;
const apiErrors = require('../apiErrors');
const logAPI = require('../../../utils/loggingUtil').logAPI;
const ZERO = 0;
const ONE = 1;

/**
* Given an array, return true if there
* are duplicates. False otherwise.
*
* @param {Array} tagsArr The input array
* @returns {Boolean} whether input array
* contains duplicates
*/
function checkDuplicates(tagsArr) {
const LEN = tagsArr.length - ONE;
// to store lowercase copies
const copyArr = [];
let toAdd;
for (let i = LEN; i >= ZERO; i--) {
toAdd = tagsArr[i].toLowerCase();
// if duplicate found, return true
if (copyArr.indexOf(toAdd) > -ONE) {
return true;
}
copyArr.push(toAdd);
}
return false;
}

/**
* Validates the given fields from request body or url.
* If fails, throws a corresponding error.
* @param {Object} requestBody Fields from request body
* @param {Object} params Fields from url
*/
function validateRequest(requestBody, params) {
let absolutePath = '';
let tags = [];
if (requestBody) {
tags = requestBody.tags;
absolutePath = requestBody.absolutePath;
} else if (params) {
// params.tags.value is a comma delimited string, not empty.
tags = params.tags.value ? params.tags.value.split(',') : [];
}
if (absolutePath) {
throw new apiErrors.SubjectValidationError();
}
if (tags && tags.length) {
if (checkDuplicates(tags)) {
throw new apiErrors.DuplicateFieldError();
}
}
}

module.exports = {

Expand Down Expand Up @@ -72,6 +124,7 @@ module.exports = {
* @param {Function} next - The next middleware function in the stack
*/
findSubjects(req, res, next) {
validateRequest(null, req.swagger.params);
doFind(req, res, next, helper);
},

Expand Down Expand Up @@ -105,7 +158,7 @@ module.exports = {
u.findByKey(helper, params, ['hierarchy', 'samples'])
.then((o) => {
let retval = u.responsify(o, helper, req.method);
if (depth > 0) {
if (depth > ZERO) {
retval = helper.deleteChildren(retval, depth);
}

Expand Down Expand Up @@ -208,10 +261,7 @@ module.exports = {
* @param {Function} next - The next middleware function in the stack
*/
patchSubject(req, res, next) {
if (req.body.absolutePath) {
throw new apiErrors.SubjectValidationError();
}

validateRequest(req.body);
doPatch(req, res, next, helper);
},

Expand All @@ -225,10 +275,7 @@ module.exports = {
* @param {Function} next - The next middleware function in the stack
*/
postSubject(req, res, next) {
if (req.body.absolutePath) {
throw new apiErrors.SubjectValidationError();
}

validateRequest(req.body);
doPost(req, res, next, helper);
},

Expand Down Expand Up @@ -268,10 +315,7 @@ module.exports = {
* @param {Function} next - The next middleware function in the stack
*/
putSubject(req, res, next) {
if (req.body.absolutePath) {
throw new apiErrors.SubjectValidationError();
}

validateRequest(req.body);
doPut(req, res, next, helper);
},

Expand Down
3 changes: 0 additions & 3 deletions api/v1/helpers/nouns/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ module.exports = {
POST: `Create a new ${m}`,
PUT: `Overwrite all attributes of this ${m}`,
},
scopeMap: {
withoutSensitiveInfo: 'withoutSensitiveInfo',
},
baseUrl: '/v1/users',
model: User,
modelName: 'User',
Expand Down
12 changes: 11 additions & 1 deletion api/v1/helpers/verbs/doFind.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,26 @@ function doFindAndCountAll(reqResNext, props, opts) {
* find command
*/
function doFindAll(reqResNext, props, opts) {
if (opts.where && opts.where.tags && opts.where.tags.$contains.length) {
// change to filter at the API level
opts.where.tags.$contains = [];
}

u.getScopedModel(props, opts.attributes).findAll(opts)
.then((o) => {
reqResNext.res.set(COUNT_HEADER_NAME, o.length);
const retval = o.map((row) => {
let retval = o.map((row) => {
if (props.modelName === 'Lens') {
delete row.dataValues.library;
}

return u.responsify(row, props, reqResNext.req.method);
});

const { tags } = reqResNext.req.swagger.params;
if (tags && tags.value && tags.value.length) {
retval = fu.filterArrFromArr(retval, tags.value);
}
reqResNext.res.status(httpStatus.OK).json(retval);
})
.catch((err) => u.handleError(reqResNext.next, err, props.modelName));
Expand Down
64 changes: 64 additions & 0 deletions api/v1/helpers/verbs/findUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,69 @@ function options(params, props) {
return opts;
} // options

/**
* Returns a filtered resource array,
* according to the supplied tag string
*
* @param {Array} sArr The array of resources
* to filter from
* @param {String} tagsStr Comma delimited String with
* tags to check for.
* @returns {Array} The filtered array
*/
function filterArrFromArr(sArr, tagsStr) {
const tagsArr = tagsStr.split(',');
const TAGLEN = tagsArr.length;
// assume TAGLEN has > 0 tags, since if ther's
// 0 tags express would've thrown an error
const INCLUDE = tagsArr[ZERO].charAt(ZERO) !== '-';
// if !INCLUDE, splice out the leading - in tags
// else throw exception if tag starts with -
for (let i = TAGLEN - ONE; i >= ZERO; i--) {
if (tagsArr[i].charAt(ZERO) === '-') {
if (INCLUDE) {
throw new Error('To specify EXCLUDE tags, ' +
'prepend each tag with -');
}
tagsArr[i] = tagsArr[i].slice(ONE);
}
}

let filteredArr = [];
// append iff subject's tags contains all tags in tagsArr
if (INCLUDE) {
for (let i = ZERO; i < sArr.length; i++) {
let count = ZERO;
const tags = sArr[i].tags;
for (let j = TAGLEN - ONE; j >= ZERO; j--) {
if (tags.indexOf(tagsArr[j]) > -ONE) {
count++;
}
}
if (count === TAGLEN) {
filteredArr.push(sArr[i]);
}
}
} else {
// EXCLUDE: append iff none of subject's tags
// is in tagsArr
for (let i = ZERO; i < sArr.length; i++) {
let addToArr = true;
const tags = sArr[i].tags;
for (let j = TAGLEN - ONE; j >= ZERO; j--) {
if (tags.indexOf(tagsArr[j]) > -ONE) {
addToArr = false;
break;
}
}
if (addToArr) {
filteredArr.push(sArr[i]);
}
}
}
return filteredArr;
}

/**
* Generates the "next" URL for paginated result sets.
*
Expand All @@ -244,4 +307,5 @@ function getNextUrl(url, limit, offset) {
module.exports = {
getNextUrl,
options,
filterArrFromArr, // for testing
}; // exports

0 comments on commit 8b37ebe

Please sign in to comment.