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

View File

@ -32,7 +32,7 @@ class LeftMenuLink extends React.Component { // eslint-disable-line react/prefer
id={this.props.label} id={this.props.label}
defaultMessage='{label}' defaultMessage='{label}'
values={{ values={{
label: this.props.label, label: `${this.props.label} ${this.props.source !== 'content-manager' ? '⬖' : ''}`,
}} }}
className={styles.linkLabel} 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 virtuals: true
}); });
if (!plugin) { if (!plugin) {
global[definition.globalName] = instance.model(definition.globalName, collection.schema); global[definition.globalName] = instance.model(definition.globalName, collection.schema);
} else { } else {
@ -218,22 +217,24 @@ module.exports = function (strapi) {
definition.loadedModel[name].type = utils(instance).convertType(details.type); definition.loadedModel[name].type = utils(instance).convertType(details.type);
} }
let FK;
switch (verbose) { switch (verbose) {
case 'hasOne': case 'hasOne': {
const ref = details.plugin ? _.upperFirst(_.camelCase(`${details.plugin}-${details.model}`)) : _.capitalize(details.model);
definition.loadedModel[name] = { definition.loadedModel[name] = {
type: instance.Schema.Types.ObjectId, type: instance.Schema.Types.ObjectId,
ref: _.capitalize(details.model) ref
}; };
break; 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) { if (FK) {
definition.loadedModel[name] = { definition.loadedModel[name] = {
type: 'virtual', type: 'virtual',
ref: _.capitalize(details.collection), ref,
via: FK.via, via: FK.via,
justOne: false justOne: false
}; };
@ -243,17 +244,19 @@ module.exports = function (strapi) {
} else { } else {
definition.loadedModel[name] = [{ definition.loadedModel[name] = [{
type: instance.Schema.Types.ObjectId, type: instance.Schema.Types.ObjectId,
ref: _.capitalize(details.collection) ref
}]; }];
} }
break; 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') { if (FK && FK.nature !== 'oneToOne' && FK.nature !== 'manyToOne') {
definition.loadedModel[name] = { definition.loadedModel[name] = {
type: 'virtual', type: 'virtual',
ref: _.capitalize(details.model), ref,
via: FK.via, via: FK.via,
justOne: true justOne: true
}; };
@ -263,19 +266,21 @@ module.exports = function (strapi) {
} else { } else {
definition.loadedModel[name] = { definition.loadedModel[name] = {
type: instance.Schema.Types.ObjectId, type: instance.Schema.Types.ObjectId,
ref: _.capitalize(details.model) ref
}; };
} }
break; 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. // One-side of the relationship has to be a virtual field to be bidirectional.
if ((FK && _.isUndefined(FK.via)) || details.dominant !== true) { if ((FK && _.isUndefined(FK.via)) || details.dominant !== true) {
definition.loadedModel[name] = { definition.loadedModel[name] = {
type: 'virtual', type: 'virtual',
ref: _.capitalize(FK.collection), ref,
via: FK.via via: FK.via
}; };
@ -284,10 +289,11 @@ module.exports = function (strapi) {
} else { } else {
definition.loadedModel[name] = [{ definition.loadedModel[name] = [{
type: instance.Schema.Types.ObjectId, type: instance.Schema.Types.ObjectId,
ref: _.capitalize(details.collection) ref
}]; }];
} }
break; break;
}
default: default:
break; break;
} }

View File

@ -20,14 +20,17 @@ import styles from './styles.scss';
class EditFormRelations extends React.Component { // eslint-disable-line react/prefer-stateless-function class EditFormRelations extends React.Component { // eslint-disable-line react/prefer-stateless-function
componentDidMount() { 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(); this.props.toggleNull();
} }
} }
render() { render() {
const source = getQueryParameters(this.props.location.search, 'source'); 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) => { const relations = map(currentSchema.relations, (relation, i) => {
@ -43,6 +46,7 @@ class EditFormRelations extends React.Component { // eslint-disable-line react/p
relation={relation} relation={relation}
schema={this.props.schema} schema={this.props.schema}
setRecordAttribute={this.props.setRecordAttribute} setRecordAttribute={this.props.setRecordAttribute}
location={this.props.location}
/> />
); );
} }
@ -57,6 +61,7 @@ class EditFormRelations extends React.Component { // eslint-disable-line react/p
relation={relation} relation={relation}
schema={this.props.schema} schema={this.props.schema}
setRecordAttribute={this.props.setRecordAttribute} setRecordAttribute={this.props.setRecordAttribute}
location={this.props.location}
/> />
); );
default: default:

View File

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

View File

