init edit and delete content type with schema manager

This commit is contained in:
Alexandre Bodin 2019-11-20 14:42:53 +01:00
parent 22ca3c476a
commit f255d0d700
7 changed files with 191 additions and 165 deletions

View File

@ -127,9 +127,10 @@ module.exports = (scope, cb) => {
// Get default connection
try {
scope.connection =
_.get(scope.args, 'connection') ||
JSON.parse(
scope.connection = scope.args.connection;
if (!scope.args.connection) {
try {
scope.connection = JSON.parse(
fs.readFileSync(
path.resolve(
scope.rootPath,
@ -139,8 +140,11 @@ module.exports = (scope, cb) => {
'database.json'
)
)
).defaultConnection ||
'';
).defaultConnection;
} catch (err) {
scope.connection = 'default';
}
}
} catch (err) {
return cb.invalid(err);
}

View File

@ -67,6 +67,7 @@ module.exports = {
ctx.send({ data: { uid: component.uid } }, 201);
} catch (error) {
strapi.log.error(error);
ctx.send({ error: error.message }, 400);
}
},
@ -98,6 +99,7 @@ module.exports = {
ctx.send({ data: { uid: component.uid } });
} catch (error) {
strapi.log.error(error);
ctx.send({ error: error.message }, 400);
}
},
@ -119,6 +121,7 @@ module.exports = {
ctx.send({ data: { uid: component.uid } });
} catch (error) {
strapi.log.error(error);
ctx.send({ error: error.message }, 400);
}
},

View File

