diff --git a/packages/strapi-plugin-content-manager/config/policies/routing.js b/packages/strapi-plugin-content-manager/config/policies/routing.js index 31dc601016..78f78ca152 100644 --- a/packages/strapi-plugin-content-manager/config/policies/routing.js +++ b/packages/strapi-plugin-content-manager/config/policies/routing.js @@ -2,9 +2,6 @@ const _ = require('lodash'); -const parseMultipartBody = require('../../utils/parse-multipart'); -const uploadFiles = require('../../utils/upload-files'); - module.exports = async (ctx, next) => { const { model } = ctx.params; @@ -22,24 +19,6 @@ module.exports = async (ctx, next) => { const [controller, action] = _.get(target, actionPath, []).split('.'); if (controller && action) { - if (ctx.is('multipart')) { - const { data, files } = parseMultipartBody(ctx); - ctx.request.body = data; - ctx.request.files = {}; - - await target.controllers[controller.toLowerCase()][action](ctx); - const resBody = ctx.body; - - if (ctx.status >= 300) return; - - await uploadFiles(resBody, files, { - model: ct.modelName, - source: ct.plugin, - }); - - return ctx.send(resBody); - } - return await target.controllers[controller.toLowerCase()][action](ctx); } } diff --git a/packages/strapi-plugin-content-manager/controllers/collection-types.js b/packages/strapi-plugin-content-manager/controllers/collection-types.js index e4ecbecd03..f0092c3750 100644 --- a/packages/strapi-plugin-content-manager/controllers/collection-types.js +++ b/packages/strapi-plugin-content-manager/controllers/collection-types.js @@ -5,7 +5,6 @@ const { has, pipe } = require('lodash/fp'); const { getService, wrapBadRequest, - parseBody, setCreatorFields, pickWritableAttributes, } = require('../utils'); @@ -16,6 +15,7 @@ module.exports = { const { model } = ctx.params; const { query } = ctx.request; + const entityManager = getService('entity-manager'); const permissionChecker = getService('permission-checker').create({ userAbility, model }); if (permissionChecker.cannot.read()) { @@ -26,10 +26,7 @@ module.exports = { const permissionQuery = permissionChecker.buildPermissionQuery(query); - const { results, pagination } = await getService('entity-manager')[method]( - permissionQuery, - model - ); + const { results, pagination } = await entityManager[method](permissionQuery, model); ctx.body = { results: results.map(entity => permissionChecker.sanitizeOutput(entity)), @@ -41,13 +38,14 @@ module.exports = { const { userAbility } = ctx.state; const { model, id } = ctx.params; + const entityManager = getService('entity-manager'); const permissionChecker = getService('permission-checker').create({ userAbility, model }); if (permissionChecker.cannot.read()) { return ctx.forbidden(); } - const entity = await getService('entity-manager').findOneWithCreatorRoles(id, model); + const entity = await entityManager.findOneWithCreatorRoles(id, model); if (!entity) { return ctx.notFound(); @@ -63,8 +61,9 @@ module.exports = { async create(ctx) { const { userAbility, user } = ctx.state; const { model } = ctx.params; - const { files, data } = parseBody(ctx); + const { body } = ctx.request; + const entityManager = getService('entity-manager'); const permissionChecker = getService('permission-checker').create({ userAbility, model }); if (permissionChecker.cannot.create()) { @@ -78,10 +77,7 @@ module.exports = { const sanitizeFn = pipe([pickWritables, pickPermittedFields, setCreator]); await wrapBadRequest(async () => { - const entity = await getService('entity-manager').create( - { data: sanitizeFn(data), files }, - model - ); + const entity = await entityManager.create(sanitizeFn(body), model); ctx.body = permissionChecker.sanitizeOutput(entity); await strapi.telemetry.send('didCreateFirstContentTypeEntry', { model }); @@ -91,15 +87,16 @@ module.exports = { async update(ctx) { const { userAbility, user } = ctx.state; const { id, model } = ctx.params; - const { files, data } = parseBody(ctx); + const { body } = ctx.request; + const entityManager = getService('entity-manager'); const permissionChecker = getService('permission-checker').create({ userAbility, model }); if (permissionChecker.cannot.update()) { return ctx.forbidden(); } - const entity = await getService('entity-manager').findOneWithCreatorRoles(id, model); + const entity = await entityManager.findOneWithCreatorRoles(id, model); if (!entity) { return ctx.notFound(); @@ -116,11 +113,7 @@ module.exports = { const sanitizeFn = pipe([pickWritables, pickPermittedFields, setCreator]); await wrapBadRequest(async () => { - const updatedEntity = await getService('entity-manager').update( - entity, - { data: sanitizeFn(data), files }, - model - ); + const updatedEntity = await entityManager.update(entity, sanitizeFn(body), model); ctx.body = permissionChecker.sanitizeOutput(updatedEntity); })(); @@ -130,13 +123,14 @@ module.exports = { const { userAbility } = ctx.state; const { id, model } = ctx.params; + const entityManager = getService('entity-manager'); const permissionChecker = getService('permission-checker').create({ userAbility, model }); if (permissionChecker.cannot.delete()) { return ctx.forbidden(); } - const entity = await getService('entity-manager').findOneWithCreatorRoles(id, model); + const entity = await entityManager.findOneWithCreatorRoles(id, model); if (!entity) { return ctx.notFound(); @@ -146,7 +140,7 @@ module.exports = { return ctx.forbidden(); } - const result = await getService('entity-manager').delete(entity, model); + const result = await entityManager.delete(entity, model); ctx.body = permissionChecker.sanitizeOutput(result); }, @@ -155,13 +149,14 @@ module.exports = { const { userAbility } = ctx.state; const { id, model } = ctx.params; + const entityManager = getService('entity-manager'); const permissionChecker = getService('permission-checker').create({ userAbility, model }); if (permissionChecker.cannot.publish()) { return ctx.forbidden(); } - const entity = await getService('entity-manager').findOneWithCreatorRoles(id, model); + const entity = await entityManager.findOneWithCreatorRoles(id, model); if (!entity) { return ctx.notFound(); @@ -171,7 +166,7 @@ module.exports = { return ctx.forbidden(); } - const result = await getService('entity-manager').publish(entity, model); + const result = await entityManager.publish(entity, model); ctx.body = permissionChecker.sanitizeOutput(result); }, @@ -180,13 +175,14 @@ module.exports = { const { userAbility } = ctx.state; const { id, model } = ctx.params; + const entityManager = getService('entity-manager'); const permissionChecker = getService('permission-checker').create({ userAbility, model }); if (permissionChecker.cannot.unpublish()) { return ctx.forbidden(); } - const entity = await getService('entity-manager').findOneWithCreatorRoles(id, model); + const entity = await entityManager.findOneWithCreatorRoles(id, model); if (!entity) { return ctx.notFound(); @@ -196,7 +192,7 @@ module.exports = { return ctx.forbidden(); } - const result = await getService('entity-manager').unpublish(entity, model); + const result = await entityManager.unpublish(entity, model); ctx.body = permissionChecker.sanitizeOutput(result); }, @@ -207,6 +203,7 @@ module.exports = { const { query, body } = ctx.request; const { ids } = body; + const entityManager = getService('entity-manager'); const permissionChecker = getService('permission-checker').create({ userAbility, model }); if (permissionChecker.cannot.delete()) { @@ -222,7 +219,7 @@ module.exports = { _where: [idsWhereClause].concat(permissionQuery._where || {}), }; - const results = await strapi.entityService.delete({ params }, { model }); + const results = await entityManager.findAndDelete(params, model); ctx.body = results.map(result => permissionChecker.sanitizeOutput(result)); }, diff --git a/packages/strapi-plugin-content-manager/controllers/single-types.js b/packages/strapi-plugin-content-manager/controllers/single-types.js index c0a49a623e..4057aacd4a 100644 --- a/packages/strapi-plugin-content-manager/controllers/single-types.js +++ b/packages/strapi-plugin-content-manager/controllers/single-types.js @@ -4,7 +4,6 @@ const { pipe } = require('lodash/fp'); const { getService, wrapBadRequest, - parseBody, setCreatorFields, pickWritableAttributes, } = require('../utils'); @@ -48,9 +47,9 @@ module.exports = { async createOrUpdate(ctx) { const { user, userAbility } = ctx.state; const { model } = ctx.params; + const { body } = ctx.request; - const { data, files } = parseBody(ctx); - + const entityManager = getService('entity-manager'); const permissionChecker = getService('permission-checker').create({ userAbility, model }); if (permissionChecker.cannot.create() && permissionChecker.cannot.update()) { @@ -73,11 +72,7 @@ module.exports = { await wrapBadRequest(async () => { if (!entity) { - const entity = await getService('entity-manager').create( - { data: sanitizeFn(data), files }, - model - ); - + const entity = await entityManager.create(sanitizeFn(body), model); ctx.body = permissionChecker.sanitizeOutput(entity); await strapi.telemetry.send('didCreateFirstContentTypeEntry', { model }); @@ -88,12 +83,7 @@ module.exports = { return ctx.forbidden(); } - const updatedEntity = await getService('entity-manager').update( - entity, - { data: sanitizeFn(data), files }, - model - ); - + const updatedEntity = await entityManager.update(entity, sanitizeFn(body), model); ctx.body = permissionChecker.sanitizeOutput(updatedEntity); })(); }, @@ -102,6 +92,7 @@ module.exports = { const { userAbility } = ctx.state; const { model } = ctx.params; + const entityManager = getService('entity-manager'); const permissionChecker = getService('permission-checker').create({ userAbility, model }); if (permissionChecker.cannot.delete()) { @@ -118,7 +109,7 @@ module.exports = { return ctx.forbidden(); } - const deletedEntity = await getService('entity-manager').delete(entity, model); + const deletedEntity = await entityManager.delete(entity, model); ctx.body = permissionChecker.sanitizeOutput(deletedEntity); }, @@ -127,6 +118,7 @@ module.exports = { const { userAbility } = ctx.state; const { model } = ctx.params; + const entityManager = getService('entity-manager'); const permissionChecker = getService('permission-checker').create({ userAbility, model }); if (permissionChecker.cannot.publish()) { @@ -143,7 +135,7 @@ module.exports = { return ctx.forbidden(); } - const publishedEntity = await getService('entity-manager').publish(entity, model); + const publishedEntity = await entityManager.publish(entity, model); ctx.body = permissionChecker.sanitizeOutput(publishedEntity); }, @@ -152,6 +144,7 @@ module.exports = { const { userAbility } = ctx.state; const { model } = ctx.params; + const entityManager = getService('entity-manager'); const permissionChecker = getService('permission-checker').create({ userAbility, model }); if (permissionChecker.cannot.unpublish()) { @@ -168,7 +161,7 @@ module.exports = { return ctx.forbidden(); } - const unpublishedEntity = await getService('entity-manager').unpublish(entity, model); + const unpublishedEntity = await entityManager.unpublish(entity, model); ctx.body = permissionChecker.sanitizeOutput(unpublishedEntity); }, diff --git a/packages/strapi-plugin-content-manager/services/entity-manager.js b/packages/strapi-plugin-content-manager/services/entity-manager.js index ab4703728a..0beecc7a85 100644 --- a/packages/strapi-plugin-content-manager/services/entity-manager.js +++ b/packages/strapi-plugin-content-manager/services/entity-manager.js @@ -79,23 +79,21 @@ module.exports = { }, async create(body, model) { - const { data, files } = body; - const modelDef = strapi.getModel(model); - const publishData = { ...data }; + const publishData = { ...body }; if (hasDraftAndPublish(modelDef)) { publishData[PUBLISHED_AT_ATTRIBUTE] = null; } - return strapi.entityService.create({ data: publishData, files }, { model }); + return strapi.entityService.create({ data: publishData }, { model }); }, - update(entity, { data, files }, model) { + update(entity, body, model) { const params = { id: entity.id }; - const publishData = omitPublishedAtField(data); + const publishData = omitPublishedAtField(body); - return strapi.entityService.update({ params, data: publishData, files }, { model }); + return strapi.entityService.update({ params, data: publishData }, { model }); }, delete(entity, model) { @@ -103,6 +101,10 @@ module.exports = { return strapi.entityService.delete({ params }, { model }); }, + findAnddelete(params, model) { + return strapi.entityService.delete({ params }, { model }); + }, + publish: emitEvent(ENTRY_PUBLISH, async (entity, model) => { if (entity[PUBLISHED_AT_ATTRIBUTE]) { throw strapi.errors.badRequest('already.published'); diff --git a/packages/strapi-plugin-content-manager/utils/index.js b/packages/strapi-plugin-content-manager/utils/index.js index 47eb0964ae..a8b07037de 100644 --- a/packages/strapi-plugin-content-manager/utils/index.js +++ b/packages/strapi-plugin-content-manager/utils/index.js @@ -1,7 +1,6 @@ 'use strict'; const { prop } = require('lodash/fp'); -const parseBody = require('./parse-body'); const wrapBadRequest = require('./wrap-bad-request'); const setCreatorFields = require('./set-creator-fields'); const pickWritableAttributes = require('./pick-writable-attributes'); @@ -13,7 +12,6 @@ const getService = name => { module.exports = { getService, - parseBody, wrapBadRequest, setCreatorFields, pickWritableAttributes, diff --git a/packages/strapi-plugin-content-manager/utils/parse-body.js b/packages/strapi-plugin-content-manager/utils/parse-body.js deleted file mode 100644 index bca016ed18..0000000000 --- a/packages/strapi-plugin-content-manager/utils/parse-body.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -const parseMultipartBody = require('./parse-multipart'); - -module.exports = ctx => { - const { body } = ctx.request; - return ctx.is('multipart') ? parseMultipartBody(ctx) : { data: body }; -}; diff --git a/packages/strapi-plugin-content-manager/utils/parse-multipart.js b/packages/strapi-plugin-content-manager/utils/parse-multipart.js deleted file mode 100644 index 883bb830fe..0000000000 --- a/packages/strapi-plugin-content-manager/utils/parse-multipart.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -const _ = require('lodash'); - -module.exports = ctx => { - const { body = {}, files = {} } = ctx.request; - - if (!body.data) { - throw strapi.errors.badRequest( - `When using multipart/form-data you need to provide your data in a JSON 'data' field.` - ); - } - - let data; - try { - data = JSON.parse(body.data); - } catch (error) { - throw strapi.errors.badRequest( - `Invalid 'data' field. 'data' should be a valid JSON.` - ); - } - - const filesToUpload = Object.keys(files).reduce((acc, key) => { - const fullPath = _.toPath(key); - - if (fullPath.length <= 1 || fullPath[0] !== 'files') { - throw strapi.errors.badRequest( - `When using multipart/form-data you need to provide your files by prefixing them witht the 'files'.` - ); - } - - const path = _.tail(fullPath); - acc[path.join('.')] = files[key]; - return acc; - }, {}); - - return { - data, - files: filesToUpload, - }; -}; diff --git a/packages/strapi-plugin-content-manager/utils/upload-files.js b/packages/strapi-plugin-content-manager/utils/upload-files.js deleted file mode 100644 index e6bbed203d..0000000000 --- a/packages/strapi-plugin-content-manager/utils/upload-files.js +++ /dev/null @@ -1,71 +0,0 @@ -'use strict'; - -const _ = require('lodash'); - -module.exports = async (entry, files, { model, source }) => { - const entity = strapi.getModel(model, source); - - if (!_.has(strapi.plugins, 'upload')) return entry; - - const uploadService = strapi.plugins.upload.services.upload; - - const findModelFromUploadPath = path => { - if (path.length === 0) return { model, source }; - - let currentPath = []; - let tmpModel = entity; - let modelName = model; - let sourceName; - - for (let i = 0; i < path.length; i++) { - if (!tmpModel) return {}; - const part = path[i]; - const attr = tmpModel.attributes[part]; - - currentPath.push(part); - - // ignore array indexes => handled in the dynamic zone section - if (_.isFinite(_.toNumber(path[i]))) { - continue; - } - - if (!attr) return {}; - - if (attr.type === 'component') { - modelName = attr.component; - tmpModel = strapi.components[attr.component]; - } else if (attr.type === 'dynamiczone') { - const entryIdx = path[i + 1]; // get component index - const value = _.get(entry, [...currentPath, entryIdx]); - - if (!value) return {}; - - modelName = value.__component; // get component type - tmpModel = strapi.components[modelName]; - } else if (_.has(attr, 'model') || _.has(attr, 'collection')) { - sourceName = attr.plugin; - modelName = attr.model || attr.collection; - tmpModel = strapi.getModel(attr.model || attr.collection, source); - } else { - return {}; - } - } - - return { model: modelName, source: sourceName }; - }; - - const doUpload = async (key, files) => { - const parts = key.split('.'); - const [path, field] = [_.initial(parts), _.last(parts)]; - - const { model, source } = findModelFromUploadPath(path); - - if (model) { - const id = _.get(entry, path.concat('id')); - - return uploadService.uploadToEntity({ id, model, field }, files, source); - } - }; - - await Promise.all(Object.keys(files).map(key => doUpload(key, files[key]))); -};