Merge pull request #9 from sartography/feature/get_script_info

added script to get the process info and do not set error message whe…
This commit is contained in:
Kevin Burnett 2022-10-28 20:46:55 +00:00 committed by GitHub
commit 0b901d513b
12 changed files with 110 additions and 40 deletions

View File

@ -21,7 +21,7 @@ groups:
] ]
Finance Team: Finance Team:
users: [finance_user1] users: [finance_user1, jason]
Project Lead: Project Lead:
users: users:

View File

@ -0,0 +1,12 @@
"""Script_attributes_context."""
from dataclasses import dataclass
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
@dataclass
class ScriptAttributesContext():
"""ScriptAttributesContext."""
task: SpiffTask
environment_identifier: str
process_instance_id: int
process_model_identifier: str

View File

@ -1,5 +1,4 @@
"""APIs for dealing with process groups, process models, and process instances.""" """APIs for dealing with process groups, process models, and process instances."""
import dataclasses
import json import json
import os import os
import random import random
@ -749,7 +748,6 @@ def process_instance_delete(
"""Create_process_instance.""" """Create_process_instance."""
process_instance = find_process_instance_by_id_or_raise(process_instance_id) process_instance = find_process_instance_by_id_or_raise(process_instance_id)
# import pdb; pdb.set_trace()
# (Pdb) db.session.delete # (Pdb) db.session.delete
# <bound method delete of <sqlalchemy.orm.scoping.scoped_session object at 0x103eaab30>> # <bound method delete of <sqlalchemy.orm.scoping.scoped_session object at 0x103eaab30>>
db.session.delete(process_instance) db.session.delete(process_instance)
@ -1352,13 +1350,6 @@ def get_spiff_task_from_process_instance(
task_uuid = uuid.UUID(task_id) task_uuid = uuid.UUID(task_id)
spiff_task = processor.bpmn_process_instance.get_task(task_uuid) spiff_task = processor.bpmn_process_instance.get_task(task_uuid)
# FOR DEBUGGING: save this variable so we get it in sentry when something fails
active_task = ActiveTaskModel.query.filter_by(task_id=task_id).first()
if active_task:
task_json = dataclasses.asdict(active_task)
print(f"task_json: {task_json}")
########
if spiff_task is None: if spiff_task is None:
raise ( raise (
ApiError( ApiError(

View File

@ -1,8 +1,9 @@
"""Fact_service.""" """Fact_service."""
from typing import Any from typing import Any
from typing import Optional
from SpiffWorkflow.task import Task as SpiffTask # type: ignore from spiffworkflow_backend.models.script_attributes_context import (
ScriptAttributesContext,
)
from spiffworkflow_backend.scripts.script import Script from spiffworkflow_backend.scripts.script import Script
@ -16,8 +17,7 @@ class FactService(Script):
def run( def run(
self, self,
task: Optional[SpiffTask], script_attributes_context: ScriptAttributesContext,
environment_identifier: str,
*args: Any, *args: Any,
**kwargs: Any **kwargs: Any
) -> Any: ) -> Any:

View File

@ -1,8 +1,9 @@
"""Get_env.""" """Get_env."""
from typing import Any from typing import Any
from typing import Optional
from SpiffWorkflow.task import Task as SpiffTask # type: ignore from spiffworkflow_backend.models.script_attributes_context import (
ScriptAttributesContext,
)
from spiffworkflow_backend.scripts.script import Script from spiffworkflow_backend.scripts.script import Script
@ -15,10 +16,9 @@ class GetEnv(Script):
def run( def run(
self, self,
task: Optional[SpiffTask], script_attributes_context: ScriptAttributesContext,
environment_identifier: str,
*_args: Any, *_args: Any,
**kwargs: Any **kwargs: Any
) -> Any: ) -> Any:
"""Run.""" """Run."""
return environment_identifier return script_attributes_context.environment_identifier

View File

@ -1,11 +1,12 @@
"""Get_localtime.""" """Get_localtime."""
from datetime import datetime from datetime import datetime
from typing import Any from typing import Any
from typing import Optional
import pytz import pytz
from flask_bpmn.api.api_error import ApiError from flask_bpmn.api.api_error import ApiError
from SpiffWorkflow.task import Task as SpiffTask # type: ignore from spiffworkflow_backend.models.script_attributes_context import (
ScriptAttributesContext,
)
from spiffworkflow_backend.scripts.script import Script from spiffworkflow_backend.scripts.script import Script
@ -19,8 +20,7 @@ class GetLocaltime(Script):
def run( def run(
self, self,
task: Optional[SpiffTask], script_attributes_context: ScriptAttributesContext,
environment_identifier: str,
*args: Any, *args: Any,
**kwargs: Any **kwargs: Any
) -> datetime: ) -> datetime:

View File

@ -0,0 +1,25 @@
"""Get_process_info."""
from typing import Any
from spiffworkflow_backend.models.script_attributes_context import ScriptAttributesContext
from spiffworkflow_backend.scripts.script import Script
class GetProcessInfo(Script):
"""GetUser."""
def get_description(self) -> str:
"""Get_description."""
return """Returns a dictionary of information about the currently running process."""
def run(
self,
script_attributes_context: ScriptAttributesContext,
*_args: Any,
**kwargs: Any
) -> Any:
"""Run."""
return {
'process_instance_id': script_attributes_context.process_instance_id,
'process_model_identifier': script_attributes_context.process_model_identifier,
}

View File

@ -1,9 +1,10 @@
"""Get_env.""" """Get_env."""
from typing import Any from typing import Any
from typing import Optional
from flask import g from flask import g
from SpiffWorkflow.task import Task as SpiffTask # type: ignore from spiffworkflow_backend.models.script_attributes_context import (
ScriptAttributesContext,
)
from spiffworkflow_backend.scripts.script import Script from spiffworkflow_backend.scripts.script import Script
@ -16,8 +17,7 @@ class GetUser(Script):
def run( def run(
self, self,
task: Optional[SpiffTask], script_attributes_context: ScriptAttributesContext,
environment_identifier: str,
*_args: Any, *_args: Any,
**kwargs: Any **kwargs: Any
) -> Any: ) -> Any:

View File

@ -9,7 +9,9 @@ from typing import Any
from typing import Callable from typing import Callable
from flask_bpmn.api.api_error import ApiError from flask_bpmn.api.api_error import ApiError
from SpiffWorkflow.task import Task as SpiffTask # type: ignore from spiffworkflow_backend.models.script_attributes_context import (
ScriptAttributesContext,
)
# Generally speaking, having some global in a flask app is TERRIBLE. # Generally speaking, having some global in a flask app is TERRIBLE.
# This is here, because after loading the application this will never change under # This is here, because after loading the application this will never change under
@ -28,8 +30,7 @@ class Script:
@abstractmethod @abstractmethod
def run( def run(
self, self,
task: SpiffTask, script_attributes_context: ScriptAttributesContext,
environment_identifier: str,
*args: Any, *args: Any,
**kwargs: Any, **kwargs: Any,
) -> Any: ) -> Any:
@ -43,7 +44,7 @@ class Script:
@staticmethod @staticmethod
def generate_augmented_list( def generate_augmented_list(
task: SpiffTask, environment_identifier: str script_attributes_context: ScriptAttributesContext,
) -> dict[str, Callable]: ) -> dict[str, Callable]:
"""This makes a dictionary of lambda functions that are closed over the class instance that they represent. """This makes a dictionary of lambda functions that are closed over the class instance that they represent.
@ -56,7 +57,8 @@ class Script:
""" """
def make_closure( def make_closure(
subclass: type[Script], task: SpiffTask, environment_identifier: str subclass: type[Script],
script_attributes_context: ScriptAttributesContext,
) -> Callable: ) -> Callable:
"""Yes - this is black magic. """Yes - this is black magic.
@ -70,8 +72,7 @@ class Script:
instance = subclass() instance = subclass()
return lambda *ar, **kw: subclass.run( return lambda *ar, **kw: subclass.run(
instance, instance,
task, script_attributes_context,
environment_identifier,
*ar, *ar,
**kw, **kw,
) )
@ -81,7 +82,7 @@ class Script:
for x in range(len(subclasses)): for x in range(len(subclasses)):
subclass = subclasses[x] subclass = subclasses[x]
execlist[subclass.__module__.split(".")[-1]] = make_closure( execlist[subclass.__module__.split(".")[-1]] = make_closure(
subclass, task=task, environment_identifier=environment_identifier subclass, script_attributes_context=script_attributes_context
) )
return execlist return execlist

View File

@ -73,6 +73,9 @@ from spiffworkflow_backend.models.message_instance import MessageModel
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus
from spiffworkflow_backend.models.process_model import ProcessModelInfo from spiffworkflow_backend.models.process_model import ProcessModelInfo
from spiffworkflow_backend.models.script_attributes_context import (
ScriptAttributesContext,
)
from spiffworkflow_backend.models.task_event import TaskAction from spiffworkflow_backend.models.task_event import TaskAction
from spiffworkflow_backend.models.task_event import TaskEventModel from spiffworkflow_backend.models.task_event import TaskEventModel
from spiffworkflow_backend.models.user import UserModel from spiffworkflow_backend.models.user import UserModel
@ -126,6 +129,10 @@ class PotentialOwnerUserNotFoundError(Exception):
"""PotentialOwnerUserNotFoundError.""" """PotentialOwnerUserNotFoundError."""
class MissingProcessInfoError(Exception):
"""MissingProcessInfoError."""
class CustomBpmnScriptEngine(PythonScriptEngine): # type: ignore class CustomBpmnScriptEngine(PythonScriptEngine): # type: ignore
"""This is a custom script processor that can be easily injected into Spiff Workflow. """This is a custom script processor that can be easily injected into Spiff Workflow.
@ -139,9 +146,26 @@ class CustomBpmnScriptEngine(PythonScriptEngine): # type: ignore
def __get_augment_methods(self, task: SpiffTask) -> Dict[str, Callable]: def __get_augment_methods(self, task: SpiffTask) -> Dict[str, Callable]:
"""__get_augment_methods.""" """__get_augment_methods."""
return Script.generate_augmented_list( tld = current_app.config["THREAD_LOCAL_DATA"]
task, current_app.config["ENV_IDENTIFIER"]
if not hasattr(tld, "process_model_identifier"):
raise MissingProcessInfoError(
"Could not find process_model_identifier from app config"
)
if not hasattr(tld, "process_instance_id"):
raise MissingProcessInfoError(
"Could not find process_instance_id from app config"
)
process_model_identifier = tld.process_model_identifier
process_instance_id = tld.process_instance_id
script_attributes_context = ScriptAttributesContext(
task=task,
environment_identifier=current_app.config["ENV_IDENTIFIER"],
process_instance_id=process_instance_id,
process_model_identifier=process_model_identifier,
) )
return Script.generate_augmented_list(script_attributes_context)
def evaluate(self, task: SpiffTask, expression: str) -> Any: def evaluate(self, task: SpiffTask, expression: str) -> Any:
"""Evaluate.""" """Evaluate."""
@ -254,6 +278,12 @@ class ProcessInstanceProcessor:
"THREAD_LOCAL_DATA" "THREAD_LOCAL_DATA"
].process_instance_id = process_instance_model.id ].process_instance_id = process_instance_model.id
# we want this to be the fully qualified path to the process model including all group subcomponents
current_app.config["THREAD_LOCAL_DATA"].process_model_identifier = (
f"{process_instance_model.process_group_identifier}/"
f"{process_instance_model.process_model_identifier}"
)
self.process_instance_model = process_instance_model self.process_instance_model = process_instance_model
self.process_model_service = ProcessModelService() self.process_model_service = ProcessModelService()
bpmn_process_spec = None bpmn_process_spec = None