@ -66,127 +66,53 @@ module.exports = {
ctx.send({ data: { uid: component.uid } }, 201);
} catch (error) {
strapi.log.error(error);
strapi.emit('didNotCreateContentType', error);
ctx.send({ error: error.message }, 400);
}
// strapi.reload.isWatching = false;
// try {
// const contentTypeSchema = contentTypeService.createContentTypeSchema(
// body.contentType
// );
// await contentTypeService.generateAPI(modelName, contentTypeSchema);
// await contentTypeService.generateReversedRelations({
// attributes: body.contentType.attributes,
// modelName,
// });
// if (_.isEmpty(strapi.api)) {
// strapi.emit('didCreateFirstContentType');
// } else {
// strapi.emit('didCreateContentType');
// }
// } catch (e) {
// strapi.log.error(e);
// strapi.emit('didNotCreateContentType', e);
// return ctx.badRequest(null, [
// { messages: [{ id: 'request.error.model.write' }] },
// ]);
// }
// setImmediate(() => strapi.reload());
// ctx.send(
// {
// data: {
// uid,
// },
// },
// 201
// );
},
async updateContentType(ctx) {
const { uid } = ctx.params;
const { body } = ctx.request;
const contentType = strapi.contentTypes[uid];
if (!contentType) {
return ctx.send({ error: 'contentType.notFound' }, 404);
}
try {
await validateUpdateContentTypeInput(body);
} catch (error) {
return ctx.send({ error }, 400);
}
try {
strapi.reload.isWatching = false;
try {
const newSchema = contentTypeService.updateContentTypeSchema(
contentType.__schema__,
body.contentType
);
await contentTypeService.writeContentType({ uid, schema: newSchema });
// delete all relations directed to the updated ct except for oneWay and manyWay
await contentTypeService.deleteBidirectionalRelations(contentType);
await contentTypeService.generateReversedRelations({
attributes: body.contentType.attributes,
modelName: contentType.modelName,
plugin: contentType.plugin,
const component = await contentTypeService.editContentType(uid, {
contentType: body.contentType,
components: body.components,
});
if (_.isEmpty(strapi.api)) {
strapi.emit('didCreateFirstContentType');
} else {
strapi.emit('didCreateContentType');
}
} catch (error) {
strapi.emit('didNotCreateContentType', error);
throw error;
}
setImmediate(() => strapi.reload());
ctx.send({
data: {
uid,
},
});
ctx.send({ data: { uid: component.uid } }, 201);
} catch (error) {
strapi.log.error(error);
ctx.send({ error: error.message }, 400);
}
},
async deleteContentType(ctx) {
const { uid } = ctx.params;
const contentType = strapi.contentTypes[uid];
if (!contentType) {
return ctx.send({ error: 'contentType.notFound' }, 404);
}
if (!_.has(contentType, 'apiName')) {
return ctx.send({ error: 'contentType.not.deletable' }, 400);
}
try {
strapi.reload.isWatching = false;
await contentTypeService.deleteAllRelations(contentType);
await contentTypeService.removeContentType(contentType);
const component = await contentTypeService.deleteContentType(uid);
setImmediate(() => strapi.reload());
ctx.send({
data: {
uid,
},
});
ctx.send({ data: { uid: component.uid } });
} catch (error) {
strapi.log.error(error);
ctx.send({ error: error.message }, 400);
}
},
};

View File

@ -1,8 +1,12 @@
'use strict';
const _ = require('lodash');
const pluralize = require('pluralize');
const generator = require('strapi-generate');
const { formatAttributes } = require('../utils/attributes');
const getSchemaManager = require('./schema-manager');
const { nameToSlug } = require('../utils/helpers');
/**
* Creates a component and handle the nested components sent with it
@ -10,7 +14,10 @@ const getSchemaManager = require('./schema-manager');
* @param {Object} params.component Main component to create
* @param {Array<Object>} params.components List of nested components to created or edit
*/
const createContentType = ({ contentType, components = [] }) => {
const createContentType = async ({ contentType, components = [] }) => {
// generate api squeleton
await generateAPI(contentType.name);
const componentsToCreate = components.filter(compo => !_.has(compo, 'uid'));
const componentsToEdit = components.filter(compo => _.has(compo, 'uid'));
@ -24,8 +31,81 @@ const createContentType = ({ contentType, components = [] }) => {
});
};
/**
* Generate a squeleton API
* @param {*} name
* @param {*} contentType
*/
const generateAPI = name => {
return new Promise((resolve, reject) => {
const scope = {
generatorType: 'api',
id: nameToSlug(name),
name: nameToSlug(name),
rootPath: strapi.dir,
args: {
attributes: {},
},
};
generator(scope, {
success: () => resolve(),
error: err => reject(err),
});
});
};
/**
* Edits a contentType and handle the nested contentTypes sent with it
* @param {Object} params params object
* @param {Object} params.contentType Main contentType to create
* @param {Array<Object>} params.components List of nested components to created or edit
*/
const editContentType = (uid, { contentType, components = [] }) => {
const componentsToCreate = components.filter(compo => !_.has(compo, 'uid'));
const componentsToEdit = components.filter(compo => _.has(compo, 'uid'));
return getSchemaManager().edit(ctx => {
const updatedComponent = ctx.editContentType({
uid,
...contentType,
});
componentsToCreate.forEach(ctx.createComponent);
componentsToEdit.forEach(ctx.editComponent);
return updatedComponent;
});
};
const deleteContentType = uid => {
return getSchemaManager().edit(ctx => {
return ctx.deleteContentType(uid);
});
};
const formatContentType = contentType => {
const { uid, plugin, connection, collectionName, info } = contentType;
return {
uid,
plugin,
schema: {
name: _.get(info, 'name') || _.upperFirst(pluralize(uid)),
description: _.get(info, 'description', ''),
connection,
collectionName,
attributes: formatAttributes(contentType),
},
};
};
module.exports = {
createContentType,
editContentType,
deleteContentType,
formatContentType,
};
// const path = require('path');
@ -267,51 +347,6 @@ module.exports = {
// return fse.writeFile(filePath, JSON.stringify(schema, null, 2));
// };
// const formatContentType = contentType => {
// const { uid, plugin, connection, collectionName, info } = contentType;
// return {
// uid,
// plugin,
// schema: {
// name: _.get(info, 'name') || _.upperFirst(pluralize(uid)),
// description: _.get(info, 'description', ''),
// connection,
// collectionName,
// attributes: formatAttributes(contentType),
// },
// };
// };
// const createContentTypeSchema = infos => ({
// connection:
// infos.connection ||
// _.get(
// strapi,
// ['config', 'currentEnvironment', 'database', 'defaultConnection'],
// 'default'
// ),
// collectionName:
// infos.collectionName || `${nameToCollectionName(pluralize(infos.name))}`,
// info: {
// name: infos.name,
// description: infos.description,
// },
// attributes: convertAttributes(infos.attributes),
// });
// const updateContentTypeSchema = (old, infos) => ({
// ...old,
// connection: infos.connection || old.connection,
// collectionName: infos.collectionName || old.collectionName,
// info: {
// name: infos.name || old.info.name,
// description: infos.description || old.info.description,
// },
// // TODO: keep old params like autoMigration, private, configurable
// attributes: convertAttributes(infos.attributes),
// });
// const generateAPI = (name, contentType) => {
// // create api
// return new Promise((resolve, reject) => {

View File

@ -15,7 +15,7 @@ const createSchemaHandler = require('./schema-handler');
const createComponentUID = ({ category, name }) =>
`${nameToSlug(category)}.${nameToSlug(name)}`;
module.exports = function createComponentBuilder({ tmpComponents }) {
module.exports = function createComponentBuilder() {
return {
/**
* create a component in the tmpComponent map
@ -23,7 +23,7 @@ module.exports = function createComponentBuilder({ tmpComponents }) {
createComponent(infos) {
const uid = createComponentUID(infos);
if (tmpComponents.has(uid)) {
if (this.components.has(uid)) {
throw new Error('component.alreadyExists');
}
@ -51,7 +51,7 @@ module.exports = function createComponentBuilder({ tmpComponents }) {
.set(['info', 'description'], infos.description)
.set('attributes', convertAttributes(infos.attributes));
tmpComponents.set(uid, handler);
this.components.set(uid, handler);
return handler;
},
@ -62,18 +62,18 @@ module.exports = function createComponentBuilder({ tmpComponents }) {
editComponent(infos) {
const { uid } = infos;
if (!tmpComponents.has(uid)) {
if (!this.components.has(uid)) {
throw new Error('component.notFound');
}
const handler = tmpComponents.get(uid);
const handler = this.components.get(uid);
const [, nameUID] = uid.split('.');
const newCategory = nameToSlug(infos.category);
const newUID = `${newCategory}.${nameUID}`;
if (newUID !== uid && tmpComponents.has(newUID)) {
if (newUID !== uid && this.components.has(newUID)) {
throw new Error('component.edit.alreadyExists');
}
@ -87,6 +87,7 @@ module.exports = function createComponentBuilder({ tmpComponents }) {
.set(['info', 'name'], infos.name)
.set(['info', 'icon'], infos.icon)
.set(['info', 'description'], infos.description)
// TODO: keep configurable args etc...
.set('attributes', convertAttributes(infos.attributes));
if (newUID !== uid) {
@ -103,7 +104,7 @@ module.exports = function createComponentBuilder({ tmpComponents }) {
},
deleteComponent(uid) {
if (!tmpComponents.has(uid)) {
if (!this.components.has(uid)) {
throw new Error('component.notFound');
}
@ -115,7 +116,7 @@ module.exports = function createComponentBuilder({ tmpComponents }) {
ct.removeComponent(uid);
});
return tmpComponents.get(uid).delete();
return this.components.get(uid).delete();
},
};
};

View File

@ -15,7 +15,7 @@ const createSchemaHandler = require('./schema-handler');
const createContentTypeUID = ({ name }) =>
`application::${nameToSlug(name)}.${nameToSlug(name)}`;
module.exports = function createComponentBuilder({ tmpContentTypes }) {
module.exports = function createComponentBuilder() {
return {
/**
* create a component in the tmpComponent map
@ -23,13 +23,13 @@ module.exports = function createComponentBuilder({ tmpContentTypes }) {
createContentType(infos) {
const uid = createContentTypeUID(infos);
if (tmpContentTypes.has(uid)) {
if (this.contentTypes.has(uid)) {
throw new Error('contentType.alreadyExists');
}
const handler = createSchemaHandler({
dir: path.join(strapi.dir, 'api', nameToSlug(infos.name), 'models'),
filename: `${nameToSlug(infos.name)}.json`,
filename: `${nameToSlug(infos.name)}.settings.json`,
});
const defaultConnection = _.get(
@ -50,9 +50,51 @@ module.exports = function createComponentBuilder({ tmpContentTypes }) {
.set(['info', 'description'], infos.description)
.set('attributes', convertAttributes(infos.attributes));
tmpContentTypes.set(uid, handler);
this.contentTypes.set(uid, handler);
// TODO: add reversed relations
return handler;
},
editContentType(infos) {
const { uid } = infos;
if (!this.contentTypes.has(uid)) {
throw new Error('contentType.notFound');
}
const handler = this.contentTypes.get(uid);
handler
.set('connection', infos.connection)
.set('collectionName', infos.collectionName)
.set(['info', 'name'], infos.name)
.set(['info', 'description'], infos.description)
// TODO: keep configurable args etc...
.set('attributes', convertAttributes(infos.attributes));
// TODO: clear old relations
// TODO: build new reversed relations
return handler;
},
deleteContentType(uid) {
if (!this.contentTypes.has(uid)) {
throw new Error('contentType.notFound');
}
this.components.forEach(compo => {
compo.removeContentType(uid);
});
this.contentTypes.forEach(ct => {
ct.removeContentType(uid);
});
// TODO: clear api when a contentType is deleted
return this.contentTypes.get(uid).delete();
},
};
};

View File

@ -78,6 +78,21 @@ module.exports = function createSchemaHandler(infos) {
return this;
},
removeContentType(uid) {
const { attributes } = state.schema;
Object.keys(attributes).forEach(key => {
const attr = attributes[key];
const target = attr.model || attr.collection;
if (target === uid) {
this.unset(['attributes', key]);
}
});
return this;
},
// utils
removeComponent(uid) {
const { attributes } = state.schema;