@strapi/review-workflows 5.41.0 → 5.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/admin/routes/settings/components/Stages.js +26 -14
  2. package/dist/admin/routes/settings/components/Stages.js.map +1 -1
  3. package/dist/admin/routes/settings/components/Stages.mjs +26 -14
  4. package/dist/admin/routes/settings/components/Stages.mjs.map +1 -1
  5. package/dist/admin/routes/settings/id.js +21 -6
  6. package/dist/admin/routes/settings/id.js.map +1 -1
  7. package/dist/admin/routes/settings/id.mjs +21 -6
  8. package/dist/admin/routes/settings/id.mjs.map +1 -1
  9. package/dist/admin/src/routes/settings/components/Stages.d.ts +1 -1
  10. package/dist/server/controllers/stages.js +18 -3
  11. package/dist/server/controllers/stages.js.map +1 -1
  12. package/dist/server/controllers/stages.mjs +18 -3
  13. package/dist/server/controllers/stages.mjs.map +1 -1
  14. package/dist/server/controllers/workflows.js +15 -8
  15. package/dist/server/controllers/workflows.js.map +1 -1
  16. package/dist/server/controllers/workflows.mjs +16 -9
  17. package/dist/server/controllers/workflows.mjs.map +1 -1
  18. package/dist/server/migrations/setup-stage-transfer-to-roles.js +70 -0
  19. package/dist/server/migrations/setup-stage-transfer-to-roles.js.map +1 -0
  20. package/dist/server/migrations/setup-stage-transfer-to-roles.mjs +68 -0
  21. package/dist/server/migrations/setup-stage-transfer-to-roles.mjs.map +1 -0
  22. package/dist/server/register.js +2 -1
  23. package/dist/server/register.js.map +1 -1
  24. package/dist/server/register.mjs +2 -1
  25. package/dist/server/register.mjs.map +1 -1
  26. package/dist/server/services/stage-permissions.js +72 -3
  27. package/dist/server/services/stage-permissions.js.map +1 -1
  28. package/dist/server/services/stage-permissions.mjs +73 -4
  29. package/dist/server/services/stage-permissions.mjs.map +1 -1
  30. package/dist/server/services/stages.js +72 -39
  31. package/dist/server/services/stages.js.map +1 -1
  32. package/dist/server/services/stages.mjs +72 -39
  33. package/dist/server/services/stages.mjs.map +1 -1
  34. package/dist/server/src/controllers/stages.d.ts +1 -1
  35. package/dist/server/src/controllers/stages.d.ts.map +1 -1
  36. package/dist/server/src/controllers/workflows.d.ts.map +1 -1
  37. package/dist/server/src/index.d.ts +35 -4
  38. package/dist/server/src/index.d.ts.map +1 -1
  39. package/dist/server/src/migrations/setup-stage-transfer-to-roles.d.ts +6 -0
  40. package/dist/server/src/migrations/setup-stage-transfer-to-roles.d.ts.map +1 -0
  41. package/dist/server/src/register.d.ts.map +1 -1
  42. package/dist/server/src/services/index.d.ts +35 -4
  43. package/dist/server/src/services/index.d.ts.map +1 -1
  44. package/dist/server/src/services/stage-permissions.d.ts +39 -4
  45. package/dist/server/src/services/stage-permissions.d.ts.map +1 -1
  46. package/dist/server/src/services/stages.d.ts.map +1 -1
  47. package/dist/server/src/validation/review-workflows.d.ts.map +1 -1
  48. package/dist/server/validation/review-workflows.js +20 -10
  49. package/dist/server/validation/review-workflows.js.map +1 -1
  50. package/dist/server/validation/review-workflows.mjs +20 -10
  51. package/dist/server/validation/review-workflows.mjs.map +1 -1
  52. package/dist/shared/contracts/review-workflows.d.ts +4 -2
  53. package/dist/shared/contracts/review-workflows.d.ts.map +1 -1
  54. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"id.mjs","sources":["../../../../admin/src/routes/settings/id.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport {\n ConfirmDialog,\n BackButton,\n useNotification,\n useAPIErrorHandler,\n useRBAC,\n Form,\n Page,\n FormProps,\n FormHelpers,\n} from '@strapi/admin/strapi-admin';\nimport { useLicenseLimits } from '@strapi/admin/strapi-admin/ee';\nimport { Box, Button, Dialog, Flex, Typography } from '@strapi/design-system';\nimport { Check } from '@strapi/icons';\nimport { generateNKeysBetween } from 'fractional-indexing';\nimport { useIntl } from 'react-intl';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport * as yup from 'yup';\n\nimport { LimitsModal } from '../../components/LimitsModal';\nimport {\n CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME,\n CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME,\n} from '../../constants';\nimport { useTypedSelector } from '../../modules/hooks';\nimport { isBaseQueryError } from '../../utils/api';\n\nimport * as Layout from './components/Layout';\nimport { Stages, WorkflowStage } from './components/Stages';\nimport { WorkflowAttributes } from './components/WorkflowAttributes';\nimport { useReviewWorkflows } from './hooks/useReviewWorkflows';\n\nimport type { Stage, Workflow } from '../../../../shared/contracts/review-workflows';\n\n/* -------------------------------------------------------------------------------------------------\n * EditPage\n * -----------------------------------------------------------------------------------------------*/\n\nconst WORKFLOW_SCHEMA = yup.object({\n contentTypes: yup.array().of(yup.string()),\n name: yup\n .string()\n .max(255, {\n id: 'review-workflows.validation.name.max-length',\n defaultMessage: 'Name can not be longer than 255 characters',\n })\n .required()\n .nullable(),\n stages: yup\n .array()\n .of(\n yup.object().shape({\n name: yup\n .string()\n .nullable()\n .required({\n id: 'review-workflows.validation.stage.name',\n defaultMessage: 'Name is required',\n })\n .max(255, {\n id: 'review-workflows.validation.stage.max-length',\n defaultMessage: 'Name can not be longer than 255 characters',\n })\n .test(\n 'unique-name',\n {\n id: 'review-workflows.validation.stage.duplicate',\n defaultMessage: 'Stage name must be unique',\n },\n (stageName, context) => {\n // @ts-expect-error it does exist.\n const { stages } = context.from[1].value;\n\n return stages.filter((stage: Stage) => stage.name === stageName).length === 1;\n }\n ),\n color: yup\n .string()\n .nullable()\n .required({\n id: 'review-workflows.validation.stage.color',\n defaultMessage: 'Color is required',\n })\n .matches(/^#(?:[0-9a-fA-F]{3}){1,2}$/i),\n\n permissions: yup\n .array(\n yup.object({\n role: yup\n .number()\n .strict()\n .typeError({\n id: 'review-workflows.validation.stage.permissions.role.number',\n defaultMessage: 'Role must be of type number',\n })\n .required(),\n action: yup.string().required({\n id: 'review-workflows.validation.stage.permissions.action.required',\n defaultMessage: 'Action is a required argument',\n }),\n })\n )\n .strict(),\n })\n )\n .min(1),\n stageRequiredToPublish: yup.string().nullable(),\n});\n\nconst EditPage = () => {\n const { id = '' } = useParams<{ id: string }>();\n const isCreatingWorkflow = id === 'create';\n const { formatMessage } = useIntl();\n const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();\n const navigate = useNavigate();\n const { toggleNotification } = useNotification();\n const {\n isLoading: isLoadingWorkflow,\n meta,\n workflows,\n error,\n update,\n create,\n } = useReviewWorkflows();\n const permissions = useTypedSelector(\n (state) => state.admin_app.permissions['settings']?.['review-workflows']\n );\n const {\n allowedActions: { canDelete, canUpdate, canCreate },\n } = useRBAC(permissions);\n\n const [savePrompts, setSavePrompts] = React.useState<{\n hasDeletedServerStages?: boolean;\n hasReassignedContentTypes?: boolean;\n }>({});\n const { getFeature, isLoading: isLicenseLoading } = useLicenseLimits();\n const [showLimitModal, setShowLimitModal] = React.useState<'workflow' | 'stage' | null>(null);\n\n const currentWorkflow = workflows?.find((workflow) => workflow.id === parseInt(id, 10));\n const contentTypesFromOtherWorkflows = workflows\n ?.filter((workflow) => workflow.id !== parseInt(id, 10))\n .flatMap((workflow) => workflow.contentTypes);\n\n const limits = getFeature<string>('review-workflows');\n const numberOfWorkflows = limits?.[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME];\n const stagesPerWorkflow = limits?.[CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME];\n\n interface FormValues {\n name: string;\n stages: WorkflowStage[];\n contentTypes: string[];\n stageRequiredToPublish: string | null;\n }\n\n const submitForm = async (data: FormValues, helpers: Pick<FormHelpers, 'setErrors'>) => {\n try {\n const { stageRequiredToPublish, ...rest } = data;\n const stageRequiredToPublishName =\n stageRequiredToPublish === ''\n ? null\n : rest.stages.find(\n (stage) =>\n stage.id === Number(stageRequiredToPublish) ||\n stage.__temp_key__ === stageRequiredToPublish\n )?.name;\n\n if (!isCreatingWorkflow) {\n const res = await update(id, {\n ...rest,\n // compare permissions of stages and only submit them if at least one has\n // changed; this enables partial updates e.g. for users who don't have\n // permissions to see roles\n stages: rest.stages.map((stage) => {\n let hasUpdatedPermissions = true;\n const serverStage = currentWorkflow?.stages?.find(\n (serverStage) => serverStage.id === stage?.id\n );\n if (serverStage) {\n hasUpdatedPermissions =\n serverStage.permissions?.length !== stage.permissions?.length ||\n !serverStage.permissions?.every(\n (serverPermission) =>\n !!stage.permissions?.find(\n (permission) => permission.role === serverPermission.role\n )\n );\n }\n return {\n ...stage,\n permissions: hasUpdatedPermissions ? stage.permissions : undefined,\n } satisfies Stage;\n }),\n stageRequiredToPublishName,\n });\n\n if ('error' in res && isBaseQueryError(res.error) && res.error.name === 'ValidationError') {\n helpers.setErrors(formatValidationErrors(res.error));\n }\n } else {\n const res = await create({\n ...rest,\n stageRequiredToPublishName,\n });\n\n if ('error' in res && isBaseQueryError(res.error) && res.error.name === 'ValidationError') {\n helpers.setErrors(formatValidationErrors(res.error));\n } else if ('data' in res) {\n navigate(`../${res.data.id}`, { replace: true });\n }\n }\n } catch (error) {\n toggleNotification({\n type: 'danger',\n message: formatMessage({\n id: 'notification.error',\n defaultMessage: 'An error occurred',\n }),\n });\n }\n setSavePrompts({});\n };\n\n const handleConfirmDeleteDialog =\n (data: FormValues, helpers: Pick<FormHelpers, 'setErrors'>) => async () => {\n await submitForm(data, helpers);\n };\n\n const handleConfirmClose = () => {\n setSavePrompts({});\n };\n\n const handleSubmit: FormProps<FormValues>['onSubmit'] = async (data, helpers) => {\n const isContentTypeReassignment = data.contentTypes.some((contentType) =>\n contentTypesFromOtherWorkflows?.includes(contentType)\n );\n const hasDeletedServerStages =\n !isCreatingWorkflow &&\n !currentWorkflow?.stages.every((stage) =>\n data.stages.some((newStage) => newStage.id === stage.id)\n );\n\n if (meta && numberOfWorkflows && meta?.workflowCount > parseInt(numberOfWorkflows, 10)) {\n /**\n * If the current license has a limit, check if the total count of workflows\n * exceeds that limit and display the limits modal instead of sending the\n * update, because it would throw an API error.\n */\n setShowLimitModal('workflow');\n\n /**\n * If the current license has a limit, check if the total count of stages\n * exceeds that limit and display the limits modal instead of sending the\n * update, because it would throw an API error.\n */\n } else if (\n data.stages &&\n stagesPerWorkflow &&\n data.stages.length > parseInt(stagesPerWorkflow, 10)\n ) {\n setShowLimitModal('stage');\n } else if (hasDeletedServerStages || isContentTypeReassignment) {\n if (hasDeletedServerStages) {\n setSavePrompts((prev) => ({ ...prev, hasDeletedServerStages: true }));\n }\n\n if (isContentTypeReassignment) {\n setSavePrompts((prev) => ({ ...prev, hasReassignedContentTypes: true }));\n }\n } else {\n await submitForm(data, helpers);\n }\n };\n\n /**\n * If the current license has a limit:\n * check if the total count of workflows or stages exceeds that limit and display\n * the limits modal on page load. It can be closed by the user, but the\n * API will throw an error in case they try to create a new workflow or update the\n * stages.\n *\n * If the current license does not have a limit (e.g. offline license):\n * do nothing (for now). In case they are trying to create the 201st workflow/ stage\n * the API will throw an error.\n *\n */\n React.useEffect(() => {\n if (!isLoadingWorkflow && !isLicenseLoading) {\n if (meta && numberOfWorkflows && meta?.workflowCount > parseInt(numberOfWorkflows, 10)) {\n setShowLimitModal('workflow');\n } else if (\n currentWorkflow &&\n currentWorkflow.stages &&\n stagesPerWorkflow &&\n currentWorkflow.stages.length > parseInt(stagesPerWorkflow, 10)\n ) {\n setShowLimitModal('stage');\n }\n }\n }, [\n currentWorkflow,\n isLicenseLoading,\n isLoadingWorkflow,\n limits,\n meta,\n numberOfWorkflows,\n stagesPerWorkflow,\n ]);\n\n const initialValues: FormValues = React.useMemo(() => {\n if (isCreatingWorkflow || !currentWorkflow) {\n return {\n name: '',\n stages: [],\n contentTypes: [],\n stageRequiredToPublish: '',\n };\n } else {\n return {\n name: currentWorkflow.name,\n stages: addTmpKeysToStages(currentWorkflow.stages),\n contentTypes: currentWorkflow.contentTypes,\n stageRequiredToPublish: currentWorkflow.stageRequiredToPublish?.id.toString() ?? '',\n };\n }\n }, [currentWorkflow, isCreatingWorkflow]);\n\n if (isLoadingWorkflow) {\n return <Page.Loading />;\n }\n\n if (error) {\n return <Page.Error />;\n }\n\n return (\n <>\n <Layout.DragLayerRendered />\n\n <Form\n method={isCreatingWorkflow ? 'POST' : 'PUT'}\n initialValues={initialValues}\n validationSchema={WORKFLOW_SCHEMA}\n onSubmit={handleSubmit}\n >\n {({ modified, isSubmitting, values, setErrors }) => (\n <>\n <Layout.Header\n navigationAction={\n // The back link for mobile works differently; it is placed higher up in the DOM.\n <Box display={{ initial: 'none', medium: 'block' }}>\n <BackButton fallback=\"..\" />\n </Box>\n }\n primaryAction={\n canUpdate || canCreate ? (\n <Button\n startIcon={<Check />}\n type=\"submit\"\n disabled={!modified || isSubmitting || values.stages.length === 0}\n // if the confirm dialog is open the loading state is on\n // the confirm button already\n loading={!Boolean(Object.keys(savePrompts).length > 0) && isSubmitting}\n fullWidth\n >\n {formatMessage({\n id: 'global.save',\n defaultMessage: 'Save',\n })}\n </Button>\n ) : null\n }\n subtitle={formatMessage(\n {\n id: 'review-workflows.page.subtitle',\n defaultMessage: '{count, plural, one {# stage} other {# stages}}',\n },\n { count: currentWorkflow?.stages?.length ?? 0 }\n )}\n title={\n currentWorkflow?.name ||\n formatMessage({\n id: 'Settings.review-workflows.create.page.title',\n defaultMessage: 'Create Review Workflow',\n })\n }\n />\n <Layout.Root>\n <Flex alignItems=\"stretch\" direction=\"column\" gap={7}>\n <WorkflowAttributes canUpdate={canUpdate || canCreate} />\n <Stages\n canDelete={canDelete}\n canUpdate={canUpdate || canCreate}\n isCreating={isCreatingWorkflow}\n />\n </Flex>\n </Layout.Root>\n <Dialog.Root\n open={Object.keys(savePrompts).length > 0}\n onOpenChange={handleConfirmClose}\n >\n <ConfirmDialog onConfirm={handleConfirmDeleteDialog(values, { setErrors })}>\n <Flex direction=\"column\" gap={5}>\n {savePrompts.hasDeletedServerStages && (\n <Typography textAlign=\"center\" variant=\"omega\">\n {formatMessage({\n id: 'review-workflows.page.delete.confirm.stages.body',\n defaultMessage:\n 'All entries assigned to deleted stages will be moved to the previous stage.',\n })}\n </Typography>\n )}\n\n {savePrompts.hasReassignedContentTypes && (\n <Typography textAlign=\"center\" variant=\"omega\">\n {formatMessage(\n {\n id: 'review-workflows.page.delete.confirm.contentType.body',\n defaultMessage:\n '{count} {count, plural, one {content-type} other {content-types}} {count, plural, one {is} other {are}} already mapped to {count, plural, one {another workflow} other {other workflows}}. If you save changes, {count, plural, one {this} other {these}} {count, plural, one {content-type} other {{count} content-types}} will no more be mapped to the {count, plural, one {another workflow} other {other workflows}} and all corresponding information will be removed.',\n },\n {\n count:\n contentTypesFromOtherWorkflows?.filter((contentType) =>\n values.contentTypes.includes(contentType)\n ).length ?? 0,\n }\n )}\n </Typography>\n )}\n\n <Typography textAlign=\"center\" variant=\"omega\">\n {formatMessage({\n id: 'review-workflows.page.delete.confirm.confirm',\n defaultMessage: 'Are you sure you want to save?',\n })}\n </Typography>\n </Flex>\n </ConfirmDialog>\n </Dialog.Root>\n </>\n )}\n </Form>\n\n <LimitsModal.Root\n open={showLimitModal === 'workflow'}\n onOpenChange={() => setShowLimitModal(null)}\n >\n <LimitsModal.Title>\n {formatMessage({\n id: 'review-workflows.edit.page.workflows.limit.title',\n defaultMessage: 'You’ve reached the limit of workflows in your plan',\n })}\n </LimitsModal.Title>\n\n <LimitsModal.Body>\n {formatMessage({\n id: 'review-workflows.edit.page.workflows.limit.body',\n defaultMessage: 'Delete a workflow or contact Sales to enable more workflows.',\n })}\n </LimitsModal.Body>\n </LimitsModal.Root>\n\n <LimitsModal.Root\n open={showLimitModal === 'stage'}\n onOpenChange={() => setShowLimitModal(null)}\n >\n <LimitsModal.Title>\n {formatMessage({\n id: 'review-workflows.edit.page.stages.limit.title',\n defaultMessage: 'You have reached the limit of stages for this workflow in your plan',\n })}\n </LimitsModal.Title>\n\n <LimitsModal.Body>\n {formatMessage({\n id: 'review-workflows.edit.page.stages.limit.body',\n defaultMessage: 'Try deleting some stages or contact Sales to enable more stages.',\n })}\n </LimitsModal.Body>\n </LimitsModal.Root>\n </>\n );\n};\n\nconst addTmpKeysToStages = (data: Workflow['stages']) => {\n const keys = generateNKeysBetween(undefined, undefined, data.length);\n\n return data.map((datum, index) => ({\n ...datum,\n __temp_key__: keys[index],\n }));\n};\n\n/* -------------------------------------------------------------------------------------------------\n * ProtectedEditPage\n * -----------------------------------------------------------------------------------------------*/\n\nconst ProtectedEditPage = () => {\n const permissions = useTypedSelector((state) => {\n const {\n create = [],\n update = [],\n read = [],\n } = state.admin_app.permissions.settings?.['review-workflows'] ?? {};\n\n return [...create, ...update, ...read];\n });\n\n return (\n <Page.Protect permissions={permissions}>\n <EditPage />\n </Page.Protect>\n );\n};\n\nexport { ProtectedEditPage };\n"],"names":["WORKFLOW_SCHEMA","yup","object","contentTypes","array","of","string","name","max","id","defaultMessage","required","nullable","stages","shape","test","stageName","context","from","value","filter","stage","length","color","matches","permissions","role","number","strict","typeError","action","min","stageRequiredToPublish","EditPage","useParams","isCreatingWorkflow","formatMessage","useIntl","_unstableFormatValidationErrors","formatValidationErrors","useAPIErrorHandler","navigate","useNavigate","toggleNotification","useNotification","isLoading","isLoadingWorkflow","meta","workflows","error","update","create","useReviewWorkflows","useTypedSelector","state","admin_app","allowedActions","canDelete","canUpdate","canCreate","useRBAC","savePrompts","setSavePrompts","React","useState","getFeature","isLicenseLoading","useLicenseLimits","showLimitModal","setShowLimitModal","currentWorkflow","find","workflow","parseInt","contentTypesFromOtherWorkflows","flatMap","limits","numberOfWorkflows","CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME","stagesPerWorkflow","CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME","submitForm","data","helpers","rest","stageRequiredToPublishName","Number","__temp_key__","res","map","hasUpdatedPermissions","serverStage","every","serverPermission","permission","undefined","isBaseQueryError","setErrors","replace","type","message","handleConfirmDeleteDialog","handleConfirmClose","handleSubmit","isContentTypeReassignment","some","contentType","includes","hasDeletedServerStages","newStage","workflowCount","prev","hasReassignedContentTypes","useEffect","initialValues","useMemo","addTmpKeysToStages","toString","_jsx","Page","Loading","Error","_jsxs","_Fragment","Layout","Form","method","validationSchema","onSubmit","modified","isSubmitting","values","navigationAction","Box","display","initial","medium","BackButton","fallback","primaryAction","Button","startIcon","Check","disabled","loading","Boolean","Object","keys","fullWidth","subtitle","count","title","Flex","alignItems","direction","gap","WorkflowAttributes","Stages","isCreating","Dialog","Root","open","onOpenChange","ConfirmDialog","onConfirm","Typography","textAlign","variant","LimitsModal","Title","Body","generateNKeysBetween","datum","index","ProtectedEditPage","read","settings","Protect"],"mappings":"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"}
