mirror of
https://github.com/strapi/strapi.git
synced 2025-07-16 21:41:59 +00:00
Merge branch 'v2' of github.com:wistityhq/strapi into v2
This commit is contained in:
commit
c45ea07a27
@ -1,4 +1,10 @@
|
|||||||
# Strapi [](https://travis-ci.org/wistityhq/strapi) [](http://slack.strapi.io)
|
# Strapi
|
||||||
|
|
||||||
|
[](https://www.npmjs.org/package/strapi)
|
||||||
|
[](https://www.npmjs.org/package/strapi)
|
||||||
|
[](https://david-dm.org/wistityhq/strapi)
|
||||||
|
[](https://travis-ci.org/wistityhq/strapi)
|
||||||
|
[](http://slack.strapi.io)
|
||||||
|
|
||||||
[Website](http://strapi.io/) - [Getting Started](#user-content-getting-started-in-a-minute) - [Documentation](http://strapi.io/documentation/introduction) - [Support](http://strapi.io/support)
|
[Website](http://strapi.io/) - [Getting Started](#user-content-getting-started-in-a-minute) - [Documentation](http://strapi.io/documentation/introduction) - [Support](http://strapi.io/support)
|
||||||
|
|
||||||
@ -55,7 +61,6 @@ This will generate a Strapi application without:
|
|||||||
- the built-in `user`, `email` and `upload` APIs,
|
- the built-in `user`, `email` and `upload` APIs,
|
||||||
- the `grant` hook,
|
- the `grant` hook,
|
||||||
- the open-source admin panel,
|
- the open-source admin panel,
|
||||||
- the Waterline ORM (`waterline` and `blueprints` hooks disabled),
|
|
||||||
- the Strapi Studio connection (`studio` hook disabled).
|
- the Strapi Studio connection (`studio` hook disabled).
|
||||||
|
|
||||||
This feature allows you to only use Strapi for your HTTP server structure if you want to.
|
This feature allows you to only use Strapi for your HTTP server structure if you want to.
|
||||||
|
@ -39,6 +39,10 @@ cmd = program.command('version');
|
|||||||
cmd.description('output your version of Strapi');
|
cmd.description('output your version of Strapi');
|
||||||
cmd.action(program.versionInformation);
|
cmd.action(program.versionInformation);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic commands
|
||||||
|
*/
|
||||||
|
|
||||||
// `$ strapi new <name>`
|
// `$ strapi new <name>`
|
||||||
cmd = program.command('new');
|
cmd = program.command('new');
|
||||||
cmd.unknownOption = NOOP;
|
cmd.unknownOption = NOOP;
|
||||||
@ -64,24 +68,16 @@ cmd.unknownOption = NOOP;
|
|||||||
cmd.description('open the Strapi framework console');
|
cmd.description('open the Strapi framework console');
|
||||||
cmd.action(require('./strapi-console'));
|
cmd.action(require('./strapi-console'));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commands for the Strapi Studio
|
||||||
|
*/
|
||||||
|
|
||||||
// `$ strapi link`
|
// `$ strapi link`
|
||||||
cmd = program.command('link');
|
cmd = program.command('link');
|
||||||
cmd.unknownOption = NOOP;
|
cmd.unknownOption = NOOP;
|
||||||
cmd.description('link an existing application to the Strapi Studio');
|
cmd.description('link an existing application to the Strapi Studio');
|
||||||
cmd.action(require('./strapi-link'));
|
cmd.action(require('./strapi-link'));
|
||||||
|
|
||||||
// `$ strapi config`
|
|
||||||
cmd = program.command('config');
|
|
||||||
cmd.unknownOption = NOOP;
|
|
||||||
cmd.description('extend the Strapi framework with custom generators');
|
|
||||||
cmd.action(require('./strapi-config'));
|
|
||||||
|
|
||||||
// `$ strapi update`
|
|
||||||
cmd = program.command('update');
|
|
||||||
cmd.unknownOption = NOOP;
|
|
||||||
cmd.description('pull the latest updates of your custom generators');
|
|
||||||
cmd.action(require('./strapi-update'));
|
|
||||||
|
|
||||||
// `$ strapi login`
|
// `$ strapi login`
|
||||||
cmd = program.command('login');
|
cmd = program.command('login');
|
||||||
cmd.unknownOption = NOOP;
|
cmd.unknownOption = NOOP;
|
||||||
@ -94,6 +90,22 @@ cmd.unknownOption = NOOP;
|
|||||||
cmd.description('logout your account from the Strapi Studio');
|
cmd.description('logout your account from the Strapi Studio');
|
||||||
cmd.action(require('./strapi-logout'));
|
cmd.action(require('./strapi-logout'));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customization commands
|
||||||
|
*/
|
||||||
|
|
||||||
|
// `$ strapi config`
|
||||||
|
cmd = program.command('config');
|
||||||
|
cmd.unknownOption = NOOP;
|
||||||
|
cmd.description('extend the Strapi framework with custom generators');
|
||||||
|
cmd.action(require('./strapi-config'));
|
||||||
|
|
||||||
|
// `$ strapi update`
|
||||||
|
cmd = program.command('update');
|
||||||
|
cmd.unknownOption = NOOP;
|
||||||
|
cmd.description('pull the latest updates of your custom generators');
|
||||||
|
cmd.action(require('./strapi-update'));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize help argument
|
* Normalize help argument
|
||||||
*/
|
*/
|
||||||
|
@ -1,240 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Public node modules.
|
|
||||||
const _ = require('lodash');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Populate the query according to the specified or default
|
|
||||||
* association attributes.
|
|
||||||
*
|
|
||||||
* @param {Object} query
|
|
||||||
* @param {Object} _ctx
|
|
||||||
* @param {Object} model
|
|
||||||
*
|
|
||||||
* @return {Object} populated query
|
|
||||||
*/
|
|
||||||
|
|
||||||
populateEach: function (query, _ctx, model) {
|
|
||||||
let shouldPopulate = strapi.config.blueprints.populate;
|
|
||||||
let aliasFilter = (_ctx.request.query && _ctx.request.query.populate) || (_ctx.request.body && _ctx.request.body.populate);
|
|
||||||
|
|
||||||
// Convert the string representation of the filter list to an array. We
|
|
||||||
// need this to provide flexibility in the request param. This way both
|
|
||||||
// list string representations are supported:
|
|
||||||
// /model?populate=alias1,alias2,alias3
|
|
||||||
// /model?populate=[alias1,alias2,alias3]
|
|
||||||
if (typeof aliasFilter === 'string') {
|
|
||||||
aliasFilter = aliasFilter.replace(/\[|\]/g, '');
|
|
||||||
aliasFilter = (aliasFilter) ? aliasFilter.split(',') : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return _(model.associations).reduce(function populateEachAssociation(query, association) {
|
|
||||||
|
|
||||||
// If an alias filter was provided, override the blueprint config.
|
|
||||||
if (aliasFilter) {
|
|
||||||
shouldPopulate = _.contains(aliasFilter, association.alias);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate associations and set the according limit.
|
|
||||||
if (shouldPopulate) {
|
|
||||||
return query.populate(association.alias, {
|
|
||||||
limit: strapi.config.blueprints.defaultLimit || 30
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return query;
|
|
||||||
}
|
|
||||||
}, query);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the model to use
|
|
||||||
*
|
|
||||||
* @param {_ctx} _ctx
|
|
||||||
*
|
|
||||||
* @return {WLCollection}
|
|
||||||
*/
|
|
||||||
|
|
||||||
parseModel: function (_ctx) {
|
|
||||||
|
|
||||||
// Determine the model according to the context.
|
|
||||||
const model = _ctx.model || _ctx.params.model;
|
|
||||||
|
|
||||||
if (!model) {
|
|
||||||
throw new Error({
|
|
||||||
message: 'Please provide a valid model.'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select the Waterline model.
|
|
||||||
const Model = strapi.orm.collections[model];
|
|
||||||
if (!Model) {
|
|
||||||
throw new Error({
|
|
||||||
message: 'Invalid Model.'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Model.name = model;
|
|
||||||
|
|
||||||
return Model;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse `values` for a Waterline `create` or `update` from all
|
|
||||||
* request parameters.
|
|
||||||
*
|
|
||||||
* @param {Request} _ctx
|
|
||||||
*
|
|
||||||
* @return {Object}
|
|
||||||
*/
|
|
||||||
|
|
||||||
parseValues: function (_ctx) {
|
|
||||||
const values = _ctx.request.body || _ctx.request.query;
|
|
||||||
|
|
||||||
return values;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse `criteria` for a Waterline `find` or `update` from all
|
|
||||||
* request parameters.
|
|
||||||
*
|
|
||||||
* @param {Request} _ctx
|
|
||||||
*
|
|
||||||
* @return {Object} the where criteria object
|
|
||||||
*/
|
|
||||||
|
|
||||||
parseCriteria: function (_ctx) {
|
|
||||||
|
|
||||||
// List of properties to remove.
|
|
||||||
const blacklist = ['limit', 'skip', 'sort', 'populate'];
|
|
||||||
|
|
||||||
// Validate blacklist to provide a more helpful error msg.
|
|
||||||
if (blacklist && !_.isArray(blacklist)) {
|
|
||||||
throw new Error('Invalid `_ctx.options.criteria.blacklist`. Should be an array of strings (parameter names.)');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for explicitly specified `where` parameter.
|
|
||||||
let where = _ctx.request.query.where;
|
|
||||||
|
|
||||||
// If `where` parameter is a string, try to interpret it as JSON.
|
|
||||||
if (_.isString(where)) {
|
|
||||||
try {
|
|
||||||
where = JSON.parse(where);
|
|
||||||
} catch (err) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If `where` has not been specified, but other unbound parameter variables
|
|
||||||
// are specified, build the `where` option using them.
|
|
||||||
if (!where) {
|
|
||||||
|
|
||||||
// Prune params which aren't fit to be used as `where` criteria
|
|
||||||
// to build a proper where query.
|
|
||||||
where = _ctx.request.body;
|
|
||||||
|
|
||||||
// Omit built-in runtime config (like query modifiers).
|
|
||||||
where = _.omit(where, blacklist || ['limit', 'skip', 'sort']);
|
|
||||||
|
|
||||||
// Omit any params with undefined values.
|
|
||||||
where = _.omit(where, function (p) {
|
|
||||||
if (_.isUndefined(p)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge with `_ctx.options.where` and return.
|
|
||||||
where = _.merge({}, where) || undefined;
|
|
||||||
|
|
||||||
return where;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse primary key value
|
|
||||||
*
|
|
||||||
* @param {Object} _ctx
|
|
||||||
*
|
|
||||||
* @return {Integer|String} pk
|
|
||||||
*/
|
|
||||||
|
|
||||||
parsePk: function (_ctx) {
|
|
||||||
let pk = (_ctx.request.body && _ctx.request.body.where && _ctx.request.body.where.id) || _ctx.params.id;
|
|
||||||
|
|
||||||
// Exclude criteria on id field.
|
|
||||||
pk = _.isPlainObject(pk) ? undefined : pk;
|
|
||||||
return pk;
|
|
||||||
},
|
|
||||||
|
|
||||||
requirePk: function (_ctx) {
|
|
||||||
const pk = module.exports.parsePk(_ctx);
|
|
||||||
|
|
||||||
// Validate the required `id` parameter.
|
|
||||||
if (!pk) {
|
|
||||||
const err = new Error({
|
|
||||||
message: 'No `id` provided'
|
|
||||||
});
|
|
||||||
_ctx.status = 400;
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pk;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse sort params.
|
|
||||||
*
|
|
||||||
* @param {Object} _ctx
|
|
||||||
*/
|
|
||||||
|
|
||||||
parseSort: function (_ctx) {
|
|
||||||
_ctx.options = _ctx.options || {};
|
|
||||||
let sort = _ctx.request.query.sort || _ctx.options.sort;
|
|
||||||
if (typeof sort === 'undefined') {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
if (typeof sort === 'string') {
|
|
||||||
try {
|
|
||||||
sort = JSON.parse(sort);
|
|
||||||
} catch (err) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sort;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse limit params.
|
|
||||||
*
|
|
||||||
* @param {Object} _ctx
|
|
||||||
*/
|
|
||||||
|
|
||||||
parseLimit: function (_ctx) {
|
|
||||||
_ctx.options = _ctx.options || {};
|
|
||||||
let limit = Number(_ctx.request.query.limit) || strapi.config.blueprints.defaultLimit || 30;
|
|
||||||
if (limit) {
|
|
||||||
limit = +limit;
|
|
||||||
}
|
|
||||||
return limit;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse skip params.
|
|
||||||
*
|
|
||||||
* @param {Object} _ctx
|
|
||||||
*/
|
|
||||||
|
|
||||||
parseSkip: function (_ctx) {
|
|
||||||
_ctx.options = _ctx.options || {};
|
|
||||||
let skip = _ctx.request.query.skip || 0;
|
|
||||||
if (skip) {
|
|
||||||
skip = +skip;
|
|
||||||
}
|
|
||||||
return skip;
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,184 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Public node modules.
|
|
||||||
const _ = require('lodash');
|
|
||||||
const async = require('async');
|
|
||||||
|
|
||||||
// Local utils.
|
|
||||||
const actionUtil = require('../actionUtil');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an entry to a specific parent entry
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function destroy(_ctx) {
|
|
||||||
const deferred = Promise.defer();
|
|
||||||
|
|
||||||
// Ensure a model and alias can be deduced from the request.
|
|
||||||
const Model = actionUtil.parseModel(_ctx);
|
|
||||||
const relation = _ctx.params.relation;
|
|
||||||
if (!relation) {
|
|
||||||
_ctx.status = 500;
|
|
||||||
return deferred.reject({
|
|
||||||
message: 'Missing required route option, `_ctx.params.relation`.'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// The primary key of the parent record.
|
|
||||||
const parentPk = _ctx.params.parentId;
|
|
||||||
|
|
||||||
// Find the alias key.
|
|
||||||
const associationAttr = _.findWhere(strapi.orm.collections[_ctx.model].associations, {alias: relation});
|
|
||||||
|
|
||||||
// Init the child model.
|
|
||||||
const ChildModel = strapi.orm.collections[associationAttr.collection];
|
|
||||||
const childPkAttr = ChildModel.primaryKey;
|
|
||||||
|
|
||||||
_ctx.options = _ctx.options || {};
|
|
||||||
|
|
||||||
// The child record to associate is defined by either...
|
|
||||||
// a primary key or an object of values.
|
|
||||||
let child;
|
|
||||||
const supposedChildPk = actionUtil.parsePk(_ctx);
|
|
||||||
if (supposedChildPk) {
|
|
||||||
child = {};
|
|
||||||
child[childPkAttr] = supposedChildPk;
|
|
||||||
} else {
|
|
||||||
_ctx.options.values = _ctx.options.values || {};
|
|
||||||
_ctx.options.values.blacklist = _ctx.options.values.blacklist || ['limit', 'skip', 'sort', 'id', 'parentId'];
|
|
||||||
child = actionUtil.parseValues(_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!child) {
|
|
||||||
_ctx.status = 400;
|
|
||||||
deferred.reject({
|
|
||||||
message: 'You must specify the record to add (either the primary key of an existing record to link, or a new object without a primary key which will be used to create a record then link it.)'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async.auto({
|
|
||||||
|
|
||||||
// Look up the parent record.
|
|
||||||
parent: function (cb) {
|
|
||||||
Model.findOne(parentPk).exec(function foundParent(err, parentRecord) {
|
|
||||||
if (err) {
|
|
||||||
return cb(err);
|
|
||||||
}
|
|
||||||
if (!parentRecord) {
|
|
||||||
return cb({status: 404});
|
|
||||||
}
|
|
||||||
if (!parentRecord[relation]) {
|
|
||||||
return cb({status: 404});
|
|
||||||
}
|
|
||||||
cb(null, parentRecord);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// If a primary key was specified in the `child` object we parsed
|
|
||||||
// from the request, look it up to make sure it exists. Send back its primary key value.
|
|
||||||
// This is here because, although you can do this with `.save()`, you can't actually
|
|
||||||
// get ahold of the created child record data, unless you create it first.
|
|
||||||
actualChildPkValue: ['parent', function (cb) {
|
|
||||||
|
|
||||||
// Below, we use the primary key attribute to pull out the primary key value
|
|
||||||
// (which might not have existed until now, if the .add() resulted in a `create()`).
|
|
||||||
// If the primary key was specified for the child record, we should try to find
|
|
||||||
// it before we create it.
|
|
||||||
// Otherwise, it must be referring to a new thing, so create it.
|
|
||||||
if (child[childPkAttr]) {
|
|
||||||
ChildModel.findOne(child[childPkAttr]).exec(function foundChild(err, childRecord) {
|
|
||||||
if (err) {
|
|
||||||
return cb(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Didn't find it? Then try creating it.
|
|
||||||
if (!childRecord) {
|
|
||||||
return createChild();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise use the one we found.
|
|
||||||
return cb(null, childRecord[childPkAttr]);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return createChild();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new instance and send out any required pub/sub messages.
|
|
||||||
function createChild() {
|
|
||||||
ChildModel.create(child).exec(function createdNewChild(err, newChildRecord) {
|
|
||||||
if (err) {
|
|
||||||
return cb(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cb(null, newChildRecord[childPkAttr]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
|
|
||||||
// Add the child record to the parent's collection.
|
|
||||||
add: ['parent', 'actualChildPkValue', function (cb, asyncData) {
|
|
||||||
|
|
||||||
// `collection` is the parent record's collection we
|
|
||||||
// want to add the child to.
|
|
||||||
try {
|
|
||||||
const collection = asyncData.parent[relation];
|
|
||||||
collection.add(asyncData.actualChildPkValue);
|
|
||||||
return cb();
|
|
||||||
} catch (err) {
|
|
||||||
if (err) {
|
|
||||||
return cb(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cb();
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
|
|
||||||
// Save the parent record.
|
|
||||||
function readyToSave(err, asyncData) {
|
|
||||||
if (err) {
|
|
||||||
_ctx.status = 400;
|
|
||||||
deferred.reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
asyncData.parent.save(function saved(err) {
|
|
||||||
|
|
||||||
// Ignore `insert` errors for duplicate adds
|
|
||||||
// (but keep in mind, we should not `publishAdd` if this is the case...)
|
|
||||||
const isDuplicateInsertError = (err && typeof err === 'object' && err.length && err[0] && err[0].type === 'insert');
|
|
||||||
if (err && !isDuplicateInsertError) {
|
|
||||||
deferred.reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, look up the parent record again and populate the relevant collection.
|
|
||||||
let query = Model.findOne(parentPk);
|
|
||||||
|
|
||||||
query = actionUtil.populateEach(query, _ctx, Model);
|
|
||||||
query.populate(relation);
|
|
||||||
|
|
||||||
query.exec(function (err, matchingRecord) {
|
|
||||||
if (err) {
|
|
||||||
return deferred.reject(err);
|
|
||||||
}
|
|
||||||
if (!matchingRecord) {
|
|
||||||
return deferred.reject({
|
|
||||||
message: 'Matching record not found.'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (!matchingRecord[relation]) {
|
|
||||||
return deferred.reject({
|
|
||||||
message: '`matchingRecord[relation]` not found.'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return deferred.resolve(matchingRecord);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferred.promise;
|
|
||||||
};
|
|
@ -1,93 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Public node modules.
|
|
||||||
const _ = require('lodash');
|
|
||||||
|
|
||||||
// Local utils.
|
|
||||||
const actionUtil = require('../actionUtil');
|
|
||||||
const associationUtil = require('../associationUtil');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an entry
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function create(_ctx) {
|
|
||||||
const deferred = Promise.defer();
|
|
||||||
|
|
||||||
// Return the model used.
|
|
||||||
const Model = actionUtil.parseModel(_ctx);
|
|
||||||
|
|
||||||
// Parse the values of the record to create.
|
|
||||||
const values = actionUtil.parseValues(_ctx);
|
|
||||||
|
|
||||||
// Associations validation.
|
|
||||||
const associationsValidationPromises = [];
|
|
||||||
|
|
||||||
// Check if the relations are existing for `OneWay` associations.
|
|
||||||
_.forEach(_.where(Model.associations, {nature: 'oneWay'}), function (association) {
|
|
||||||
if (values[association.alias] || association.required) {
|
|
||||||
associationsValidationPromises.push(associationUtil.doesRecordExist(association.model, values[association.alias]));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check if the relations are existing for `OneToOne` associations.
|
|
||||||
_.forEach(_.where(Model.associations, {nature: 'oneToOne'}), function (association) {
|
|
||||||
if (values[association.alias] || association.required) {
|
|
||||||
associationsValidationPromises.push(associationUtil.doesRecordExist(association.model, values[association.alias]));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Promise.all(associationsValidationPromises)
|
|
||||||
.then(function () {
|
|
||||||
Model.create(values).exec(function created(err, newInstance) {
|
|
||||||
if (err) {
|
|
||||||
_ctx.status = 400;
|
|
||||||
return deferred.reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update `oneToOneRelations`.
|
|
||||||
const relationPromises = [];
|
|
||||||
|
|
||||||
// Update the `oneToOne` relations.
|
|
||||||
_.forEach(_.where(Model.associations, {nature: 'oneToOne'}), function (relation) {
|
|
||||||
relationPromises.push(associationUtil.oneToOneRelationUpdated(_ctx.model || _ctx.params.model, newInstance.id, relation.model, newInstance[relation.alias]));
|
|
||||||
});
|
|
||||||
|
|
||||||
Promise.all(relationPromises)
|
|
||||||
|
|
||||||
// Related records updated.
|
|
||||||
.then(function () {
|
|
||||||
let query = Model.findOne(newInstance[Model.primaryKey]);
|
|
||||||
query = actionUtil.populateEach(query, _ctx, Model);
|
|
||||||
query.exec(function foundAgain(err, populatedRecord) {
|
|
||||||
if (err) {
|
|
||||||
_ctx.status = 500;
|
|
||||||
return deferred.reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entry created.
|
|
||||||
_ctx.status = 201;
|
|
||||||
deferred.resolve(populatedRecord);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
// Error during related records update.
|
|
||||||
.catch(function (err) {
|
|
||||||
_ctx.status = 400;
|
|
||||||
deferred.reject(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
// Error during related records check.
|
|
||||||
.catch(function (err) {
|
|
||||||
_ctx.status = 400;
|
|
||||||
deferred.reject(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferred.promise;
|
|
||||||
};
|
|
@ -1,80 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Public node modules.
|
|
||||||
const _ = require('lodash');
|
|
||||||
|
|
||||||
// Local utils.
|
|
||||||
const actionUtil = require('../actionUtil');
|
|
||||||
const associationUtil = require('../associationUtil');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy an entry
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function destroy(_ctx) {
|
|
||||||
const deferred = Promise.defer();
|
|
||||||
|
|
||||||
// Return the model used.
|
|
||||||
const Model = actionUtil.parseModel(_ctx);
|
|
||||||
|
|
||||||
// Locate and validate the required `id` parameter.
|
|
||||||
const pk = actionUtil.requirePk(_ctx);
|
|
||||||
|
|
||||||
// First, check if the record exists.
|
|
||||||
const query = Model.findOne(pk);
|
|
||||||
query.exec(function foundRecord(err, record) {
|
|
||||||
if (err) {
|
|
||||||
_ctx.status = 500;
|
|
||||||
deferred.reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record not found.
|
|
||||||
if (!record) {
|
|
||||||
_ctx.status = 404;
|
|
||||||
deferred.reject({
|
|
||||||
message: 'No record found with the specified `id`.'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy the record.
|
|
||||||
Model.destroy(pk).exec(function destroyedRecord(err, deletedRecords) {
|
|
||||||
if (err) {
|
|
||||||
_ctx.status = 500;
|
|
||||||
return deferred.reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select the first object of the updated records.
|
|
||||||
const deletedRecord = deletedRecords[0];
|
|
||||||
|
|
||||||
// Update the `oneToOne` relations.
|
|
||||||
const relationPromises = [];
|
|
||||||
_.forEach(_.where(Model.associations, {nature: 'oneToOne'}), function (relation) {
|
|
||||||
relationPromises.push(associationUtil.removeRelationsOut(_ctx.model || _ctx.params.model, deletedRecord.id, relation.model));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update the `oneToMany` relations.
|
|
||||||
_.forEach(_.where(Model.associations, {nature: 'oneToMany'}), function (relation) {
|
|
||||||
relationPromises.push(associationUtil.removeRelationsOut(_ctx.model || _ctx.params.model, deletedRecord.id, relation.collection));
|
|
||||||
});
|
|
||||||
|
|
||||||
Promise.all(relationPromises)
|
|
||||||
|
|
||||||
// Related records updated.
|
|
||||||
.then(function () {
|
|
||||||
deferred.resolve(deletedRecord);
|
|
||||||
})
|
|
||||||
|
|
||||||
// Error during related records update.
|
|
||||||
.catch(function (err) {
|
|
||||||
_ctx.status = 500;
|
|
||||||
deferred.reject(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferred.promise;
|
|
||||||
};
|
|
@ -1,44 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Local utils.
|
|
||||||
const actionUtil = require('../actionUtil');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find entries
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function find(_ctx) {
|
|
||||||
const deferred = Promise.defer();
|
|
||||||
|
|
||||||
// Use the `findOne` action if an `id` is specified.
|
|
||||||
if (actionUtil.parsePk(_ctx)) {
|
|
||||||
return require('./findOne')(_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look up the model.
|
|
||||||
const Model = actionUtil.parseModel(_ctx);
|
|
||||||
|
|
||||||
// Init the query.
|
|
||||||
let query = Model.find()
|
|
||||||
.where(actionUtil.parseCriteria(_ctx))
|
|
||||||
.limit(actionUtil.parseLimit(_ctx))
|
|
||||||
.skip(actionUtil.parseSkip(_ctx))
|
|
||||||
.sort(actionUtil.parseSort(_ctx));
|
|
||||||
|
|
||||||
query = actionUtil.populateEach(query, _ctx, Model);
|
|
||||||
query.exec(function found(err, matchingRecords) {
|
|
||||||
if (err) {
|
|
||||||
_ctx.status = 500;
|
|
||||||
deferred.reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Records found.
|
|
||||||
deferred.resolve(matchingRecords);
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferred.promise;
|
|
||||||
};
|
|
@ -1,44 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Local utils.
|
|
||||||
const actionUtil = require('../actionUtil');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a specific entry
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function destroy(_ctx) {
|
|
||||||
const deferred = Promise.defer();
|
|
||||||
|
|
||||||
// Return the model used.
|
|
||||||
const Model = actionUtil.parseModel(_ctx);
|
|
||||||
|
|
||||||
// Locate and validate the required `id` parameter.
|
|
||||||
const pk = actionUtil.requirePk(_ctx);
|
|
||||||
|
|
||||||
// Init the query.
|
|
||||||
let query = Model.findOne(pk);
|
|
||||||
query = actionUtil.populateEach(query, _ctx, Model);
|
|
||||||
query.exec(function found(err, matchingRecord) {
|
|
||||||
if (err) {
|
|
||||||
_ctx.status = 500;
|
|
||||||
deferred.reject(err);
|
|
||||||
}
|
|
||||||
if (!matchingRecord) {
|
|
||||||
_ctx.status = 404;
|
|
||||||
|
|
||||||
return deferred.reject({
|
|
||||||
message: 'No ' + Model.name + ' found with the specified `id`.'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record found.
|
|
||||||
deferred.resolve(matchingRecord);
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferred.promise;
|
|
||||||
};
|
|
@ -1,109 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Public node modules.
|
|
||||||
const _ = require('lodash');
|
|
||||||
|
|
||||||
// Local utils.
|
|
||||||
const actionUtil = require('../actionUtil');
|
|
||||||
const associationUtil = require('../associationUtil');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove an entry to a specific parent entry
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function remove(_ctx) {
|
|
||||||
const deferred = Promise.defer();
|
|
||||||
|
|
||||||
// Ensure a model and alias can be deduced from the request.
|
|
||||||
const Model = actionUtil.parseModel(_ctx);
|
|
||||||
_ctx.options = _ctx.options || {};
|
|
||||||
const relation = _ctx.params.relation;
|
|
||||||
const associationAttr = _.findWhere(strapi.orm.collections[_ctx.model].associations, {alias: relation});
|
|
||||||
|
|
||||||
if (!associationAttr) {
|
|
||||||
_ctx.status = 500;
|
|
||||||
return deferred.reject({
|
|
||||||
message: 'Missing required route option, `_ctx.options.alias`.'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// The primary key of the parent record.
|
|
||||||
const parentPk = _ctx.params.parentId;
|
|
||||||
|
|
||||||
// The primary key of the child record to remove
|
|
||||||
// from the aliased collection.
|
|
||||||
let childPk = actionUtil.parsePk(_ctx);
|
|
||||||
|
|
||||||
// Check if the `childPk` is defined.
|
|
||||||
if (_.isUndefined(childPk)) {
|
|
||||||
_ctx.status = 400;
|
|
||||||
return deferred.reject({
|
|
||||||
message: 'Missing required child PK.'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the parent object.
|
|
||||||
Model.findOne(parentPk)
|
|
||||||
.populate(relation)
|
|
||||||
.exec(function found(err, parentRecord) {
|
|
||||||
if (err) {
|
|
||||||
_ctx.status = 500;
|
|
||||||
return deferred.reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format `childPk` for the `findWhere` used next.
|
|
||||||
childPk = isNaN(childPk) ? childPk : Number(childPk);
|
|
||||||
|
|
||||||
if (!parentRecord || !parentRecord[relation] || (!_.findWhere(parentRecord[relation], {id: childPk})) && parentRecord[relation].id !== childPk) {
|
|
||||||
_ctx.status = 404;
|
|
||||||
return deferred.reject({
|
|
||||||
message: 'Not found'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const relationPromises = [];
|
|
||||||
|
|
||||||
if (parentRecord[relation].id === childPk) {
|
|
||||||
|
|
||||||
// Set to null
|
|
||||||
parentRecord[relation] = null;
|
|
||||||
relationPromises.push(associationUtil.removeRelationsOut(_ctx.model || _ctx.params.model, parentRecord.id, relation));
|
|
||||||
} else if (_.findWhere(parentRecord[relation], {id: childPk})) {
|
|
||||||
|
|
||||||
// Remove.
|
|
||||||
parentRecord[relation].remove(childPk);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save.
|
|
||||||
parentRecord.save(function (err) {
|
|
||||||
if (err) {
|
|
||||||
_ctx.status = 400;
|
|
||||||
return deferred.reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
Promise.all(relationPromises)
|
|
||||||
.then(function () {
|
|
||||||
|
|
||||||
// New query to `findOne` and properly populate it.
|
|
||||||
let query = Model.findOne(parentPk);
|
|
||||||
query = actionUtil.populateEach(query, _ctx, Model);
|
|
||||||
query.exec(function found(err, parentRecord) {
|
|
||||||
if (err || !parentRecord) {
|
|
||||||
_ctx.status = 500;
|
|
||||||
return deferred.reject(err);
|
|
||||||
}
|
|
||||||
return deferred.resolve(parentRecord);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(function (err) {
|
|
||||||
deferred.reject(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferred.promise;
|
|
||||||
};
|
|
@ -1,119 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Public node modules.
|
|
||||||
const _ = require('lodash');
|
|
||||||
|
|
||||||
// Local utils.
|
|
||||||
const actionUtil = require('../actionUtil');
|
|
||||||
const associationUtil = require('../associationUtil');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy an entry
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function update(_ctx) {
|
|
||||||
const deferred = Promise.defer();
|
|
||||||
|
|
||||||
// Return the model used.
|
|
||||||
const Model = actionUtil.parseModel(_ctx);
|
|
||||||
|
|
||||||
// Locate and validate the required `id` parameter.
|
|
||||||
const pk = actionUtil.requirePk(_ctx);
|
|
||||||
|
|
||||||
// Parse the values of the record to update.
|
|
||||||
const values = actionUtil.parseValues(_ctx);
|
|
||||||
|
|
||||||
// No matter what, don't allow changing the `pk` via the update blueprint
|
|
||||||
// (you should just drop and re-add the record if that's what you really want).
|
|
||||||
if (typeof values[Model.primaryKey] !== 'undefined' && values[Model.primaryKey] !== pk) {
|
|
||||||
strapi.log.warn('Cannot change primary key via update action; ignoring value sent for `' + Model.primaryKey + '`');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the primary key is unchanged.
|
|
||||||
values[Model.primaryKey] = pk;
|
|
||||||
|
|
||||||
Model.findOne(pk).exec(function found(err, matchingRecord) {
|
|
||||||
if (err) {
|
|
||||||
_ctx.status = 500;
|
|
||||||
return deferred.reject(err);
|
|
||||||
}
|
|
||||||
if (!matchingRecord) {
|
|
||||||
_ctx.status = 404;
|
|
||||||
return deferred.reject('Record not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Associations validation.
|
|
||||||
const associationsValidationPromises = [];
|
|
||||||
|
|
||||||
// One way associations.
|
|
||||||
_.forEach(_.where(Model.associations, {nature: 'oneWay'}), function (association) {
|
|
||||||
if (values[association.alias] || association.required) {
|
|
||||||
associationsValidationPromises.push(associationUtil.doesRecordExist(association.model, values[association.alias]));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// One to one associations.
|
|
||||||
_.forEach(_.where(Model.associations, {nature: 'oneToOne'}), function (association) {
|
|
||||||
if (values[association.alias] || association.required) {
|
|
||||||
associationsValidationPromises.push(associationUtil.doesRecordExist(association.model, values[association.alias]));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check relations params.
|
|
||||||
Promise.all(associationsValidationPromises)
|
|
||||||
.then(function () {
|
|
||||||
|
|
||||||
Model.update(pk, values).exec(function updated(err, records) {
|
|
||||||
if (err) {
|
|
||||||
_ctx.status = 400;
|
|
||||||
return deferred.reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select the first and only one record.
|
|
||||||
const updatedRecord = records[0];
|
|
||||||
|
|
||||||
// Update `oneToOneRelations`.
|
|
||||||
const relationPromises = [];
|
|
||||||
_.forEach(_.where(Model.associations, {nature: 'oneToOne'}), function (relation) {
|
|
||||||
relationPromises.push(associationUtil.oneToOneRelationUpdated(_ctx.model || _ctx.params.model, pk, relation.model, updatedRecord[relation.alias]));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update the related records.
|
|
||||||
Promise.all(relationPromises)
|
|
||||||
.then(function () {
|
|
||||||
|
|
||||||
// Extra query to find and populate the updated record.
|
|
||||||
let query = Model.findOne(updatedRecord[Model.primaryKey]);
|
|
||||||
query = actionUtil.populateEach(query, _ctx, Model);
|
|
||||||
|
|
||||||
query.exec(function foundAgain(err, populatedRecord) {
|
|
||||||
if (err) {
|
|
||||||
_ctx.status = 500;
|
|
||||||
return deferred.reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
deferred.resolve(populatedRecord);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
// Error during related records update.
|
|
||||||
.catch(function (err) {
|
|
||||||
_ctx.status = 400;
|
|
||||||
deferred.reject(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
// Error during the new related records check.
|
|
||||||
.catch(function (err) {
|
|
||||||
_ctx.status = 400;
|
|
||||||
deferred.reject(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferred.promise;
|
|
||||||
};
|
|
@ -1,215 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Public node modules.
|
|
||||||
const _ = require('lodash');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper which returns a promise and then
|
|
||||||
* the found record
|
|
||||||
*
|
|
||||||
* @param {Object} model
|
|
||||||
* @param {string|int} id
|
|
||||||
*
|
|
||||||
* @return {Function|promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
doesRecordExist: function doesRecordExist(model, id) {
|
|
||||||
const deferred = Promise.defer();
|
|
||||||
|
|
||||||
strapi.orm
|
|
||||||
.collections[model]
|
|
||||||
.findOne(id)
|
|
||||||
.exec(function (err, foundRecord) {
|
|
||||||
if (err) {
|
|
||||||
return deferred.reject(err);
|
|
||||||
}
|
|
||||||
if (!foundRecord) {
|
|
||||||
return deferred.reject({
|
|
||||||
message: 'No ' + model + ' found with the specified `id`.'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
deferred.resolve(foundRecord);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferred.promise;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper which remove the relations of a specific entry and
|
|
||||||
* update the new relation if a relationId is specified
|
|
||||||
*
|
|
||||||
* @param originalModelAlias
|
|
||||||
* @param originalModelId
|
|
||||||
* @param relationModel
|
|
||||||
* @param relationId
|
|
||||||
*
|
|
||||||
* @return {Function|promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
oneToOneRelationUpdated: function oneToOneRelationUpdated(originalModelAlias, originalModelId, relationModel, relationId) {
|
|
||||||
const deferred = Promise.defer();
|
|
||||||
|
|
||||||
// First remove all relations
|
|
||||||
const promises = [];
|
|
||||||
|
|
||||||
// Update the relation of the origin model
|
|
||||||
promises.push(module.exports.removeRelationsOut(originalModelAlias, originalModelId, relationModel));
|
|
||||||
|
|
||||||
// Update the entries of the same collection
|
|
||||||
// of the original model.
|
|
||||||
promises.push(module.exports.removeRelationsIn(originalModelAlias, originalModelId, relationModel, relationId));
|
|
||||||
|
|
||||||
Promise.all(promises)
|
|
||||||
.then(function () {
|
|
||||||
|
|
||||||
// If a relationId is provided, update the new linked entry.
|
|
||||||
if (relationId) {
|
|
||||||
strapi.orm.collections[relationModel]
|
|
||||||
.findOne(relationId)
|
|
||||||
.exec(function (err, record) {
|
|
||||||
if (err) {
|
|
||||||
return deferred.reject(err);
|
|
||||||
}
|
|
||||||
if (!record) {
|
|
||||||
return deferred.reject({
|
|
||||||
message: 'Relation not found'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
record[originalModelAlias] = originalModelId;
|
|
||||||
record.save(function (err, record) {
|
|
||||||
if (err) {
|
|
||||||
return deferred.reject(err);
|
|
||||||
}
|
|
||||||
deferred.resolve(record);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
deferred.resolve();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(function (err) {
|
|
||||||
deferred.reject(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferred.promise;
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper which remove all the relations
|
|
||||||
* of a specific model
|
|
||||||
*
|
|
||||||
* @param originalModelAlias
|
|
||||||
* @param originalModelId
|
|
||||||
* @param relationModel
|
|
||||||
*
|
|
||||||
* @return {Function|promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
removeRelationsOut: function removeRelationsOut(originalModelAlias, originalModelId, relationModel) {
|
|
||||||
const deferred = Promise.defer();
|
|
||||||
|
|
||||||
if (!originalModelAlias) {
|
|
||||||
return deferred.reject({
|
|
||||||
message: 'originalModelAlias invalid.'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Params object used for the `find`function.
|
|
||||||
const findParams = {};
|
|
||||||
findParams[originalModelAlias] = originalModelId;
|
|
||||||
|
|
||||||
// Find all the matching entries of the original model.
|
|
||||||
strapi.orm.collections[relationModel]
|
|
||||||
.find(findParams)
|
|
||||||
.exec(function (err, records) {
|
|
||||||
if (err) {
|
|
||||||
return deferred.reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init the array of promises.
|
|
||||||
const savePromises = [];
|
|
||||||
|
|
||||||
// Set the relation to null.
|
|
||||||
// Save the entry and add the promise in the array.
|
|
||||||
_.forEach(records, function (record) {
|
|
||||||
record[originalModelAlias] = null;
|
|
||||||
savePromises.push(record.save());
|
|
||||||
});
|
|
||||||
|
|
||||||
Promise.all(savePromises)
|
|
||||||
.then(function () {
|
|
||||||
deferred.resolve(records);
|
|
||||||
})
|
|
||||||
.catch(function (err) {
|
|
||||||
deferred.reject(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferred.promise;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper which remove all the relations
|
|
||||||
* of a specific model
|
|
||||||
*
|
|
||||||
* @param originalModelAlias
|
|
||||||
* @param originalModelId
|
|
||||||
* @param relationModel
|
|
||||||
* @param {number|string}relationId
|
|
||||||
*
|
|
||||||
* @return {Function|promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
removeRelationsIn: function removeRelationsIn(originalModelAlias, originalModelId, relationModel, relationId) {
|
|
||||||
const deferred = Promise.defer();
|
|
||||||
|
|
||||||
// Params object used for the `find` function.
|
|
||||||
const findParams = {};
|
|
||||||
findParams[relationModel] = relationId;
|
|
||||||
findParams.id = {
|
|
||||||
'!': originalModelId
|
|
||||||
};
|
|
||||||
|
|
||||||
// Find all the matching entries of the original model.
|
|
||||||
strapi.orm.collections[originalModelAlias]
|
|
||||||
.find(findParams)
|
|
||||||
.exec(function (err, records) {
|
|
||||||
if (err) {
|
|
||||||
return deferred.reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init the array of promises.
|
|
||||||
const savePromises = [];
|
|
||||||
|
|
||||||
_.forEach(records, function (record) {
|
|
||||||
|
|
||||||
// Set the relation to null
|
|
||||||
if (record[relationModel]) {
|
|
||||||
record[relationModel] = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the entry and add the promise in the array
|
|
||||||
savePromises.push(record.save());
|
|
||||||
});
|
|
||||||
|
|
||||||
Promise.all(savePromises)
|
|
||||||
.then(function () {
|
|
||||||
deferred.resolve();
|
|
||||||
})
|
|
||||||
.catch(function (err) {
|
|
||||||
deferred.reject(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferred.promise;
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,48 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Blueprints hook
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function () {
|
|
||||||
const hook = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default options
|
|
||||||
*/
|
|
||||||
|
|
||||||
defaults: {
|
|
||||||
blueprints: {
|
|
||||||
defaultLimit: 30,
|
|
||||||
populate: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Export functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Utils
|
|
||||||
actionUtil: require('./actionUtil'),
|
|
||||||
associationUtil: require('./associationUtil'),
|
|
||||||
|
|
||||||
// Actions
|
|
||||||
find: require('./actions/find'),
|
|
||||||
findOne: require('./actions/findOne'),
|
|
||||||
create: require('./actions/create'),
|
|
||||||
update: require('./actions/update'),
|
|
||||||
destroy: require('./actions/destroy'),
|
|
||||||
remove: require('./actions/remove'),
|
|
||||||
add: require('./actions/add'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the hook
|
|
||||||
*/
|
|
||||||
|
|
||||||
initialize: function (cb) {
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return hook;
|
|
||||||
};
|
|
@ -8,7 +8,6 @@ module.exports = {
|
|||||||
_config: true,
|
_config: true,
|
||||||
_api: true,
|
_api: true,
|
||||||
responseTime: true,
|
responseTime: true,
|
||||||
waterline: true,
|
|
||||||
bodyParser: true,
|
bodyParser: true,
|
||||||
session: true,
|
session: true,
|
||||||
grant: true,
|
grant: true,
|
||||||
@ -22,7 +21,6 @@ module.exports = {
|
|||||||
i18n: true,
|
i18n: true,
|
||||||
cron: true,
|
cron: true,
|
||||||
logger: true,
|
logger: true,
|
||||||
blueprints: true,
|
|
||||||
views: true,
|
views: true,
|
||||||
router: true,
|
router: true,
|
||||||
static: true,
|
static: true,
|
||||||
|
@ -103,20 +103,6 @@ module.exports = function (strapi) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Define GraphQL route with modified Waterline models to GraphQL schema
|
|
||||||
// or disable the global variable
|
|
||||||
if (strapi.config.graphql.enabled === true) {
|
|
||||||
// Wait GraphQL schemas generation
|
|
||||||
strapi.once('waterline:graphql:ready', function () {
|
|
||||||
strapi.router.get(strapi.config.graphql.route, strapi.middlewares.graphql({
|
|
||||||
schema: strapi.schemas,
|
|
||||||
pretty: true
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
global.graphql = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let the router use our routes and allowed methods.
|
// Let the router use our routes and allowed methods.
|
||||||
strapi.app.use(strapi.router.routes());
|
strapi.app.use(strapi.router.routes());
|
||||||
strapi.app.use(strapi.router.allowedMethods());
|
strapi.app.use(strapi.router.allowedMethods());
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Locale helpers.
|
|
||||||
const isManyToOneAssociation = require('./isManyToOneAssociation');
|
|
||||||
const isOneToOneAssociation = require('./isOneToOneAssociation');
|
|
||||||
const isOneWayAssociation = require('./isOneWayAssociation');
|
|
||||||
const isOneToManyAssociation = require('./isOneToManyAssociation');
|
|
||||||
const isManyToManyAssociation = require('./isManyToManyAssociation');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper which returns the association type of the attribute
|
|
||||||
*
|
|
||||||
* @param {Object} currentModel
|
|
||||||
* @param {Object} association
|
|
||||||
*
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
getAssociationType: function (currentModel, association) {
|
|
||||||
let associationType;
|
|
||||||
|
|
||||||
if (association.type === 'model') {
|
|
||||||
if (isManyToOneAssociation(currentModel, association)) {
|
|
||||||
associationType = 'manyToOne';
|
|
||||||
} else if (isOneToOneAssociation(currentModel, association)) {
|
|
||||||
associationType = 'oneToOne';
|
|
||||||
} else if (isOneWayAssociation(currentModel, association)) {
|
|
||||||
associationType = 'oneWay';
|
|
||||||
} else {
|
|
||||||
associationType = 'unknown';
|
|
||||||
}
|
|
||||||
} else if (association.type === 'collection') {
|
|
||||||
if (isOneToManyAssociation(currentModel, association)) {
|
|
||||||
associationType = 'oneToMany';
|
|
||||||
} else if (isManyToManyAssociation(currentModel, association)) {
|
|
||||||
associationType = 'manyToMany';
|
|
||||||
} else {
|
|
||||||
associationType = 'unknown';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return associationType;
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,24 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Public node modules.
|
|
||||||
const _ = require('lodash');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper which returns a boolean. True if the type
|
|
||||||
* of the relation is `manyToMany`.
|
|
||||||
*
|
|
||||||
* @param {Object} currentModel
|
|
||||||
* @param {Object} association
|
|
||||||
*
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function isManyToManyAssociation(currentModel, association) {
|
|
||||||
return _.findWhere(strapi.models[association.collection] && strapi.models[association.collection].associations, {
|
|
||||||
collection: currentModel
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,24 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Public node modules.
|
|
||||||
const _ = require('lodash');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper which returns a boolean. True if the type
|
|
||||||
* of the relation is `manyToOne`.
|
|
||||||
*
|
|
||||||
* @param {Object} currentModel
|
|
||||||
* @param {Object} association
|
|
||||||
*
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function isManyToOneAssociation(currentModel, association) {
|
|
||||||
return _.findWhere(strapi.models[association.model] && strapi.models[association.model].associations, {
|
|
||||||
collection: currentModel
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,24 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Public node modules.
|
|
||||||
const _ = require('lodash');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper which returns a boolean. True if the type
|
|
||||||
* of the relation is `oneToMany`.
|
|
||||||
*
|
|
||||||
* @param {Object} currentModel
|
|
||||||
* @param {Object} association
|
|
||||||
*
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function isOneToManyAssociation(currentModel, association) {
|
|
||||||
return _.findWhere(strapi.models[association.collection] && strapi.models[association.collection].associations, {
|
|
||||||
model: currentModel
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,24 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Public node modules.
|
|
||||||
const _ = require('lodash');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper which returns a boolean. True if the type
|
|
||||||
* of the relation is `oneToOne`.
|
|
||||||
*
|
|
||||||
* @param {Object} currentModel
|
|
||||||
* @param {Object} association
|
|
||||||
*
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function isOneToOneAssociation(currentModel, association) {
|
|
||||||
return _.findWhere(strapi.models[association.model] && strapi.models[association.model].associations, {
|
|
||||||
model: currentModel
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,23 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Locale helpers.
|
|
||||||
const isOneToManyAssociation = require('./isOneToManyAssociation');
|
|
||||||
const isOneToOneAssociation = require('./isOneToOneAssociation');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper which returns a boolean. True if the type
|
|
||||||
* of the relation is `oneToOne`.
|
|
||||||
*
|
|
||||||
* @param {Object} currentModel
|
|
||||||
* @param {Object} association
|
|
||||||
*
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function isOneWayAssociation(currentModel, association) {
|
|
||||||
return !(isOneToManyAssociation(currentModel, association) || isOneToOneAssociation(currentModel, association));
|
|
||||||
};
|
|
@ -1,302 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Node.js core.
|
|
||||||
const cluster = require('cluster');
|
|
||||||
const path = require('path');
|
|
||||||
const spawn = require('child_process').spawn;
|
|
||||||
|
|
||||||
// Public node modules.
|
|
||||||
const _ = require('lodash');
|
|
||||||
const async = require('async');
|
|
||||||
const Waterline = require('waterline');
|
|
||||||
const WaterlineGraphQL = require('waterline-graphql');
|
|
||||||
|
|
||||||
// Local utilities.
|
|
||||||
const helpers = require('./helpers/index');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Waterline ORM hook
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function (strapi) {
|
|
||||||
const hook = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default options
|
|
||||||
*/
|
|
||||||
|
|
||||||
defaults: {
|
|
||||||
orm: {
|
|
||||||
adapters: {
|
|
||||||
disk: 'sails-disk'
|
|
||||||
},
|
|
||||||
defaultConnection: 'default',
|
|
||||||
connections: {
|
|
||||||
default: {
|
|
||||||
adapter: 'disk',
|
|
||||||
filePath: '.tmp/',
|
|
||||||
fileName: 'default.db',
|
|
||||||
migrate: 'alter'
|
|
||||||
},
|
|
||||||
permanent: {
|
|
||||||
adapter: 'disk',
|
|
||||||
filePath: './data/',
|
|
||||||
fileName: 'permanent.db',
|
|
||||||
migrate: 'alter'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
globals: {
|
|
||||||
models: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the hook
|
|
||||||
*/
|
|
||||||
|
|
||||||
initialize: function (cb) {
|
|
||||||
if (_.isPlainObject(strapi.config.orm) && !_.isEmpty(strapi.config.orm) && (((cluster.isWorker && strapi.config.reload.workers > 0) || (cluster.isMaster && strapi.config.reload.workers < 1)) || !strapi.config.reload && cluster.isMaster)) {
|
|
||||||
strapi.adapters = {};
|
|
||||||
strapi.collections = [];
|
|
||||||
|
|
||||||
// Expose a new instance of Waterline.
|
|
||||||
if (!strapi.orm) {
|
|
||||||
strapi.orm = new Waterline();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prefix every adapter and require them from the
|
|
||||||
// `node_modules` directory of the application.
|
|
||||||
_.forEach(strapi.config.orm.adapters, function (adapter, name) {
|
|
||||||
try {
|
|
||||||
strapi.adapters[name] = require(path.resolve(strapi.config.appPath, 'node_modules', adapter));
|
|
||||||
} catch (err) {
|
|
||||||
strapi.log.error('The adapter `' + adapter + '` is not installed.');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check if the adapter in every connections exists.
|
|
||||||
_.forEach(strapi.config.orm.connections, function (settings, name) {
|
|
||||||
if (!_.has(strapi.config.orm.adapters, settings.adapter)) {
|
|
||||||
strapi.log.error('Unknown adapter `' + settings.adapter + '` for connection `' + name + '`.');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Parse each models.
|
|
||||||
_.forEach(strapi.models, function (definition, model) {
|
|
||||||
_.bindAll(definition);
|
|
||||||
|
|
||||||
// Make sure the model has a connection.
|
|
||||||
// If not, use the default connection.
|
|
||||||
if (_.isEmpty(definition.connection)) {
|
|
||||||
definition.connection = strapi.config.orm.defaultConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure this connection exists.
|
|
||||||
if (!_.has(strapi.config.orm.connections, definition.connection)) {
|
|
||||||
strapi.log.error('The connection `' + definition.connection + '` specified in the `' + model + '` model does not exist.');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure this connection has an appropriate migrate strategy.
|
|
||||||
// If not, use the appropriate strategy.
|
|
||||||
if (!_.has(strapi.config.orm.connections[definition.connection], 'migrate')) {
|
|
||||||
if (strapi.config.environment === 'production') {
|
|
||||||
strapi.log.warn('Setting the migrate strategy of the `' + model + '` model to `safe`.');
|
|
||||||
strapi.config.orm.connections[definition.connection].migrate = 'safe';
|
|
||||||
} else {
|
|
||||||
strapi.log.warn('Setting the migrate strategy of the `' + model + '` model to `alter`.');
|
|
||||||
strapi.config.orm.connections[definition.connection].migrate = 'alter';
|
|
||||||
}
|
|
||||||
} else if (strapi.config.environment === 'production' && strapi.config.orm.connections[definition.connection].migrate === ('alter' || 'drop')) {
|
|
||||||
strapi.log.warn('Setting the migrate strategy of the `' + model + '` model to `safe`.');
|
|
||||||
strapi.config.orm.connections[definition.connection].migrate = 'safe';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply the migrate strategy to the model.
|
|
||||||
definition.migrate = strapi.config.orm.connections[definition.connection].migrate;
|
|
||||||
|
|
||||||
// Derive information about this model's associations from its schema
|
|
||||||
// and attach/expose the metadata as `SomeModel.associations` (an array).
|
|
||||||
definition.associations = _.reduce(definition.attributes, function (associatedWith, attrDef, attrName) {
|
|
||||||
if (typeof attrDef === 'object' && (attrDef.model || attrDef.collection)) {
|
|
||||||
const assoc = {
|
|
||||||
alias: attrName,
|
|
||||||
type: attrDef.model ? 'model' : 'collection'
|
|
||||||
};
|
|
||||||
|
|
||||||
if (attrDef.model) {
|
|
||||||
assoc.model = attrDef.model;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attrDef.collection) {
|
|
||||||
assoc.collection = attrDef.collection;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attrDef.via) {
|
|
||||||
assoc.via = attrDef.via;
|
|
||||||
}
|
|
||||||
|
|
||||||
associatedWith.push(assoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
return associatedWith;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Finally, load the collection in the Waterline instance.
|
|
||||||
try {
|
|
||||||
const collection = strapi.orm.loadCollection(Waterline.Collection.extend(definition));
|
|
||||||
|
|
||||||
if (_.isFunction(collection)) {
|
|
||||||
strapi.collections.push(collection);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
strapi.log.error('Impossible to register the `' + model + '` model.');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Finally, initialize the Waterline ORM and
|
|
||||||
// globally expose models.
|
|
||||||
strapi.orm.initialize({
|
|
||||||
adapters: strapi.adapters,
|
|
||||||
connections: strapi.config.orm.connections,
|
|
||||||
collections: strapi.collections,
|
|
||||||
defaults: {
|
|
||||||
connection: strapi.config.orm.defaultConnection
|
|
||||||
}
|
|
||||||
}, function () {
|
|
||||||
if (strapi.config.globals.models === true) {
|
|
||||||
_.forEach(strapi.models, function (definition, model) {
|
|
||||||
const globalName = _.capitalize(strapi.models[model].globalId);
|
|
||||||
global[globalName] = strapi.orm.collections[model];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse each models and look for associations.
|
|
||||||
_.forEach(strapi.orm.collections, function (definition, model) {
|
|
||||||
_.forEach(definition.associations, function (association) {
|
|
||||||
association.nature = helpers.getAssociationType(model, association);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (strapi.config.graphql.enabled === true) {
|
|
||||||
// Parse each models and add associations array
|
|
||||||
_.forEach(strapi.orm.collections, function (collection, key) {
|
|
||||||
if (strapi.models.hasOwnProperty(key)) {
|
|
||||||
collection.associations = strapi.models[key].associations || [];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Expose the GraphQL schemas at `strapi.schemas`
|
|
||||||
WaterlineGraphQL.getGraphQLSchema({
|
|
||||||
collections: strapi.orm.collections,
|
|
||||||
usefulFunctions: true
|
|
||||||
}, function (schemas) {
|
|
||||||
strapi.schemas = schemas;
|
|
||||||
|
|
||||||
strapi.emit('waterline:graphql:ready');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
cb();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reload the hook
|
|
||||||
*/
|
|
||||||
|
|
||||||
reload: function () {
|
|
||||||
hook.teardown(function () {
|
|
||||||
delete strapi.orm;
|
|
||||||
|
|
||||||
hook.initialize(function (err) {
|
|
||||||
if (err) {
|
|
||||||
strapi.log.error('Failed to reinitialize the ORM hook.');
|
|
||||||
strapi.stop();
|
|
||||||
} else {
|
|
||||||
strapi.emit('hook:waterline:reloaded');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Teardown adapters
|
|
||||||
*/
|
|
||||||
|
|
||||||
teardown: function (cb) {
|
|
||||||
cb = cb || function (err) {
|
|
||||||
if (err) {
|
|
||||||
strapi.log.error('Failed to teardown ORM adapters.');
|
|
||||||
strapi.stop();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
async.forEach(Object.keys(strapi.adapters || {}), function (name, next) {
|
|
||||||
if (strapi.adapters[name].teardown) {
|
|
||||||
strapi.adapters[name].teardown(null, next);
|
|
||||||
} else {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
}, cb);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Installation adapters
|
|
||||||
*/
|
|
||||||
|
|
||||||
installation: function () {
|
|
||||||
const done = _.after(_.size(strapi.config.orm.adapters), function () {
|
|
||||||
strapi.emit('hook:waterline:installed');
|
|
||||||
});
|
|
||||||
|
|
||||||
_.forEach(strapi.config.orm.adapters, function (adapter) {
|
|
||||||
try {
|
|
||||||
require(path.resolve(strapi.config.appPath, 'node_modules', adapter));
|
|
||||||
|
|
||||||
done();
|
|
||||||
} catch (err) {
|
|
||||||
if (strapi.config.environment === 'development') {
|
|
||||||
strapi.log.warn('Installing the `' + adapter + '` adapter, please wait...');
|
|
||||||
console.log();
|
|
||||||
|
|
||||||
const process = spawn('npm', ['install', adapter, '--save']);
|
|
||||||
|
|
||||||
process.on('error', function (error) {
|
|
||||||
strapi.log.error('The adapter `' + adapter + '` has not been installed.');
|
|
||||||
strapi.log.error(error);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
process.on('close', function (code) {
|
|
||||||
if (code !== 0) {
|
|
||||||
strapi.log.error('The adapter `' + adapter + '` has not been installed.');
|
|
||||||
strapi.log.error('Code: ' + code);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
strapi.log.info('`' + adapter + '` successfully installed');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
strapi.log.error('The adapter `' + adapter + '` is not installed.');
|
|
||||||
strapi.log.error('Execute `$ npm install ' + adapter + ' --save` to install it.');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return hook;
|
|
||||||
};
|
|
@ -39,10 +39,8 @@ module.exports = function (strapi) {
|
|||||||
|
|
||||||
// Remove undesired hooks when this is a `dry` application.
|
// Remove undesired hooks when this is a `dry` application.
|
||||||
if (strapi.config.dry) {
|
if (strapi.config.dry) {
|
||||||
delete hooks.blueprints;
|
|
||||||
delete hooks.grant;
|
delete hooks.grant;
|
||||||
delete hooks.studio;
|
delete hooks.studio;
|
||||||
delete hooks.waterline;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle folder-defined modules (default to `./lib/index.js`)
|
// Handle folder-defined modules (default to `./lib/index.js`)
|
||||||
@ -130,7 +128,7 @@ module.exports = function (strapi) {
|
|||||||
|
|
||||||
// Prepare all other hooks.
|
// Prepare all other hooks.
|
||||||
prepare: function prepareHooks(cb) {
|
prepare: function prepareHooks(cb) {
|
||||||
async.each(_.without(_.keys(hooks), '_config', '_api', 'studio', 'router', 'waterline'), function (id, cb) {
|
async.each(_.without(_.keys(hooks), '_config', '_api', 'studio', 'router'), function (id, cb) {
|
||||||
prepareHook(id);
|
prepareHook(id);
|
||||||
process.nextTick(cb);
|
process.nextTick(cb);
|
||||||
}, cb);
|
}, cb);
|
||||||
@ -138,7 +136,7 @@ module.exports = function (strapi) {
|
|||||||
|
|
||||||
// Apply the default config for all other hooks.
|
// Apply the default config for all other hooks.
|
||||||
defaults: function defaultConfigHooks(cb) {
|
defaults: function defaultConfigHooks(cb) {
|
||||||
async.each(_.without(_.keys(hooks), '_config', '_api', 'studio', 'router', 'waterline'), function (id, cb) {
|
async.each(_.without(_.keys(hooks), '_config', '_api', 'studio', 'router'), function (id, cb) {
|
||||||
const hook = hooks[id];
|
const hook = hooks[id];
|
||||||
applyDefaults(hook);
|
applyDefaults(hook);
|
||||||
process.nextTick(cb);
|
process.nextTick(cb);
|
||||||
@ -147,7 +145,7 @@ module.exports = function (strapi) {
|
|||||||
|
|
||||||
// Load all other hooks.
|
// Load all other hooks.
|
||||||
load: function loadOtherHooks(cb) {
|
load: function loadOtherHooks(cb) {
|
||||||
async.each(_.without(_.keys(hooks), '_config', '_api', 'studio', 'router', 'waterline'), function (id, cb) {
|
async.each(_.without(_.keys(hooks), '_config', '_api', 'studio', 'router'), function (id, cb) {
|
||||||
loadHook(id, cb);
|
loadHook(id, cb);
|
||||||
}, cb);
|
}, cb);
|
||||||
},
|
},
|
||||||
@ -160,16 +158,6 @@ module.exports = function (strapi) {
|
|||||||
prepareHook('router');
|
prepareHook('router');
|
||||||
applyDefaults(hooks.router);
|
applyDefaults(hooks.router);
|
||||||
loadHook('router', cb);
|
loadHook('router', cb);
|
||||||
},
|
|
||||||
|
|
||||||
// Load the waterline hook.
|
|
||||||
waterline: function loadWaterlineHook(cb) {
|
|
||||||
if (!hooks.waterline) {
|
|
||||||
return cb();
|
|
||||||
}
|
|
||||||
prepareHook('waterline');
|
|
||||||
applyDefaults(hooks.waterline);
|
|
||||||
loadHook('waterline', cb);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -55,7 +55,6 @@ module.exports = cb => {
|
|||||||
|
|
||||||
// Run adapters installation
|
// Run adapters installation
|
||||||
if (cluster.isMaster) {
|
if (cluster.isMaster) {
|
||||||
strapi.hooks.waterline.installation();
|
|
||||||
|
|
||||||
++count;
|
++count;
|
||||||
|
|
||||||
@ -72,44 +71,34 @@ module.exports = cb => {
|
|||||||
console.log();
|
console.log();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Teardown Waterline adapters and
|
// Reload the router.
|
||||||
// reload the Waterline ORM.
|
strapi.after('hook:router:reloaded', () => {
|
||||||
strapi.after('hook:waterline:reloaded', () => {
|
process.nextTick(() => cb());
|
||||||
strapi.after('hook:router:reloaded', () => {
|
|
||||||
process.nextTick(() => cb());
|
|
||||||
|
|
||||||
// Update `strapi` status.
|
// Update `strapi` status.
|
||||||
strapi.reloaded = true;
|
strapi.reloaded = true;
|
||||||
strapi.reloading = false;
|
strapi.reloading = false;
|
||||||
|
|
||||||
// Finally inform the developer everything seems ok.
|
// Finally inform the developer everything seems ok.
|
||||||
if (cluster.isMaster && _.isPlainObject(strapi.config.reload) && !_.isEmpty(strapi.config.reload) && strapi.config.reload.workers < 1) {
|
if (cluster.isMaster && _.isPlainObject(strapi.config.reload) && !_.isEmpty(strapi.config.reload) && strapi.config.reload.workers < 1) {
|
||||||
strapi.log.info('Application\'s dictionnary updated');
|
strapi.log.info('Application\'s dictionnary updated');
|
||||||
strapi.log.warn('You still need to restart your server to fully enjoy changes...');
|
strapi.log.warn('You still need to restart your server to fully enjoy changes...');
|
||||||
}
|
}
|
||||||
|
|
||||||
strapi.once('restart:done', function () {
|
strapi.once('restart:done', function () {
|
||||||
strapi.log.info('Application successfully restarted');
|
strapi.log.info('Application successfully restarted');
|
||||||
});
|
|
||||||
|
|
||||||
if (cluster.isMaster) {
|
|
||||||
_.forEach(cluster.workers, worker => worker.on('message', () => strapi.emit('restart:done')));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kill every worker processes.
|
|
||||||
_.forEach(cluster.workers, () => process.kill(process.pid, 'SIGHUP'));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reloading the router.
|
if (cluster.isMaster) {
|
||||||
strapi.hooks.router.reload();
|
_.forEach(cluster.workers, worker => worker.on('message', () => strapi.emit('restart:done')));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kill every worker processes.
|
||||||
|
_.forEach(cluster.workers, () => process.kill(process.pid, 'SIGHUP'));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reloading the ORM.
|
// Reloading the router.
|
||||||
strapi.hooks.waterline.reload();
|
strapi.hooks.router.reload();
|
||||||
});
|
|
||||||
|
|
||||||
strapi.after('hook:waterline:installed', () => {
|
|
||||||
installed();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
strapi.after('hook:views:installed', () => {
|
strapi.after('hook:views:installed', () => {
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
"security",
|
"security",
|
||||||
"socket.io",
|
"socket.io",
|
||||||
"sockets",
|
"sockets",
|
||||||
"waterline",
|
|
||||||
"websockets"
|
"websockets"
|
||||||
],
|
],
|
||||||
"directories": {
|
"directories": {
|
||||||
@ -67,9 +66,9 @@
|
|||||||
"node-schedule": "~0.6.0",
|
"node-schedule": "~0.6.0",
|
||||||
"prompt": "~0.2.14",
|
"prompt": "~0.2.14",
|
||||||
"request": "~2.67.0",
|
"request": "~2.67.0",
|
||||||
"sails-disk": "~0.10.8",
|
|
||||||
"socket.io": "~1.3.7",
|
"socket.io": "~1.3.7",
|
||||||
"socket.io-client": "~1.3.7",
|
"socket.io-client": "~1.3.7",
|
||||||
|
"strapi-bookshelf": "~1.5.0",
|
||||||
"strapi-generate": "~1.5.0",
|
"strapi-generate": "~1.5.0",
|
||||||
"strapi-generate-admin": "~1.5.0",
|
"strapi-generate-admin": "~1.5.0",
|
||||||
"strapi-generate-api": "~1.5.0",
|
"strapi-generate-api": "~1.5.0",
|
||||||
@ -78,8 +77,6 @@
|
|||||||
"strapi-generate-upload": "~1.5.0",
|
"strapi-generate-upload": "~1.5.0",
|
||||||
"strapi-generate-users": "~1.5.0",
|
"strapi-generate-users": "~1.5.0",
|
||||||
"unzip2": "~0.2.5",
|
"unzip2": "~0.2.5",
|
||||||
"waterline": "~0.10.28",
|
|
||||||
"waterline-graphql": "~1.1.0",
|
|
||||||
"winston": "~2.1.1"
|
"winston": "~2.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -167,8 +164,8 @@
|
|||||||
"url": "https://github.com/wistityhq/strapi/issues"
|
"url": "https://github.com/wistityhq/strapi/issues"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.12.0",
|
"node": ">= 4.0.0",
|
||||||
"npm": ">= 2.0.0"
|
"npm": ">= 3.0.0"
|
||||||
},
|
},
|
||||||
"preferGlobal": true,
|
"preferGlobal": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user