diff --git a/executor/workflows/tasks.py b/executor/workflows/tasks.py
index ee0a75d7f..f4a7c32a6 100644
--- a/executor/workflows/tasks.py
+++ b/executor/workflows/tasks.py
@@ -1,11 +1,16 @@
import logging
from datetime import timedelta, datetime
+import time
+
from celery import shared_task
from django.conf import settings
from accounts.models import Account
from executor.crud.playbook_execution_crud import create_playbook_execution, get_db_playbook_execution
+from executor.crud.playbooks_crud import get_db_playbook_step, get_db_playbook_task_definitions
+from executor.models import PlayBook
+from executor.task_executor import execute_task
from executor.tasks import execute_playbook
from executor.workflows.action.action_executor import action_executor
from executor.workflows.crud.workflow_execution_crud import get_db_workflow_executions, \
@@ -21,7 +26,7 @@
from playbooks.utils.utils import current_datetime
from protos.base_pb2 import TimeRange
from protos.playbooks.intelligence_layer.interpreter_pb2 import InterpreterType, Interpretation as InterpretationProto
-from protos.playbooks.playbook_pb2 import PlaybookExecution as PlaybookExecutionProto
+from protos.playbooks.playbook_pb2 import PlaybookExecution as PlaybookExecutionProto, PlaybookExecutionLog, PlaybookTaskDefinition, PlaybookTaskExecutionResult
from protos.playbooks.workflow_pb2 import WorkflowExecutionStatusType, Workflow as WorkflowProto, \
WorkflowAction as WorkflowActionProto, WorkflowActionNotificationConfig, WorkflowActionSlackNotificationConfig
from utils.proto_utils import dict_to_proto, proto_to_dict
@@ -195,3 +200,50 @@ def workflow_action_execution(account_id, workflow_id, workflow_execution_id, pl
workflow_action_execution_prerun_notifier = publish_pre_run_task(workflow_action_execution)
workflow_action_execution_failure_notifier = publish_task_failure(workflow_action_execution)
workflow_action_execution_postrun_notifier = publish_post_run_task(workflow_action_execution)
+
+
+# @shared_task()
+def test_workflow_notification(account_id, workflow, message_type):
+ if message_type == WorkflowActionSlackNotificationConfig.MessageType.MESSAGE:
+ pe_logs = []
+ account = Account.objects.get(id=account_id)
+ time_range = { "time_lt": str(int(time.time())), "time_geq": str(int(time.time()) - 3600) }
+ tr: TimeRange = dict_to_proto(time_range, TimeRange)
+
+ playbook_id = workflow.playbooks[0].id.value
+ playbook = PlayBook.objects.get(id=playbook_id)
+ p_proto = playbook.proto
+
+ playbook_steps = get_db_playbook_step(account, playbook_id, is_active=True)
+ try:
+ all_step_executions = {}
+ for step in list(playbook_steps):
+ playbook_task_definitions = get_db_playbook_task_definitions(account, playbook_id, step.id, is_active=True)
+ playbook_task_definitions = playbook_task_definitions.order_by('created_at')
+ all_task_executions = []
+ for task in playbook_task_definitions:
+ task_proto = task.proto
+ task_result = execute_task(account_id, tr, task_proto)
+ all_task_executions.append({
+ 'task': task,
+ 'task_result': proto_to_dict(task_result),
+ 'task_result_proto': task_result,
+ })
+ all_step_executions[step] = all_task_executions
+
+ for step, all_task_results in all_step_executions.items():
+ for result in all_task_results:
+ playbook_execution_log = PlaybookExecutionLog(
+ playbook=playbook,
+ playbook_step=step,
+ playbook_task_definition=result['task'].proto,
+ playbook_task_result=result['task_result_proto'],
+ )
+ pe_logs.append(playbook_execution_log)
+
+ except Exception as exc:
+ logger.error(f"Error occurred while running playbook: {exc}")
+
+ execution_output: [InterpretationProto] = playbook_execution_result_interpret(InterpreterType.BASIC_I, p_proto,
+ pe_logs)
+ action_executor(account, workflow.actions[0], execution_output)
\ No newline at end of file
diff --git a/executor/workflows/urls.py b/executor/workflows/urls.py
index c8e298e93..7ed6a3178 100644
--- a/executor/workflows/urls.py
+++ b/executor/workflows/urls.py
@@ -9,6 +9,9 @@
path('create', workflow_views.workflows_create),
path('update', workflow_views.workflows_update),
+ # Test Notification
+ path('test_notification', workflow_views.test_workflows_notification),
+
# Workflow Execution APIs
path('execute', workflow_views.workflows_execute),
path('executions/get', workflow_views.workflows_execution_get),
diff --git a/executor/workflows/views.py b/executor/workflows/views.py
index 1bd5971f5..69eac5bc1 100644
--- a/executor/workflows/views.py
+++ b/executor/workflows/views.py
@@ -11,6 +11,7 @@
from executor.workflows.crud.workflow_execution_utils import create_workflow_execution_util
from executor.workflows.crud.workflows_crud import create_db_workflow
from executor.workflows.crud.workflows_update_processor import workflows_update_processor
+from executor.workflows.tasks import test_workflow_notification
from playbooks.utils.decorators import web_api
from playbooks.utils.meta import get_meta
from playbooks.utils.queryset import filter_page
@@ -20,7 +21,7 @@
CreateWorkflowResponse, UpdateWorkflowRequest, UpdateWorkflowResponse, ExecuteWorkflowRequest, \
ExecuteWorkflowResponse, ExecutionWorkflowGetRequest, ExecutionWorkflowGetResponse, ExecutionsWorkflowsListResponse, \
ExecutionsWorkflowsListRequest
-from protos.playbooks.workflow_pb2 import Workflow as WorkflowProto, WorkflowSchedule as WorkflowScheduleProto
+from protos.playbooks.workflow_pb2 import Workflow as WorkflowProto, WorkflowActionSlackNotificationConfig, WorkflowSchedule as WorkflowScheduleProto
from utils.proto_utils import dict_to_proto
logger = logging.getLogger(__name__)
@@ -94,6 +95,32 @@ def workflows_update(request_message: UpdateWorkflowRequest) -> Union[UpdateWork
return UpdateWorkflowResponse(success=BoolValue(value=True))
+@web_api(CreateWorkflowRequest)
+def test_workflows_notification(request_message: CreateWorkflowRequest) -> Union[CreateWorkflowResponse, HttpResponse]:
+ account: Account = get_request_account()
+ user = get_request_user()
+ workflow: WorkflowProto = request_message.workflow
+
+ if not workflow.playbooks or workflow.playbooks == []:
+ return CreateWorkflowResponse(success=BoolValue(value=False),
+ message=Message(title="Invalid Request", description="Select a playbook"))
+
+ if not workflow.entry_points or workflow.entry_points == []:
+ return CreateWorkflowResponse(success=BoolValue(value=False),
+ message=Message(title="Invalid Request", description="Select the trigger type"))
+
+ if not workflow.entry_points[0].alert_config.slack_channel_alert_config.slack_channel_id:
+ return CreateWorkflowResponse(success=BoolValue(value=False),
+ message=Message(title="Invalid Request", description="Select a slack channel"))
+
+ if not workflow.actions or workflow.actions == []:
+ return CreateWorkflowResponse(success=BoolValue(value=False),
+ message=Message(title="Invalid Request", description="Select a notification type"))
+
+ test_workflow_notification(account.id, workflow, workflow.actions[0].notification_config.slack_config.message_type)
+ return CreateWorkflowResponse(success=BoolValue(value=True))
+
+
@web_api(ExecuteWorkflowRequest)
def workflows_execute(request_message: ExecuteWorkflowRequest) -> Union[ExecuteWorkflowResponse, HttpResponse]:
account: Account = get_request_account()
diff --git a/web/src/components/Workflows/create/CreateWorkflow.jsx b/web/src/components/Workflows/create/CreateWorkflow.jsx
index 4c93b5a3c..0c48c2d23 100644
--- a/web/src/components/Workflows/create/CreateWorkflow.jsx
+++ b/web/src/components/Workflows/create/CreateWorkflow.jsx
@@ -16,6 +16,7 @@ import { showSnackbar } from "../../../store/features/snackbar/snackbarSlice.ts"
import { useLazyGetWorkflowQuery } from "../../../store/features/workflow/api/getWorkflowApi.ts";
import Loading from "../../common/Loading/index.tsx";
import { useUpdateWorkflowMutation } from "../../../store/features/workflow/api/updateWorkflowApi.ts";
+import { useLazyTestWorkflowNotificationQuery } from "../../../store/features/workflow/api/testWorkflowNotificationApi.ts";
import { stateToWorkflow } from "../../../utils/parser/workflow/stateToWorkflow.ts";
import { validate } from "./utils/validation.ts";
@@ -28,6 +29,8 @@ function CreateTrigger() {
useUpdateWorkflowMutation();
const [triggerGetWorkflow, { isLoading: workflowLoading }] =
useLazyGetWorkflowQuery();
+ const [triggerTestWorkflowNotification] =
+ useLazyTestWorkflowNotificationQuery();
const currentWorkflow = useSelector(currentWorkflowSelector);
const handleSave = async () => {
@@ -51,6 +54,11 @@ function CreateTrigger() {
}
};
+ const handleTestNotification = () => {
+ triggerTestWorkflowNotification();
+ dispatch(showSnackbar("Test Notification Sent"));
+ };
+
useEffect(() => {
return () => {
dispatch(resetWorkflowState());
@@ -89,6 +97,12 @@ function CreateTrigger() {
type="submit">
{workflowId ? "Update" : "Save"}
+ {/* */}
{(isLoading || updateLoading) && }
diff --git a/web/src/constants/api/workflows.ts b/web/src/constants/api/workflows.ts
index 8e554bf12..92f953049 100644
--- a/web/src/constants/api/workflows.ts
+++ b/web/src/constants/api/workflows.ts
@@ -2,6 +2,7 @@
export const GET_WORKFLOWS = "/executor/workflows/get";
export const CREATE_WORKFLOW = "/executor/workflows/create";
+export const TEST_WORKFLOW_NOTIFICATION = "/executor/workflows/test_notification";
export const UPDATE_WORKFLOW = "/executor/workflows/update";
export const DELETE_WORKFLOW = "/executor/workflows/update";
export const GET_WORKFLOW_EXECUTIONS = "/executor/workflows/executions/list";
diff --git a/web/src/store/features/workflow/api/index.ts b/web/src/store/features/workflow/api/index.ts
index f0e16c024..3f33031e5 100644
--- a/web/src/store/features/workflow/api/index.ts
+++ b/web/src/store/features/workflow/api/index.ts
@@ -1,2 +1,3 @@
export * from "./getWorkflowsApi.ts";
export * from "./createWorkflowApi.ts";
+export * from "./testWorkflowNotificationApi.ts";
diff --git a/web/src/store/features/workflow/api/testWorkflowNotificationApi.ts b/web/src/store/features/workflow/api/testWorkflowNotificationApi.ts
new file mode 100644
index 000000000..3609d5543
--- /dev/null
+++ b/web/src/store/features/workflow/api/testWorkflowNotificationApi.ts
@@ -0,0 +1,17 @@
+import { TEST_WORKFLOW_NOTIFICATION } from "../../../../constants/index.ts";
+import { stateToWorkflow } from "../../../../utils/parser/workflow/stateToWorkflow.ts";
+import { apiSlice } from "../../../app/apiSlice.ts";
+
+export const testWorkflowNotificationApi = apiSlice.injectEndpoints({
+ endpoints: (builder) => ({
+ testWorkflowNotification: builder.query({
+ query: () => ({
+ url: TEST_WORKFLOW_NOTIFICATION,
+ body: stateToWorkflow(),
+ method: "POST",
+ })
+ }),
+ }),
+});
+
+export const { useLazyTestWorkflowNotificationQuery } = testWorkflowNotificationApi;