From b4ac2f90d8c83643d16a6a1743a82d74ea3a5ef0 Mon Sep 17 00:00:00 2001 From: Nathan Pichon Date: Fri, 23 Jun 2023 17:18:32 +0200 Subject: [PATCH] feat(review-workflows): remove deleted content-types in assigned workflows (#17053) * feat(review-workflows): migrate old to new stage attribute name * feat(reviewWorkflows): remove ct from workflows when deleted * fix(operators): re-add $jsonSupersetOf to available operators --- ...eview-workflows-deleted-ct-in-workflows.js | 39 +++++++++++++++++++ packages/core/admin/ee/server/register.js | 10 +++-- .../review-workflows/workflows/index.js | 12 ++---- .../admin/ee/server/utils/review-workflows.js | 8 ++++ packages/core/utils/lib/operators.js | 1 + 5 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 packages/core/admin/ee/server/migrations/review-workflows-deleted-ct-in-workflows.js diff --git a/packages/core/admin/ee/server/migrations/review-workflows-deleted-ct-in-workflows.js b/packages/core/admin/ee/server/migrations/review-workflows-deleted-ct-in-workflows.js new file mode 100644 index 0000000000..fad34bede6 --- /dev/null +++ b/packages/core/admin/ee/server/migrations/review-workflows-deleted-ct-in-workflows.js @@ -0,0 +1,39 @@ +'use strict'; + +const { difference, keys } = require('lodash/fp'); +const { mapAsync } = require('@strapi/utils'); +const { WORKFLOW_MODEL_UID } = require('../constants/workflows'); +const { getWorkflowContentTypeFilter } = require('../utils/review-workflows'); + +/** + * @param {Object} oldContentTypes + * @param {Object} contentTypes + * @return {Promise} + */ +async function migrateDeletedCTInWorkflows({ oldContentTypes, contentTypes }) { + const deletedContentTypes = difference(keys(oldContentTypes), keys(contentTypes)) ?? []; + + if (deletedContentTypes.length) { + await mapAsync(deletedContentTypes, async (deletedContentTypeUID) => { + const workflow = await strapi.query(WORKFLOW_MODEL_UID).findOne({ + select: ['id', 'contentTypes'], + where: { + contentTypes: getWorkflowContentTypeFilter({ strapi }, deletedContentTypeUID), + }, + }); + + if (workflow) { + await strapi.query(WORKFLOW_MODEL_UID).update({ + where: { id: workflow.id }, + data: { + contentTypes: workflow.contentTypes.filter( + (contentTypeUID) => contentTypeUID !== deletedContentTypeUID + ), + }, + }); + } + }); + } +} + +module.exports = migrateDeletedCTInWorkflows; diff --git a/packages/core/admin/ee/server/register.js b/packages/core/admin/ee/server/register.js index a1c3deb91d..1cf11872a0 100644 --- a/packages/core/admin/ee/server/register.js +++ b/packages/core/admin/ee/server/register.js @@ -7,6 +7,7 @@ const migrateReviewWorkflowStagesColor = require('./migrations/review-workflows- const migrateReviewWorkflowName = require('./migrations/review-workflows-workflow-name'); const migrateWorkflowsContentTypes = require('./migrations/review-workflows-content-types'); const migrateStageAttribute = require('./migrations/review-workflows-stage-attribute'); +const migrateDeletedCTInWorkflows = require('./migrations/review-workflows-deleted-ct-in-workflows'); const createAuditLogsService = require('./services/audit-logs'); const reviewWorkflowsMiddlewares = require('./middlewares/review-workflows'); const { getService } = require('./utils'); @@ -22,9 +23,12 @@ module.exports = async ({ strapi }) => { } if (features.isEnabled('review-workflows')) { strapi.hook('strapi::content-types.beforeSync').register(migrateStageAttribute); - strapi.hook('strapi::content-types.afterSync').register(migrateReviewWorkflowStagesColor); - strapi.hook('strapi::content-types.afterSync').register(migrateReviewWorkflowName); - strapi.hook('strapi::content-types.afterSync').register(migrateWorkflowsContentTypes); + strapi + .hook('strapi::content-types.afterSync') + .register(migrateReviewWorkflowStagesColor) + .register(migrateReviewWorkflowName) + .register(migrateWorkflowsContentTypes) + .register(migrateDeletedCTInWorkflows); const reviewWorkflowService = getService('review-workflows'); reviewWorkflowsMiddlewares.contentTypeMiddleware(strapi); diff --git a/packages/core/admin/ee/server/services/review-workflows/workflows/index.js b/packages/core/admin/ee/server/services/review-workflows/workflows/index.js index 514224f529..7854ef6f68 100644 --- a/packages/core/admin/ee/server/services/review-workflows/workflows/index.js +++ b/packages/core/admin/ee/server/services/review-workflows/workflows/index.js @@ -4,20 +4,14 @@ const { set, isString } = require('lodash/fp'); const { ApplicationError, ValidationError } = require('@strapi/utils').errors; const { WORKFLOW_MODEL_UID } = require('../../../constants/workflows'); const { getService } = require('../../../utils'); +const { getWorkflowContentTypeFilter } = require('../../../utils/review-workflows'); const workflowsContentTypesFactory = require('./content-types'); -const getContentTypeFilter = ({ strapi }, contentType) => { - if (strapi.db.dialect.supportsOperator('$jsonSupersetOf')) { - return { $jsonSupersetOf: JSON.stringify([contentType]) }; - } - return { $contains: `"${contentType}"` }; -}; - const processFilters = ({ strapi }, filters = {}) => { const processedFilters = { ...filters }; if (isString(filters.contentTypes)) { - processedFilters.contentTypes = getContentTypeFilter({ strapi }, filters.contentTypes); + processedFilters.contentTypes = getWorkflowContentTypeFilter({ strapi }, filters.contentTypes); } return processedFilters; @@ -169,7 +163,7 @@ module.exports = ({ strapi }) => { async getAssignedWorkflow(uid, opts = {}) { const workflows = await this.find({ ...opts, - filters: { contentTypes: getContentTypeFilter({ strapi }, uid) }, + filters: { contentTypes: getWorkflowContentTypeFilter({ strapi }, uid) }, }); return workflows.length > 0 ? workflows[0] : null; }, diff --git a/packages/core/admin/ee/server/utils/review-workflows.js b/packages/core/admin/ee/server/utils/review-workflows.js index f267c9fced..c6974cbe03 100644 --- a/packages/core/admin/ee/server/utils/review-workflows.js +++ b/packages/core/admin/ee/server/utils/review-workflows.js @@ -16,7 +16,15 @@ const getVisibleContentTypesUID = pipe([ const hasStageAttribute = has(['attributes', ENTITY_STAGE_ATTRIBUTE]); +const getWorkflowContentTypeFilter = ({ strapi }, contentType) => { + if (strapi.db.dialect.supportsOperator('$jsonSupersetOf')) { + return { $jsonSupersetOf: JSON.stringify([contentType]) }; + } + return { $contains: `"${contentType}"` }; +}; + module.exports = { getVisibleContentTypesUID, hasStageAttribute, + getWorkflowContentTypeFilter, }; diff --git a/packages/core/utils/lib/operators.js b/packages/core/utils/lib/operators.js index bdb57b866d..eb0077e4d1 100644 --- a/packages/core/utils/lib/operators.js +++ b/packages/core/utils/lib/operators.js @@ -24,6 +24,7 @@ const WHERE_OPERATORS = [ '$notContains', '$containsi', '$notContainsi', + '$jsonSupersetOf', ]; const CAST_OPERATORS = [