View File

@ -4,6 +4,9 @@ import datetime
import pytz import pytz
from flask.app import Flask from flask.app import Flask
from flask.testing import FlaskClient from flask.testing import FlaskClient
from spiffworkflow_backend.models.script_attributes_context import (
ScriptAttributesContext,
)
from spiffworkflow_backend.scripts.get_localtime import GetLocaltime from spiffworkflow_backend.scripts.get_localtime import GetLocaltime
from spiffworkflow_backend.services.process_instance_processor import ( from spiffworkflow_backend.services.process_instance_processor import (
ProcessInstanceProcessor, ProcessInstanceProcessor,
@ -22,9 +25,16 @@ class TestGetLocaltime(BaseTest):
"""Test_get_localtime_script_directly.""" """Test_get_localtime_script_directly."""
current_time = datetime.datetime.now() current_time = datetime.datetime.now()
timezone = "US/Pacific" timezone = "US/Pacific"
result = GetLocaltime().run( process_model_identifier = "test_process_model"
process_instance_id = 1
script_attributes_context = ScriptAttributesContext(
task=None, task=None,
environment_identifier="testing", environment_identifier="testing",
process_instance_id=process_instance_id,
process_model_identifier=process_model_identifier,
)
result = GetLocaltime().run(
script_attributes_context,
datetime=current_time, datetime=current_time,
timezone=timezone, timezone=timezone,
) )

View File

@ -20,13 +20,14 @@ export default function TaskShow() {
HttpService.makeCallToBackend({ HttpService.makeCallToBackend({
path: `/tasks/${params.process_instance_id}/${params.task_id}`, path: `/tasks/${params.process_instance_id}/${params.task_id}`,
successCallback: setTask, successCallback: setTask,
failureCallback: setErrorMessage, // This causes the page to continuously reload
// failureCallback: setErrorMessage,
}); });
HttpService.makeCallToBackend({ HttpService.makeCallToBackend({
path: `/process-instance/${params.process_instance_id}/tasks`, path: `/process-instance/${params.process_instance_id}/tasks`,
successCallback: setUserTasks, successCallback: setUserTasks,
}); });
}, [params, setErrorMessage]); }, [params]);
const processSubmitResult = (result: any) => { const processSubmitResult = (result: any) => {
setErrorMessage(null); setErrorMessage(null);