mirror of
https://github.com/strapi/strapi.git
synced 2025-08-26 17:53:10 +00:00
Update component servie
This commit is contained in:
parent
05f1dd7b19
commit
1e28d8b9d9
@ -1,9 +1,13 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
validateComponentInput,
|
validateComponentInput,
|
||||||
validateUpdateComponentInput,
|
validateUpdateComponentInput,
|
||||||
} = require('./validation/component');
|
} = require('./validation/component');
|
||||||
|
|
||||||
|
const _ = require('lodash');
|
||||||
|
const componentService = require('../services/Components');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Components controller
|
* Components controller
|
||||||
*/
|
*/
|
||||||
@ -15,8 +19,9 @@ module.exports = {
|
|||||||
* @param {Object} ctx - koa context
|
* @param {Object} ctx - koa context
|
||||||
*/
|
*/
|
||||||
async getComponents(ctx) {
|
async getComponents(ctx) {
|
||||||
const service = strapi.plugins['content-type-builder'].services.components;
|
const data = Object.keys(strapi.components).map(uid => {
|
||||||
const data = service.getComponents();
|
return componentService.formatComponent(strapi.components[uid]);
|
||||||
|
});
|
||||||
|
|
||||||
ctx.send({ data });
|
ctx.send({ data });
|
||||||
},
|
},
|
||||||
@ -29,14 +34,13 @@ module.exports = {
|
|||||||
async getComponent(ctx) {
|
async getComponent(ctx) {
|
||||||
const { uid } = ctx.params;
|
const { uid } = ctx.params;
|
||||||
|
|
||||||
const service = strapi.plugins['content-type-builder'].services.components;
|
const component = strapi.components[uid];
|
||||||
const component = service.getComponent(uid);
|
|
||||||
|
|
||||||
if (!component) {
|
if (!component) {
|
||||||
return ctx.send({ error: 'component.notFound' }, 404);
|
return ctx.send({ error: 'component.notFound' }, 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.send({ data: component });
|
ctx.send({ data: componentService.formatComponent(component) });
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,16 +57,18 @@ module.exports = {
|
|||||||
return ctx.send({ error }, 400);
|
return ctx.send({ error }, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
const service = strapi.plugins['content-type-builder'].services.components;
|
const uid = componentService.createComponentUID(body);
|
||||||
const uid = service.createComponentUID(body);
|
|
||||||
|
|
||||||
if (service.getComponent(uid)) {
|
if (_.has(strapi.components, uid)) {
|
||||||
return ctx.send({ error: 'component.alreadyExists' }, 400);
|
return ctx.send({ error: 'component.alreadyExists' }, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
strapi.reload.isWatching = false;
|
strapi.reload.isWatching = false;
|
||||||
|
|
||||||
const newComponent = await service.createComponent({ uid, infos: body });
|
const newComponent = await componentService.createComponent({
|
||||||
|
uid,
|
||||||
|
infos: body,
|
||||||
|
});
|
||||||
|
|
||||||
strapi.reload();
|
strapi.reload();
|
||||||
|
|
||||||
@ -78,8 +84,7 @@ module.exports = {
|
|||||||
const { uid } = ctx.params;
|
const { uid } = ctx.params;
|
||||||
const { body } = ctx.request;
|
const { body } = ctx.request;
|
||||||
|
|
||||||
const service = strapi.plugins['content-type-builder'].services.components;
|
const component = strapi.components[uid];
|
||||||
const component = service.getComponent(uid);
|
|
||||||
|
|
||||||
if (!component) {
|
if (!component) {
|
||||||
return ctx.send({ error: 'component.notFound' }, 404);
|
return ctx.send({ error: 'component.notFound' }, 404);
|
||||||
@ -91,23 +96,26 @@ module.exports = {
|
|||||||
return ctx.send({ error }, 400);
|
return ctx.send({ error }, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newUID = service.createComponentUID(body);
|
const newUID = componentService.editComponentUID(body);
|
||||||
if (newUID !== uid && service.getComponent(newUID)) {
|
if (newUID !== uid && _.has(strapi.components, newUID)) {
|
||||||
return ctx.send({ error: 'new.component.alreadyExists' }, 400);
|
return ctx.send({ error: 'new.component.alreadyExists' }, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
strapi.reload.isWatching = false;
|
strapi.reload.isWatching = false;
|
||||||
|
|
||||||
const updatedComponent = await service.updateComponent({
|
const updatedComponent = await componentService.updateComponent({
|
||||||
newUID,
|
uid,
|
||||||
component,
|
|
||||||
infos: body,
|
infos: body,
|
||||||
});
|
});
|
||||||
await service.updateComponentInModels(component.uid, updatedComponent.uid);
|
|
||||||
|
|
||||||
strapi.reload();
|
await componentService.updateComponentInModels(
|
||||||
|
component.uid,
|
||||||
|
updatedComponent.uid
|
||||||
|
);
|
||||||
|
|
||||||
ctx.send({ data: updatedComponent }, 200);
|
setImmediate(() => strapi.reload());
|
||||||
|
|
||||||
|
ctx.send({ data: updatedComponent });
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,8 +126,7 @@ module.exports = {
|
|||||||
async deleteComponent(ctx) {
|
async deleteComponent(ctx) {
|
||||||
const { uid } = ctx.params;
|
const { uid } = ctx.params;
|
||||||
|
|
||||||
const service = strapi.plugins['content-type-builder'].services.components;
|
const component = strapi.components[uid];
|
||||||
const component = service.getComponent(uid);
|
|
||||||
|
|
||||||
if (!component) {
|
if (!component) {
|
||||||
return ctx.send({ error: 'component.notFound' }, 404);
|
return ctx.send({ error: 'component.notFound' }, 404);
|
||||||
@ -127,11 +134,11 @@ module.exports = {
|
|||||||
|
|
||||||
strapi.reload.isWatching = false;
|
strapi.reload.isWatching = false;
|
||||||
|
|
||||||
await service.deleteComponent(component);
|
await componentService.deleteComponentInModels(component.uid);
|
||||||
await service.deleteComponentInModels(component.uid);
|
await componentService.deleteComponent(component);
|
||||||
|
|
||||||
strapi.reload();
|
setImmediate(() => strapi.reload());
|
||||||
|
|
||||||
ctx.send({ data: { uid } }, 200);
|
ctx.send({ data: { uid } });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const pluralize = require('pluralize');
|
|
||||||
const fse = require('fs-extra');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const generator = require('strapi-generate');
|
|
||||||
const { formatAttributes, convertAttributes } = require('../utils/attributes');
|
|
||||||
const { nameToSlug } = require('../utils/helpers');
|
const { nameToSlug } = require('../utils/helpers');
|
||||||
const {
|
const {
|
||||||
validateContentTypeInput,
|
validateContentTypeInput,
|
||||||
validateUpdateContentTypeInput,
|
validateUpdateContentTypeInput,
|
||||||
} = require('./validation/content-type');
|
} = require('./validation/content-type');
|
||||||
|
|
||||||
|
const contentTypeService = require('../services/ContentTypes');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getContentTypes(ctx) {
|
getContentTypes(ctx) {
|
||||||
const contentTypes = Object.keys(strapi.contentTypes)
|
const contentTypes = Object.keys(strapi.contentTypes)
|
||||||
@ -22,7 +19,9 @@ module.exports = {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
.map(uid => formatContentType(strapi.contentTypes[uid]));
|
.map(uid =>
|
||||||
|
contentTypeService.formatContentType(strapi.contentTypes[uid])
|
||||||
|
);
|
||||||
|
|
||||||
ctx.send({
|
ctx.send({
|
||||||
data: contentTypes,
|
data: contentTypes,
|
||||||
@ -38,7 +37,7 @@ module.exports = {
|
|||||||
return ctx.send({ error: 'contentType.notFound' }, 404);
|
return ctx.send({ error: 'contentType.notFound' }, 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.send({ data: formatContentType(contentType) });
|
ctx.send({ data: contentTypeService.formatContentType(contentType) });
|
||||||
},
|
},
|
||||||
|
|
||||||
async createContentType(ctx) {
|
async createContentType(ctx) {
|
||||||
@ -60,11 +59,11 @@ module.exports = {
|
|||||||
strapi.reload.isWatching = false;
|
strapi.reload.isWatching = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const contentType = createContentTypeSchema(body);
|
const contentType = contentTypeService.createContentTypeSchema(body);
|
||||||
|
|
||||||
await generateAPI(modelName, contentType);
|
await contentTypeService.generateAPI(modelName, contentType);
|
||||||
|
|
||||||
await generateReversedRelations({
|
await contentTypeService.generateReversedRelations({
|
||||||
attributes: body.attributes,
|
attributes: body.attributes,
|
||||||
modelName,
|
modelName,
|
||||||
});
|
});
|
||||||
@ -84,11 +83,14 @@ module.exports = {
|
|||||||
|
|
||||||
setImmediate(() => strapi.reload());
|
setImmediate(() => strapi.reload());
|
||||||
|
|
||||||
ctx.send({
|
ctx.send(
|
||||||
data: {
|
{
|
||||||
uid,
|
data: {
|
||||||
|
uid,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
201
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
async updateContentType(ctx) {
|
async updateContentType(ctx) {
|
||||||
@ -110,14 +112,17 @@ module.exports = {
|
|||||||
strapi.reload.isWatching = false;
|
strapi.reload.isWatching = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const newSchema = updateContentTypeSchema(contentType.__schema__, body);
|
const newSchema = contentTypeService.updateContentTypeSchema(
|
||||||
|
contentType.__schema__,
|
||||||
|
body
|
||||||
|
);
|
||||||
|
|
||||||
await writeContentType({ uid, schema: newSchema });
|
await contentTypeService.writeContentType({ uid, schema: newSchema });
|
||||||
|
|
||||||
// delete all relations directed to the updated ct except for oneWay and manyWay
|
// delete all relations directed to the updated ct except for oneWay and manyWay
|
||||||
await deleteBidirectionalRelations(contentType);
|
await contentTypeService.deleteBidirectionalRelations(contentType);
|
||||||
|
|
||||||
await generateReversedRelations({
|
await contentTypeService.generateReversedRelations({
|
||||||
attributes: body.attributes,
|
attributes: body.attributes,
|
||||||
modelName: contentType.modelName,
|
modelName: contentType.modelName,
|
||||||
plugin: contentType.plugin,
|
plugin: contentType.plugin,
|
||||||
@ -128,12 +133,9 @@ module.exports = {
|
|||||||
} else {
|
} else {
|
||||||
strapi.emit('didCreateContentType');
|
strapi.emit('didCreateContentType');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
strapi.log.error(e);
|
strapi.emit('didNotCreateContentType', error);
|
||||||
strapi.emit('didNotCreateContentType', e);
|
throw error;
|
||||||
return ctx.badRequest(null, [
|
|
||||||
{ messages: [{ id: 'request.error.model.write' }] },
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setImmediate(() => strapi.reload());
|
setImmediate(() => strapi.reload());
|
||||||
@ -160,8 +162,8 @@ module.exports = {
|
|||||||
|
|
||||||
strapi.reload.isWatching = false;
|
strapi.reload.isWatching = false;
|
||||||
|
|
||||||
await removeContentType(contentType);
|
await contentTypeService.deleteAllRelations(contentType);
|
||||||
await deleteAllRelations(contentType);
|
await contentTypeService.removeContentType(contentType);
|
||||||
|
|
||||||
setImmediate(() => strapi.reload());
|
setImmediate(() => strapi.reload());
|
||||||
|
|
||||||
@ -172,303 +174,3 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteAllRelations = ({ modelName, plugin }) => {
|
|
||||||
const contentTypeUpdates = Object.keys(strapi.contentTypes).map(uid => {
|
|
||||||
const { __schema__ } = strapi.contentTypes[uid];
|
|
||||||
|
|
||||||
const keysToDelete = Object.keys(__schema__.attributes).filter(key => {
|
|
||||||
const attr = __schema__.attributes[key];
|
|
||||||
const target = attr.model || attr.collection;
|
|
||||||
|
|
||||||
const sameModel = target === modelName;
|
|
||||||
const samePluginOrNoPlugin =
|
|
||||||
(attr.plugin && attr.plugin === plugin) || !attr.plugin;
|
|
||||||
|
|
||||||
if (samePluginOrNoPlugin && sameModel) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (keysToDelete.length > 0) {
|
|
||||||
const newchema = {
|
|
||||||
...__schema__,
|
|
||||||
attributes: _.omit(__schema__.attributes, keysToDelete),
|
|
||||||
};
|
|
||||||
|
|
||||||
return writeContentType({ uid, schema: newchema });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const componentUpdates = Object.keys(strapi.components).map(uid => {
|
|
||||||
const { __schema__ } = strapi.components[uid];
|
|
||||||
|
|
||||||
const keysToDelete = Object.keys(__schema__.attributes).filter(key => {
|
|
||||||
const attr = __schema__.attributes[key];
|
|
||||||
const target = attr.model || attr.collection;
|
|
||||||
|
|
||||||
const sameModel = target === modelName;
|
|
||||||
const samePluginOrNoPlugin =
|
|
||||||
(attr.plugin && attr.plugin === plugin) || !attr.plugin;
|
|
||||||
|
|
||||||
if (samePluginOrNoPlugin && sameModel) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (keysToDelete.length > 0) {
|
|
||||||
const newchema = {
|
|
||||||
...__schema__,
|
|
||||||
attributes: _.omit(__schema__.attributes, keysToDelete),
|
|
||||||
};
|
|
||||||
|
|
||||||
return strapi.plugins[
|
|
||||||
'content-type-builder'
|
|
||||||
].services.components.writeComponent({ uid, schema: newchema });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all([...contentTypeUpdates, ...componentUpdates]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const deleteBidirectionalRelations = ({ modelName, plugin }) => {
|
|
||||||
const updates = Object.keys(strapi.contentTypes).map(uid => {
|
|
||||||
const { __schema__ } = strapi.contentTypes[uid];
|
|
||||||
|
|
||||||
const keysToDelete = Object.keys(__schema__.attributes).filter(key => {
|
|
||||||
const attr = __schema__.attributes[key];
|
|
||||||
const target = attr.model || attr.collection;
|
|
||||||
|
|
||||||
const sameModel = target === modelName;
|
|
||||||
const samePluginOrNoPlugin =
|
|
||||||
(attr.plugin && attr.plugin === plugin) || !attr.plugin;
|
|
||||||
|
|
||||||
const isBiDirectionnal = _.has(attr, 'via');
|
|
||||||
|
|
||||||
if (samePluginOrNoPlugin && sameModel && isBiDirectionnal) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (keysToDelete.length > 0) {
|
|
||||||
const newchema = {
|
|
||||||
...__schema__,
|
|
||||||
attributes: _.omit(__schema__.attributes, keysToDelete),
|
|
||||||
};
|
|
||||||
|
|
||||||
return writeContentType({ uid, schema: newchema });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all(updates);
|
|
||||||
};
|
|
||||||
|
|
||||||
const buildReversedRelation = ({ key, attr, plugin, modelName }) => {
|
|
||||||
const targetAttributeOptions = {
|
|
||||||
via: key,
|
|
||||||
columnName: attr.targetColumnName,
|
|
||||||
plugin,
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (attr.nature) {
|
|
||||||
case 'manyWay':
|
|
||||||
case 'oneWay':
|
|
||||||
return;
|
|
||||||
case 'oneToOne':
|
|
||||||
case 'oneToMany':
|
|
||||||
targetAttributeOptions.model = modelName;
|
|
||||||
break;
|
|
||||||
case 'manyToOne':
|
|
||||||
targetAttributeOptions.collection = modelName;
|
|
||||||
break;
|
|
||||||
case 'manyToMany': {
|
|
||||||
targetAttributeOptions.collection = modelName;
|
|
||||||
|
|
||||||
if (!targetAttributeOptions.dominant) {
|
|
||||||
targetAttributeOptions.dominant = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
return targetAttributeOptions;
|
|
||||||
};
|
|
||||||
|
|
||||||
const generateReversedRelations = ({ attributes, modelName, plugin }) => {
|
|
||||||
const promises = Object.keys(attributes)
|
|
||||||
.filter(key => _.has(attributes[key], 'target'))
|
|
||||||
.map(key => {
|
|
||||||
const attr = attributes[key];
|
|
||||||
const target = strapi.contentTypes[attr.target];
|
|
||||||
|
|
||||||
const schema = _.merge({}, target.__schema__, {
|
|
||||||
attributes: {
|
|
||||||
[attr.targetAttribute]: buildReversedRelation({
|
|
||||||
key,
|
|
||||||
attr,
|
|
||||||
plugin,
|
|
||||||
modelName,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return writeContentType({ uid: attr.target, schema });
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all(promises);
|
|
||||||
};
|
|
||||||
|
|
||||||
const removeContentType = async ({ uid }) => {
|
|
||||||
const { apiName, __filename__ } = strapi.contentTypes[uid];
|
|
||||||
|
|
||||||
const baseName = path.basename(__filename__, '.settings.json');
|
|
||||||
const apiFolder = path.join(strapi.dir, 'api', apiName);
|
|
||||||
|
|
||||||
const deleteFile = async filePath => {
|
|
||||||
const fileName = path.basename(filePath);
|
|
||||||
|
|
||||||
if (_.startsWith(_.toLower(fileName), _.toLower(baseName) + '.')) {
|
|
||||||
await fse.remove(filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileName === 'routes.json') {
|
|
||||||
const { routes } = await fse.readJSON(filePath);
|
|
||||||
|
|
||||||
const clearedRoutes = routes.filter(route => {
|
|
||||||
return !_.startsWith(
|
|
||||||
_.toLower(route.handler),
|
|
||||||
_.toLower(baseName) + '.'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (clearedRoutes.length === 0) {
|
|
||||||
await fse.remove(filePath);
|
|
||||||
} else {
|
|
||||||
await fse.writeJSON(
|
|
||||||
filePath,
|
|
||||||
{
|
|
||||||
routes: clearedRoutes,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
spaces: 2,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const recursiveRemoveFiles = async folder => {
|
|
||||||
const filesName = await fse.readdir(folder);
|
|
||||||
|
|
||||||
for (const fileName of filesName) {
|
|
||||||
const filePath = path.join(folder, fileName);
|
|
||||||
|
|
||||||
const stat = await fse.stat(filePath);
|
|
||||||
|
|
||||||
if (stat.isDirectory()) {
|
|
||||||
await recursiveRemoveFiles(filePath);
|
|
||||||
} else {
|
|
||||||
await deleteFile(filePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const files = await fse.readdir(folder);
|
|
||||||
if (files.length === 0) {
|
|
||||||
await fse.remove(folder);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
await recursiveRemoveFiles(apiFolder);
|
|
||||||
};
|
|
||||||
|
|
||||||
const writeContentType = async ({ uid, schema }) => {
|
|
||||||
const { plugin, apiName, __filename__ } = strapi.contentTypes[uid];
|
|
||||||
|
|
||||||
let fileDir;
|
|
||||||
if (plugin) {
|
|
||||||
fileDir = `./extensions/${plugin}/models`;
|
|
||||||
} else {
|
|
||||||
fileDir = `./api/${apiName}/models`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const filePath = path.join(strapi.dir, fileDir, __filename__);
|
|
||||||
|
|
||||||
await fse.ensureFile(filePath);
|
|
||||||
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 || `${_.snakeCase(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) => {
|
|
||||||
const scope = {
|
|
||||||
generatorType: 'api',
|
|
||||||
id: name,
|
|
||||||
name,
|
|
||||||
rootPath: strapi.dir,
|
|
||||||
args: {
|
|
||||||
displayName: contentType.info.name,
|
|
||||||
description: contentType.info.description,
|
|
||||||
connection: contentType.connection,
|
|
||||||
collectionName: contentType.collectionName,
|
|
||||||
attributes: contentType.attributes,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
generator(scope, {
|
|
||||||
success: () => resolve(),
|
|
||||||
error: err => reject(err),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
@ -5,36 +5,17 @@ const _ = require('lodash');
|
|||||||
const fse = require('fs-extra');
|
const fse = require('fs-extra');
|
||||||
const pluralize = require('pluralize');
|
const pluralize = require('pluralize');
|
||||||
|
|
||||||
|
const contentTypeService = require('./ContentTypes');
|
||||||
const { formatAttributes, convertAttributes } = require('../utils/attributes');
|
const { formatAttributes, convertAttributes } = require('../utils/attributes');
|
||||||
const { nameToSlug } = require('../utils/helpers');
|
const { nameToSlug } = require('../utils/helpers');
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of all available components with formatted attributes
|
|
||||||
*/
|
|
||||||
const getComponents = () => {
|
|
||||||
return Object.keys(strapi.components).map(uid => {
|
|
||||||
return formatComponent(uid, strapi.components[uid]);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a component by uid
|
|
||||||
* @param {string} uid - component's UID
|
|
||||||
*/
|
|
||||||
const getComponent = uid => {
|
|
||||||
const component = strapi.components[uid];
|
|
||||||
if (!component) return null;
|
|
||||||
|
|
||||||
return formatComponent(uid, component);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats a component attributes
|
* Formats a component attributes
|
||||||
* @param {string} uid - string
|
* @param {string} uid - string
|
||||||
* @param {Object} component - strapi component model
|
* @param {Object} component - strapi component model
|
||||||
*/
|
*/
|
||||||
const formatComponent = (uid, component) => {
|
const formatComponent = component => {
|
||||||
const { connection, collectionName, info, category } = component;
|
const { uid, connection, collectionName, info, category } = component;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uid,
|
uid,
|
||||||
@ -58,7 +39,12 @@ const formatComponent = (uid, component) => {
|
|||||||
async function createComponent({ uid, infos }) {
|
async function createComponent({ uid, infos }) {
|
||||||
const schema = createSchema(infos);
|
const schema = createSchema(infos);
|
||||||
|
|
||||||
await writeSchema({ uid, schema });
|
await writeSchema({
|
||||||
|
category: nameToSlug(infos.category),
|
||||||
|
name: nameToSlug(infos.name),
|
||||||
|
schema,
|
||||||
|
});
|
||||||
|
|
||||||
return { uid };
|
return { uid };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,49 +53,43 @@ async function createComponent({ uid, infos }) {
|
|||||||
* @param {Object} component
|
* @param {Object} component
|
||||||
* @param {Object} infos
|
* @param {Object} infos
|
||||||
*/
|
*/
|
||||||
async function updateComponent({ component, newUID, infos }) {
|
async function updateComponent({ component, infos }) {
|
||||||
const { uid, schema: oldSchema } = component;
|
const { uid, __schema__: oldSchema } = component;
|
||||||
|
|
||||||
// don't update collectionName if not provided
|
// don't update collectionName if not provided
|
||||||
const updatedSchema = {
|
const updatedSchema = {
|
||||||
info: {
|
...oldSchema,
|
||||||
icon: infos.icon,
|
|
||||||
name: infos.name,
|
|
||||||
description: infos.description || oldSchema.description,
|
|
||||||
},
|
|
||||||
connection: infos.connection || oldSchema.connection,
|
connection: infos.connection || oldSchema.connection,
|
||||||
collectionName: infos.collectionName || oldSchema.collectionName,
|
collectionName: infos.collectionName || oldSchema.collectionName,
|
||||||
|
info: {
|
||||||
|
name: infos.name || oldSchema.info.name,
|
||||||
|
icon: infos.icon || oldSchema.info.icon,
|
||||||
|
description: infos.description || oldSchema.info.description,
|
||||||
|
},
|
||||||
attributes: convertAttributes(infos.attributes),
|
attributes: convertAttributes(infos.attributes),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (uid !== newUID) {
|
await editSchema({ uid, schema: updatedSchema });
|
||||||
await deleteSchema(uid);
|
|
||||||
|
|
||||||
if (_.has(strapi.plugins, ['content-manager', 'services', 'components'])) {
|
if (component.category !== infos.category) {
|
||||||
await _.get(strapi.plugins, [
|
const oldDir = path.join(strapi.dir, 'components', component.category);
|
||||||
'content-manager',
|
const newDir = path.join(strapi.dir, 'components', infos.category);
|
||||||
'services',
|
|
||||||
'components',
|
await fse.move(
|
||||||
]).updateUID(uid, newUID);
|
path.join(oldDir, component.__filename__),
|
||||||
|
path.join(newDir, component.__filename__)
|
||||||
|
);
|
||||||
|
|
||||||
|
const list = await fse.readdir(oldDir);
|
||||||
|
if (list.length === 0) {
|
||||||
|
await fse.remove(oldDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
await writeSchema({
|
return {
|
||||||
uid: newUID,
|
uid: `${infos.category}.${component.modelName}`,
|
||||||
schema: updatedSchema,
|
};
|
||||||
});
|
|
||||||
|
|
||||||
const [category] = uid.split('.');
|
|
||||||
|
|
||||||
const categoryDir = path.join(strapi.dir, 'components', category);
|
|
||||||
const categoryCompos = await fse.readdir(categoryDir);
|
|
||||||
if (categoryCompos.length === 0) {
|
|
||||||
await fse.remove(categoryDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
return { uid: newUID };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await writeSchema({ uid, schema: updatedSchema });
|
|
||||||
return { uid };
|
return { uid };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,14 +144,27 @@ async function deleteComponent(component) {
|
|||||||
/**
|
/**
|
||||||
* Writes a component schema file
|
* Writes a component schema file
|
||||||
*/
|
*/
|
||||||
async function writeSchema({ uid, schema }) {
|
async function writeSchema({ category, name, schema }) {
|
||||||
const [category, filename] = uid.split('.');
|
const filePath = path.join(
|
||||||
const categoryDir = path.join(strapi.dir, 'components', category);
|
strapi.dir,
|
||||||
|
'components',
|
||||||
|
category,
|
||||||
|
`${name}.json`
|
||||||
|
);
|
||||||
|
|
||||||
await fse.ensureDir(categoryDir);
|
await fse.ensureFile(filePath);
|
||||||
|
await fse.writeJSON(filePath, schema, { spaces: 2 });
|
||||||
|
}
|
||||||
|
|
||||||
const filepath = path.join(categoryDir, `${filename}.json`);
|
/**
|
||||||
await fse.writeFile(filepath, JSON.stringify(schema, null, 2));
|
* Edit a component schema file
|
||||||
|
*/
|
||||||
|
async function editSchema({ uid, schema }) {
|
||||||
|
const { category, __filename__ } = strapi.components[uid];
|
||||||
|
const filePath = path.join(strapi.dir, 'components', category, __filename__);
|
||||||
|
|
||||||
|
await fse.ensureFile(filePath);
|
||||||
|
await fse.writeJSON(filePath, schema, { spaces: 2 });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -179,156 +172,131 @@ async function writeSchema({ uid, schema }) {
|
|||||||
* @param {string} ui
|
* @param {string} ui
|
||||||
*/
|
*/
|
||||||
async function deleteSchema(uid) {
|
async function deleteSchema(uid) {
|
||||||
const [category, filename] = uid.split('.');
|
const { category, __filename__ } = strapi.components[uid];
|
||||||
await strapi.fs.removeAppFile(`components/${category}/${filename}.json`);
|
await strapi.fs.removeAppFile(`components/${category}/${__filename__}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateComponentInModels = (oldUID, newUID) => {
|
const updateComponentInModels = (oldUID, newUID) => {
|
||||||
const contentTypeService =
|
const contentTypeUpdates = Object.keys(strapi.contentTypes).map(uid => {
|
||||||
strapi.plugins['content-type-builder'].services.contenttypebuilder;
|
const { __schema__: oldSchema } = strapi.contentTypes[uid];
|
||||||
|
|
||||||
const updateModels = (models, { plugin } = {}) => {
|
const componentsToUpdate = Object.keys(oldSchema.attributes).reduce(
|
||||||
Object.keys(models).forEach(modelKey => {
|
(acc, key) => {
|
||||||
const model = models[modelKey];
|
if (
|
||||||
|
oldSchema.attributes[key].type === 'component' &&
|
||||||
|
oldSchema.attributes[key].component === oldUID
|
||||||
|
) {
|
||||||
|
acc.push(key);
|
||||||
|
}
|
||||||
|
|
||||||
const attributesToModify = Object.keys(model.attributes).reduce(
|
return acc;
|
||||||
(acc, key) => {
|
},
|
||||||
if (
|
[]
|
||||||
model.attributes[key].type === 'component' &&
|
);
|
||||||
model.attributes[key].component === oldUID
|
|
||||||
) {
|
|
||||||
acc.push(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc;
|
const dynamiczonesToUpdate = Object.keys(oldSchema.attributes).filter(
|
||||||
},
|
key => {
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const dynamicoznesToUpdate = Object.keys(model.attributes).filter(key => {
|
|
||||||
return (
|
return (
|
||||||
model.attributes[key].type === 'dynamiczone' &&
|
oldSchema.attributes[key].type === 'dynamiczone' &&
|
||||||
model.attributes[key].components.includes(oldUID)
|
oldSchema.attributes[key].components.includes(oldUID)
|
||||||
);
|
);
|
||||||
}, []);
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
if (attributesToModify.length > 0) {
|
if (componentsToUpdate.length > 0 || dynamiczonesToUpdate.length > 0) {
|
||||||
const modelJSON = contentTypeService.readModel(modelKey, {
|
const newSchema = _.cloneDeep(oldSchema);
|
||||||
plugin,
|
|
||||||
api: model.apiName,
|
|
||||||
});
|
|
||||||
|
|
||||||
attributesToModify.forEach(key => {
|
componentsToUpdate.forEach(key => {
|
||||||
modelJSON.attributes[key].component = newUID;
|
|
||||||
});
|
|
||||||
|
|
||||||
dynamicoznesToUpdate.forEach(key => {
|
|
||||||
modelJSON.attributes[key] = {
|
|
||||||
...modelJSON.attributes[key],
|
|
||||||
components: modelJSON.attributes[key].components.map(val =>
|
|
||||||
val !== oldUID ? val : newUID
|
|
||||||
),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
contentTypeService.writeModel(modelKey, modelJSON, {
|
|
||||||
plugin,
|
|
||||||
api: model.apiName,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
updateModels(strapi.models);
|
|
||||||
|
|
||||||
Object.keys(strapi.plugins).forEach(pluginKey => {
|
|
||||||
updateModels(strapi.plugins[pluginKey].models, { plugin: pluginKey });
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.keys(strapi.components).forEach(uid => {
|
|
||||||
const component = strapi.components[uid];
|
|
||||||
|
|
||||||
const componentsToRemove = Object.keys(component.attributes).filter(key => {
|
|
||||||
return (
|
|
||||||
component.attributes[key].type === 'component' &&
|
|
||||||
component.attributes[key].component === oldUID
|
|
||||||
);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (componentsToRemove.length > 0) {
|
|
||||||
const newSchema = {
|
|
||||||
info: component.info,
|
|
||||||
connection: component.connection,
|
|
||||||
collectionName: component.collectionName,
|
|
||||||
attributes: component.attributes,
|
|
||||||
};
|
|
||||||
|
|
||||||
componentsToRemove.forEach(key => {
|
|
||||||
newSchema.attributes[key].component = newUID;
|
newSchema.attributes[key].component = newUID;
|
||||||
});
|
});
|
||||||
|
|
||||||
writeSchema({ uid, schema: newSchema });
|
dynamiczonesToUpdate.forEach(key => {
|
||||||
|
newSchema.attributes[key].components = oldSchema.attributes[
|
||||||
|
key
|
||||||
|
].components.map(val => (val !== oldUID ? val : newUID));
|
||||||
|
});
|
||||||
|
|
||||||
|
return contentTypeService.writeContentType({ uid, schema: newSchema });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const componentUpdates = Object.keys(strapi.components).map(uid => {
|
||||||
|
const { __schema__: oldSchema } = strapi.components[uid];
|
||||||
|
|
||||||
|
const componentsToUpdate = Object.keys(oldSchema.attributes).filter(key => {
|
||||||
|
return (
|
||||||
|
oldSchema.attributes[key].type === 'component' &&
|
||||||
|
oldSchema.attributes[key].component === oldUID
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (componentsToUpdate.length > 0) {
|
||||||
|
const newSchema = {
|
||||||
|
...oldSchema,
|
||||||
|
};
|
||||||
|
|
||||||
|
componentsToUpdate.forEach(key => {
|
||||||
|
newSchema.attributes[key].component = newUID;
|
||||||
|
});
|
||||||
|
|
||||||
|
return editSchema({ uid, schema: newSchema });
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all([...contentTypeUpdates, ...componentUpdates]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteComponentInModels = async componentUID => {
|
const deleteComponentInModels = async componentUID => {
|
||||||
const [category] = componentUID.split('.');
|
const component = strapi.components[componentUID];
|
||||||
const contentTypeService =
|
|
||||||
strapi.plugins['content-type-builder'].services.contenttypebuilder;
|
|
||||||
|
|
||||||
const updateModels = (models, { plugin } = {}) => {
|
const contentTypeUpdates = Object.keys(strapi.contentTypes).map(uid => {
|
||||||
Object.keys(models).forEach(modelKey => {
|
const { __schema__: oldSchema } = strapi.contentTypes[uid];
|
||||||
const model = models[modelKey];
|
|
||||||
|
|
||||||
const componentsToRemove = Object.keys(model.attributes).filter(key => {
|
const componentsToRemove = Object.keys(oldSchema.attributes).filter(key => {
|
||||||
|
return (
|
||||||
|
oldSchema.attributes[key].type === 'component' &&
|
||||||
|
oldSchema.attributes[key].component === componentUID
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const dynamiczonesToUpdate = Object.keys(oldSchema.attributes).filter(
|
||||||
|
key => {
|
||||||
return (
|
return (
|
||||||
model.attributes[key].type === 'component' &&
|
oldSchema.attributes[key].type === 'dynamiczone' &&
|
||||||
model.attributes[key].component === componentUID
|
oldSchema.attributes[key].components.includes(componentUID)
|
||||||
);
|
);
|
||||||
}, []);
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const dynamicoznesToUpdate = Object.keys(model.attributes).filter(key => {
|
if (componentsToRemove.length > 0 || dynamiczonesToUpdate.length > 0) {
|
||||||
return (
|
const newSchema = _.cloneDeep(oldSchema);
|
||||||
model.attributes[key].type === 'dynamiczone' &&
|
|
||||||
model.attributes[key].components.includes(componentUID)
|
|
||||||
);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (componentsToRemove.length > 0 || dynamicoznesToUpdate.length > 0) {
|
componentsToRemove.forEach(key => {
|
||||||
const modelJSON = contentTypeService.readModel(modelKey, {
|
delete newSchema.attributes[key];
|
||||||
plugin,
|
});
|
||||||
api: model.apiName,
|
|
||||||
});
|
|
||||||
|
|
||||||
componentsToRemove.forEach(key => {
|
dynamiczonesToUpdate.forEach(key => {
|
||||||
delete modelJSON.attributes[key];
|
newSchema.attributes[key] = {
|
||||||
});
|
...newSchema.attributes[key],
|
||||||
|
components: newSchema.attributes[key].components.filter(
|
||||||
|
val => val !== componentUID
|
||||||
|
),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
dynamicoznesToUpdate.forEach(key => {
|
return contentTypeService.writeContentType({ uid, schema: newSchema });
|
||||||
modelJSON.attributes[key] = {
|
}
|
||||||
...modelJSON.attributes[key],
|
|
||||||
components: modelJSON.attributes[key].components.filter(
|
|
||||||
val => val !== componentUID
|
|
||||||
),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
contentTypeService.writeModel(modelKey, modelJSON, {
|
return Promise.resolve();
|
||||||
plugin,
|
|
||||||
api: model.apiName,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
updateModels(strapi.models);
|
|
||||||
|
|
||||||
Object.keys(strapi.plugins).forEach(pluginKey => {
|
|
||||||
updateModels(strapi.plugins[pluginKey].models, { plugin: pluginKey });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.keys(strapi.components).forEach(uid => {
|
const componentUpdates = Object.keys(strapi.components).map(uid => {
|
||||||
const component = strapi.components[uid];
|
const component = strapi.components[uid];
|
||||||
|
|
||||||
const componentsToRemove = Object.keys(component.attributes).filter(key => {
|
const componentsToRemove = Object.keys(component.attributes).filter(key => {
|
||||||
@ -350,25 +318,28 @@ const deleteComponentInModels = async componentUID => {
|
|||||||
delete newSchema.attributes[key];
|
delete newSchema.attributes[key];
|
||||||
});
|
});
|
||||||
|
|
||||||
writeSchema({ uid, schema: newSchema });
|
return editSchema({ uid, schema: newSchema });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
const categoryDir = path.join(strapi.dir, 'components', category);
|
await Promise.all([...contentTypeUpdates, ...componentUpdates]);
|
||||||
const categoryCompos = await fse.readdir(categoryDir);
|
|
||||||
if (categoryCompos.length === 0) {
|
const categoryDir = path.join(strapi.dir, 'components', component.category);
|
||||||
|
const list = await fse.readdir(categoryDir);
|
||||||
|
if (list.length === 0) {
|
||||||
await fse.remove(categoryDir);
|
await fse.remove(categoryDir);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getComponents,
|
|
||||||
getComponent,
|
|
||||||
createComponent,
|
createComponent,
|
||||||
createComponentUID,
|
createComponentUID,
|
||||||
updateComponent,
|
updateComponent,
|
||||||
deleteComponent,
|
deleteComponent,
|
||||||
writeComponent: writeSchema,
|
editSchema,
|
||||||
|
formatComponent,
|
||||||
|
|
||||||
// export for testing only
|
// export for testing only
|
||||||
createSchema,
|
createSchema,
|
||||||
|
@ -0,0 +1,322 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const _ = require('lodash');
|
||||||
|
const pluralize = require('pluralize');
|
||||||
|
const fse = require('fs-extra');
|
||||||
|
const generator = require('strapi-generate');
|
||||||
|
|
||||||
|
const componentService = require('./Components');
|
||||||
|
const { formatAttributes, convertAttributes } = require('../utils/attributes');
|
||||||
|
|
||||||
|
const deleteAllRelations = ({ modelName, plugin }) => {
|
||||||
|
const contentTypeUpdates = Object.keys(strapi.contentTypes).map(uid => {
|
||||||
|
const { __schema__ } = strapi.contentTypes[uid];
|
||||||
|
|
||||||
|
const keysToDelete = Object.keys(__schema__.attributes).filter(key => {
|
||||||
|
const attr = __schema__.attributes[key];
|
||||||
|
const target = attr.model || attr.collection;
|
||||||
|
|
||||||
|
const sameModel = target === modelName;
|
||||||
|
const samePluginOrNoPlugin =
|
||||||
|
(attr.plugin && attr.plugin === plugin) || !attr.plugin;
|
||||||
|
|
||||||
|
if (samePluginOrNoPlugin && sameModel) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (keysToDelete.length > 0) {
|
||||||
|
const newchema = {
|
||||||
|
...__schema__,
|
||||||
|
attributes: _.omit(__schema__.attributes, keysToDelete),
|
||||||
|
};
|
||||||
|
|
||||||
|
return writeContentType({ uid, schema: newchema });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const componentUpdates = Object.keys(strapi.components).map(uid => {
|
||||||
|
const { __schema__ } = strapi.components[uid];
|
||||||
|
|
||||||
|
const keysToDelete = Object.keys(__schema__.attributes).filter(key => {
|
||||||
|
const attr = __schema__.attributes[key];
|
||||||
|
const target = attr.model || attr.collection;
|
||||||
|
|
||||||
|
const sameModel = target === modelName;
|
||||||
|
const samePluginOrNoPlugin =
|
||||||
|
(attr.plugin && attr.plugin === plugin) || !attr.plugin;
|
||||||
|
|
||||||
|
if (samePluginOrNoPlugin && sameModel) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (keysToDelete.length > 0) {
|
||||||
|
const newchema = {
|
||||||
|
...__schema__,
|
||||||
|
attributes: _.omit(__schema__.attributes, keysToDelete),
|
||||||
|
};
|
||||||
|
|
||||||
|
return componentService.editSchema({ uid, schema: newchema });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all([...contentTypeUpdates, ...componentUpdates]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteBidirectionalRelations = ({ modelName, plugin }) => {
|
||||||
|
const updates = Object.keys(strapi.contentTypes).map(uid => {
|
||||||
|
const { __schema__ } = strapi.contentTypes[uid];
|
||||||
|
|
||||||
|
const keysToDelete = Object.keys(__schema__.attributes).filter(key => {
|
||||||
|
const attr = __schema__.attributes[key];
|
||||||
|
const target = attr.model || attr.collection;
|
||||||
|
|
||||||
|
const sameModel = target === modelName;
|
||||||
|
const samePluginOrNoPlugin =
|
||||||
|
(attr.plugin && attr.plugin === plugin) || !attr.plugin;
|
||||||
|
|
||||||
|
const isBiDirectionnal = _.has(attr, 'via');
|
||||||
|
|
||||||
|
if (samePluginOrNoPlugin && sameModel && isBiDirectionnal) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (keysToDelete.length > 0) {
|
||||||
|
const newchema = {
|
||||||
|
...__schema__,
|
||||||
|
attributes: _.omit(__schema__.attributes, keysToDelete),
|
||||||
|
};
|
||||||
|
|
||||||
|
return writeContentType({ uid, schema: newchema });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(updates);
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildReversedRelation = ({ key, attr, plugin, modelName }) => {
|
||||||
|
const targetAttributeOptions = {
|
||||||
|
via: key,
|
||||||
|
columnName: attr.targetColumnName,
|
||||||
|
plugin,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (attr.nature) {
|
||||||
|
case 'manyWay':
|
||||||
|
case 'oneWay':
|
||||||
|
return;
|
||||||
|
case 'oneToOne':
|
||||||
|
case 'oneToMany':
|
||||||
|
targetAttributeOptions.model = modelName;
|
||||||
|
break;
|
||||||
|
case 'manyToOne':
|
||||||
|
targetAttributeOptions.collection = modelName;
|
||||||
|
break;
|
||||||
|
case 'manyToMany': {
|
||||||
|
targetAttributeOptions.collection = modelName;
|
||||||
|
|
||||||
|
if (!targetAttributeOptions.dominant) {
|
||||||
|
targetAttributeOptions.dominant = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetAttributeOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateReversedRelations = ({ attributes, modelName, plugin }) => {
|
||||||
|
const promises = Object.keys(attributes)
|
||||||
|
.filter(key => _.has(attributes[key], 'target'))
|
||||||
|
.map(key => {
|
||||||
|
const attr = attributes[key];
|
||||||
|
const target = strapi.contentTypes[attr.target];
|
||||||
|
|
||||||
|
const schema = _.merge({}, target.__schema__, {
|
||||||
|
attributes: {
|
||||||
|
[attr.targetAttribute]: buildReversedRelation({
|
||||||
|
key,
|
||||||
|
attr,
|
||||||
|
plugin,
|
||||||
|
modelName,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return writeContentType({ uid: attr.target, schema });
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises);
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeContentType = async ({ uid }) => {
|
||||||
|
const { apiName, __filename__ } = strapi.contentTypes[uid];
|
||||||
|
|
||||||
|
const baseName = path.basename(__filename__, '.settings.json');
|
||||||
|
const apiFolder = path.join(strapi.dir, 'api', apiName);
|
||||||
|
|
||||||
|
const deleteFile = async filePath => {
|
||||||
|
const fileName = path.basename(filePath);
|
||||||
|
|
||||||
|
if (_.startsWith(_.toLower(fileName), _.toLower(baseName) + '.')) {
|
||||||
|
await fse.remove(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileName === 'routes.json') {
|
||||||
|
const { routes } = await fse.readJSON(filePath);
|
||||||
|
|
||||||
|
const clearedRoutes = routes.filter(route => {
|
||||||
|
return !_.startsWith(
|
||||||
|
_.toLower(route.handler),
|
||||||
|
_.toLower(baseName) + '.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (clearedRoutes.length === 0) {
|
||||||
|
await fse.remove(filePath);
|
||||||
|
} else {
|
||||||
|
await fse.writeJSON(
|
||||||
|
filePath,
|
||||||
|
{
|
||||||
|
routes: clearedRoutes,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spaces: 2,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const recursiveRemoveFiles = async folder => {
|
||||||
|
const filesName = await fse.readdir(folder);
|
||||||
|
|
||||||
|
for (const fileName of filesName) {
|
||||||
|
const filePath = path.join(folder, fileName);
|
||||||
|
|
||||||
|
const stat = await fse.stat(filePath);
|
||||||
|
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
await recursiveRemoveFiles(filePath);
|
||||||
|
} else {
|
||||||
|
await deleteFile(filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const files = await fse.readdir(folder);
|
||||||
|
if (files.length === 0) {
|
||||||
|
await fse.remove(folder);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await recursiveRemoveFiles(apiFolder);
|
||||||
|
};
|
||||||
|
|
||||||
|
const writeContentType = async ({ uid, schema }) => {
|
||||||
|
const { plugin, apiName, __filename__ } = strapi.contentTypes[uid];
|
||||||
|
|
||||||
|
let fileDir;
|
||||||
|
if (plugin) {
|
||||||
|
fileDir = `./extensions/${plugin}/models`;
|
||||||
|
} else {
|
||||||
|
fileDir = `./api/${apiName}/models`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filePath = path.join(strapi.dir, fileDir, __filename__);
|
||||||
|
|
||||||
|
await fse.ensureFile(filePath);
|
||||||
|
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 || `${_.snakeCase(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) => {
|
||||||
|
const scope = {
|
||||||
|
generatorType: 'api',
|
||||||
|
id: name,
|
||||||
|
name,
|
||||||
|
rootPath: strapi.dir,
|
||||||
|
args: {
|
||||||
|
displayName: contentType.info.name,
|
||||||
|
description: contentType.info.description,
|
||||||
|
connection: contentType.connection,
|
||||||
|
collectionName: contentType.collectionName,
|
||||||
|
attributes: contentType.attributes,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
generator(scope, {
|
||||||
|
success: () => resolve(),
|
||||||
|
error: err => reject(err),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
generateAPI,
|
||||||
|
createContentTypeSchema,
|
||||||
|
updateContentTypeSchema,
|
||||||
|
|
||||||
|
deleteAllRelations,
|
||||||
|
deleteBidirectionalRelations,
|
||||||
|
generateReversedRelations,
|
||||||
|
|
||||||
|
formatContentType,
|
||||||
|
writeContentType,
|
||||||
|
removeContentType,
|
||||||
|
};
|
@ -17,6 +17,7 @@ module.exports = async ({ dir }) => {
|
|||||||
Object.keys(map[category]).forEach(key => {
|
Object.keys(map[category]).forEach(key => {
|
||||||
acc[`${category}.${key}`] = Object.assign(map[category][key], {
|
acc[`${category}.${key}`] = Object.assign(map[category][key], {
|
||||||
category,
|
category,
|
||||||
|
modelName: key,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return acc;
|
return acc;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user