Fix process data get subprocess (#1493) (#1514)

* added test to make sure we can get the data object of a sub process

* avoid the processor altogether to get data objects but use the db directly

---------

Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
jasquat 2024-05-07 21:11:17 +00:00 committed by GitHub
parent d86f3958f8
commit a7370cd293
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 74 additions and 29 deletions

View File

@ -3,7 +3,6 @@ import os
import uuid import uuid
from typing import Any from typing import Any
from typing import TypedDict from typing import TypedDict
from uuid import UUID
import flask.wrappers import flask.wrappers
import sentry_sdk import sentry_sdk
@ -30,9 +29,11 @@ from spiffworkflow_backend.exceptions.error import HumanTaskAlreadyCompletedErro
from spiffworkflow_backend.exceptions.error import HumanTaskNotFoundError from spiffworkflow_backend.exceptions.error import HumanTaskNotFoundError
from spiffworkflow_backend.exceptions.error import UserDoesNotHaveAccessToTaskError from spiffworkflow_backend.exceptions.error import UserDoesNotHaveAccessToTaskError
from spiffworkflow_backend.exceptions.process_entity_not_found_error import ProcessEntityNotFoundError from spiffworkflow_backend.exceptions.process_entity_not_found_error import ProcessEntityNotFoundError
from spiffworkflow_backend.models.bpmn_process import BpmnProcessModel
from spiffworkflow_backend.models.db import db from spiffworkflow_backend.models.db import db
from spiffworkflow_backend.models.human_task import HumanTaskModel from spiffworkflow_backend.models.human_task import HumanTaskModel
from spiffworkflow_backend.models.human_task_user import HumanTaskUserModel from spiffworkflow_backend.models.human_task_user import HumanTaskUserModel
from spiffworkflow_backend.models.json_data import JsonDataModel
from spiffworkflow_backend.models.principal import PrincipalModel from spiffworkflow_backend.models.principal import PrincipalModel
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
@ -135,43 +136,35 @@ def _process_data_fetcher(
bpmn_process_guid: str | None = None, bpmn_process_guid: str | None = None,
process_identifier: str | None = None, process_identifier: str | None = None,
) -> flask.wrappers.Response: ) -> flask.wrappers.Response:
if process_identifier and bpmn_process_guid is None:
raise ApiError(
error_code="missing_required_parameter",
message="process_identifier was given but bpmn_process_guid was not. Both must be provided if either is required.",
status_code=404,
)
if process_identifier is None and bpmn_process_guid:
raise ApiError(
error_code="missing_required_parameter",
message="bpmn_process_guid was given but process_identifier was not. Both must be provided if either is required.",
status_code=404,
)
process_instance = _find_process_instance_by_id_or_raise(process_instance_id) process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
processor = ProcessInstanceProcessor(process_instance) if bpmn_process_guid is not None:
bpmn_process = BpmnProcessModel.query.filter_by(guid=bpmn_process_guid).first()
else:
bpmn_process = process_instance.bpmn_process
if bpmn_process is None:
raise ApiError(
error_code="bpmn_process_not_found",
message=f"Cannot find a bpmn process with guid '{bpmn_process_guid}' for process instance {process_instance.id}",
status_code=404,
)
bpmn_process_instance = processor.bpmn_process_instance bpmn_process_data = JsonDataModel.find_data_dict_by_hash(bpmn_process.json_data_hash)
bpmn_process_data = processor.get_data() if bpmn_process_data is None:
if process_identifier and bpmn_process_instance.spec.name != process_identifier: raise ApiError(
bpmn_process_instance = processor.bpmn_process_instance.subprocesses.get(UUID(bpmn_process_guid)) error_code="bpmn_process_data_not_found",
if bpmn_process_instance is None: message=f"Cannot find a bpmn process data with guid '{bpmn_process_guid}' for process instance {process_instance.id}",
raise ApiError( status_code=404,
error_code="bpmn_process_not_found", )
message=f"Cannot find a bpmn process with guid '{bpmn_process_guid}' for process instance {process_instance.id}",
status_code=404,
)
bpmn_process_data = bpmn_process_instance.data
data_objects = bpmn_process_instance.spec.data_objects data_objects = bpmn_process_data["data_objects"]
data_object = data_objects.get(process_data_identifier) data_object = data_objects.get(process_data_identifier)
if data_object is None: if data_object is None:
raise ApiError( raise ApiError(
error_code="data_object_not_found", error_code="data_object_not_found",
message=( message=(
f"Cannot find a data object with identifier '{process_data_identifier}' for bpmn process '{process_identifier}'" f"Cannot find a data object with identifier '{process_data_identifier}' for bpmn process"
f" in process instance {process_instance.id}" f" '{bpmn_process.bpmn_process_definition.bpmn_identifier}' in process instance {process_instance.id}"
), ),
status_code=404, status_code=404,
) )

