Split Content-Manager logic into service & allow CRUD and associations w/ plugin's models w/ Mongoose

This commit is contained in:
Aurelsicoko 2017-12-11 18:23:15 +01:00
parent d53287362a
commit 8db92c22fd
13 changed files with 150 additions and 93 deletions

View File

@ -40,7 +40,6 @@ import auth from 'utils/auth';
import configureStore from './store';
import { translationMessages, languages } from './i18n';
import { findIndex } from 'lodash';
/* eslint-enable */
const plugins = (() => {
try {
@ -49,6 +48,7 @@ const plugins = (() => {
return [];
}
})();
/* eslint-enable */
// Create redux store with history
const initialState = {};

View File

@ -32,7 +32,7 @@ class LeftMenuLink extends React.Component { // eslint-disable-line react/prefer
id={this.props.label}
defaultMessage='{label}'
values={{
label: this.props.label,
label: `${this.props.label} ${this.props.source !== 'content-manager' ? '⬖' : ''}`,
}}
className={styles.linkLabel}
/>

File diff suppressed because one or more lines are too long

View File

@ -132,7 +132,6 @@ module.exports = function (strapi) {
virtuals: true
});
if (!plugin) {
global[definition.globalName] = instance.model(definition.globalName, collection.schema);
} else {
@ -162,7 +161,7 @@ module.exports = function (strapi) {
}
definition.globalName = _.upperFirst(_.camelCase(definition.globalId));
// Make sure the model has a connection.
// If not, use the default connection.
if (_.isEmpty(definition.connection)) {
@ -218,22 +217,24 @@ module.exports = function (strapi) {
definition.loadedModel[name].type = utils(instance).convertType(details.type);
}
let FK;
switch (verbose) {
case 'hasOne':
case 'hasOne': {
const ref = details.plugin ? _.upperFirst(_.camelCase(`${details.plugin}-${details.model}`)) : _.capitalize(details.model);
definition.loadedModel[name] = {
type: instance.Schema.Types.ObjectId,
ref: _.capitalize(details.model)
ref
};
break;
case 'hasMany':
FK = _.find(definition.associations, {alias: name});
}
case 'hasMany': {
const FK = _.find(definition.associations, {alias: name});
const ref = details.plugin ? _.upperFirst(_.camelCase(`${details.plugin}-${details.collection}`)) : _.capitalize(details.collection);
if (FK) {
definition.loadedModel[name] = {
type: 'virtual',
ref: _.capitalize(details.collection),
ref,
via: FK.via,
justOne: false
};
@ -243,17 +244,19 @@ module.exports = function (strapi) {
} else {
definition.loadedModel[name] = [{
type: instance.Schema.Types.ObjectId,
ref: _.capitalize(details.collection)
ref
}];
}
break;
case 'belongsTo':
FK = _.find(definition.associations, {alias: name});
}
case 'belongsTo': {
const FK = _.find(definition.associations, {alias: name});
const ref = details.plugin ? _.upperFirst(_.camelCase(`${details.plugin}-${details.model}`)) : _.capitalize(details.model);
if (FK && FK.nature !== 'oneToOne' && FK.nature !== 'manyToOne') {
definition.loadedModel[name] = {
type: 'virtual',
ref: _.capitalize(details.model),
ref,
via: FK.via,
justOne: true
};
@ -263,19 +266,21 @@ module.exports = function (strapi) {
} else {
definition.loadedModel[name] = {
type: instance.Schema.Types.ObjectId,
ref: _.capitalize(details.model)
ref
};
}
break;
case 'belongsToMany':
FK = _.find(definition.associations, {alias: name});
}
case 'belongsToMany': {
const FK = _.find(definition.associations, {alias: name});
const ref = details.plugin ? _.upperFirst(_.camelCase(`${details.plugin}-${details.collection}`)) : _.capitalize(details.collection);
// One-side of the relationship has to be a virtual field to be bidirectional.
if ((FK && _.isUndefined(FK.via)) || details.dominant !== true) {
definition.loadedModel[name] = {
type: 'virtual',
ref: _.capitalize(FK.collection),
ref,
via: FK.via
};
@ -284,10 +289,11 @@ module.exports = function (strapi) {
} else {
definition.loadedModel[name] = [{
type: instance.Schema.Types.ObjectId,
ref: _.capitalize(details.collection)
ref
}];
}
break;
}
default:
break;
}

View File

@ -20,14 +20,17 @@ import styles from './styles.scss';
class EditFormRelations extends React.Component { // eslint-disable-line react/prefer-stateless-function
componentDidMount() {
if (size(get(this.props.schema, [this.props.currentModelName, 'relations'])) === 0 && !this.props.isNull) {
const source = getQueryParameters(this.props.location.search, 'source');
const currentSchema = source !== 'content-manager' ? get(this.props.schema, ['plugins', source, this.props.currentModelName]) : get(this.props.schema, [this.props.currentModelName]);
if (size(get(currentSchema, ['relations'])) === 0 && !this.props.isNull) {
this.props.toggleNull();
}
}
render() {
const source = getQueryParameters(this.props.location.search, 'source');
const currentSchema = get(this.props.schema, [this.props.currentModelName]) || get(this.props.schema, ['plugins', source, this.props.currentModelName]);
const currentSchema = source !== 'content-manager' ? get(this.props.schema, ['plugins', source, this.props.currentModelName]) : get(this.props.schema, [this.props.currentModelName]);
const relations = map(currentSchema.relations, (relation, i) => {
@ -43,6 +46,7 @@ class EditFormRelations extends React.Component { // eslint-disable-line react/p
relation={relation}
schema={this.props.schema}
setRecordAttribute={this.props.setRecordAttribute}
location={this.props.location}
/>
);
}
@ -57,6 +61,7 @@ class EditFormRelations extends React.Component { // eslint-disable-line react/p
relation={relation}
schema={this.props.schema}
setRecordAttribute={this.props.setRecordAttribute}
location={this.props.location}
/>
);
default:

View File

@ -27,6 +27,7 @@ class SelectMany extends React.Component { // eslint-disable-line react/prefer-s
getOptions = (query) => {
const params = {
limit: 20,
source: this.props.relation.plugin || 'content-manager',
};
// Set `query` parameter if necessary

View File

@ -27,6 +27,7 @@ class SelectOne extends React.Component { // eslint-disable-line react/prefer-st
getOptions = (query) => {
const params = {
limit: 20,
source: this.props.relation.plugin || 'content-manager',
};
// Set `query` parameter if necessary

View File

@ -66,7 +66,7 @@ module.exports = {
if (response[current] && _.isObject(response[current]) && response[current][this.primaryKey] !== value[current]) {
virtualFields.push(
strapi.query(details.collection || details.model).update({
strapi.query(details.collection || details.model, details.plugin).update({
id: response[current][this.primaryKey],
values: {
[details.via]: null
@ -78,7 +78,7 @@ module.exports = {
// Remove previous relationship asynchronously if it exists.
virtualFields.push(
strapi.query(details.model || details.collection).findOne({ id : recordId })
strapi.query(details.model || details.collection, details.plugin).findOne({ id : recordId })
.then(record => {
if (record && _.isObject(record[details.via])) {
return module.exports.update.call(this, {
@ -96,7 +96,7 @@ module.exports = {
// Update the record on the other side.
// When params.values[current] is null this means that we are removing the relation.
virtualFields.push(strapi.query(details.model || details.collection).update({
virtualFields.push(strapi.query(details.model || details.collection, details.plugin).update({
id: recordId,
values: {
[details.via]: _.isNull(params.values[current]) ? null : value[this.primaryKey] || value.id || value._id
@ -127,14 +127,16 @@ module.exports = {
// Push the work into the flow process.
toAdd.forEach(value => {
if (association.nature === 'manyToMany' && !_.isArray(params.values[this.primaryKey] || params[this.primaryKey])) {
value[details.via] = (value[details.via] || []).concat([(params.values[this.primaryKey] || params[this.primaryKey])]).filter(x => {
return x !== null && x !== undefined;
});
value[details.via] = (value[details.via] || [])
.concat([(params.values[this.primaryKey] || params[this.primaryKey])])
.filter(x => {
return x !== null && x !== undefined;
});
} else {
value[details.via] = params[this.primaryKey] || params.id;
}
virtualFields.push(strapi.query(details.model || details.collection).addRelation({
virtualFields.push(strapi.query(details.model || details.collection, details.plugin).addRelation({
id: value[this.primaryKey] || value.id || value._id,
values: value,
foreignKey: current
@ -148,7 +150,7 @@ module.exports = {
value[details.via] = null;
}
virtualFields.push(strapi.query(details.model || details.collection).removeRelation({
virtualFields.push(strapi.query(details.model || details.collection, details.plugin).removeRelation({
id: value[this.primaryKey] || value.id || value._id,
values: value,
foreignKey: current

View File

@ -35,25 +35,14 @@ module.exports = {
},
find: async ctx => {
const { limit, skip = 0, sort, query, queryAttribute, source, page } = ctx.request.query;
// Find entries using `queries` system
const entries = await strapi.query(ctx.params.model, source).find({
limit,
skip,
sort,
query,
queryAttribute
});
ctx.body = entries;
ctx.body = await strapi.plugins['content-manager'].services['contentmanager'].fetchAll(ctx.params, ctx.request.query);
},
count: async ctx => {
const { source } = ctx.request.query;
// Count using `queries` system
const count = await strapi.query(ctx.params.model, source).count();
const count = await strapi.plugins['content-manager'].services['contentmanager'].count(ctx.params, source);
ctx.body = {
count: _.isNumber(count) ? count : _.toNumber(count)
@ -64,9 +53,7 @@ module.exports = {
const { source } = ctx.request.query;
// Find an entry using `queries` system
const entry = await strapi.query(ctx.params.model, source).findOne({
id: ctx.params.id
});
const entry = await strapi.plugins['content-manager'].services['contentmanager'].fetch(ctx.params, source);
// Entry not found
if (!entry) {
@ -81,12 +68,9 @@ module.exports = {
try {
// Create an entry using `queries` system
const entryCreated = await strapi.query(ctx.params.model, source).create({
values: ctx.request.body
});
ctx.body = entryCreated;
ctx.body = await strapi.plugins['content-manager'].services['contentmanager'].add(ctx.params, ctx.request.body, source);
} catch(error) {
console.log(error);
ctx.badRequest(null, ctx.request.admin ? [{ messages: [{ id: error.message, field: error.field }] }] : error.message);
}
},
@ -95,14 +79,8 @@ module.exports = {
const { source } = ctx.request.query;
try {
// Add current model to the flow of updates.
const entry = strapi.query(ctx.params.model, source).update({
id: ctx.params.id,
values: ctx.request.body
});
// Return the last one which is the current model.
ctx.body = entry;
ctx.body = await strapi.plugins['content-manager'].services['contentmanager'].edit(ctx.params, ctx.request.body, source);
} catch(error) {
// TODO handle error update
ctx.badRequest(null, ctx.request.admin ? [{ messages: [{ id: error.message, field: error.field }] }] : error.message);
@ -110,34 +88,6 @@ module.exports = {
},
delete: async ctx => {
const { source } = ctx.request.query;
const params = ctx.params;
const response = await strapi.query(params.model, source).findOne({
id: params.id
});
params.values = Object.keys(JSON.parse(JSON.stringify(response))).reduce((acc, current) => {
const association = (strapi.models[params.model] || strapi.plugins[source].models[params.model]).associations.filter(x => x.alias === current)[0];
// Remove relationships.
if (association) {
acc[current] = _.isArray(response[current]) ? [] : null;
}
return acc;
}, {});
if (!_.isEmpty(params.values)) {
// Run update to remove all relationships.
await strapi.query(params.model, source).update(params);
}
// Delete an entry using `queries` system
const entryDeleted = await strapi.query(params.model, source).delete({
id: params.id
});
ctx.body = entryDeleted;
ctx.body = await strapi.plugins['content-manager'].services['contentmanager'].delete(ctx.params, ctx.request.query);
},
};

View File

@ -0,0 +1,73 @@
'use strict';
const _ = require('lodash');
/**
* A set of functions called "actions" for `ContentManager`
*/
module.exports = {
fetchAll: async (params, query) => {
const { limit, skip = 0, sort, query : request, queryAttribute, source, page } = query;
// Find entries using `queries` system
return await strapi.query(params.model, source).find({
limit,
skip,
sort,
query: request,
queryAttribute
});
},
count: async (params, source) => {
return await strapi.query(params.model, source).count();
},
fetch: async (params, source) => {
return await strapi.query(params.model, source).findOne({
id: params.id
});
},
add: async (params, values, source) => {
// Create an entry using `queries` system
return await strapi.query(params.model, source).create({
values
});
},
edit: async (params, values, source) => {
return strapi.query(params.model, source).update({
id: params.id,
values
});
},
delete: async (params, { source }) => {
const response = await strapi.query(params.model, source).findOne({
id: params.id
});
params.values = Object.keys(JSON.parse(JSON.stringify(response))).reduce((acc, current) => {
const association = (strapi.models[params.model] || strapi.plugins[source].models[params.model]).associations.filter(x => x.alias === current)[0];
// Remove relationships.
if (association) {
acc[current] = _.isArray(response[current]) ? [] : null;
}
return acc;
}, {});
if (!_.isEmpty(params.values)) {
// Run update to remove all relationships.
await strapi.query(params.model, source).update(params);
}
// Delete an entry using `queries` system
return await strapi.query(params.model, source).delete({
id: params.id
});
},
};

View File

@ -28,9 +28,9 @@
"role": {
"type": "integer"
},
"posts": {
"collection": "post",
"via": "author"
"post": {
"model": "post",
"via": "authors"
}
}
}

View File

@ -30,6 +30,13 @@ module.exports = {
values.role = '1';
}
// Use Content Manager business logic to handle relation.
if (strapi.plugins['content-manager']) {
return await strapi.plugins['content-manager'].services['contentmanager'].add({
model: 'user'
}, values, 'users-permissions');
}
return strapi.query('user', 'users-permissions').create(values);
},
@ -47,6 +54,11 @@ module.exports = {
values.password = await strapi.plugins['users-permissions'].services.user.hashPassword(values);
}
// Use Content Manager business logic to handle relation.
if (strapi.plugins['content-manager']) {
return await strapi.plugins['content-manager'].services['contentmanager'].edit(params, values, 'users-permissions');
}
return strapi.query('user', 'users-permissions').update(_.assign(params, values));
},
@ -97,6 +109,11 @@ module.exports = {
*/
remove: async params => {
// Use Content Manager business logic to handle relation.
if (strapi.plugins['content-manager']) {
await strapi.plugins['content-manager'].services['contentmanager'].delete(params, 'users-permissions');
}
return strapi.query('user', 'users-permissions').delete(params);
},

View File

@ -243,7 +243,8 @@ module.exports = {
via: association.via || undefined,
nature: infos.nature,
autoPopulate: _.get(association, 'autoPopulate', true),
dominant: details.dominant !== true
dominant: details.dominant !== true,
plugin: association.plugin || undefined,
});
} else if (association.hasOwnProperty('model')) {
definition.associations.push({
@ -253,7 +254,8 @@ module.exports = {
via: association.via || undefined,
nature: infos.nature,
autoPopulate: _.get(association, 'autoPopulate', true),
dominant: details.dominant !== true
dominant: details.dominant !== true,
plugin: association.plugin || undefined,
});
}
},