@ -27,6 +27,7 @@ class SelectOne extends React.Component { // eslint-disable-line react/prefer-st
getOptions = (query) => { getOptions = (query) => {
const params = { const params = {
limit: 20, limit: 20,
source: this.props.relation.plugin || 'content-manager',
}; };
// Set `query` parameter if necessary // 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]) { if (response[current] && _.isObject(response[current]) && response[current][this.primaryKey] !== value[current]) {
virtualFields.push( virtualFields.push(
strapi.query(details.collection || details.model).update({ strapi.query(details.collection || details.model, details.plugin).update({
id: response[current][this.primaryKey], id: response[current][this.primaryKey],
values: { values: {
[details.via]: null [details.via]: null
@ -78,7 +78,7 @@ module.exports = {
// Remove previous relationship asynchronously if it exists. // Remove previous relationship asynchronously if it exists.
virtualFields.push( virtualFields.push(
strapi.query(details.model || details.collection).findOne({ id : recordId }) strapi.query(details.model || details.collection, details.plugin).findOne({ id : recordId })
.then(record => { .then(record => {
if (record && _.isObject(record[details.via])) { if (record && _.isObject(record[details.via])) {
return module.exports.update.call(this, { return module.exports.update.call(this, {
@ -96,7 +96,7 @@ module.exports = {
// Update the record on the other side. // Update the record on the other side.
// When params.values[current] is null this means that we are removing the relation. // 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, id: recordId,
values: { values: {
[details.via]: _.isNull(params.values[current]) ? null : value[this.primaryKey] || value.id || value._id [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. // Push the work into the flow process.
toAdd.forEach(value => { toAdd.forEach(value => {
if (association.nature === 'manyToMany' && !_.isArray(params.values[this.primaryKey] || params[this.primaryKey])) { 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 => { value[details.via] = (value[details.via] || [])
.concat([(params.values[this.primaryKey] || params[this.primaryKey])])
.filter(x => {
return x !== null && x !== undefined; return x !== null && x !== undefined;
}); });
} else { } else {
value[details.via] = params[this.primaryKey] || params.id; 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, id: value[this.primaryKey] || value.id || value._id,
values: value, values: value,
foreignKey: current foreignKey: current
@ -148,7 +150,7 @@ module.exports = {
value[details.via] = null; 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, id: value[this.primaryKey] || value.id || value._id,
values: value, values: value,
foreignKey: current foreignKey: current

View File

@ -35,25 +35,14 @@ module.exports = {
}, },
find: async ctx => { find: async ctx => {
const { limit, skip = 0, sort, query, queryAttribute, source, page } = ctx.request.query; ctx.body = await strapi.plugins['content-manager'].services['contentmanager'].fetchAll(ctx.params, 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;
}, },
count: async ctx => { count: async ctx => {
const { source } = ctx.request.query; const { source } = ctx.request.query;
// Count using `queries` system // 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 = { ctx.body = {
count: _.isNumber(count) ? count : _.toNumber(count) count: _.isNumber(count) ? count : _.toNumber(count)
@ -64,9 +53,7 @@ module.exports = {
const { source } = ctx.request.query; const { source } = ctx.request.query;
// Find an entry using `queries` system // Find an entry using `queries` system
const entry = await strapi.query(ctx.params.model, source).findOne({ const entry = await strapi.plugins['content-manager'].services['contentmanager'].fetch(ctx.params, source);
id: ctx.params.id
});
// Entry not found // Entry not found
if (!entry) { if (!entry) {
@ -81,12 +68,9 @@ module.exports = {
try { try {
// Create an entry using `queries` system // Create an entry using `queries` system
const entryCreated = await strapi.query(ctx.params.model, source).create({ ctx.body = await strapi.plugins['content-manager'].services['contentmanager'].add(ctx.params, ctx.request.body, source);
values: ctx.request.body
});
ctx.body = entryCreated;
} catch(error) { } catch(error) {
console.log(error);
ctx.badRequest(null, ctx.request.admin ? [{ messages: [{ id: error.message, field: error.field }] }] : error.message); 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; const { source } = ctx.request.query;
try { 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. // 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) { } catch(error) {
// TODO handle error update // TODO handle error update
ctx.badRequest(null, ctx.request.admin ? [{ messages: [{ id: error.message, field: error.field }] }] : error.message); ctx.badRequest(null, ctx.request.admin ? [{ messages: [{ id: error.message, field: error.field }] }] : error.message);
@ -110,34 +88,6 @@ module.exports = {
}, },
delete: async ctx => { delete: async ctx => {
const { source } = ctx.request.query; ctx.body = await strapi.plugins['content-manager'].services['contentmanager'].delete(ctx.params, 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;
}, },
}; };

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": { "role": {
"type": "integer" "type": "integer"
}, },
"posts": { "post": {
"collection": "post", "model": "post",
"via": "author" "via": "authors"
} }
} }
} }

View File

@ -30,6 +30,13 @@ module.exports = {
values.role = '1'; 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); 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); 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)); return strapi.query('user', 'users-permissions').update(_.assign(params, values));
}, },
@ -97,6 +109,11 @@ module.exports = {
*/ */
remove: async params => { 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); return strapi.query('user', 'users-permissions').delete(params);
}, },

View File

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