diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/development.yml b/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/development.yml index 957a654c..ccb70abd 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/development.yml +++ b/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/development.yml @@ -21,7 +21,7 @@ groups: ] Finance Team: - users: [finance_user1] + users: [finance_user1, jason] Project Lead: users: diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/script_attributes_context.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/script_attributes_context.py new file mode 100644 index 00000000..6d250d33 --- /dev/null +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/script_attributes_context.py @@ -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 diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py index 18ad9e10..dda516ae 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py @@ -1,5 +1,4 @@ """APIs for dealing with process groups, process models, and process instances.""" -import dataclasses import json import os import random @@ -749,7 +748,6 @@ def process_instance_delete( """Create_process_instance.""" process_instance = find_process_instance_by_id_or_raise(process_instance_id) - # import pdb; pdb.set_trace() # (Pdb) db.session.delete # > db.session.delete(process_instance) @@ -1352,13 +1350,6 @@ def get_spiff_task_from_process_instance( task_uuid = uuid.UUID(task_id) 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: raise ( ApiError( diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/fact_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/fact_service.py index 387939ae..ee86a84a 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/fact_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/fact_service.py @@ -1,8 +1,9 @@ """Fact_service.""" 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 @@ -16,8 +17,7 @@ class FactService(Script): def run( self, - task: Optional[SpiffTask], - environment_identifier: str, + script_attributes_context: ScriptAttributesContext, *args: Any, **kwargs: Any ) -> Any: diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_env.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_env.py index 45b86179..cd586ae0 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_env.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_env.py @@ -1,8 +1,9 @@ """Get_env.""" 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 @@ -15,10 +16,9 @@ class GetEnv(Script): def run( self, - task: Optional[SpiffTask], - environment_identifier: str, + script_attributes_context: ScriptAttributesContext, *_args: Any, **kwargs: Any ) -> Any: """Run.""" - return environment_identifier + return script_attributes_context.environment_identifier diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_localtime.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_localtime.py index 019313da..16b9bf57 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_localtime.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_localtime.py @@ -1,11 +1,12 @@ """Get_localtime.""" from datetime import datetime from typing import Any -from typing import Optional import pytz 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 @@ -19,8 +20,7 @@ class GetLocaltime(Script): def run( self, - task: Optional[SpiffTask], - environment_identifier: str, + script_attributes_context: ScriptAttributesContext, *args: Any, **kwargs: Any ) -> datetime: diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_process_info.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_process_info.py new file mode 100644 index 00000000..bfd1e3dd --- /dev/null +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_process_info.py @@ -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, + } diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_user.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_user.py index db0561a4..f49e3fd8 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_user.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_user.py @@ -1,9 +1,10 @@ """Get_env.""" from typing import Any -from typing import Optional 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 @@ -16,8 +17,7 @@ class GetUser(Script): def run( self, - task: Optional[SpiffTask], - environment_identifier: str, + script_attributes_context: ScriptAttributesContext, *_args: Any, **kwargs: Any ) -> Any: diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/script.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/script.py index f36e4ace..7ed745d6 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/script.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/script.py @@ -9,7 +9,9 @@ from typing import Any from typing import Callable 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. # This is here, because after loading the application this will never change under @@ -28,8 +30,7 @@ class Script: @abstractmethod def run( self, - task: SpiffTask, - environment_identifier: str, + script_attributes_context: ScriptAttributesContext, *args: Any, **kwargs: Any, ) -> Any: @@ -43,7 +44,7 @@ class Script: @staticmethod def generate_augmented_list( - task: SpiffTask, environment_identifier: str + script_attributes_context: ScriptAttributesContext, ) -> dict[str, Callable]: """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( - subclass: type[Script], task: SpiffTask, environment_identifier: str + subclass: type[Script], + script_attributes_context: ScriptAttributesContext, ) -> Callable: """Yes - this is black magic. @@ -70,8 +72,7 @@ class Script: instance = subclass() return lambda *ar, **kw: subclass.run( instance, - task, - environment_identifier, + script_attributes_context, *ar, **kw, ) @@ -81,7 +82,7 @@ class Script: for x in range(len(subclasses)): subclass = subclasses[x] execlist[subclass.__module__.split(".")[-1]] = make_closure( - subclass, task=task, environment_identifier=environment_identifier + subclass, script_attributes_context=script_attributes_context ) return execlist diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 3c49ec7c..af378a38 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -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 ProcessInstanceStatus 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 TaskEventModel from spiffworkflow_backend.models.user import UserModel @@ -126,6 +129,10 @@ class PotentialOwnerUserNotFoundError(Exception): """PotentialOwnerUserNotFoundError.""" +class MissingProcessInfoError(Exception): + """MissingProcessInfoError.""" + + class CustomBpmnScriptEngine(PythonScriptEngine): # type: ignore """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]: """__get_augment_methods.""" - return Script.generate_augmented_list( - task, current_app.config["ENV_IDENTIFIER"] + tld = current_app.config["THREAD_LOCAL_DATA"] + + 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: """Evaluate.""" @@ -254,6 +278,12 @@ class ProcessInstanceProcessor: "THREAD_LOCAL_DATA" ].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_model_service = ProcessModelService() bpmn_process_spec = None diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_localtime.py b/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_localtime.py index cb81ce61..a6eb4f12 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_localtime.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_localtime.py @@ -4,6 +4,9 @@ import datetime import pytz from flask.app import Flask 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.services.process_instance_processor import ( ProcessInstanceProcessor, @@ -22,9 +25,16 @@ class TestGetLocaltime(BaseTest): """Test_get_localtime_script_directly.""" current_time = datetime.datetime.now() timezone = "US/Pacific" - result = GetLocaltime().run( + process_model_identifier = "test_process_model" + process_instance_id = 1 + script_attributes_context = ScriptAttributesContext( task=None, environment_identifier="testing", + process_instance_id=process_instance_id, + process_model_identifier=process_model_identifier, + ) + result = GetLocaltime().run( + script_attributes_context, datetime=current_time, timezone=timezone, ) diff --git a/spiffworkflow-frontend/src/routes/TaskShow.tsx b/spiffworkflow-frontend/src/routes/TaskShow.tsx index 2f1dfd53..28fc8582 100644 --- a/spiffworkflow-frontend/src/routes/TaskShow.tsx +++ b/spiffworkflow-frontend/src/routes/TaskShow.tsx @@ -20,13 +20,14 @@ export default function TaskShow() { HttpService.makeCallToBackend({ path: `/tasks/${params.process_instance_id}/${params.task_id}`, successCallback: setTask, - failureCallback: setErrorMessage, + // This causes the page to continuously reload + // failureCallback: setErrorMessage, }); HttpService.makeCallToBackend({ path: `/process-instance/${params.process_instance_id}/tasks`, successCallback: setUserTasks, }); - }, [params, setErrorMessage]); + }, [params]); const processSubmitResult = (result: any) => { setErrorMessage(null);