From acb32546eb5518d04b2197bc01cc8a41f21b2148 Mon Sep 17 00:00:00 2001 From: Andre Turner Date: Thu, 6 Jun 2024 17:45:13 -0500 Subject: [PATCH] Validate role for internship projects --- .../project/workflow/project-workflow.ts | 5 ++-- .../workflow/transitions/conditions.ts | 30 +++++++++++++++++++ .../workflow/transitions/dynamic-step.ts | 2 ++ src/components/workflow/workflow.service.ts | 6 +++- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/components/project/workflow/project-workflow.ts b/src/components/project/workflow/project-workflow.ts index a8825b969f..9d142fbcf7 100644 --- a/src/components/project/workflow/project-workflow.ts +++ b/src/components/project/workflow/project-workflow.ts @@ -3,6 +3,7 @@ import { TransitionType as Type } from '../../workflow/dto'; import { ProjectStep as Step } from '../dto'; import { ProjectWorkflowEvent } from './dto'; import { + hasValidRoleForProjectType, IsMultiplication, IsNotMultiplication, RequireOngoingEngagementsToBeFinalizingCompletion, @@ -116,7 +117,7 @@ export const ProjectWorkflow = defineWorkflow({ to: Step.PrepForFinancialEndorsement, label: 'Endorse Plan', type: Type.Approve, - conditions: IsNotMultiplication, + conditions: [IsNotMultiplication, hasValidRoleForProjectType], }, 'Pending Consultant Endorsement -> Prep for Financial Endorsement Without Consultant Endorsement': { @@ -124,7 +125,7 @@ export const ProjectWorkflow = defineWorkflow({ to: Step.PrepForFinancialEndorsement, label: 'Do Not Endorse Plan', type: Type.Neutral, - conditions: IsNotMultiplication, + conditions: [IsNotMultiplication, hasValidRoleForProjectType], }, // Prep for Financial Endorsement diff --git a/src/components/project/workflow/transitions/conditions.ts b/src/components/project/workflow/transitions/conditions.ts index 6ac9e09884..f3ee97f4bb 100644 --- a/src/components/project/workflow/transitions/conditions.ts +++ b/src/components/project/workflow/transitions/conditions.ts @@ -1,3 +1,4 @@ +import { ScopedRole } from '../../../authorization/dto'; import { EngagementService } from '../../../engagement'; import { EngagementStatus } from '../../../engagement/dto'; import { TransitionCondition } from '../../../workflow/transitions/conditions'; @@ -23,6 +24,35 @@ export const IsMultiplication: Condition = { }, }; +export const hasValidRoleForProjectType: Condition = { + description: 'Validate role by project type', + resolve({ project, session }) { + const validRoles: ScopedRole[] = [ + 'global:Administrator', + 'global:Consultant', + 'global:ConsultantManager', + ]; + const hasAtLeastOneValidRole = validRoles.some((role) => + session?.roles.includes(role), + ); + + switch (project.type) { + case 'MomentumTranslation': + return { + status: 'ENABLED', + }; + case 'Internship': + return { + status: hasAtLeastOneValidRole ? 'ENABLED' : 'OMIT', + }; + default: + return { + status: 'OMIT', + }; + } + }, +}; + export const RequireOngoingEngagementsToBeFinalizingCompletion: Condition = { description: 'All engagements must be Finalizing Completion or in a terminal status', diff --git a/src/components/project/workflow/transitions/dynamic-step.ts b/src/components/project/workflow/transitions/dynamic-step.ts index e2d15f36c3..7c49c61ed2 100644 --- a/src/components/project/workflow/transitions/dynamic-step.ts +++ b/src/components/project/workflow/transitions/dynamic-step.ts @@ -1,4 +1,5 @@ import { ModuleRef } from '@nestjs/core'; +import { Session } from '~/common'; import { DynamicState } from '../../../workflow/transitions/dynamic-state'; import { Project, ProjectStep, ProjectStep as Step } from '../../dto'; import { ProjectWorkflowRepository } from '../project-workflow.repository'; @@ -6,6 +7,7 @@ import { ProjectWorkflowRepository } from '../project-workflow.repository'; export interface ResolveParams { project: Project; moduleRef: ModuleRef; + session?: Session; } export const BackTo = ( diff --git a/src/components/workflow/workflow.service.ts b/src/components/workflow/workflow.service.ts index 35a8ea55e7..7f407538c5 100644 --- a/src/components/workflow/workflow.service.ts +++ b/src/components/workflow/workflow.service.ts @@ -31,6 +31,7 @@ export const WorkflowService = (workflow: W) => { dynamicContext: W['context'], session: Session, ) { + const dynamicContextWithSession = { ...dynamicContext, session }; let available = this.workflow.transitions; // Filter out non applicable transitions @@ -52,7 +53,10 @@ export const WorkflowService = (workflow: W) => { await Promise.all( [...new Set(conditions)].map( async (condition) => - [condition, await condition.resolve(dynamicContext)] as const, + [ + condition, + await condition.resolve(dynamicContextWithSession), + ] as const, ), ), );