2016-01-26 18:03:52 +01:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Module dependencies
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Public node modules.
|
|
|
|
const _ = require('lodash');
|
2016-01-28 16:12:16 +01:00
|
|
|
const utils = require('../utils/utils');
|
2016-01-26 18:03:52 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* JSON API helper
|
|
|
|
*/
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
|
|
|
|
default: {},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse request
|
|
|
|
*/
|
|
|
|
|
2016-01-28 16:12:16 +01:00
|
|
|
parse: function * (ctx) {
|
2016-01-27 14:20:09 +01:00
|
|
|
switch (ctx.method.toUpperCase()) {
|
|
|
|
case 'GET':
|
|
|
|
console.log('GET');
|
|
|
|
break;
|
2016-01-28 16:12:16 +01:00
|
|
|
case 'PATCH':
|
2016-01-27 14:20:09 +01:00
|
|
|
case 'POST':
|
2016-01-28 16:12:16 +01:00
|
|
|
try {
|
|
|
|
yield this.fetchSchema(ctx);
|
|
|
|
yield this.formatBody(ctx);
|
|
|
|
} catch (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2016-01-27 14:20:09 +01:00
|
|
|
break;
|
|
|
|
case 'DELETE':
|
|
|
|
console.log('DELETE');
|
|
|
|
break;
|
|
|
|
default:
|
2016-01-28 16:12:16 +01:00
|
|
|
throw {
|
|
|
|
status: 403,
|
|
|
|
body: 'Invalid HTTP method'
|
|
|
|
};
|
2016-01-27 14:20:09 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-01-28 16:12:16 +01:00
|
|
|
/**
|
|
|
|
* Format attributes for more simple API
|
|
|
|
*/
|
|
|
|
|
|
|
|
formatBody: function * (ctx) {
|
|
|
|
const body = ctx.request.body;
|
|
|
|
const values = _.assign({}, body.data.attributes);
|
|
|
|
|
|
|
|
_.forEach(body.data.relationships, function (relation, key) {
|
|
|
|
values[key] = _.isArray(relation.data) ? _.map(relation.data, 'id') : relation.data.id;
|
|
|
|
});
|
|
|
|
|
|
|
|
ctx.request.body = values;
|
|
|
|
},
|
|
|
|
|
2016-01-27 14:20:09 +01:00
|
|
|
/**
|
|
|
|
* Fetch attributes schema
|
|
|
|
*/
|
|
|
|
|
2016-01-28 16:12:16 +01:00
|
|
|
fetchSchema: function * (ctx) {
|
|
|
|
const body = ctx.request.body;
|
2016-01-27 14:20:09 +01:00
|
|
|
|
2016-01-28 16:12:16 +01:00
|
|
|
if (!body.hasOwnProperty('data')) {
|
|
|
|
throw {
|
2016-01-27 16:45:44 +01:00
|
|
|
status: 403,
|
|
|
|
body: 'Missing `data` member'
|
2016-01-28 16:12:16 +01:00
|
|
|
};
|
|
|
|
} else if (!utils.isRessourceObject(body.data) && ctx.method !== 'POST') {
|
|
|
|
throw {
|
2016-01-27 16:45:44 +01:00
|
|
|
status: 403,
|
2016-01-28 16:12:16 +01:00
|
|
|
body: 'Invalid ressource object'
|
|
|
|
};
|
|
|
|
} else if (!body.data.hasOwnProperty('type') && ctx.method === 'POST') {
|
|
|
|
throw {
|
2016-01-27 16:45:44 +01:00
|
|
|
status: 403,
|
2016-01-28 16:12:16 +01:00
|
|
|
body: 'Invalid ressource object'
|
|
|
|
};
|
|
|
|
} else if (!strapi.models.hasOwnProperty(body.data.type)) {
|
|
|
|
throw {
|
|
|
|
status: 403,
|
|
|
|
body: 'Unknow `type` ' + body.data.type
|
|
|
|
};
|
2016-01-27 14:20:09 +01:00
|
|
|
}
|
2016-01-27 16:45:44 +01:00
|
|
|
|
|
|
|
// Extract required attributes
|
2016-01-28 16:12:16 +01:00
|
|
|
const requiredAttributes = _.omit(_.mapValues(strapi.models[body.data.type].attributes, function (attr) {
|
|
|
|
return (attr.required && attr.type) ? attr : undefined;
|
2016-01-27 16:45:44 +01:00
|
|
|
}), _.isUndefined);
|
|
|
|
// Identify missing attributes
|
2016-01-28 16:12:16 +01:00
|
|
|
const missingAttributes = body.data.hasOwnProperty('attributes') ? _.difference(_.keys(requiredAttributes), _.keys(body.data.attributes)) : null;
|
2016-01-27 16:45:44 +01:00
|
|
|
|
|
|
|
if (!_.isEmpty(missingAttributes)) {
|
2016-01-28 16:12:16 +01:00
|
|
|
throw {
|
2016-01-27 16:45:44 +01:00
|
|
|
status: 403,
|
|
|
|
body: 'Missing required attributes (' + missingAttributes.toString() + ')'
|
2016-01-28 16:12:16 +01:00
|
|
|
};
|
2016-01-27 16:45:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Extract required relationships
|
2016-01-28 16:12:16 +01:00
|
|
|
const requiredRelationships = _.omit(_.mapValues(strapi.models[body.data.type].attributes, function (attr) {
|
|
|
|
return (attr.required && (attr.model || attr.collection)) ? attr : undefined;
|
|
|
|
}), _.isUndefined);
|
2016-01-27 16:45:44 +01:00
|
|
|
// Identify missing relationships
|
2016-01-28 16:12:16 +01:00
|
|
|
const missingRelationships = body.data.hasOwnProperty('relationships') ? _.difference(_.keys(requiredRelationships), _.keys(body.data.relationships)) : null;
|
2016-01-27 16:45:44 +01:00
|
|
|
|
|
|
|
if (!_.isEmpty(missingRelationships)) {
|
2016-01-28 16:12:16 +01:00
|
|
|
throw {
|
2016-01-27 16:45:44 +01:00
|
|
|
status: 403,
|
|
|
|
body: 'Missing required relationships (' + missingRelationships.toString() + ')'
|
2016-01-28 16:12:16 +01:00
|
|
|
};
|
2016-01-27 16:45:44 +01:00
|
|
|
}
|
|
|
|
|
2016-01-28 16:12:16 +01:00
|
|
|
// Build array of errors
|
|
|
|
if (_.size(requiredRelationships)) {
|
|
|
|
const errors = _.remove(_.flattenDeep(_.map(body.data.relationships, function (relation, key) {
|
|
|
|
if (!relation.hasOwnProperty('data')) {
|
|
|
|
return 'Missing `data` member for relationships ' + relation;
|
|
|
|
} else if (_.isArray(relation.data)) {
|
|
|
|
return _.map(relation.data, function (ressource) {
|
|
|
|
if (!utils.isRessourceObject(ressource)) {
|
|
|
|
return 'Invalid ressource object in relationships ' + key;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else if (!utils.isRessourceObject(relation.data)) {
|
|
|
|
return 'Invalid ressource object for relationships ' + key;
|
|
|
|
}
|
|
|
|
})), function (n) {
|
|
|
|
return !_.isUndefined(n);
|
|
|
|
});
|
2016-01-27 16:45:44 +01:00
|
|
|
|
2016-01-28 16:12:16 +01:00
|
|
|
if (!_.isEmpty(errors)) {
|
|
|
|
throw {
|
|
|
|
status: 403,
|
|
|
|
body: errors.toString()
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
2016-01-27 14:20:09 +01:00
|
|
|
}
|
2016-01-26 18:03:52 +01:00
|
|
|
};
|