-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add enable workflow trigger endpoint #6443
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { | ||
InternalServerError, | ||
UserInputError, | ||
} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; | ||
import { | ||
WorkflowTriggerException, | ||
WorkflowTriggerExceptionCode, | ||
} from 'src/modules/workflow/standard-objects/workflow-trigger/workflow-trigger.exception'; | ||
|
||
export const workflowTriggerGraphqlApiExceptionHandler = (error: Error) => { | ||
if (error instanceof WorkflowTriggerException) { | ||
switch (error.code) { | ||
case WorkflowTriggerExceptionCode.INVALID_INPUT: | ||
throw new UserInputError(error.message); | ||
case WorkflowTriggerExceptionCode.INVALID_WORKFLOW_TRIGGER: | ||
case WorkflowTriggerExceptionCode.INVALID_WORKFLOW_VERSION: | ||
default: | ||
throw new InternalServerError(error.message); | ||
} | ||
} | ||
|
||
throw error; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { Module } from '@nestjs/common'; | ||
|
||
import { WorkflowTriggerResolver } from 'src/engine/core-modules/workflow/workflow-trigger.resolver'; | ||
import { WorkflowTriggerService } from 'src/modules/workflow/standard-objects/workflow-trigger/workflow-trigger.service'; | ||
|
||
@Module({ | ||
providers: [WorkflowTriggerService, WorkflowTriggerResolver], | ||
}) | ||
export class WorkflowTriggerModule {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { UseGuards } from '@nestjs/common'; | ||
import { Args, Mutation, Resolver } from '@nestjs/graphql'; | ||
|
||
import { workflowTriggerGraphqlApiExceptionHandler } from 'src/engine/core-modules/workflow/utils/workflow-trigger-graphql-api-exception-handler.util'; | ||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; | ||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator'; | ||
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard'; | ||
import { WorkflowTriggerService } from 'src/modules/workflow/standard-objects/workflow-trigger/workflow-trigger.service'; | ||
|
||
@UseGuards(JwtAuthGuard) | ||
@Resolver() | ||
export class WorkflowTriggerResolver { | ||
constructor( | ||
private readonly workflowTriggerService: WorkflowTriggerService, | ||
) {} | ||
|
||
@Mutation(() => Boolean) | ||
async enableWorkflowTrigger( | ||
@AuthWorkspace() { id: workspaceId }: Workspace, | ||
@Args('workflowVersionId') workflowVersionId: string, | ||
) { | ||
try { | ||
return await this.workflowTriggerService.enableWorkflowTrigger( | ||
workspaceId, | ||
workflowVersionId, | ||
); | ||
} catch (error) { | ||
workflowTriggerGraphqlApiExceptionHandler(error); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface'; | ||
|
||
import { FeatureFlagKeys } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; | ||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; | ||
import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; | ||
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; | ||
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; | ||
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; | ||
import { WorkspaceGate } from 'src/engine/twenty-orm/decorators/workspace-gate.decorator'; | ||
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; | ||
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; | ||
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; | ||
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; | ||
import { WORKFLOW_EVENT_LISTENER_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; | ||
import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; | ||
import { WorkflowWorkspaceEntity } from 'src/modules/workflow/standard-objects/workflow.workspace-entity'; | ||
|
||
@WorkspaceEntity({ | ||
standardId: STANDARD_OBJECT_IDS.workflowEventListener, | ||
namePlural: 'workflowEventListeners', | ||
labelSingular: 'WorkflowEventListener', | ||
labelPlural: 'WorkflowEventListeners', | ||
description: 'A workflow event listener', | ||
labelIdentifierStandardId: | ||
WORKFLOW_EVENT_LISTENER_STANDARD_FIELD_IDS.eventName, | ||
}) | ||
@WorkspaceGate({ | ||
featureFlag: FeatureFlagKeys.IsWorkflowEnabled, | ||
}) | ||
@WorkspaceIsSystem() | ||
export class WorkflowEventListenerWorkspaceEntity extends BaseWorkspaceEntity { | ||
@WorkspaceField({ | ||
standardId: WORKFLOW_EVENT_LISTENER_STANDARD_FIELD_IDS.eventName, | ||
type: FieldMetadataType.TEXT, | ||
label: 'Name', | ||
description: 'The workflow event listener name', | ||
icon: 'IconPhoneCheck', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you sure about the icon? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nope, but I did not find a better one. Since this is a system object, does it really matters? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, but in that case, just remove |
||
}) | ||
eventName: string; | ||
|
||
// Relations | ||
@WorkspaceRelation({ | ||
standardId: WORKFLOW_EVENT_LISTENER_STANDARD_FIELD_IDS.workflow, | ||
type: RelationMetadataType.MANY_TO_ONE, | ||
label: 'Workflow', | ||
description: 'WorkflowEventListener workflow', | ||
icon: 'IconSettingsAutomation', | ||
inverseSideTarget: () => WorkflowWorkspaceEntity, | ||
inverseSideFieldKey: 'eventListeners', | ||
}) | ||
@WorkspaceIsNullable() | ||
workflow: Relation<WorkflowWorkspaceEntity>; | ||
|
||
@WorkspaceJoinColumn('workflow') | ||
workflowId: string; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { CustomException } from 'src/utils/custom-exception'; | ||
|
||
export class WorkflowTriggerException extends CustomException { | ||
code: WorkflowTriggerExceptionCode; | ||
constructor(message: string, code: WorkflowTriggerExceptionCode) { | ||
super(message, code); | ||
} | ||
} | ||
|
||
export enum WorkflowTriggerExceptionCode { | ||
INVALID_INPUT = 'INVALID_INPUT', | ||
INVALID_WORKFLOW_TRIGGER = 'INVALID_WORKFLOW_TRIGGER', | ||
INVALID_WORKFLOW_VERSION = 'INVALID_WORKFLOW_VERSION', | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { Injectable } from '@nestjs/common'; | ||
|
||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; | ||
import { WorkflowEventListenerWorkspaceEntity } from 'src/modules/workflow/standard-objects/workflow-event-listener.workspace-entity'; | ||
import { | ||
WorkflowTriggerException, | ||
WorkflowTriggerExceptionCode, | ||
} from 'src/modules/workflow/standard-objects/workflow-trigger/workflow-trigger.exception'; | ||
import { | ||
WorkflowDatabaseEventTrigger, | ||
WorkflowTrigger, | ||
WorkflowTriggerType, | ||
WorkflowVersionWorkspaceEntity, | ||
} from 'src/modules/workflow/standard-objects/workflow-version.workspace-entity'; | ||
|
||
@Injectable() | ||
export class WorkflowTriggerService { | ||
constructor( | ||
private readonly twentyORMGlobalManager: TwentyORMGlobalManager, | ||
) {} | ||
|
||
async enableWorkflowTrigger(workspaceId: string, workflowVersionId: string) { | ||
const workflowVersionRepository = | ||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<WorkflowVersionWorkspaceEntity>( | ||
workspaceId, | ||
'workflowVersion', | ||
); | ||
|
||
const workflowVersion = await workflowVersionRepository.findOne({ | ||
where: { | ||
id: workflowVersionId, | ||
}, | ||
}); | ||
|
||
if (!workflowVersion) { | ||
throw new WorkflowTriggerException( | ||
'Workflow version not found', | ||
WorkflowTriggerExceptionCode.INVALID_INPUT, | ||
); | ||
} | ||
|
||
const trigger = workflowVersion.trigger as unknown as WorkflowTrigger; | ||
|
||
if (!trigger || !trigger?.type) { | ||
throw new WorkflowTriggerException( | ||
'Workflow version does not contains trigger', | ||
WorkflowTriggerExceptionCode.INVALID_WORKFLOW_VERSION, | ||
); | ||
} | ||
|
||
switch (trigger.type) { | ||
case WorkflowTriggerType.DATABASE_EVENT: | ||
await this.upsertWorkflowEventListener( | ||
workspaceId, | ||
workflowVersion.workflowId, | ||
trigger, | ||
); | ||
break; | ||
default: | ||
break; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
private async upsertWorkflowEventListener( | ||
workspaceId: string, | ||
workflowId: string, | ||
trigger: WorkflowDatabaseEventTrigger, | ||
) { | ||
const eventName = trigger?.settings?.eventName; | ||
|
||
if (!eventName) { | ||
throw new WorkflowTriggerException( | ||
'No event name provided in database event trigger', | ||
WorkflowTriggerExceptionCode.INVALID_WORKFLOW_TRIGGER, | ||
); | ||
} | ||
|
||
const workflowEventListenerRepository = | ||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<WorkflowEventListenerWorkspaceEntity>( | ||
workspaceId, | ||
'workflowEventListener', | ||
); | ||
|
||
// TODO: Use upsert when available for workspace entities | ||
await workflowEventListenerRepository.delete({ | ||
workflowId, | ||
eventName, | ||
}); | ||
|
||
const workflowEventListener = await workflowEventListenerRepository.create({ | ||
workflowId, | ||
eventName, | ||
}); | ||
|
||
await workflowEventListenerRepository.save(workflowEventListener); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
enableWorkflowTrigger
-> I don't understand the naming heretriggerWorkflow
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@martmull It does not really trigger the workflow. It setup the workflow trigger, so it will get triggered later.
I could rename it
setupWorflowTrigger
but this is not that fare fromenableWorkflowTrigger
. So for this one let's remain consistent withactivePieces
? Wdyt?