Skip to content

Commit

Permalink
Add Flow validation
Browse files Browse the repository at this point in the history
  • Loading branch information
abuaboud committed Dec 28, 2022
1 parent e4998c8 commit b457255
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 45 deletions.
8 changes: 6 additions & 2 deletions src/worker/packages/backend/src/flows/flow.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import {StatusCodes} from "http-status-codes";
import {ActivepiecesError, ErrorCode} from "../helper/activepieces-error";
import {flowService} from "./flow-service";
import {FlowOperationRequestSchema} from "shared";

export const flowController = async (fastify: FastifyInstance, options: FastifyPluginOptions) => {

Expand All @@ -23,8 +24,11 @@ export const flowController = async (fastify: FastifyInstance, options: FastifyP
})


// TODO ADD VALIDATION
fastify.post('/:flowId', {}, async (_request: FastifyRequest<{
fastify.post('/:flowId', {
schema: {
body: FlowOperationRequestSchema
}
}, async (_request: FastifyRequest<{
Params: {
flowId: FlowId
},
Expand Down
63 changes: 56 additions & 7 deletions src/worker/packages/shared/src/flows/actions/action.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import {Type} from "@sinclair/typebox";


export type Action = CodeAction | PieceAction | StorageAction | LoopOnItemsAction;
export enum ActionType {
CODE = "CODE",
STORAGE = "STORAGE",
PIECE = "PIECE",
LOOP_ON_ITEMS = "LOOP_ON_ITEMS"
}


interface BaseAction<T, V> {
Expand All @@ -12,6 +18,8 @@ interface BaseAction<T, V> {
nextAction: BaseAction<any, any> | undefined;
}

// Code Action

export type CodeActionSettings = {
artifact?: string;
artifactSourceId: string;
Expand All @@ -22,6 +30,18 @@ export type CodeActionSettings = {
export interface CodeAction extends BaseAction<ActionType.CODE, CodeActionSettings> {
}

export const CodeActionSchema = Type.Object({
name: Type.String({}),
displayName: Type.String({}),
type: Type.Literal(ActionType.CODE),
settings: Type.Object({
artifactSourceId: Type.String({}),
input: Type.Object({})
})
})

// Piece Action

export type PieceActionSettings = {
pieceName: string;
actionName: string;
Expand All @@ -31,6 +51,19 @@ export type PieceActionSettings = {
export interface PieceAction extends BaseAction<ActionType.PIECE, PieceActionSettings> {
};

export const PieceActionSchema = Type.Object({
name: Type.String({}),
displayName: Type.String({}),
type: Type.Literal(ActionType.CODE),
settings: Type.Object({
pieceName: Type.String({}),
actionName: Type.String({}),
input: Type.Object({})
})
})

// Storage Action

export enum StoreOperation {
PUT = "PUT",
GET = "GET"
Expand All @@ -45,6 +78,18 @@ export type StorageActionSettings = {
export interface StorageAction extends BaseAction<ActionType.STORAGE, StorageActionSettings> {
}

export const StorageActionSchema = Type.Object({
name: Type.String({}),
displayName: Type.String({}),
type: Type.Literal(ActionType.STORAGE),
settings: Type.Object({
operation: Type.Enum(StoreOperation),
key: Type.String({}),
value: Type.Any({})
})
})

// Loop Items

export type LoopOnItemsActionSettings = {
items: unknown;
Expand All @@ -54,10 +99,14 @@ export interface LoopOnItemsAction extends BaseAction<ActionType.LOOP_ON_ITEMS,
firstLoopAction: BaseAction<any, any> | undefined;
}

export const LoopOnItemsActionSchema = Type.Object({
name: Type.String({}),
displayName: Type.String({}),
type: Type.Literal(ActionType.STORAGE),
settings: Type.Object({
items: Type.Array(Type.Any({}))
})
})

export enum ActionType {
CODE = "CODE",
STORAGE = "STORAGE",
PIECE = "PIECE",
LOOP_ON_ITEMS = "LOOP_ON_ITEMS"
}
export type Action = CodeAction | PieceAction | StorageAction | LoopOnItemsAction;
export const ActionSchema = Type.Union([CodeActionSchema, PieceActionSchema, StorageActionSchema, LoopOnItemsActionSchema]);
64 changes: 44 additions & 20 deletions src/worker/packages/shared/src/flows/flow-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,23 @@ import {
UpdateActionRequest,
UpdateTriggerRequest
} from "./flow-operations";
import {Action, ActionType, CodeAction, PieceAction, LoopOnItemsAction, StorageAction} from "./actions/action";
import {Trigger, TriggerType} from "./triggers/trigger";

import {
Action,
ActionType,
CodeAction,
PieceAction,
LoopOnItemsAction,
StorageAction,
ActionSchema
} from "./actions/action";
import {Trigger, TriggerSchema, TriggerType} from "./triggers/trigger";
import {TypeCompiler} from "@sinclair/typebox/compiler";

const actionSchemaValidator = TypeCompiler.Compile(ActionSchema);
const triggerSchemaValidation = TypeCompiler.Compile(TriggerSchema);

function isValid(flowVersion: FlowVersion){
let valid = false;
let valid = true;
let step : Action | Trigger | undefined = flowVersion.trigger;
while(step !== undefined){
valid = valid && step.valid;
Expand Down Expand Up @@ -69,32 +79,39 @@ function createAction(request: UpdateActionRequest, nextAction: Action | undefin
valid: false,
nextAction: nextAction
};
let action;
switch (request.type) {
case ActionType.STORAGE:
return {
action = {
...baseProperties,
type: ActionType.STORAGE,
settings: request.settings,
} as StorageAction;
break;
case ActionType.LOOP_ON_ITEMS:
return {
action = {
...baseProperties,
type: ActionType.LOOP_ON_ITEMS,
settings: request.settings,
} as LoopOnItemsAction;
break;
case ActionType.PIECE:
return {
action = {
...baseProperties,
type: ActionType.PIECE,
settings: request.settings,
} as PieceAction;
break;
case ActionType.CODE:
return {
action = {
...baseProperties,
type: ActionType.CODE,
settings: request.settings,
} as CodeAction;
break;
}
action.valid = actionSchemaValidator.Check(action);
return action;
}

function createTrigger(name: string, request: UpdateTriggerRequest, nextAction: Action | undefined): Trigger {
Expand All @@ -104,56 +121,63 @@ function createTrigger(name: string, request: UpdateTriggerRequest, nextAction:
valid: false,
nextAction: nextAction
};
let trigger: Trigger;
switch (request.type) {
case TriggerType.EMPTY:
return {
trigger = {
...baseProperties,
type: TriggerType.EMPTY,
settings: request.settings
};
break;
case TriggerType.SCHEDULE:
return {
trigger = {
...baseProperties,
type: TriggerType.SCHEDULE,
settings: request.settings
};
case TriggerType.COMPONENT:
return {
break;
case TriggerType.PIECE:
trigger = {
...baseProperties,
type: TriggerType.COMPONENT,
type: TriggerType.PIECE,
settings: request.settings
};
break;
case TriggerType.WEBHOOK:
return {
trigger = {
...baseProperties,
type: TriggerType.WEBHOOK,
settings: request.settings
};
break;
}
trigger.valid = triggerSchemaValidation.Check(trigger);
return trigger;
}

export const flowHelper = {
apply(flowVersion: FlowVersion, operation: FlowOperationRequest): FlowVersion {
const clonedVersion: FlowVersion = JSON.parse(JSON.stringify(flowVersion));
switch (operation.type) {
case FlowOperationType.CHANGE_NAME:
flowVersion.displayName = operation.request.displayName;
clonedVersion.displayName = operation.request.displayName;
break;
case FlowOperationType.DELETE_ACTION:
deleteAction(flowVersion, operation.request);
deleteAction(clonedVersion, operation.request);
break;
case FlowOperationType.ADD_ACTION:
addAction(flowVersion, operation.request);
addAction(clonedVersion, operation.request);
break;
case FlowOperationType.UPDATE_ACTION:
updateAction(flowVersion, operation.request);
updateAction(clonedVersion, operation.request);
break;
case FlowOperationType.UPDATE_TRIGGER:
flowVersion.trigger = createTrigger(clonedVersion.trigger.name, operation.request, clonedVersion.trigger.nextAction);
clonedVersion.trigger = createTrigger(clonedVersion.trigger.name, operation.request, clonedVersion.trigger.nextAction);
break;
}
clonedVersion.valid = isValid(clonedVersion);
return flowVersion;
return clonedVersion;
},
getStep: getStep
}
33 changes: 31 additions & 2 deletions src/worker/packages/shared/src/flows/flow-operations.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {
ActionType, CodeActionSettings, LoopOnItemsActionSettings, PieceActionSettings, StorageActionSettings,
} from "./actions/action";
import {ComponentTriggerSettings, ScheduleTriggerSettings, TriggerType} from "./triggers/trigger";
import {PieceTriggerSettings, ScheduleTriggerSettings, TriggerType} from "./triggers/trigger";
import {Type} from "@sinclair/typebox";


export enum FlowOperationType {
Expand All @@ -18,6 +19,34 @@ export type FlowOperationRequest = BasicOperationRequest<FlowOperationType.UPDAT
| BasicOperationRequest<FlowOperationType.CHANGE_NAME, ChangeNameRequest>
| BasicOperationRequest<FlowOperationType.DELETE_ACTION, DeleteActionRequest>;


export const FlowOperationRequestSchema = Type.Union([
Type.Object({
type: Type.Literal(FlowOperationType.CHANGE_NAME),
request: Type.Object({
displayName: Type.String()
})
}),
Type.Object({
type: Type.Literal(FlowOperationType.DELETE_ACTION),
request: Type.Object({
name: Type.String()
})
}),
Type.Object({
type: Type.Literal(FlowOperationType.UPDATE_TRIGGER),
request: Type.Object({})
}),
Type.Object({
type: Type.Literal(FlowOperationType.ADD_ACTION),
request: Type.Object({})
}),
Type.Object({
type: Type.Literal(FlowOperationType.UPDATE_TRIGGER),
request: Type.Object({})
})
]);

export type ChangeNameRequest = {
displayName: string;
}
Expand Down Expand Up @@ -47,7 +76,7 @@ interface BasicActionStep<A, V> {
export type UpdateTriggerRequest = BasicTriggerRequest<TriggerType.WEBHOOK, {}>
| BasicTriggerRequest<TriggerType.SCHEDULE, ScheduleTriggerSettings>
| BasicTriggerRequest<TriggerType.EMPTY, {}>
| BasicTriggerRequest<TriggerType.COMPONENT, ComponentTriggerSettings>
| BasicTriggerRequest<TriggerType.PIECE, PieceTriggerSettings>


interface BasicTriggerRequest<A, V> {
Expand Down
Loading

0 comments on commit b457255

Please sign in to comment.