View File

@ -5,6 +5,7 @@ import os
import time import time
from hashlib import sha256 from hashlib import sha256
from typing import Any from typing import Any
from unittest.mock import patch
import flask import flask
import pytest import pytest
@ -12,6 +13,8 @@ from flask.app import Flask
from flask.testing import FlaskClient from flask.testing import FlaskClient
from SpiffWorkflow.util.task import TaskState # type: ignore from SpiffWorkflow.util.task import TaskState # type: ignore
from spiffworkflow_backend.exceptions.process_entity_not_found_error import ProcessEntityNotFoundError from spiffworkflow_backend.exceptions.process_entity_not_found_error import ProcessEntityNotFoundError
from spiffworkflow_backend.models.bpmn_process import BpmnProcessModel
from spiffworkflow_backend.models.bpmn_process_definition import BpmnProcessDefinitionModel
from spiffworkflow_backend.models.db import db from spiffworkflow_backend.models.db import db
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
@ -3323,6 +3326,55 @@ class TestProcessApi(BaseTest):
assert response.json is not None assert response.json is not None
assert response.json["process_data_value"] == "hey" assert response.json["process_data_value"] == "hey"
def test_process_data_show_with_sub_process(
self,
app: Flask,
client: FlaskClient,
with_db_and_bpmn_file_cleanup: None,
with_super_admin_user: UserModel,
) -> None:
process_model = load_test_spec(
"test_group/with-service-task-call-activity-sub-process",
process_model_source_directory="with-service-task-call-activity-sub-process",
)
process_instance_one = self.create_process_instance_from_process_model(process_model)
processor = ProcessInstanceProcessor(process_instance_one)
connector_response = {
"body": '{"ok": true}',
"mimetype": "application/json",
"http_status": 200,
"operator_identifier": "http/GetRequestV2",
}
with patch("requests.post") as mock_post:
mock_post.return_value.status_code = 200
mock_post.return_value.ok = True
mock_post.return_value.text = json.dumps(connector_response)
processor.do_engine_steps(save=True)
self.complete_next_manual_task(processor, execution_mode="synchronous")
self.complete_next_manual_task(processor, execution_mode="synchronous", data={"firstName": "Chuck"})
assert process_instance_one.status == "complete"
process_identifier = "call_activity_sub_process"
bpmn_processes = (
BpmnProcessModel.query.join(
BpmnProcessDefinitionModel, BpmnProcessDefinitionModel.id == BpmnProcessModel.bpmn_process_definition_id
)
.filter(BpmnProcessDefinitionModel.bpmn_identifier == process_identifier)
.all()
)
assert len(bpmn_processes) == 1
bpmn_process = bpmn_processes[0]
response = client.get(
f"/v1.0/process-data/default/{self.modify_process_identifier_for_path_param(process_model.id)}/sub_level_data_object_three/"
f"{process_instance_one.id}?process_identifier={process_identifier}&bpmn_process_guid={bpmn_process.guid}",
headers=self.logged_in_headers(with_super_admin_user),
)
assert response.status_code == 200
assert response.json is not None
assert response.json["process_data_value"] == "d"
def _setup_testing_instance( def _setup_testing_instance(
self, self,
client: FlaskClient, client: FlaskClient,