1
+ {"version":3,"file":"id.mjs","sources":["../../../../admin/src/routes/settings/id.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport {\n ConfirmDialog,\n BackButton,\n useNotification,\n useAPIErrorHandler,\n useRBAC,\n Form,\n Page,\n FormProps,\n FormHelpers,\n} from '@strapi/admin/strapi-admin';\nimport { useLicenseLimits } from '@strapi/admin/strapi-admin/ee';\nimport { Box, Button, Dialog, Flex, Typography } from '@strapi/design-system';\nimport { Check } from '@strapi/icons';\nimport { generateNKeysBetween } from 'fractional-indexing';\nimport { useIntl } from 'react-intl';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport * as yup from 'yup';\n\nimport { LimitsModal } from '../../components/LimitsModal';\nimport {\n CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME,\n CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME,\n} from '../../constants';\nimport { useTypedSelector } from '../../modules/hooks';\nimport { isBaseQueryError } from '../../utils/api';\n\nimport * as Layout from './components/Layout';\nimport { Stages, WorkflowStage } from './components/Stages';\nimport { WorkflowAttributes } from './components/WorkflowAttributes';\nimport { useReviewWorkflows } from './hooks/useReviewWorkflows';\n\nimport type {\n Stage,\n StagePermission,\n Workflow,\n} from '../../../../shared/contracts/review-workflows';\n\nconst havePermissionsChanged = (before?: StagePermission[], after?: StagePermission[]): boolean => {\n if (before?.length !== after?.length) {\n return true;\n }\n return !before?.every((beforePermission) =>\n after?.some((afterPermission) => afterPermission.role === beforePermission.role)\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * EditPage\n * -----------------------------------------------------------------------------------------------*/\n\nconst WORKFLOW_SCHEMA = yup.object({\n contentTypes: yup.array().of(yup.string()),\n name: yup\n .string()\n .max(255, {\n id: 'review-workflows.validation.name.max-length',\n defaultMessage: 'Name can not be longer than 255 characters',\n })\n .required()\n .nullable(),\n stages: yup\n .array()\n .of(\n yup.object().shape({\n name: yup\n .string()\n .nullable()\n .required({\n id: 'review-workflows.validation.stage.name',\n defaultMessage: 'Name is required',\n })\n .max(255, {\n id: 'review-workflows.validation.stage.max-length',\n defaultMessage: 'Name can not be longer than 255 characters',\n })\n .test(\n 'unique-name',\n {\n id: 'review-workflows.validation.stage.duplicate',\n defaultMessage: 'Stage name must be unique',\n },\n (stageName, context) => {\n // @ts-expect-error it does exist.\n const { stages } = context.from[1].value;\n\n return stages.filter((stage: Stage) => stage.name === stageName).length === 1;\n }\n ),\n color: yup\n .string()\n .nullable()\n .required({\n id: 'review-workflows.validation.stage.color',\n defaultMessage: 'Color is required',\n })\n .matches(/^#(?:[0-9a-fA-F]{3}){1,2}$/i),\n\n fromPermissions: yup\n .array(\n yup.object({\n role: yup\n .number()\n .strict()\n .typeError({\n id: 'review-workflows.validation.stage.permissions.role.number',\n defaultMessage: 'Role must be of type number',\n })\n .required(),\n action: yup.string().required({\n id: 'review-workflows.validation.stage.permissions.action.required',\n defaultMessage: 'Action is a required argument',\n }),\n })\n )\n .strict(),\n\n toPermissions: yup\n .array(\n yup.object({\n role: yup\n .number()\n .strict()\n .typeError({\n id: 'review-workflows.validation.stage.permissions.role.number',\n defaultMessage: 'Role must be of type number',\n })\n .required(),\n action: yup.string().required({\n id: 'review-workflows.validation.stage.permissions.action.required',\n defaultMessage: 'Action is a required argument',\n }),\n })\n )\n .strict(),\n })\n )\n .min(1),\n stageRequiredToPublish: yup.string().nullable(),\n});\n\nconst EditPage = () => {\n const { id = '' } = useParams<{ id: string }>();\n const isCreatingWorkflow = id === 'create';\n const { formatMessage } = useIntl();\n const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();\n const navigate = useNavigate();\n const { toggleNotification } = useNotification();\n const {\n isLoading: isLoadingWorkflow,\n meta,\n workflows,\n error,\n update,\n create,\n } = useReviewWorkflows();\n const permissions = useTypedSelector(\n (state) => state.admin_app.permissions['settings']?.['review-workflows']\n );\n const {\n allowedActions: { canDelete, canUpdate, canCreate },\n } = useRBAC(permissions);\n\n const [savePrompts, setSavePrompts] = React.useState<{\n hasDeletedServerStages?: boolean;\n hasReassignedContentTypes?: boolean;\n }>({});\n const { getFeature, isLoading: isLicenseLoading } = useLicenseLimits();\n const [showLimitModal, setShowLimitModal] = React.useState<'workflow' | 'stage' | null>(null);\n\n const currentWorkflow = workflows?.find((workflow) => workflow.id === parseInt(id, 10));\n const contentTypesFromOtherWorkflows = workflows\n ?.filter((workflow) => workflow.id !== parseInt(id, 10))\n .flatMap((workflow) => workflow.contentTypes);\n\n const limits = getFeature<string>('review-workflows');\n const numberOfWorkflows = limits?.[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME];\n const stagesPerWorkflow = limits?.[CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME];\n\n interface FormValues {\n name: string;\n stages: WorkflowStage[];\n contentTypes: string[];\n stageRequiredToPublish: string | null;\n }\n\n const submitForm = async (data: FormValues, helpers: Pick<FormHelpers, 'setErrors'>) => {\n try {\n const { stageRequiredToPublish, ...rest } = data;\n const stageRequiredToPublishName =\n stageRequiredToPublish === ''\n ? null\n : rest.stages.find(\n (stage) =>\n stage.id === Number(stageRequiredToPublish) ||\n stage.__temp_key__ === stageRequiredToPublish\n )?.name;\n\n if (!isCreatingWorkflow) {\n const res = await update(id, {\n ...rest,\n // compare permissions of stages and only submit them if at least one has\n // changed; this enables partial updates e.g. for users who don't have\n // permissions to see roles\n stages: rest.stages.map((stage) => {\n const serverStage = currentWorkflow?.stages?.find(\n (serverStage) => serverStage.id === stage?.id\n );\n\n const hasUpdatedPermissions =\n !serverStage ||\n havePermissionsChanged(serverStage.fromPermissions, stage.fromPermissions);\n const hasUpdatedToPermissions =\n !serverStage ||\n havePermissionsChanged(serverStage.toPermissions, stage.toPermissions);\n\n return {\n ...stage,\n fromPermissions: hasUpdatedPermissions ? stage.fromPermissions : undefined,\n toPermissions: hasUpdatedToPermissions ? stage.toPermissions : undefined,\n } satisfies Stage;\n }),\n stageRequiredToPublishName,\n });\n\n if ('error' in res && isBaseQueryError(res.error) && res.error.name === 'ValidationError') {\n helpers.setErrors(formatValidationErrors(res.error));\n }\n } else {\n const res = await create({\n ...rest,\n stageRequiredToPublishName,\n });\n\n if ('error' in res && isBaseQueryError(res.error) && res.error.name === 'ValidationError') {\n helpers.setErrors(formatValidationErrors(res.error));\n } else if ('data' in res) {\n navigate(`../${res.data.id}`, { replace: true });\n }\n }\n } catch (error) {\n toggleNotification({\n type: 'danger',\n message: formatMessage({\n id: 'notification.error',\n defaultMessage: 'An error occurred',\n }),\n });\n }\n setSavePrompts({});\n };\n\n const handleConfirmDeleteDialog =\n (data: FormValues, helpers: Pick<FormHelpers, 'setErrors'>) => async () => {\n await submitForm(data, helpers);\n };\n\n const handleConfirmClose = () => {\n setSavePrompts({});\n };\n\n const handleSubmit: FormProps<FormValues>['onSubmit'] = async (data, helpers) => {\n const isContentTypeReassignment = data.contentTypes.some((contentType) =>\n contentTypesFromOtherWorkflows?.includes(contentType)\n );\n const hasDeletedServerStages =\n !isCreatingWorkflow &&\n !currentWorkflow?.stages.every((stage) =>\n data.stages.some((newStage) => newStage.id === stage.id)\n );\n\n if (meta && numberOfWorkflows && meta?.workflowCount > parseInt(numberOfWorkflows, 10)) {\n /**\n * If the current license has a limit, check if the total count of workflows\n * exceeds that limit and display the limits modal instead of sending the\n * update, because it would throw an API error.\n */\n setShowLimitModal('workflow');\n\n /**\n * If the current license has a limit, check if the total count of stages\n * exceeds that limit and display the limits modal instead of sending the\n * update, because it would throw an API error.\n */\n } else if (\n data.stages &&\n stagesPerWorkflow &&\n data.stages.length > parseInt(stagesPerWorkflow, 10)\n ) {\n setShowLimitModal('stage');\n } else if (hasDeletedServerStages || isContentTypeReassignment) {\n if (hasDeletedServerStages) {\n setSavePrompts((prev) => ({ ...prev, hasDeletedServerStages: true }));\n }\n\n if (isContentTypeReassignment) {\n setSavePrompts((prev) => ({ ...prev, hasReassignedContentTypes: true }));\n }\n } else {\n await submitForm(data, helpers);\n }\n };\n\n /**\n * If the current license has a limit:\n * check if the total count of workflows or stages exceeds that limit and display\n * the limits modal on page load. It can be closed by the user, but the\n * API will throw an error in case they try to create a new workflow or update the\n * stages.\n *\n * If the current license does not have a limit (e.g. offline license):\n * do nothing (for now). In case they are trying to create the 201st workflow/ stage\n * the API will throw an error.\n *\n */\n React.useEffect(() => {\n if (!isLoadingWorkflow && !isLicenseLoading) {\n if (meta && numberOfWorkflows && meta?.workflowCount > parseInt(numberOfWorkflows, 10)) {\n setShowLimitModal('workflow');\n } else if (\n currentWorkflow &&\n currentWorkflow.stages &&\n stagesPerWorkflow &&\n currentWorkflow.stages.length > parseInt(stagesPerWorkflow, 10)\n ) {\n setShowLimitModal('stage');\n }\n }\n }, [\n currentWorkflow,\n isLicenseLoading,\n isLoadingWorkflow,\n limits,\n meta,\n numberOfWorkflows,\n stagesPerWorkflow,\n ]);\n\n const initialValues: FormValues = React.useMemo(() => {\n if (isCreatingWorkflow || !currentWorkflow) {\n return {\n name: '',\n stages: [],\n contentTypes: [],\n stageRequiredToPublish: '',\n };\n } else {\n return {\n name: currentWorkflow.name,\n stages: addTmpKeysToStages(currentWorkflow.stages),\n contentTypes: currentWorkflow.contentTypes,\n stageRequiredToPublish: currentWorkflow.stageRequiredToPublish?.id.toString() ?? '',\n };\n }\n }, [currentWorkflow, isCreatingWorkflow]);\n\n if (isLoadingWorkflow) {\n return <Page.Loading />;\n }\n\n if (error) {\n return <Page.Error />;\n }\n\n return (\n <>\n <Layout.DragLayerRendered />\n\n <Form\n method={isCreatingWorkflow ? 'POST' : 'PUT'}\n initialValues={initialValues}\n validationSchema={WORKFLOW_SCHEMA}\n onSubmit={handleSubmit}\n >\n {({ modified, isSubmitting, values, setErrors }) => (\n <>\n <Layout.Header\n navigationAction={\n // The back link for mobile works differently; it is placed higher up in the DOM.\n <Box display={{ initial: 'none', medium: 'block' }}>\n <BackButton fallback=\"..\" />\n </Box>\n }\n primaryAction={\n canUpdate || canCreate ? (\n <Button\n startIcon={<Check />}\n type=\"submit\"\n disabled={!modified || isSubmitting || values.stages.length === 0}\n // if the confirm dialog is open the loading state is on\n // the confirm button already\n loading={!Boolean(Object.keys(savePrompts).length > 0) && isSubmitting}\n fullWidth\n >\n {formatMessage({\n id: 'global.save',\n defaultMessage: 'Save',\n })}\n </Button>\n ) : null\n }\n subtitle={formatMessage(\n {\n id: 'review-workflows.page.subtitle',\n defaultMessage: '{count, plural, one {# stage} other {# stages}}',\n },\n { count: currentWorkflow?.stages?.length ?? 0 }\n )}\n title={\n currentWorkflow?.name ||\n formatMessage({\n id: 'Settings.review-workflows.create.page.title',\n defaultMessage: 'Create Review Workflow',\n })\n }\n />\n <Layout.Root>\n <Flex alignItems=\"stretch\" direction=\"column\" gap={7}>\n <WorkflowAttributes canUpdate={canUpdate || canCreate} />\n <Stages\n canDelete={canDelete}\n canUpdate={canUpdate || canCreate}\n isCreating={isCreatingWorkflow}\n />\n </Flex>\n </Layout.Root>\n <Dialog.Root\n open={Object.keys(savePrompts).length > 0}\n onOpenChange={handleConfirmClose}\n >\n <ConfirmDialog onConfirm={handleConfirmDeleteDialog(values, { setErrors })}>\n <Flex direction=\"column\" gap={5}>\n {savePrompts.hasDeletedServerStages && (\n <Typography textAlign=\"center\" variant=\"omega\">\n {formatMessage({\n id: 'review-workflows.page.delete.confirm.stages.body',\n defaultMessage:\n 'All entries assigned to deleted stages will be moved to the previous stage.',\n })}\n </Typography>\n )}\n\n {savePrompts.hasReassignedContentTypes && (\n <Typography textAlign=\"center\" variant=\"omega\">\n {formatMessage(\n {\n id: 'review-workflows.page.delete.confirm.contentType.body',\n defaultMessage:\n '{count} {count, plural, one {content-type} other {content-types}} {count, plural, one {is} other {are}} already mapped to {count, plural, one {another workflow} other {other workflows}}. If you save changes, {count, plural, one {this} other {these}} {count, plural, one {content-type} other {{count} content-types}} will no more be mapped to the {count, plural, one {another workflow} other {other workflows}} and all corresponding information will be removed.',\n },\n {\n count:\n contentTypesFromOtherWorkflows?.filter((contentType) =>\n values.contentTypes.includes(contentType)\n ).length ?? 0,\n }\n )}\n </Typography>\n )}\n\n <Typography textAlign=\"center\" variant=\"omega\">\n {formatMessage({\n id: 'review-workflows.page.delete.confirm.confirm',\n defaultMessage: 'Are you sure you want to save?',\n })}\n </Typography>\n </Flex>\n </ConfirmDialog>\n </Dialog.Root>\n </>\n )}\n </Form>\n\n <LimitsModal.Root\n open={showLimitModal === 'workflow'}\n onOpenChange={() => setShowLimitModal(null)}\n >\n <LimitsModal.Title>\n {formatMessage({\n id: 'review-workflows.edit.page.workflows.limit.title',\n defaultMessage: 'You’ve reached the limit of workflows in your plan',\n })}\n </LimitsModal.Title>\n\n <LimitsModal.Body>\n {formatMessage({\n id: 'review-workflows.edit.page.workflows.limit.body',\n defaultMessage: 'Delete a workflow or contact Sales to enable more workflows.',\n })}\n </LimitsModal.Body>\n </LimitsModal.Root>\n\n <LimitsModal.Root\n open={showLimitModal === 'stage'}\n onOpenChange={() => setShowLimitModal(null)}\n >\n <LimitsModal.Title>\n {formatMessage({\n id: 'review-workflows.edit.page.stages.limit.title',\n defaultMessage: 'You have reached the limit of stages for this workflow in your plan',\n })}\n </LimitsModal.Title>\n\n <LimitsModal.Body>\n {formatMessage({\n id: 'review-workflows.edit.page.stages.limit.body',\n defaultMessage: 'Try deleting some stages or contact Sales to enable more stages.',\n })}\n </LimitsModal.Body>\n </LimitsModal.Root>\n </>\n );\n};\n\nconst addTmpKeysToStages = (data: Workflow['stages']) => {\n const keys = generateNKeysBetween(undefined, undefined, data.length);\n\n return data.map((datum, index) => ({\n ...datum,\n __temp_key__: keys[index],\n }));\n};\n\n/* -------------------------------------------------------------------------------------------------\n * ProtectedEditPage\n * -----------------------------------------------------------------------------------------------*/\n\nconst ProtectedEditPage = () => {\n const permissions = useTypedSelector((state) => {\n const {\n create = [],\n update = [],\n read = [],\n } = state.admin_app.permissions.settings?.['review-workflows'] ?? {};\n\n return [...create, ...update, ...read];\n });\n\n return (\n <Page.Protect permissions={permissions}>\n <EditPage />\n </Page.Protect>\n );\n};\n\nexport { ProtectedEditPage };\n"],"names":["havePermissionsChanged","before","after","length","every","beforePermission","some","afterPermission","role","WORKFLOW_SCHEMA","yup","object","contentTypes","array","of","string","name","max","id","defaultMessage","required","nullable","stages","shape","test","stageName","context","from","value","filter","stage","color","matches","fromPermissions","number","strict","typeError","action","toPermissions","min","stageRequiredToPublish","EditPage","useParams","isCreatingWorkflow","formatMessage","useIntl","_unstableFormatValidationErrors","formatValidationErrors","useAPIErrorHandler","navigate","useNavigate","toggleNotification","useNotification","isLoading","isLoadingWorkflow","meta","workflows","error","update","create","useReviewWorkflows","permissions","useTypedSelector","state","admin_app","allowedActions","canDelete","canUpdate","canCreate","useRBAC","savePrompts","setSavePrompts","React","useState","getFeature","isLicenseLoading","useLicenseLimits","showLimitModal","setShowLimitModal","currentWorkflow","find","workflow","parseInt","contentTypesFromOtherWorkflows","flatMap","limits","numberOfWorkflows","CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME","stagesPerWorkflow","CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME","submitForm","data","helpers","rest","stageRequiredToPublishName","Number","__temp_key__","res","map","serverStage","hasUpdatedPermissions","hasUpdatedToPermissions","undefined","isBaseQueryError","setErrors","replace","type","message","handleConfirmDeleteDialog","handleConfirmClose","handleSubmit","isContentTypeReassignment","contentType","includes","hasDeletedServerStages","newStage","workflowCount","prev","hasReassignedContentTypes","useEffect","initialValues","useMemo","addTmpKeysToStages","toString","_jsx","Page","Loading","Error","_jsxs","_Fragment","Layout","Form","method","validationSchema","onSubmit","modified","isSubmitting","values","navigationAction","Box","display","initial","medium","BackButton","fallback","primaryAction","Button","startIcon","Check","disabled","loading","Boolean","Object","keys","fullWidth","subtitle","count","title","Flex","alignItems","direction","gap","WorkflowAttributes","Stages","isCreating","Dialog","Root","open","onOpenChange","ConfirmDialog","onConfirm","Typography","textAlign","variant","LimitsModal","Title","Body","generateNKeysBetween","datum","index","ProtectedEditPage","read","settings","Protect"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { Stage as IStage } from '../../../../../shared/contracts/review-workflows';
2
- interface WorkflowStage extends Pick<IStage, 'id' | 'name' | 'permissions' | 'color'> {
2
+ interface WorkflowStage extends Pick<IStage, 'id' | 'name' | 'fromPermissions' | 'toPermissions' | 'color'> {
3
3
  __temp_key__: string;
4
4
  }
5
5
  interface StagesProps {
@@ -99,6 +99,10 @@ var stages = {
99
99
  }, 'You should pass an id to the body of the put request.');
100
100
  const workflow = await workflowService.assertContentTypeBelongsToWorkflow(modelUID);
101
101
  workflowService.assertStageBelongsToWorkflow(stageId, workflow);
102
+ const canTransitionTo = await stagePermissions.canTransitionToStage(stageId);
103
+ if (!canTransitionTo) {
104
+ ctx.throw(403, 'Forbidden stage transition');
105
+ }
102
106
  const updatedEntity = await stagesService.updateEntity(entity, modelUID, stageId);
103
107
  ctx.body = {
104
108
  data: await sanitizeOutput(updatedEntity)
@@ -106,7 +110,7 @@ var stages = {
106
110
  },
107
111
  /**
108
112
  * List all the stages that are available for a user to transition an entity to.
109
- * If the user has permission to change the current stage of the entity every other stage in the workflow is returned
113
+ * Stages are filtered by both "from" permission on the current stage AND "to" permission on each target stage.
110
114
  * @async
111
115
  * @param {*} ctx
112
116
  * @param {string} ctx.params.model_uid - The model UID of the entity.
@@ -140,7 +144,17 @@ var stages = {
140
144
  const [workflowCount, workflowResult] = await Promise.all([
141
145
  workflowService.count(),
142
146
  workflowService.getAssignedWorkflow(modelUID, {
143
- populate: 'stages'
147
+ populate: {
148
+ stages: {
149
+ populate: {
150
+ permissions: {
151
+ populate: [
152
+ 'role'
153
+ ]
154
+ }
155
+ }
156
+ }
157
+ }
144
158
  })
145
159
  ]);
146
160
  const workflowStages = workflowResult ? workflowResult.stages : [];
@@ -155,7 +169,8 @@ var stages = {
155
169
  };
156
170
  return;
157
171
  }
158
- const data = workflowStages.filter((stage)=>stage.id !== entityStageId);
172
+ const otherStages = workflowStages.filter((stage)=>stage.id !== entityStageId);
173
+ const data = otherStages.filter((stage)=>stagePermissions.canTransitionToStageWithPermissions(stage));
159
174
  ctx.body = {
160
175
  data,
161
176
  meta
@@ -1 +1 @@
1
- {"version":3,"file":"stages.js","sources":["../../../server/src/controllers/stages.ts"],"sourcesContent":["import type { Context } from 'koa';\nimport type { Core } from '@strapi/types';\n\nimport { async, validate } from '@strapi/utils';\nimport { getService } from '../utils';\nimport { validateUpdateStageOnEntity, validateLocale } from '../validation/review-workflows';\nimport {\n STAGE_MODEL_UID,\n ENTITY_STAGE_ATTRIBUTE,\n STAGE_TRANSITION_UID,\n} from '../constants/workflows';\n\n/**\n *\n * @param { Core.Strapi } strapi - Strapi instance\n * @param userAbility\n * @return { (Stage) => SanitizedStage }\n */\nfunction sanitizeStage({ strapi }: { strapi: Core.Strapi }, userAbility: unknown) {\n const permissionChecker = strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility, model: STAGE_MODEL_UID });\n\n return (entity: unknown) => permissionChecker.sanitizeOutput(entity);\n}\n\nexport default {\n /**\n * List all stages\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async find(ctx: Context) {\n const { workflow_id: workflowId } = ctx.params;\n const { populate } = ctx.query;\n const stagesService = getService('stages');\n const sanitizer = sanitizeStage({ strapi }, ctx.state.userAbility);\n\n const stages = await stagesService.find({\n workflowId,\n populate,\n });\n\n ctx.body = {\n data: await async.map(stages, sanitizer),\n };\n },\n /**\n * Get one stage\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async findById(ctx: Context) {\n const { id, workflow_id: workflowId } = ctx.params;\n const { populate } = ctx.query;\n const stagesService = getService('stages');\n const sanitizer = sanitizeStage({ strapi }, ctx.state.userAbility);\n\n const stage = await stagesService.findById(id, {\n workflowId,\n populate,\n });\n\n ctx.body = {\n data: await sanitizer(stage),\n };\n },\n\n /**\n * Updates an entity's stage.\n * @async\n * @param {Object} ctx - The Koa context object.\n * @param {Object} ctx.params - An object containing the parameters from the request URL.\n * @param {string} ctx.params.model_uid - The model UID of the entity.\n * @param {string} ctx.params.id - The ID of the entity to update.\n * @param {Object} ctx.request.body.data - Optional data object containing the new stage ID for the entity.\n * @param {string} ctx.request.body.data.id - The ID of the new stage for the entity.\n * @throws {ApplicationError} If review workflows is not activated on the specified model UID.\n * @throws {ValidationError} If the `data` object in the request body fails to pass validation.\n * @returns {Promise<void>} A promise that resolves when the entity's stage has been updated.\n */\n async updateEntity(ctx: Context) {\n const stagesService = getService('stages');\n const stagePermissions = getService('stage-permissions');\n const workflowService = getService('workflows');\n\n const { model_uid: modelUID, id: documentId } = ctx.params;\n const { body, query = {} } = ctx.request;\n\n const { sanitizeOutput } = strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility: ctx.state.userAbility, model: modelUID });\n\n // Load entity\n const locale = await validateLocale(query?.locale);\n const entity = await strapi.documents(modelUID).findOne({\n documentId,\n // @ts-expect-error - locale should be also null in the doc service types\n locale,\n populate: [ENTITY_STAGE_ATTRIBUTE],\n });\n\n if (!entity) {\n ctx.throw(404, 'Entity not found');\n }\n\n // Validate if entity stage can be updated\n const canTransition = stagePermissions.can(\n STAGE_TRANSITION_UID,\n entity[ENTITY_STAGE_ATTRIBUTE]?.id\n );\n\n if (!canTransition) {\n ctx.throw(403, 'Forbidden stage transition');\n }\n\n const { id: stageId } = await validateUpdateStageOnEntity(\n { id: Number(body?.data?.id) },\n 'You should pass an id to the body of the put request.'\n );\n\n const workflow = await workflowService.assertContentTypeBelongsToWorkflow(modelUID);\n workflowService.assertStageBelongsToWorkflow(stageId, workflow);\n\n const updatedEntity = await stagesService.updateEntity(entity, modelUID, stageId);\n\n ctx.body = { data: await sanitizeOutput(updatedEntity) };\n },\n\n /**\n * List all the stages that are available for a user to transition an entity to.\n * If the user has permission to change the current stage of the entity every other stage in the workflow is returned\n * @async\n * @param {*} ctx\n * @param {string} ctx.params.model_uid - The model UID of the entity.\n * @param {string} ctx.params.id - The ID of the entity.\n * @throws {ApplicationError} If review workflows is not activated on the specified model UID.\n */\n async listAvailableStages(ctx: Context) {\n const stagePermissions = getService('stage-permissions');\n const workflowService = getService('workflows');\n\n const { model_uid: modelUID, id: documentId } = ctx.params;\n const { query = {} } = ctx.request;\n\n if (\n strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility: ctx.state.userAbility, model: modelUID })\n .cannot.read()\n ) {\n return ctx.forbidden();\n }\n\n // Load entity\n const locale = (await validateLocale(query?.locale)) ?? undefined;\n const entity = await strapi.documents(modelUID).findOne({\n documentId,\n locale,\n populate: [ENTITY_STAGE_ATTRIBUTE],\n });\n\n if (!entity) {\n ctx.throw(404, 'Entity not found');\n }\n\n const entityStageId = entity[ENTITY_STAGE_ATTRIBUTE]?.id;\n const canTransition = stagePermissions.can(STAGE_TRANSITION_UID, entityStageId);\n\n const [workflowCount, workflowResult] = await Promise.all([\n workflowService.count(),\n workflowService.getAssignedWorkflow(modelUID, {\n populate: 'stages',\n }),\n ]);\n\n const workflowStages = workflowResult ? workflowResult.stages : [];\n\n const meta = {\n stageCount: workflowStages.length,\n workflowCount,\n };\n\n if (!canTransition) {\n ctx.body = {\n data: [],\n meta,\n };\n\n return;\n }\n\n const data = workflowStages.filter((stage: any) => stage.id !== entityStageId);\n ctx.body = {\n data,\n meta,\n };\n },\n};\n"],"names":["sanitizeStage","strapi","userAbility","permissionChecker","plugin","service","create","model","STAGE_MODEL_UID","entity","sanitizeOutput","find","ctx","workflow_id","workflowId","params","populate","query","stagesService","getService","sanitizer","state","stages","body","data","async","map","findById","id","stage","updateEntity","stagePermissions","workflowService","model_uid","modelUID","documentId","request","locale","validateLocale","documents","findOne","ENTITY_STAGE_ATTRIBUTE","throw","canTransition","can","STAGE_TRANSITION_UID","stageId","validateUpdateStageOnEntity","Number","workflow","assertContentTypeBelongsToWorkflow","assertStageBelongsToWorkflow","updatedEntity","listAvailableStages","cannot","read","forbidden","undefined","entityStageId","workflowCount","workflowResult","Promise","all","count","getAssignedWorkflow","workflowStages","meta","stageCount","length","filter"],"mappings":"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"}
1
+ {"version":3,"file":"stages.js","sources":["../../../server/src/controllers/stages.ts"],"sourcesContent":["import type { Context } from 'koa';\nimport type { Core } from '@strapi/types';\n\nimport { async, validate } from '@strapi/utils';\nimport { getService } from '../utils';\nimport { validateUpdateStageOnEntity, validateLocale } from '../validation/review-workflows';\nimport {\n STAGE_MODEL_UID,\n ENTITY_STAGE_ATTRIBUTE,\n STAGE_TRANSITION_UID,\n} from '../constants/workflows';\n\n/**\n *\n * @param { Core.Strapi } strapi - Strapi instance\n * @param userAbility\n * @return { (Stage) => SanitizedStage }\n */\nfunction sanitizeStage({ strapi }: { strapi: Core.Strapi }, userAbility: unknown) {\n const permissionChecker = strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility, model: STAGE_MODEL_UID });\n\n return (entity: unknown) => permissionChecker.sanitizeOutput(entity);\n}\n\nexport default {\n /**\n * List all stages\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async find(ctx: Context) {\n const { workflow_id: workflowId } = ctx.params;\n const { populate } = ctx.query;\n const stagesService = getService('stages');\n const sanitizer = sanitizeStage({ strapi }, ctx.state.userAbility);\n\n const stages = await stagesService.find({\n workflowId,\n populate,\n });\n\n ctx.body = {\n data: await async.map(stages, sanitizer),\n };\n },\n /**\n * Get one stage\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async findById(ctx: Context) {\n const { id, workflow_id: workflowId } = ctx.params;\n const { populate } = ctx.query;\n const stagesService = getService('stages');\n const sanitizer = sanitizeStage({ strapi }, ctx.state.userAbility);\n\n const stage = await stagesService.findById(id, {\n workflowId,\n populate,\n });\n\n ctx.body = {\n data: await sanitizer(stage),\n };\n },\n\n /**\n * Updates an entity's stage.\n * @async\n * @param {Object} ctx - The Koa context object.\n * @param {Object} ctx.params - An object containing the parameters from the request URL.\n * @param {string} ctx.params.model_uid - The model UID of the entity.\n * @param {string} ctx.params.id - The ID of the entity to update.\n * @param {Object} ctx.request.body.data - Optional data object containing the new stage ID for the entity.\n * @param {string} ctx.request.body.data.id - The ID of the new stage for the entity.\n * @throws {ApplicationError} If review workflows is not activated on the specified model UID.\n * @throws {ValidationError} If the `data` object in the request body fails to pass validation.\n * @returns {Promise<void>} A promise that resolves when the entity's stage has been updated.\n */\n async updateEntity(ctx: Context) {\n const stagesService = getService('stages');\n const stagePermissions = getService('stage-permissions');\n const workflowService = getService('workflows');\n\n const { model_uid: modelUID, id: documentId } = ctx.params;\n const { body, query = {} } = ctx.request;\n\n const { sanitizeOutput } = strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility: ctx.state.userAbility, model: modelUID });\n\n // Load entity\n const locale = await validateLocale(query?.locale);\n const entity = await strapi.documents(modelUID).findOne({\n documentId,\n // @ts-expect-error - locale should be also null in the doc service types\n locale,\n populate: [ENTITY_STAGE_ATTRIBUTE],\n });\n\n if (!entity) {\n ctx.throw(404, 'Entity not found');\n }\n\n // Validate if entity stage can be updated\n const canTransition = stagePermissions.can(\n STAGE_TRANSITION_UID,\n entity[ENTITY_STAGE_ATTRIBUTE]?.id\n );\n\n if (!canTransition) {\n ctx.throw(403, 'Forbidden stage transition');\n }\n\n const { id: stageId } = await validateUpdateStageOnEntity(\n { id: Number(body?.data?.id) },\n 'You should pass an id to the body of the put request.'\n );\n\n const workflow = await workflowService.assertContentTypeBelongsToWorkflow(modelUID);\n workflowService.assertStageBelongsToWorkflow(stageId, workflow);\n\n const canTransitionTo = await stagePermissions.canTransitionToStage(stageId);\n if (!canTransitionTo) {\n ctx.throw(403, 'Forbidden stage transition');\n }\n\n const updatedEntity = await stagesService.updateEntity(entity, modelUID, stageId);\n\n ctx.body = { data: await sanitizeOutput(updatedEntity) };\n },\n\n /**\n * List all the stages that are available for a user to transition an entity to.\n * Stages are filtered by both \"from\" permission on the current stage AND \"to\" permission on each target stage.\n * @async\n * @param {*} ctx\n * @param {string} ctx.params.model_uid - The model UID of the entity.\n * @param {string} ctx.params.id - The ID of the entity.\n * @throws {ApplicationError} If review workflows is not activated on the specified model UID.\n */\n async listAvailableStages(ctx: Context) {\n const stagePermissions = getService('stage-permissions');\n const workflowService = getService('workflows');\n\n const { model_uid: modelUID, id: documentId } = ctx.params;\n const { query = {} } = ctx.request;\n\n if (\n strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility: ctx.state.userAbility, model: modelUID })\n .cannot.read()\n ) {\n return ctx.forbidden();\n }\n\n // Load entity\n const locale = (await validateLocale(query?.locale)) ?? undefined;\n const entity = await strapi.documents(modelUID).findOne({\n documentId,\n locale,\n populate: [ENTITY_STAGE_ATTRIBUTE],\n });\n\n if (!entity) {\n ctx.throw(404, 'Entity not found');\n }\n\n const entityStageId = entity[ENTITY_STAGE_ATTRIBUTE]?.id;\n const canTransition = stagePermissions.can(STAGE_TRANSITION_UID, entityStageId);\n\n const [workflowCount, workflowResult] = await Promise.all([\n workflowService.count(),\n workflowService.getAssignedWorkflow(modelUID, {\n populate: { stages: { populate: { permissions: { populate: ['role'] } } } },\n }),\n ]);\n\n const workflowStages = workflowResult ? workflowResult.stages : [];\n\n const meta = {\n stageCount: workflowStages.length,\n workflowCount,\n };\n\n if (!canTransition) {\n ctx.body = {\n data: [],\n meta,\n };\n\n return;\n }\n\n const otherStages = workflowStages.filter(\n (stage: { id: number; permissions?: unknown[] }) => stage.id !== entityStageId\n );\n\n const data = otherStages.filter((stage: { id: number; permissions?: unknown[] }) =>\n stagePermissions.canTransitionToStageWithPermissions(stage)\n );\n\n ctx.body = {\n data,\n meta,\n };\n },\n};\n"],"names":["sanitizeStage","strapi","userAbility","permissionChecker","plugin","service","create","model","STAGE_MODEL_UID","entity","sanitizeOutput","find","ctx","workflow_id","workflowId","params","populate","query","stagesService","getService","sanitizer","state","stages","body","data","async","map","findById","id","stage","updateEntity","stagePermissions","workflowService","model_uid","modelUID","documentId","request","locale","validateLocale","documents","findOne","ENTITY_STAGE_ATTRIBUTE","throw","canTransition","can","STAGE_TRANSITION_UID","stageId","validateUpdateStageOnEntity","Number","workflow","assertContentTypeBelongsToWorkflow","assertStageBelongsToWorkflow","canTransitionTo","canTransitionToStage","updatedEntity","listAvailableStages","cannot","read","forbidden","undefined","entityStageId","workflowCount","workflowResult","Promise","all","count","getAssignedWorkflow","permissions","workflowStages","meta","stageCount","length","otherStages","filter","canTransitionToStageWithPermissions"],"mappings":"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"}
@@ -97,6 +97,10 @@ var stages = {
97
97
  }, 'You should pass an id to the body of the put request.');
98
98
  const workflow = await workflowService.assertContentTypeBelongsToWorkflow(modelUID);
99
99
  workflowService.assertStageBelongsToWorkflow(stageId, workflow);
100
+ const canTransitionTo = await stagePermissions.canTransitionToStage(stageId);
101
+ if (!canTransitionTo) {
102
+ ctx.throw(403, 'Forbidden stage transition');
103
+ }
100
104
  const updatedEntity = await stagesService.updateEntity(entity, modelUID, stageId);
101
105
  ctx.body = {
102
106
  data: await sanitizeOutput(updatedEntity)
@@ -104,7 +108,7 @@ var stages = {
104
108
  },
105
109
  /**
106
110
  * List all the stages that are available for a user to transition an entity to.
107
- * If the user has permission to change the current stage of the entity every other stage in the workflow is returned
111
+ * Stages are filtered by both "from" permission on the current stage AND "to" permission on each target stage.
108
112
  * @async
109
113
  * @param {*} ctx
110
114
  * @param {string} ctx.params.model_uid - The model UID of the entity.
@@ -138,7 +142,17 @@ var stages = {
138
142
  const [workflowCount, workflowResult] = await Promise.all([
139
143
  workflowService.count(),
140
144
  workflowService.getAssignedWorkflow(modelUID, {
141
- populate: 'stages'
145
+ populate: {
146
+ stages: {
147
+ populate: {
148
+ permissions: {
149
+ populate: [
150
+ 'role'
151
+ ]
152
+ }
153
+ }
154
+ }
155
+ }
142
156
  })
143
157
  ]);
144
158
  const workflowStages = workflowResult ? workflowResult.stages : [];
@@ -153,7 +167,8 @@ var stages = {
153
167
  };
154
168
  return;
155
169
  }
156
- const data = workflowStages.filter((stage)=>stage.id !== entityStageId);
170
+ const otherStages = workflowStages.filter((stage)=>stage.id !== entityStageId);
171
+ const data = otherStages.filter((stage)=>stagePermissions.canTransitionToStageWithPermissions(stage));
157
172
  ctx.body = {
158
173
  data,
159
174
  meta
@@ -1 +1 @@
1
- {"version":3,"file":"stages.mjs","sources":["../../../server/src/controllers/stages.ts"],"sourcesContent":["import type { Context } from 'koa';\nimport type { Core } from '@strapi/types';\n\nimport { async, validate } from '@strapi/utils';\nimport { getService } from '../utils';\nimport { validateUpdateStageOnEntity, validateLocale } from '../validation/review-workflows';\nimport {\n STAGE_MODEL_UID,\n ENTITY_STAGE_ATTRIBUTE,\n STAGE_TRANSITION_UID,\n} from '../constants/workflows';\n\n/**\n *\n * @param { Core.Strapi } strapi - Strapi instance\n * @param userAbility\n * @return { (Stage) => SanitizedStage }\n */\nfunction sanitizeStage({ strapi }: { strapi: Core.Strapi }, userAbility: unknown) {\n const permissionChecker = strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility, model: STAGE_MODEL_UID });\n\n return (entity: unknown) => permissionChecker.sanitizeOutput(entity);\n}\n\nexport default {\n /**\n * List all stages\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async find(ctx: Context) {\n const { workflow_id: workflowId } = ctx.params;\n const { populate } = ctx.query;\n const stagesService = getService('stages');\n const sanitizer = sanitizeStage({ strapi }, ctx.state.userAbility);\n\n const stages = await stagesService.find({\n workflowId,\n populate,\n });\n\n ctx.body = {\n data: await async.map(stages, sanitizer),\n };\n },\n /**\n * Get one stage\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async findById(ctx: Context) {\n const { id, workflow_id: workflowId } = ctx.params;\n const { populate } = ctx.query;\n const stagesService = getService('stages');\n const sanitizer = sanitizeStage({ strapi }, ctx.state.userAbility);\n\n const stage = await stagesService.findById(id, {\n workflowId,\n populate,\n });\n\n ctx.body = {\n data: await sanitizer(stage),\n };\n },\n\n /**\n * Updates an entity's stage.\n * @async\n * @param {Object} ctx - The Koa context object.\n * @param {Object} ctx.params - An object containing the parameters from the request URL.\n * @param {string} ctx.params.model_uid - The model UID of the entity.\n * @param {string} ctx.params.id - The ID of the entity to update.\n * @param {Object} ctx.request.body.data - Optional data object containing the new stage ID for the entity.\n * @param {string} ctx.request.body.data.id - The ID of the new stage for the entity.\n * @throws {ApplicationError} If review workflows is not activated on the specified model UID.\n * @throws {ValidationError} If the `data` object in the request body fails to pass validation.\n * @returns {Promise<void>} A promise that resolves when the entity's stage has been updated.\n */\n async updateEntity(ctx: Context) {\n const stagesService = getService('stages');\n const stagePermissions = getService('stage-permissions');\n const workflowService = getService('workflows');\n\n const { model_uid: modelUID, id: documentId } = ctx.params;\n const { body, query = {} } = ctx.request;\n\n const { sanitizeOutput } = strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility: ctx.state.userAbility, model: modelUID });\n\n // Load entity\n const locale = await validateLocale(query?.locale);\n const entity = await strapi.documents(modelUID).findOne({\n documentId,\n // @ts-expect-error - locale should be also null in the doc service types\n locale,\n populate: [ENTITY_STAGE_ATTRIBUTE],\n });\n\n if (!entity) {\n ctx.throw(404, 'Entity not found');\n }\n\n // Validate if entity stage can be updated\n const canTransition = stagePermissions.can(\n STAGE_TRANSITION_UID,\n entity[ENTITY_STAGE_ATTRIBUTE]?.id\n );\n\n if (!canTransition) {\n ctx.throw(403, 'Forbidden stage transition');\n }\n\n const { id: stageId } = await validateUpdateStageOnEntity(\n { id: Number(body?.data?.id) },\n 'You should pass an id to the body of the put request.'\n );\n\n const workflow = await workflowService.assertContentTypeBelongsToWorkflow(modelUID);\n workflowService.assertStageBelongsToWorkflow(stageId, workflow);\n\n const updatedEntity = await stagesService.updateEntity(entity, modelUID, stageId);\n\n ctx.body = { data: await sanitizeOutput(updatedEntity) };\n },\n\n /**\n * List all the stages that are available for a user to transition an entity to.\n * If the user has permission to change the current stage of the entity every other stage in the workflow is returned\n * @async\n * @param {*} ctx\n * @param {string} ctx.params.model_uid - The model UID of the entity.\n * @param {string} ctx.params.id - The ID of the entity.\n * @throws {ApplicationError} If review workflows is not activated on the specified model UID.\n */\n async listAvailableStages(ctx: Context) {\n const stagePermissions = getService('stage-permissions');\n const workflowService = getService('workflows');\n\n const { model_uid: modelUID, id: documentId } = ctx.params;\n const { query = {} } = ctx.request;\n\n if (\n strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility: ctx.state.userAbility, model: modelUID })\n .cannot.read()\n ) {\n return ctx.forbidden();\n }\n\n // Load entity\n const locale = (await validateLocale(query?.locale)) ?? undefined;\n const entity = await strapi.documents(modelUID).findOne({\n documentId,\n locale,\n populate: [ENTITY_STAGE_ATTRIBUTE],\n });\n\n if (!entity) {\n ctx.throw(404, 'Entity not found');\n }\n\n const entityStageId = entity[ENTITY_STAGE_ATTRIBUTE]?.id;\n const canTransition = stagePermissions.can(STAGE_TRANSITION_UID, entityStageId);\n\n const [workflowCount, workflowResult] = await Promise.all([\n workflowService.count(),\n workflowService.getAssignedWorkflow(modelUID, {\n populate: 'stages',\n }),\n ]);\n\n const workflowStages = workflowResult ? workflowResult.stages : [];\n\n const meta = {\n stageCount: workflowStages.length,\n workflowCount,\n };\n\n if (!canTransition) {\n ctx.body = {\n data: [],\n meta,\n };\n\n return;\n }\n\n const data = workflowStages.filter((stage: any) => stage.id !== entityStageId);\n ctx.body = {\n data,\n meta,\n };\n },\n};\n"],"names":["sanitizeStage","strapi","userAbility","permissionChecker","plugin","service","create","model","STAGE_MODEL_UID","entity","sanitizeOutput","find","ctx","workflow_id","workflowId","params","populate","query","stagesService","getService","sanitizer","state","stages","body","data","async","map","findById","id","stage","updateEntity","stagePermissions","workflowService","model_uid","modelUID","documentId","request","locale","validateLocale","documents","findOne","ENTITY_STAGE_ATTRIBUTE","throw","canTransition","can","STAGE_TRANSITION_UID","stageId","validateUpdateStageOnEntity","Number","workflow","assertContentTypeBelongsToWorkflow","assertStageBelongsToWorkflow","updatedEntity","listAvailableStages","cannot","read","forbidden","undefined","entityStageId","workflowCount","workflowResult","Promise","all","count","getAssignedWorkflow","workflowStages","meta","stageCount","length","filter"],"mappings":"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"}
1
+ {"version":3,"file":"stages.mjs","sources":["../../../server/src/controllers/stages.ts"],"sourcesContent":["import type { Context } from 'koa';\nimport type { Core } from '@strapi/types';\n\nimport { async, validate } from '@strapi/utils';\nimport { getService } from '../utils';\nimport { validateUpdateStageOnEntity, validateLocale } from '../validation/review-workflows';\nimport {\n STAGE_MODEL_UID,\n ENTITY_STAGE_ATTRIBUTE,\n STAGE_TRANSITION_UID,\n} from '../constants/workflows';\n\n/**\n *\n * @param { Core.Strapi } strapi - Strapi instance\n * @param userAbility\n * @return { (Stage) => SanitizedStage }\n */\nfunction sanitizeStage({ strapi }: { strapi: Core.Strapi }, userAbility: unknown) {\n const permissionChecker = strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility, model: STAGE_MODEL_UID });\n\n return (entity: unknown) => permissionChecker.sanitizeOutput(entity);\n}\n\nexport default {\n /**\n * List all stages\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async find(ctx: Context) {\n const { workflow_id: workflowId } = ctx.params;\n const { populate } = ctx.query;\n const stagesService = getService('stages');\n const sanitizer = sanitizeStage({ strapi }, ctx.state.userAbility);\n\n const stages = await stagesService.find({\n workflowId,\n populate,\n });\n\n ctx.body = {\n data: await async.map(stages, sanitizer),\n };\n },\n /**\n * Get one stage\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async findById(ctx: Context) {\n const { id, workflow_id: workflowId } = ctx.params;\n const { populate } = ctx.query;\n const stagesService = getService('stages');\n const sanitizer = sanitizeStage({ strapi }, ctx.state.userAbility);\n\n const stage = await stagesService.findById(id, {\n workflowId,\n populate,\n });\n\n ctx.body = {\n data: await sanitizer(stage),\n };\n },\n\n /**\n * Updates an entity's stage.\n * @async\n * @param {Object} ctx - The Koa context object.\n * @param {Object} ctx.params - An object containing the parameters from the request URL.\n * @param {string} ctx.params.model_uid - The model UID of the entity.\n * @param {string} ctx.params.id - The ID of the entity to update.\n * @param {Object} ctx.request.body.data - Optional data object containing the new stage ID for the entity.\n * @param {string} ctx.request.body.data.id - The ID of the new stage for the entity.\n * @throws {ApplicationError} If review workflows is not activated on the specified model UID.\n * @throws {ValidationError} If the `data` object in the request body fails to pass validation.\n * @returns {Promise<void>} A promise that resolves when the entity's stage has been updated.\n */\n async updateEntity(ctx: Context) {\n const stagesService = getService('stages');\n const stagePermissions = getService('stage-permissions');\n const workflowService = getService('workflows');\n\n const { model_uid: modelUID, id: documentId } = ctx.params;\n const { body, query = {} } = ctx.request;\n\n const { sanitizeOutput } = strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility: ctx.state.userAbility, model: modelUID });\n\n // Load entity\n const locale = await validateLocale(query?.locale);\n const entity = await strapi.documents(modelUID).findOne({\n documentId,\n // @ts-expect-error - locale should be also null in the doc service types\n locale,\n populate: [ENTITY_STAGE_ATTRIBUTE],\n });\n\n if (!entity) {\n ctx.throw(404, 'Entity not found');\n }\n\n // Validate if entity stage can be updated\n const canTransition = stagePermissions.can(\n STAGE_TRANSITION_UID,\n entity[ENTITY_STAGE_ATTRIBUTE]?.id\n );\n\n if (!canTransition) {\n ctx.throw(403, 'Forbidden stage transition');\n }\n\n const { id: stageId } = await validateUpdateStageOnEntity(\n { id: Number(body?.data?.id) },\n 'You should pass an id to the body of the put request.'\n );\n\n const workflow = await workflowService.assertContentTypeBelongsToWorkflow(modelUID);\n workflowService.assertStageBelongsToWorkflow(stageId, workflow);\n\n const canTransitionTo = await stagePermissions.canTransitionToStage(stageId);\n if (!canTransitionTo) {\n ctx.throw(403, 'Forbidden stage transition');\n }\n\n const updatedEntity = await stagesService.updateEntity(entity, modelUID, stageId);\n\n ctx.body = { data: await sanitizeOutput(updatedEntity) };\n },\n\n /**\n * List all the stages that are available for a user to transition an entity to.\n * Stages are filtered by both \"from\" permission on the current stage AND \"to\" permission on each target stage.\n * @async\n * @param {*} ctx\n * @param {string} ctx.params.model_uid - The model UID of the entity.\n * @param {string} ctx.params.id - The ID of the entity.\n * @throws {ApplicationError} If review workflows is not activated on the specified model UID.\n */\n async listAvailableStages(ctx: Context) {\n const stagePermissions = getService('stage-permissions');\n const workflowService = getService('workflows');\n\n const { model_uid: modelUID, id: documentId } = ctx.params;\n const { query = {} } = ctx.request;\n\n if (\n strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility: ctx.state.userAbility, model: modelUID })\n .cannot.read()\n ) {\n return ctx.forbidden();\n }\n\n // Load entity\n const locale = (await validateLocale(query?.locale)) ?? undefined;\n const entity = await strapi.documents(modelUID).findOne({\n documentId,\n locale,\n populate: [ENTITY_STAGE_ATTRIBUTE],\n });\n\n if (!entity) {\n ctx.throw(404, 'Entity not found');\n }\n\n const entityStageId = entity[ENTITY_STAGE_ATTRIBUTE]?.id;\n const canTransition = stagePermissions.can(STAGE_TRANSITION_UID, entityStageId);\n\n const [workflowCount, workflowResult] = await Promise.all([\n workflowService.count(),\n workflowService.getAssignedWorkflow(modelUID, {\n populate: { stages: { populate: { permissions: { populate: ['role'] } } } },\n }),\n ]);\n\n const workflowStages = workflowResult ? workflowResult.stages : [];\n\n const meta = {\n stageCount: workflowStages.length,\n workflowCount,\n };\n\n if (!canTransition) {\n ctx.body = {\n data: [],\n meta,\n };\n\n return;\n }\n\n const otherStages = workflowStages.filter(\n (stage: { id: number; permissions?: unknown[] }) => stage.id !== entityStageId\n );\n\n const data = otherStages.filter((stage: { id: number; permissions?: unknown[] }) =>\n stagePermissions.canTransitionToStageWithPermissions(stage)\n );\n\n ctx.body = {\n data,\n meta,\n };\n },\n};\n"],"names":["sanitizeStage","strapi","userAbility","permissionChecker","plugin","service","create","model","STAGE_MODEL_UID","entity","sanitizeOutput","find","ctx","workflow_id","workflowId","params","populate","query","stagesService","getService","sanitizer","state","stages","body","data","async","map","findById","id","stage","updateEntity","stagePermissions","workflowService","model_uid","modelUID","documentId","request","locale","validateLocale","documents","findOne","ENTITY_STAGE_ATTRIBUTE","throw","canTransition","can","STAGE_TRANSITION_UID","stageId","validateUpdateStageOnEntity","Number","workflow","assertContentTypeBelongsToWorkflow","assertStageBelongsToWorkflow","canTransitionTo","canTransitionToStage","updatedEntity","listAvailableStages","cannot","read","forbidden","undefined","entityStageId","workflowCount","workflowResult","Promise","all","count","getAssignedWorkflow","permissions","workflowStages","meta","stageCount","length","otherStages","filter","canTransitionToStageWithPermissions"],"mappings":"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"}
@@ -17,16 +17,23 @@ var workflows$1 = require('../constants/workflows.js');
17
17
  model: workflows$1.WORKFLOW_MODEL_UID
