diff --git a/packages/strapi-bookshelf/lib/index.js b/packages/strapi-bookshelf/lib/index.js index d7909d18a9..ef1e7f36da 100755 --- a/packages/strapi-bookshelf/lib/index.js +++ b/packages/strapi-bookshelf/lib/index.js @@ -88,7 +88,7 @@ module.exports = function (strapi) { // Register the final model for Bookshelf. const loadedModel = { tableName: definition.tableName, - hasTimestamps: _.get(definition, 'options.timestamps') || true + hasTimestamps: _.get(definition, 'options.timestamps') === true }; // Initialize the global variable with the @@ -122,8 +122,17 @@ module.exports = function (strapi) { }); }; + loadedModel.hidden = _.keys(_.keyBy(_.filter(definition.attributes, (value, key) => { + if (value.hasOwnProperty('columnName') && !_.isEmpty(value.columnName) && value.columnName !== key) { + return true; + } + }), 'columnName')); + const ORM = new bookshelf(strapi.connections[connectionName]); + // Load plugins + ORM.plugin('visibility'); + global[globalName] = ORM.Model.extend(loadedModel); global[pluralize(globalName)] = ORM.Collection.extend({ model: global[globalName] @@ -165,20 +174,20 @@ module.exports = function (strapi) { } }); - loadedModel[name] = () => { - return this.hasOne(global[_.capitalize(details.model)], FK); + loadedModel[name] = function () { + return this.hasOne(global[_.capitalize(details.model)], _.get(strapi.models[details.model].attributes, `${FK}.columnName`) || FK); }; break; } case 'hasMany': { - loadedModel[name] = () => { + loadedModel[name] = function () { return this.hasMany(global[_.capitalize(details.collection)], details.via); }; break; } case 'belongsTo': { - loadedModel[name] = () => { - return this.belongsTo(global[_.capitalize(details.model)], name); + loadedModel[name] = function () { + return this.belongsTo(global[_.capitalize(details.model)], _.get(details, 'columnName') || name); }; break; } @@ -203,7 +212,7 @@ module.exports = function (strapi) { relationship.attribute = pluralize.singular(details.via); } - loadedModel[name] = () => { + loadedModel[name] = function () { return this.belongsToMany(global[_.capitalize(details.collection)], tableName, relationship.attribute + '_' + relationship.column, details.attribute + '_' + details.column); }; break; diff --git a/packages/strapi-generate-api/templates/bookshelf/controller.template b/packages/strapi-generate-api/templates/bookshelf/controller.template index 1ec66dcf4a..0ec8bc2b55 100755 --- a/packages/strapi-generate-api/templates/bookshelf/controller.template +++ b/packages/strapi-generate-api/templates/bookshelf/controller.template @@ -1,122 +1,114 @@ 'use strict'; /** - * A set of functions called "actions" for `<%= globalID %>` + * <%= filename %> controller + * + * @description: A set of functions called "actions" for managing `<%= globalID %>`. */ module.exports = { + /** - * Get <%= subId || id %> entries. + * Retrieve <%= subId || id %> records. * * @return {Object|Array} */ - find: async (ctx, next) => { - try { - ctx.body = await strapi.services.<%= subId || id %>.fetchAll(ctx.query); - } catch (err) { - ctx.body = err; - } + find: async (ctx) => { + const data = await strapi.services.<%= subId || id %>.fetchAll(ctx.query); + + // Send 200 `ok` + ctx.send(data); }, /** - * Get a specific <%= subId || id %>. - * - * @return {Object|Array} - */ - - findOne: async (ctx, next) => { - try { - ctx.body = await strapi.services.<%= subId || id %>.fetch(ctx.params) - } catch (err) { - ctx.body = err; - } - }, - - /** - * Create a/an <%= subId || id %> entry. + * Retrieve a <%= subId || id %> record. * * @return {Object} */ - create: async (ctx, next) => { - try { - ctx.body = await strapi.services.<%= subId || id %>.add(ctx.request.body); - } catch (err) { - ctx.body = err; - } + findOne: async (ctx) => { + const data = await strapi.services.<%= subId || id %>.fetch(ctx.params); + + // Send 200 `ok` + ctx.send(data); }, /** - * Update a/an <%= subId || id %> entry. + * Create a/an <%= subId || id %> record. + * + * @return {Object} + */ + + create: async (ctx) => { + const data = await strapi.services.<%= subId || id %>.add(ctx.request.body); + + // Send 201 `created` + ctx.created(data); + }, + + /** + * Update a/an <%= subId || id %> record. * * @return {Object} */ update: async (ctx, next) => { - try { - ctx.body = await strapi.services.<%= subId || id %>.edit(ctx.params, ctx.request.body) ; - } catch (err) { - ctx.body = err; - } + const data = await strapi.services.<%= subId || id %>.edit(ctx.params, ctx.request.body) ; + + // Send 200 `ok` + ctx.send(data); }, /** - * Destroy a/an <%= subId || id %> entry. + * Destroy a/an <%= subId || id %> record. * * @return {Object} */ destroy: async (ctx, next) => { - try { - ctx.body = await strapi.services.<%= subId || id %>.remove(ctx.params); - } catch (err) { - ctx.body = err; - } + const data = await strapi.services.<%= subId || id %>.remove(ctx.params); + + // Send 200 `ok` + ctx.send(data); }, /** - * Add relation to a specific <%= subId || id %>. + * Add relation to a/an <%= subId || id %> record. * * @return {Object} */ createRelation: async (ctx, next) => { - try { - ctx.body = await strapi.services.<%= subId || id %>.addRelation(ctx.params, ctx.request.body); - } catch (err) { - ctx.status = 400; - ctx.body = err; - } + const data = await strapi.services.<%= subId || id %>.addRelation(ctx.params, ctx.request.body); + + // Send 200 `ok` + ctx.send(data); }, /** - * Update relation to a specific <%= subId || id %>. + * Update relation to a/an <%= subId || id %> record. * * @return {Object} */ updateRelation: async (ctx, next) => { - try { - ctx.body = await strapi.services.<%= subId || id %>.editRelation(ctx.params, ctx.request.body); - } catch (err) { - ctx.status = 400; - ctx.body = err; - } + const data = await strapi.services.<%= subId || id %>.editRelation(ctx.params, ctx.request.body); + + // Send 200 `ok` + ctx.send(data); }, /** - * Destroy relation to a specific <%= subId || id %>. + * Destroy relation to a/an <%= subId || id %> record. * * @return {Object} */ destroyRelation: async (ctx, next) => { - try { - ctx.body = await strapi.services.<%= subId || id %>.removeRelation(ctx.params, ctx.request.body); - } catch (err) { - ctx.status = 400; - ctx.body = err; - } + const data = await strapi.services.<%= subId || id %>.removeRelation(ctx.params, ctx.request.body); + + // Send 200 `ok` + ctx.send(data); } }; diff --git a/packages/strapi-generate-api/templates/bookshelf/service.template b/packages/strapi-generate-api/templates/bookshelf/service.template index c981e7527d..d243cdf95e 100755 --- a/packages/strapi-generate-api/templates/bookshelf/service.template +++ b/packages/strapi-generate-api/templates/bookshelf/service.template @@ -1,7 +1,9 @@ 'use strict'; /** - * Module dependencies + * <%= filename %> service + * + * @description: A set of functions similar to controller's actions to avoid code duplication. */ // Public dependencies. @@ -10,10 +12,6 @@ const _ = require('lodash'); // Strapi utilities. const utils = require('strapi-bookshelf/lib/utils/'); -/** - * A set of functions called "actions" for `<%= globalID %>` - */ - module.exports = { /** @@ -22,17 +20,9 @@ module.exports = { * @return {Promise} */ - fetchAll: params => { - return new Promise((resolve, reject) => { - <%= globalID %>.forge(params).query(params).fetchAll({ - withRelated: _.keys(_.groupBy(_.reject(strapi.models.<%= subId || id %>.associations, {autoPopulate: false}), 'alias')) - }) - .then(<%= subIdPluralized || idPluralized %> => { - resolve(<%= subIdPluralized || idPluralized %>); - }) - .catch(err => { - reject(err); - }); + fetchAll: (params) => { + return <%= globalID %>.forge(params).query(params).fetchAll({ + withRelated: _.keys(_.groupBy(_.reject(strapi.models.<%= subId || id %>.associations, {autoPopulate: false}), 'alias')) }); }, @@ -42,17 +32,9 @@ module.exports = { * @return {Promise} */ - fetch: params => { - return new Promise((resolve, reject) => { - <%= globalID %>.forge(_.pick(params, 'id')).fetch({ - withRelated: _.keys(_.groupBy(_.reject(strapi.models.<%= subId || id %>.associations, {autoPopulate: false}), 'alias')) - }) - .then(<%= subId || id %> => { - resolve(<%= subId || id %>); - }) - .catch(err => { - reject(err); - }); + fetch: (params) => { + return <%= globalID %>.forge(_.pick(params, 'id')).fetch({ + withRelated: _.keys(_.groupBy(_.reject(strapi.models.<%= subId || id %>.associations, {autoPopulate: false}), 'alias')) }); }, @@ -62,16 +44,8 @@ module.exports = { * @return {Promise} */ - add: values => { - return new Promise((resolve, reject) => { - <%= globalID %>.forge(values).save() - .then(<%= subId || id %> => { - resolve(<%= subId || id %>); - }) - .catch(err => { - reject(err); - }); - }); + add: (values) => { + return <%= globalID %>.forge(values).save(); }, /** @@ -81,15 +55,7 @@ module.exports = { */ edit: (params, values) => { - return new Promise((resolve, reject) => { - <%= globalID %>.forge(params).save(values, {path: true}) - .then(<%= subId || id %> => { - resolve(<%= subId || id %>); - }) - .catch(err => { - reject(err); - }); - }); + return <%= globalID %>.forge(params).save(values, {path: true}); }, /** @@ -98,16 +64,8 @@ module.exports = { * @return {Promise} */ - remove: params => { - return new Promise((resolve, reject) => { - <%= globalID %>.forge(params).destroy() - .then(<%= subId || id %> => { - resolve(<%= subId || id %>); - }) - .catch(err => { - reject(err); - }); - }); + remove: (params) => { + return <%= globalID %>.forge(params).destroy(); }, /** @@ -117,47 +75,33 @@ module.exports = { */ addRelation: (params, values) => { - return new Promise((resolve, reject) => { - const relation = _.find(strapi.models.<%= subId || id %>.associations, {alias: params.relation}); + const relation = _.find(strapi.models.<%= subId || id %>.associations, {alias: params.relation}); - if (!_.isEmpty(relation) && _.isArray(values)) { - switch (relation.nature) { - case 'manyToOne': - const PK = utils.getPK(_.get(relation, relation.type), undefined, strapi.models); + if (!_.isEmpty(relation) && _.isArray(values)) { + switch (relation.nature) { + case 'manyToOne': { + const PK = utils.getPK(_.get(relation, relation.type), undefined, strapi.models); - const arrayOfPromises = _.map(values, function (value) { - const parameters = {}; + const arrayOfPromises = _.map(values, function (value) { + const parameters = {}; - _.set(parameters, PK, value); - _.set(parameters, 'relation', relation.via); + _.set(parameters, PK, value); + _.set(parameters, 'relation', relation.via); - return strapi.services[_.get(relation, relation.type)].editRelation(parameters, [_.get(params, 'id') || null]); - }); + return strapi.services[_.get(relation, relation.type)].editRelation(parameters, [_.get(params, 'id') || null]); + }); - Promise.all(arrayOfPromises) - .then(() => { - resolve(); - }) - .catch(err => { - reject(err); - }); - break; - case 'manyToMany': - <%= globalID %>.forge(_.omit(params, 'relation'))[params.relation]().attach(values) - .then(<%= subId || id %> => { - resolve(<%= subId || id %>); - }) - .catch(err => { - reject(err); - }); - break; - default: - reject('Impossible to add relation on this type of relation'); + return Promise.all(arrayOfPromises); } - } else { - reject('Bad request'); + case 'manyToMany': { + return <%= globalID %>.forge(_.omit(params, 'relation'))[params.relation]().attach(values); + } + default: + return new Error('Impossible to add relation on this type of relation'); } - }); + } + + return new Error('Relationship Not Found'); }, /** @@ -167,108 +111,93 @@ module.exports = { */ editRelation: (params, values) => { - return new Promise((resolve, reject) => { const relation = _.find(strapi.models.<%= subId || id %>.associations, {alias: params.relation}); if (!_.isEmpty(relation) && _.isArray(values)) { switch (relation.nature) { case 'oneWay': case 'oneToOne': - case 'oneToMany': + case 'oneToMany': { const data = _.set({}, params.relation, _.first(values) || null); - <%= globalID %>.forge(_.omit(params, 'relation')).save(data, {path: true}) - .then(<%= subId || id %> => { - resolve(); - }) - .catch(err => { - reject(err); - }); - break; - case 'manyToOne': + return <%= globalID %>.forge(_.omit(params, 'relation')).save(data, {path: true}); + } + case 'manyToOne': { const PK = utils.getPK(_.get(relation, relation.type), undefined, strapi.models); - <%= globalID %>.forge(_.omit(params, 'relation')).fetch({ + const results = await <%= globalID %>.forge(_.omit(params, 'relation')).fetch({ withRelated: _.get(params, 'relation') - }) - .then(<%= subId || id %> => { - const data = <%= subId || id %>.toJSON() || {}; - const currentValues = _.keys(_.groupBy(_.get(data, _.get(params, 'relation')), PK)); - const valuesToRemove = _.difference(currentValues, values); + }); - const arrayOfPromises = _.map(valuesToRemove, value => { - const params = {}; + // Remove relationship between records. + const data = results.toJSON() || {}; + const currentValues = _.keys(_.groupBy(_.get(data, _.get(params, 'relation')), PK)); + const valuesToRemove = _.difference(currentValues, values); - _.set(params, PK, value); - _.set(params, 'relation', relation.via); + const arrayOfRemovePromises = _.map(valuesToRemove, value => { + const params = {}; - return strapi.services[_.get(relation, relation.type)].editRelation(params, [null]); - }); + _.set(params, PK, value); + _.set(params, 'relation', relation.via); - return Promise.all(arrayOfPromises); - }) - .then(() => { - const arrayOfPromises = _.map(values, value => { - const params = {}; + return strapi.services[_.get(relation, relation.type)].editRelation(params, [null]); + }); - _.set(params, PK, value); - _.set(params, 'relation', relation.via); + await Promise.all(arrayOfRemovePromises); - return strapi.services[_.get(relation, relation.type)].editRelation(params, [_.get(params, 'id') || null]); - }); + // Add relationship between records. + const arrayOfAddPromises = _.map(values, value => { + const params = {}; - return Promise.all(arrayOfPromises); - }) - .then(() => { - resolve(); - }) - .catch(err => { - reject(err); - }); - break; - case 'manyToMany': - <%= globalID %>.forge(_.omit(params, 'relation')).fetch({ + _.set(params, PK, value); + _.set(params, 'relation', relation.via); + + return strapi.services[_.get(relation, relation.type)].editRelation(params, [_.get(params, 'id') || null]); + }); + + await Promise.all(arrayOfAddPromises); + + return; + } + case 'manyToMany': { + const results = <%= globalID %>.forge(_.omit(params, 'relation')).fetch({ withRelated: _.get(params, 'relation') - }) - .then(<%= subId || id %> => { - const data = <%= subId || id %>.toJSON() || {}; - const PK = utils.getPK('<%= globalID %>', <%= globalID %>, strapi.models); + }); - const currentValues = _.keys(_.groupBy(_.get(data, _.get(params, 'relation')), PK)); - const valuesToAdd = _.difference(_.map(values, o => { - return o.toString(); - }), currentValues); + const data = results.toJSON() || {}; + const PK = utils.getPK('<%= globalID %>', <%= globalID %>, strapi.models); - return <%= globalID %>.forge(_.omit(params, 'relation'))[params.relation]().attach(valuesToAdd) - .then(function () { - return <%= subId || id %>; - }) - }) - .then(<%= subId || id %> => { - const data = <%= subId || id %>.toJSON() || {}; - const PK = utils.getPK('<%= globalID %>', <%= globalID %>, strapi.models); + // Values to add + const currentValues = _.keys(_.groupBy(_.get(data, _.get(params, 'relation')), PK)); + const valuesToAdd = _.difference(_.map(values, o => { + return o.toString(); + }), currentValues); - const currentValues = _.keys(_.groupBy(_.get(data, _.get(params, 'relation')), PK)); - const valuesToDrop = _.difference(currentValues, _.map(values, o => { - return o.toString(); - })); + try { + await <%= globalID %>.forge(_.omit(params, 'relation'))[params.relation]().attach(valuesToAdd); + } catch (err) { + return err; + } - return <%= globalID %>.forge(_.omit(params, 'relation'))[params.relation]().detach(valuesToDrop); - }) - .then(() => { - resolve(); - }) - .catch(err => { - reject(err); - }); - break; + // Values to remove + const valuesToDrop = _.difference(currentValues, _.map(values, o => { + return o.toString(); + })); + + try { + await <%= globalID %>.forge(_.omit(params, 'relation'))[params.relation]().detach(valuesToDrop); + } catch (err) { + return err; + } + + return; + } default: - reject('Impossible to update relation on this type of relation'); + return new Error('Impossible to update relation on this type of relation'); } - } else { - reject('Bad request'); } - }); + + return new Error ('Relationship Not Found'); }, /** @@ -278,46 +207,30 @@ module.exports = { */ removeRelation: (params, values) => { - return new Promise((resolve, reject) => { - const relation = _.find(strapi.models.<%= subId || id %>.associations, {alias: params.relation}); + const relation = _.find(strapi.models.<%= subId || id %>.associations, {alias: params.relation}); - if (!_.isEmpty(relation) && _.isArray(values)) { - switch (relation.nature) { - case 'manyToOne': - const PK = utils.getPK(_.get(relation, relation.type), undefined, strapi.models); + if (!_.isEmpty(relation) && _.isArray(values)) { + switch (relation.nature) { + case 'manyToOne': + const PK = utils.getPK(_.get(relation, relation.type), undefined, strapi.models); - const arrayOfPromises = _.map(values, value => { - const parameters = {}; + const arrayOfPromises = _.map(values, value => { + const parameters = {}; - _.set(parameters, PK, value); - _.set(parameters, 'relation', relation.via); + _.set(parameters, PK, value); + _.set(parameters, 'relation', relation.via); - return strapi.services[_.get(relation, relation.type)].editRelation(parameters, [null]); - }); + return strapi.services[_.get(relation, relation.type)].editRelation(parameters, [null]); + }); - Promise.all(arrayOfPromises) - .then(() => { - resolve(); - }) - .catch(err => { - reject(err); - }); - break; - case 'manyToMany': - <%= globalID %>.forge(_.omit(params, 'relation'))[params.relation]().detach(values) - .then(<%= subId || id %> => { - resolve(<%= subId || id %>); - }) - .catch(err => { - reject(err); - }); - break; - default: - reject('Impossible to delete relation on this type of relation'); - } - } else { - reject('Bad request'); + return Promise.all(arrayOfPromises); + case 'manyToMany': + return <%= globalID %>.forge(_.omit(params, 'relation'))[params.relation]().detach(values); + default: + return new Error('Impossible to delete relation on this type of relation'); } - }); + } + + return new Error('Relationship Not Found'); } }; diff --git a/packages/strapi-utils/lib/models.js b/packages/strapi-utils/lib/models.js index 2aef036f39..20d2ebb370 100644 --- a/packages/strapi-utils/lib/models.js +++ b/packages/strapi-utils/lib/models.js @@ -28,7 +28,7 @@ module.exports = { * Find primary key per ORM */ - getPK: (collectionIdentity, collection, models) => { + getPK: function (collectionIdentity, collection, models) { if (_.isString(collectionIdentity)) { const ORM = this.getORM(collectionIdentity); @@ -50,7 +50,7 @@ module.exports = { * Find primary key per ORM */ - getCount: collectionIdentity => { + getCount: function (collectionIdentity) { if (_.isString(collectionIdentity)) { const ORM = this.getORM(collectionIdentity); @@ -214,7 +214,7 @@ module.exports = { * Define associations key to models */ - defineAssociations: (model, definition, association, key) => { + defineAssociations: function (model, definition, association, key) { // Initialize associations object if (definition.associations === undefined) { definition.associations = []; diff --git a/packages/strapi/lib/configuration/hooks/core/responses/policy.js b/packages/strapi/lib/configuration/hooks/core/responses/policy.js index b4537d1dd7..e5fbd8c3c3 100644 --- a/packages/strapi/lib/configuration/hooks/core/responses/policy.js +++ b/packages/strapi/lib/configuration/hooks/core/responses/policy.js @@ -39,11 +39,13 @@ module.exports = async function (ctx, next) { try { await next(); - if (_.get(ctx.body, 'isBoom')) { - ctx.throw(ctx.status); + if (_.get(ctx.body, 'isBoom') || _.isError(ctx.body)) { + ctx.throw(); } } catch (error) { - strapi.log.error(error); + // Error object could be also in the context body... + strapi.log.error(ctx.body || error); + // Wrap error into a Boom's response const formattedError = _.get(ctx.body, 'isBoom') ? ctx.body || error.message : Boom.wrap(error, error.status, ctx.body || error.message); ctx.status = formattedError.output.statusCode || error.status || 500;