diff --git a/packages/core/admin/ee/server/services/review-workflows/review-workflows.js b/packages/core/admin/ee/server/services/review-workflows/review-workflows.js index 3f513aad8d..f3908882de 100644 --- a/packages/core/admin/ee/server/services/review-workflows/review-workflows.js +++ b/packages/core/admin/ee/server/services/review-workflows/review-workflows.js @@ -106,21 +106,45 @@ function enableReviewWorkflow({ strapi }) { const { joinTable } = strapi.db.metadata.get(target).attributes[morphBy]; const { idColumn, typeColumn } = joinTable.morphColumn; - // Execute a raw SQL query to insert records into the join table mapping the specified content type with the first stage of the default workflow. + const connection = strapi.db.getConnection(); + + // Execute an SQL query to insert records into the join table mapping the specified content type with the first stage of the default workflow. // Only entities that do not have a record in the join table yet are selected. - await strapi.db.connection - .raw(`INSERT INTO ${joinTable.name} (${idColumn.name}, field, "order", ${joinTable.joinColumn.name}, ${typeColumn.name}) - SELECT - entity.id as ${idColumn.name}, - '${ENTITY_STAGE_ATTRIBUTE}' as field, - 1 as "order", - ${firstStage.id} as ${joinTable.joinColumn.name}, - '${contentTypeUID}' as ${typeColumn.name} - FROM ${contentTypeMetadata.tableName} entity - LEFT JOIN ${joinTable.name} jointable - ON entity.id = jointable.${idColumn.name} - AND jointable.${typeColumn.name} = '${contentTypeUID}' - WHERE jointable.${idColumn.name} IS NULL`); + const selectStatement = connection + .select({ + [idColumn.name]: 'entity.id', + field: connection.raw('?', [ENTITY_STAGE_ATTRIBUTE]), + order: 1, + [joinTable.joinColumn.name]: firstStage.id, + [typeColumn.name]: connection.raw('?', [contentTypeUID]), + }) + .leftJoin(`${joinTable.name} AS jointable`, function () { + this.on('entity.id', '=', `jointable.${idColumn.name}`).andOn( + `jointable.${typeColumn.name}`, + '=', + connection.raw('?', [contentTypeUID]) + ); + }) + .where(`jointable.${idColumn.name}`, null) + .from(`${contentTypeMetadata.tableName} AS entity`) + .toSQL(); + + const columnsToInsert = [ + idColumn.name, + 'field', + connection.raw('??', ['order']), + joinTable.joinColumn.name, + typeColumn.name, + ]; + + // Insert rows for all entries of the content type that do not have a + // default stage + await connection(joinTable.name).insert( + connection.raw( + `(${columnsToInsert.join(',')}) ${selectStatement.sql}`, + selectStatement.bindings + ) + ); }; return pipe([ diff --git a/packages/core/admin/ee/server/tests/review-workflows.test.api.js b/packages/core/admin/ee/server/tests/review-workflows.test.api.js index e6dded7979..0bca5d5524 100644 --- a/packages/core/admin/ee/server/tests/review-workflows.test.api.js +++ b/packages/core/admin/ee/server/tests/review-workflows.test.api.js @@ -2,12 +2,31 @@ const { createStrapiInstance } = require('../../../../../../test/helpers/strapi'); const { createAuthRequest, createRequest } = require('../../../../../../test/helpers/request'); +const { createTestBuilder } = require('../../../../../../test/helpers/builder'); + const { describeOnCondition } = require('../utils/test'); const { STAGE_MODEL_UID, WORKFLOW_MODEL_UID } = require('../constants/workflows'); const edition = process.env.STRAPI_DISABLE_EE === 'true' ? 'CE' : 'EE'; +const productUID = 'api::product.product'; +const model = { + draftAndPublish: true, + pluginOptions: {}, + singularName: 'product', + pluralName: 'products', + displayName: 'Product', + kind: 'collectionType', + attributes: { + name: { + type: 'string', + }, + }, +}; + describeOnCondition(edition === 'EE')('Review workflows', () => { + const builder = createTestBuilder(); + const requests = { public: null, admin: null, @@ -18,11 +37,37 @@ describeOnCondition(edition === 'EE')('Review workflows', () => { let secondStage; let testWorkflow; - beforeAll(async () => { + const createEntry = async (uid, data) => { + const { body } = await requests.admin({ + method: 'POST', + url: `/content-manager/collection-types/${uid}`, + body: data, + }); + return body; + }; + + const updateContentType = async (uid, data) => { + const result = await requests.admin({ + method: 'PUT', + url: `/content-type-builder/content-types/${uid}`, + body: data, + }); + + expect(result.statusCode).toBe(201); + }; + + const restart = async () => { + await strapi.destroy(); strapi = await createStrapiInstance(); + requests.admin = await createAuthRequest({ strapi }); + }; + + beforeAll(async () => { + await builder.addContentTypes([model]).build(); // eslint-disable-next-line node/no-extraneous-require hasRW = require('@strapi/strapi/lib/utils/ee').features.isEnabled('review-workflows'); + strapi = await createStrapiInstance(); requests.public = createRequest({ strapi }); requests.admin = await createAuthRequest({ strapi }); @@ -42,6 +87,7 @@ describeOnCondition(edition === 'EE')('Review workflows', () => { afterAll(async () => { await strapi.destroy(); + await builder.cleanup(); }); describe('Get workflows', () => { @@ -269,4 +315,39 @@ describeOnCondition(edition === 'EE')('Review workflows', () => { } }); }); + + describe('Enable review workflows on a content type', () => { + test('when enabled on a content type, entries of this type should be added to the first stage of the workflow', async () => { + await createEntry(productUID, { name: 'Product' }); + await createEntry(productUID, { name: 'Product 1' }); + await createEntry(productUID, { name: 'Product 2' }); + + await updateContentType(productUID, { + components: [], + contentType: { ...model, reviewWorkflows: true }, + }); + + await restart(); + + const res = await requests.admin({ + method: 'GET', + url: `/content-type-builder/content-types/api::product.product`, + }); + + expect(res.body.data.schema.reviewWorkflows).toBeTruthy(); + + const connection = strapi.db.getConnection(); + const RWMorphTableResults = await connection + .select('*') + .from('strapi_workflows_stages_related_morphs') + .where('related_type', productUID); + + expect(RWMorphTableResults.length).toEqual(3); + for (let i = 0; i < RWMorphTableResults.length; i += 1) { + const entry = RWMorphTableResults[i]; + expect(entry.related_id).toEqual(i + 1); + expect(entry.order).toEqual(1); + } + }); + }); });