18
18
  });
19
19
  }
20
- /**
21
- * Transforms workflow to an admin UI format.
22
- * Some attributes (like permissions) are presented in a different format in the admin UI.
23
- * @param {Workflow} workflow
24
- */ function formatWorkflowToAdmin(workflow) {
20
+ function formatWorkflowToAdmin(workflow) {
25
21
  if (!workflow) return;
26
22
  if (!workflow.stages) return workflow;
27
- // Transform permissions roles to be the id string instead of an object
28
- const transformPermissions = fp.map(fp.update('role', fp.property('id')));
29
- const transformStages = fp.map(fp.update('permissions', transformPermissions));
23
+ const transformRoleToId = ({ actionParameters: _, role, ...rest })=>({
24
+ ...rest,
25
+ role: typeof role === 'object' ? role.id : role
26
+ });
27
+ const transformStages = fp.map((stage)=>{
28
+ const { permissions: allPermissions = [], ...rest } = stage;
29
+ const fromPermissions = allPermissions.filter((p)=>p.actionParameters?.from).map(transformRoleToId);
30
+ const toPermissions = allPermissions.filter((p)=>p.actionParameters?.to).map(transformRoleToId);
31
+ return {
32
+ ...rest,
33
+ fromPermissions,
34
+ toPermissions
35
+ };
36
+ });
30
37
  return fp.update('stages', transformStages, workflow);
31
38
  }
32
39
  var workflows = {
@@ -1 +1 @@
1
- {"version":3,"file":"workflows.js","sources":["../../../server/src/controllers/workflows.ts"],"sourcesContent":["import type { Context } from 'koa';\nimport { update, map, property } from 'lodash/fp';\n\nimport type { Core } from '@strapi/types';\nimport { async } from '@strapi/utils';\n\nimport { getService } from '../utils';\nimport { validateWorkflowCreate, validateWorkflowUpdate } from '../validation/review-workflows';\nimport { WORKFLOW_MODEL_UID, WORKFLOW_POPULATE } from '../constants/workflows';\n\n/**\n *\n * @param { Core.Strapi } strapi - Strapi instance\n * @param userAbility\n * @return { PermissionChecker }\n */\nfunction getWorkflowsPermissionChecker({ strapi }: { strapi: Core.Strapi }, userAbility: unknown) {\n return strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility, model: WORKFLOW_MODEL_UID });\n}\n\n/**\n * Transforms workflow to an admin UI format.\n * Some attributes (like permissions) are presented in a different format in the admin UI.\n * @param {Workflow} workflow\n */\nfunction formatWorkflowToAdmin(workflow: any) {\n if (!workflow) return;\n if (!workflow.stages) return workflow;\n\n // Transform permissions roles to be the id string instead of an object\n const transformPermissions = map(update('role', property('id')));\n const transformStages = map(update('permissions', transformPermissions));\n return update('stages', transformStages, workflow);\n}\n\nexport default {\n /**\n * Create a new workflow\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async create(ctx: Context) {\n const { body, query } = ctx.request;\n const { sanitizeCreateInput, sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(\n { strapi },\n ctx.state.userAbility\n );\n const { populate } = await sanitizedQuery.create(query);\n\n const workflowBody = await validateWorkflowCreate(body.data);\n\n const workflowService = getService('workflows');\n const createdWorkflow = await workflowService\n .create({\n data: await sanitizeCreateInput(workflowBody),\n populate,\n })\n .then(formatWorkflowToAdmin);\n\n ctx.created({\n data: await sanitizeOutput(createdWorkflow),\n });\n },\n\n /**\n * Update a workflow\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async update(ctx: Context) {\n const { id } = ctx.params;\n const { body, query } = ctx.request;\n const workflowService = getService('workflows');\n const { sanitizeUpdateInput, sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(\n { strapi },\n ctx.state.userAbility\n );\n const { populate } = await sanitizedQuery.update(query);\n const workflowBody = await validateWorkflowUpdate(body.data);\n\n // Find if workflow exists\n const workflow = await workflowService.findById(id, { populate: WORKFLOW_POPULATE });\n if (!workflow) {\n return ctx.notFound();\n }\n\n // Sanitize input data\n const getPermittedFieldToUpdate = sanitizeUpdateInput(workflow);\n const dataToUpdate = await getPermittedFieldToUpdate(workflowBody);\n\n // Update workflow\n const updatedWorkflow = await workflowService\n .update(workflow, {\n data: dataToUpdate,\n populate,\n })\n .then(formatWorkflowToAdmin);\n\n // Send sanitized response\n ctx.body = {\n data: await sanitizeOutput(updatedWorkflow),\n };\n },\n\n /**\n * Delete a workflow\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async delete(ctx: Context) {\n const { id } = ctx.params;\n const { query } = ctx.request;\n const workflowService = getService('workflows');\n const { sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(\n { strapi },\n ctx.state.userAbility\n );\n const { populate } = await sanitizedQuery.delete(query);\n\n const workflow = await workflowService.findById(id, { populate: WORKFLOW_POPULATE });\n if (!workflow) {\n return ctx.notFound(\"Workflow doesn't exist\");\n }\n\n const deletedWorkflow = await workflowService\n .delete(workflow, { populate })\n .then(formatWorkflowToAdmin);\n\n ctx.body = {\n data: await sanitizeOutput(deletedWorkflow),\n };\n },\n\n /**\n * List all workflows\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async find(ctx: Context) {\n const { query } = ctx.request;\n const workflowService = getService('workflows');\n const { sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(\n { strapi },\n ctx.state.userAbility\n );\n const { populate, filters, sort } = await sanitizedQuery.read(query);\n\n const [workflows, workflowCount] = await Promise.all([\n workflowService.find({ populate, filters, sort }).then(map(formatWorkflowToAdmin)),\n workflowService.count(),\n ]);\n\n ctx.body = {\n data: await async.map(workflows, sanitizeOutput),\n meta: {\n workflowCount,\n },\n };\n },\n};\n"],"names":["getWorkflowsPermissionChecker","strapi","userAbility","plugin","service","create","model","WORKFLOW_MODEL_UID","formatWorkflowToAdmin","workflow","stages","transformPermissions","map","update","property","transformStages","ctx","body","query","request","sanitizeCreateInput","sanitizeOutput","sanitizedQuery","state","populate","workflowBody","validateWorkflowCreate","data","workflowService","getService","createdWorkflow","then","created","id","params","sanitizeUpdateInput","validateWorkflowUpdate","findById","WORKFLOW_POPULATE","notFound","getPermittedFieldToUpdate","dataToUpdate","updatedWorkflow","delete","deletedWorkflow","find","filters","sort","read","workflows","workflowCount","Promise","all","count","async","meta"],"mappings":"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"}
1
+ {"version":3,"file":"workflows.js","sources":["../../../server/src/controllers/workflows.ts"],"sourcesContent":["import type { Context } from 'koa';\nimport { update, map, property } from 'lodash/fp';\n\nimport type { Core } from '@strapi/types';\nimport { async } from '@strapi/utils';\n\nimport type { StagePermission } from '../../../shared/contracts/review-workflows';\nimport { getService } from '../utils';\nimport { validateWorkflowCreate, validateWorkflowUpdate } from '../validation/review-workflows';\nimport { WORKFLOW_MODEL_UID, WORKFLOW_POPULATE } from '../constants/workflows';\n\n/**\n *\n * @param { Core.Strapi } strapi - Strapi instance\n * @param userAbility\n * @return { PermissionChecker }\n */\nfunction getWorkflowsPermissionChecker({ strapi }: { strapi: Core.Strapi }, userAbility: unknown) {\n return strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility, model: WORKFLOW_MODEL_UID });\n}\n\n/**\n * Transforms workflow to an admin UI format.\n * Some attributes (like permissions) are presented in a different format in the admin UI.\n *\n * Permissions stored on each stage are split into two arrays:\n * - `fromPermissions`: entries with `actionParameters.from` (controls who can move\n * content out of the stage)\n * - `toPermissions`: entries with `actionParameters.to` (controls who can move\n * content into the stage)\n *\n * Role objects are also flattened to their numeric id.\n */\n\n/**\n * Shape of a permission row as returned by the DB populate.\n */\ninterface PopulatedPermission {\n action: string;\n subject?: string | null;\n role: number | { id: number };\n actionParameters?: { from?: number; to?: number };\n}\n\ninterface PopulatedStage {\n permissions?: PopulatedPermission[];\n [key: string]: unknown;\n}\n\nfunction formatWorkflowToAdmin(workflow: { stages?: PopulatedStage[]; [key: string]: unknown }) {\n if (!workflow) return;\n if (!workflow.stages) return workflow;\n\n const transformRoleToId = ({\n actionParameters: _,\n role,\n ...rest\n }: PopulatedPermission): StagePermission => ({\n ...rest,\n role: typeof role === 'object' ? role.id : role,\n });\n\n const transformStages = map((stage: PopulatedStage) => {\n const { permissions: allPermissions = [], ...rest } = stage;\n\n const fromPermissions = allPermissions\n .filter((p) => p.actionParameters?.from)\n .map(transformRoleToId);\n\n const toPermissions = allPermissions\n .filter((p) => p.actionParameters?.to)\n .map(transformRoleToId);\n\n return {\n ...rest,\n fromPermissions,\n toPermissions,\n };\n });\n\n return update('stages', transformStages, workflow);\n}\n\nexport default {\n /**\n * Create a new workflow\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async create(ctx: Context) {\n const { body, query } = ctx.request;\n const { sanitizeCreateInput, sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(\n { strapi },\n ctx.state.userAbility\n );\n const { populate } = await sanitizedQuery.create(query);\n\n const workflowBody = await validateWorkflowCreate(body.data);\n\n const workflowService = getService('workflows');\n const createdWorkflow = await workflowService\n .create({\n data: await sanitizeCreateInput(workflowBody),\n populate,\n })\n .then(formatWorkflowToAdmin);\n\n ctx.created({\n data: await sanitizeOutput(createdWorkflow),\n });\n },\n\n /**\n * Update a workflow\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async update(ctx: Context) {\n const { id } = ctx.params;\n const { body, query } = ctx.request;\n const workflowService = getService('workflows');\n const { sanitizeUpdateInput, sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(\n { strapi },\n ctx.state.userAbility\n );\n const { populate } = await sanitizedQuery.update(query);\n const workflowBody = await validateWorkflowUpdate(body.data);\n\n // Find if workflow exists\n const workflow = await workflowService.findById(id, { populate: WORKFLOW_POPULATE });\n if (!workflow) {\n return ctx.notFound();\n }\n\n // Sanitize input data\n const getPermittedFieldToUpdate = sanitizeUpdateInput(workflow);\n const dataToUpdate = await getPermittedFieldToUpdate(workflowBody);\n\n // Update workflow\n const updatedWorkflow = await workflowService\n .update(workflow, {\n data: dataToUpdate,\n populate,\n })\n .then(formatWorkflowToAdmin);\n\n // Send sanitized response\n ctx.body = {\n data: await sanitizeOutput(updatedWorkflow),\n };\n },\n\n /**\n * Delete a workflow\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async delete(ctx: Context) {\n const { id } = ctx.params;\n const { query } = ctx.request;\n const workflowService = getService('workflows');\n const { sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(\n { strapi },\n ctx.state.userAbility\n );\n const { populate } = await sanitizedQuery.delete(query);\n\n const workflow = await workflowService.findById(id, { populate: WORKFLOW_POPULATE });\n if (!workflow) {\n return ctx.notFound(\"Workflow doesn't exist\");\n }\n\n const deletedWorkflow = await workflowService\n .delete(workflow, { populate })\n .then(formatWorkflowToAdmin);\n\n ctx.body = {\n data: await sanitizeOutput(deletedWorkflow),\n };\n },\n\n /**\n * List all workflows\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async find(ctx: Context) {\n const { query } = ctx.request;\n const workflowService = getService('workflows');\n const { sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(\n { strapi },\n ctx.state.userAbility\n );\n const { populate, filters, sort } = await sanitizedQuery.read(query);\n\n const [workflows, workflowCount] = await Promise.all([\n workflowService.find({ populate, filters, sort }).then(map(formatWorkflowToAdmin)),\n workflowService.count(),\n ]);\n\n ctx.body = {\n data: await async.map(workflows, sanitizeOutput),\n meta: {\n workflowCount,\n },\n };\n },\n};\n"],"names":["getWorkflowsPermissionChecker","strapi","userAbility","plugin","service","create","model","WORKFLOW_MODEL_UID","formatWorkflowToAdmin","workflow","stages","transformRoleToId","actionParameters","_","role","rest","id","transformStages","map","stage","permissions","allPermissions","fromPermissions","filter","p","from","toPermissions","to","update","ctx","body","query","request","sanitizeCreateInput","sanitizeOutput","sanitizedQuery","state","populate","workflowBody","validateWorkflowCreate","data","workflowService","getService","createdWorkflow","then","created","params","sanitizeUpdateInput","validateWorkflowUpdate","findById","WORKFLOW_POPULATE","notFound","getPermittedFieldToUpdate","dataToUpdate","updatedWorkflow","delete","deletedWorkflow","find","filters","sort","read","workflows","workflowCount","Promise","all","count","async","meta"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { map, update, property } from 'lodash/fp';
1
+ import { map, update } from 'lodash/fp';
2
2
  import { async } from '@strapi/utils';
3
3
  import { getService } from '../utils/index.mjs';
4
4
  import { validateWorkflowUpdate, validateWorkflowCreate } from '../validation/review-workflows.mjs';
@@ -15,16 +15,23 @@ import { WORKFLOW_POPULATE, WORKFLOW_MODEL_UID } from '../constants/workflows.mj
15
15
  model: WORKFLOW_MODEL_UID
16
16
  });
17
17
  }
18
- /**
19
- * Transforms workflow to an admin UI format.
20
- * Some attributes (like permissions) are presented in a different format in the admin UI.
21
- * @param {Workflow} workflow
22
- */ function formatWorkflowToAdmin(workflow) {
18
+ function formatWorkflowToAdmin(workflow) {
23
19
  if (!workflow) return;
24
20
  if (!workflow.stages) return workflow;
25
- // Transform permissions roles to be the id string instead of an object
26
- const transformPermissions = map(update('role', property('id')));
27
- const transformStages = map(update('permissions', transformPermissions));
21
+ const transformRoleToId = ({ actionParameters: _, role, ...rest })=>({
22
+ ...rest,
23
+ role: typeof role === 'object' ? role.id : role
24
+ });
25
+ const transformStages = map((stage)=>{
26
+ const { permissions: allPermissions = [], ...rest } = stage;
27
+ const fromPermissions = allPermissions.filter((p)=>p.actionParameters?.from).map(transformRoleToId);
28
+ const toPermissions = allPermissions.filter((p)=>p.actionParameters?.to).map(transformRoleToId);
29
+ return {
30
+ ...rest,
31
+ fromPermissions,
32
+ toPermissions
33
+ };
34
+ });
28
35
  return update('stages', transformStages, workflow);
29
36
  }
30
37
  var workflows = {
@@ -1 +1 @@
1
- {"version":3,"file":"workflows.mjs","sources":["../../../server/src/controllers/workflows.ts"],"sourcesContent":["import type { Context } from 'koa';\nimport { update, map, property } from 'lodash/fp';\n\nimport type { Core } from '@strapi/types';\nimport { async } from '@strapi/utils';\n\nimport { getService } from '../utils';\nimport { validateWorkflowCreate, validateWorkflowUpdate } from '../validation/review-workflows';\nimport { WORKFLOW_MODEL_UID, WORKFLOW_POPULATE } from '../constants/workflows';\n\n/**\n *\n * @param { Core.Strapi } strapi - Strapi instance\n * @param userAbility\n * @return { PermissionChecker }\n */\nfunction getWorkflowsPermissionChecker({ strapi }: { strapi: Core.Strapi }, userAbility: unknown) {\n return strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility, model: WORKFLOW_MODEL_UID });\n}\n\n/**\n * Transforms workflow to an admin UI format.\n * Some attributes (like permissions) are presented in a different format in the admin UI.\n * @param {Workflow} workflow\n */\nfunction formatWorkflowToAdmin(workflow: any) {\n if (!workflow) return;\n if (!workflow.stages) return workflow;\n\n // Transform permissions roles to be the id string instead of an object\n const transformPermissions = map(update('role', property('id')));\n const transformStages = map(update('permissions', transformPermissions));\n return update('stages', transformStages, workflow);\n}\n\nexport default {\n /**\n * Create a new workflow\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async create(ctx: Context) {\n const { body, query } = ctx.request;\n const { sanitizeCreateInput, sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(\n { strapi },\n ctx.state.userAbility\n );\n const { populate } = await sanitizedQuery.create(query);\n\n const workflowBody = await validateWorkflowCreate(body.data);\n\n const workflowService = getService('workflows');\n const createdWorkflow = await workflowService\n .create({\n data: await sanitizeCreateInput(workflowBody),\n populate,\n })\n .then(formatWorkflowToAdmin);\n\n ctx.created({\n data: await sanitizeOutput(createdWorkflow),\n });\n },\n\n /**\n * Update a workflow\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async update(ctx: Context) {\n const { id } = ctx.params;\n const { body, query } = ctx.request;\n const workflowService = getService('workflows');\n const { sanitizeUpdateInput, sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(\n { strapi },\n ctx.state.userAbility\n );\n const { populate } = await sanitizedQuery.update(query);\n const workflowBody = await validateWorkflowUpdate(body.data);\n\n // Find if workflow exists\n const workflow = await workflowService.findById(id, { populate: WORKFLOW_POPULATE });\n if (!workflow) {\n return ctx.notFound();\n }\n\n // Sanitize input data\n const getPermittedFieldToUpdate = sanitizeUpdateInput(workflow);\n const dataToUpdate = await getPermittedFieldToUpdate(workflowBody);\n\n // Update workflow\n const updatedWorkflow = await workflowService\n .update(workflow, {\n data: dataToUpdate,\n populate,\n })\n .then(formatWorkflowToAdmin);\n\n // Send sanitized response\n ctx.body = {\n data: await sanitizeOutput(updatedWorkflow),\n };\n },\n\n /**\n * Delete a workflow\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async delete(ctx: Context) {\n const { id } = ctx.params;\n const { query } = ctx.request;\n const workflowService = getService('workflows');\n const { sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(\n { strapi },\n ctx.state.userAbility\n );\n const { populate } = await sanitizedQuery.delete(query);\n\n const workflow = await workflowService.findById(id, { populate: WORKFLOW_POPULATE });\n if (!workflow) {\n return ctx.notFound(\"Workflow doesn't exist\");\n }\n\n const deletedWorkflow = await workflowService\n .delete(workflow, { populate })\n .then(formatWorkflowToAdmin);\n\n ctx.body = {\n data: await sanitizeOutput(deletedWorkflow),\n };\n },\n\n /**\n * List all workflows\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async find(ctx: Context) {\n const { query } = ctx.request;\n const workflowService = getService('workflows');\n const { sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(\n { strapi },\n ctx.state.userAbility\n );\n const { populate, filters, sort } = await sanitizedQuery.read(query);\n\n const [workflows, workflowCount] = await Promise.all([\n workflowService.find({ populate, filters, sort }).then(map(formatWorkflowToAdmin)),\n workflowService.count(),\n ]);\n\n ctx.body = {\n data: await async.map(workflows, sanitizeOutput),\n meta: {\n workflowCount,\n },\n };\n },\n};\n"],"names":["getWorkflowsPermissionChecker","strapi","userAbility","plugin","service","create","model","WORKFLOW_MODEL_UID","formatWorkflowToAdmin","workflow","stages","transformPermissions","map","update","property","transformStages","ctx","body","query","request","sanitizeCreateInput","sanitizeOutput","sanitizedQuery","state","populate","workflowBody","validateWorkflowCreate","data","workflowService","getService","createdWorkflow","then","created","id","params","sanitizeUpdateInput","validateWorkflowUpdate","findById","WORKFLOW_POPULATE","notFound","getPermittedFieldToUpdate","dataToUpdate","updatedWorkflow","delete","deletedWorkflow","find","filters","sort","read","workflows","workflowCount","Promise","all","count","async","meta"],"mappings":"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"}
1
+ {"version":3,"file":"workflows.mjs","sources":["../../../server/src/controllers/workflows.ts"],"sourcesContent":["import type { Context } from 'koa';\nimport { update, map, property } from 'lodash/fp';\n\nimport type { Core } from '@strapi/types';\nimport { async } from '@strapi/utils';\n\nimport type { StagePermission } from '../../../shared/contracts/review-workflows';\nimport { getService } from '../utils';\nimport { validateWorkflowCreate, validateWorkflowUpdate } from '../validation/review-workflows';\nimport { WORKFLOW_MODEL_UID, WORKFLOW_POPULATE } from '../constants/workflows';\n\n/**\n *\n * @param { Core.Strapi } strapi - Strapi instance\n * @param userAbility\n * @return { PermissionChecker }\n */\nfunction getWorkflowsPermissionChecker({ strapi }: { strapi: Core.Strapi }, userAbility: unknown) {\n return strapi\n .plugin('content-manager')\n .service('permission-checker')\n .create({ userAbility, model: WORKFLOW_MODEL_UID });\n}\n\n/**\n * Transforms workflow to an admin UI format.\n * Some attributes (like permissions) are presented in a different format in the admin UI.\n *\n * Permissions stored on each stage are split into two arrays:\n * - `fromPermissions`: entries with `actionParameters.from` (controls who can move\n * content out of the stage)\n * - `toPermissions`: entries with `actionParameters.to` (controls who can move\n * content into the stage)\n *\n * Role objects are also flattened to their numeric id.\n */\n\n/**\n * Shape of a permission row as returned by the DB populate.\n */\ninterface PopulatedPermission {\n action: string;\n subject?: string | null;\n role: number | { id: number };\n actionParameters?: { from?: number; to?: number };\n}\n\ninterface PopulatedStage {\n permissions?: PopulatedPermission[];\n [key: string]: unknown;\n}\n\nfunction formatWorkflowToAdmin(workflow: { stages?: PopulatedStage[]; [key: string]: unknown }) {\n if (!workflow) return;\n if (!workflow.stages) return workflow;\n\n const transformRoleToId = ({\n actionParameters: _,\n role,\n ...rest\n }: PopulatedPermission): StagePermission => ({\n ...rest,\n role: typeof role === 'object' ? role.id : role,\n });\n\n const transformStages = map((stage: PopulatedStage) => {\n const { permissions: allPermissions = [], ...rest } = stage;\n\n const fromPermissions = allPermissions\n .filter((p) => p.actionParameters?.from)\n .map(transformRoleToId);\n\n const toPermissions = allPermissions\n .filter((p) => p.actionParameters?.to)\n .map(transformRoleToId);\n\n return {\n ...rest,\n fromPermissions,\n toPermissions,\n };\n });\n\n return update('stages', transformStages, workflow);\n}\n\nexport default {\n /**\n * Create a new workflow\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async create(ctx: Context) {\n const { body, query } = ctx.request;\n const { sanitizeCreateInput, sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(\n { strapi },\n ctx.state.userAbility\n );\n const { populate } = await sanitizedQuery.create(query);\n\n const workflowBody = await validateWorkflowCreate(body.data);\n\n const workflowService = getService('workflows');\n const createdWorkflow = await workflowService\n .create({\n data: await sanitizeCreateInput(workflowBody),\n populate,\n })\n .then(formatWorkflowToAdmin);\n\n ctx.created({\n data: await sanitizeOutput(createdWorkflow),\n });\n },\n\n /**\n * Update a workflow\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async update(ctx: Context) {\n const { id } = ctx.params;\n const { body, query } = ctx.request;\n const workflowService = getService('workflows');\n const { sanitizeUpdateInput, sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(\n { strapi },\n ctx.state.userAbility\n );\n const { populate } = await sanitizedQuery.update(query);\n const workflowBody = await validateWorkflowUpdate(body.data);\n\n // Find if workflow exists\n const workflow = await workflowService.findById(id, { populate: WORKFLOW_POPULATE });\n if (!workflow) {\n return ctx.notFound();\n }\n\n // Sanitize input data\n const getPermittedFieldToUpdate = sanitizeUpdateInput(workflow);\n const dataToUpdate = await getPermittedFieldToUpdate(workflowBody);\n\n // Update workflow\n const updatedWorkflow = await workflowService\n .update(workflow, {\n data: dataToUpdate,\n populate,\n })\n .then(formatWorkflowToAdmin);\n\n // Send sanitized response\n ctx.body = {\n data: await sanitizeOutput(updatedWorkflow),\n };\n },\n\n /**\n * Delete a workflow\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async delete(ctx: Context) {\n const { id } = ctx.params;\n const { query } = ctx.request;\n const workflowService = getService('workflows');\n const { sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(\n { strapi },\n ctx.state.userAbility\n );\n const { populate } = await sanitizedQuery.delete(query);\n\n const workflow = await workflowService.findById(id, { populate: WORKFLOW_POPULATE });\n if (!workflow) {\n return ctx.notFound(\"Workflow doesn't exist\");\n }\n\n const deletedWorkflow = await workflowService\n .delete(workflow, { populate })\n .then(formatWorkflowToAdmin);\n\n ctx.body = {\n data: await sanitizeOutput(deletedWorkflow),\n };\n },\n\n /**\n * List all workflows\n * @param {import('koa').BaseContext} ctx - koa context\n */\n async find(ctx: Context) {\n const { query } = ctx.request;\n const workflowService = getService('workflows');\n const { sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(\n { strapi },\n ctx.state.userAbility\n );\n const { populate, filters, sort } = await sanitizedQuery.read(query);\n\n const [workflows, workflowCount] = await Promise.all([\n workflowService.find({ populate, filters, sort }).then(map(formatWorkflowToAdmin)),\n workflowService.count(),\n ]);\n\n ctx.body = {\n data: await async.map(workflows, sanitizeOutput),\n meta: {\n workflowCount,\n },\n };\n },\n};\n"],"names":["getWorkflowsPermissionChecker","strapi","userAbility","plugin","service","create","model","WORKFLOW_MODEL_UID","formatWorkflowToAdmin","workflow","stages","transformRoleToId","actionParameters","_","role","rest","id","transformStages","map","stage","permissions","allPermissions","fromPermissions","filter","p","from","toPermissions","to","update","ctx","body","query","request","sanitizeCreateInput","sanitizeOutput","sanitizedQuery","state","populate","workflowBody","validateWorkflowCreate","data","workflowService","getService","createdWorkflow","then","created","params","sanitizeUpdateInput","validateWorkflowUpdate","findById","WORKFLOW_POPULATE","notFound","getPermittedFieldToUpdate","dataToUpdate","updatedWorkflow","delete","deletedWorkflow","find","filters","sort","read","workflows","workflowCount","Promise","all","count","async","meta"],"mappings":"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"}