Squashed 'spiffworkflow-backend/' changes from 1e338f955..153061d41

153061d41 Merge branch 'main' of github.com:sartography/spiffworkflow-backend into main
3724ef7f9 Assure that the Active Task Users table is cleared out before deleting the Active Task Record. We were depending on a cascade here, which seems to fail randomly -- apparently due to some sort of race condition.
137ebbc4b Merge branch 'main' of github.com:sartography/spiffworkflow-backend
f8f38f813 pyl - prettier maybe?
02fe90969 Merge branch 'main' into feature/edit-task-data
ca7d7d9b3 Merge branch 'main' into feature/edit-task-data
c38efe2bd w/Jon Api endpoint to update task data
15b99bf90 mypy

git-subtree-dir: spiffworkflow-backend
git-subtree-split: 153061d413afc5d7ed0c9cec25b292393585f757
This commit is contained in:
Jon Herron 2022-10-25 14:20:02 -04:00
parent eff49e1ddb
commit 999e0f4d2b
6 changed files with 123 additions and 2 deletions

View File

@ -469,6 +469,33 @@ paths:
items: items:
$ref: "#/components/schemas/Workflow" $ref: "#/components/schemas/Workflow"
/process-instances/{process_instance_id}/task/{task_id}/update:
parameters:
- name: process_instance_id
in: path
required: true
description: The unique id of the process instance
schema:
type: string
- name: task_id
in: path
required: true
description: The unique id of the task
schema:
type: string
post:
operationId: spiffworkflow_backend.routes.process_api_blueprint.update_task_data
summary: Update the task data for requested instance and task
tags:
- Process Instances
responses:
"200":
description: Task Updated Successfully
content:
application/json:
schema:
$ref: "#/components/schemas/Workflow"
/process-models/{process_group_id}/{process_model_id}/script-unit-tests: /process-models/{process_group_id}/{process_model_id}/script-unit-tests:
parameters: parameters:
- name: process_group_id - name: process_group_id

View File

@ -1493,3 +1493,44 @@ def _update_form_schema_with_task_data_as_needed(
for o in value: for o in value:
if isinstance(o, dict): if isinstance(o, dict):
_update_form_schema_with_task_data_as_needed(o, task_data) _update_form_schema_with_task_data_as_needed(o, task_data)
def update_task_data(process_instance_id: str, task_id: str, body: Dict) -> Response:
"""Update task data."""
process_instance = ProcessInstanceModel.query.filter(
ProcessInstanceModel.id == int(process_instance_id)
).first()
if process_instance:
process_instance_bpmn_json_dict = json.loads(process_instance.bpmn_json)
if "new_task_data" in body:
new_task_data_str: str = body["new_task_data"]
new_task_data_dict = json.loads(new_task_data_str)
if task_id in process_instance_bpmn_json_dict["tasks"]:
process_instance_bpmn_json_dict["tasks"][task_id][
"data"
] = new_task_data_dict
process_instance.bpmn_json = json.dumps(process_instance_bpmn_json_dict)
db.session.add(process_instance)
try:
db.session.commit()
except Exception as e:
db.session.rollback()
raise ApiError(
error_code="update_task_data_error",
message=f"Could not update the Instance. Original error is {e}",
) from e
else:
raise ApiError(
error_code="update_task_data_error",
message=f"Could not find Task: {task_id} in Instance: {process_instance_id}.",
)
else:
raise ApiError(
error_code="update_task_data_error",
message=f"Could not update task data for Instance: {process_instance_id}, and Task: {task_id}.",
)
return Response(
json.dumps(ProcessInstanceModelSchema().dump(process_instance)),
status=200,
mimetype="application/json",
)

View File

@ -522,6 +522,10 @@ class ProcessInstanceProcessor:
).all() ).all()
if len(active_tasks) > 0: if len(active_tasks) > 0:
for at in active_tasks: for at in active_tasks:
active_task_users = at.active_task_users
for atu in active_task_users:
# don't trust sqlalchemy to cascade - ran into race condition here.
db.session.delete(atu)
db.session.delete(at) db.session.delete(at)
db.session.add(self.process_instance_model) db.session.add(self.process_instance_model)

View File

@ -55,7 +55,7 @@ class SecretService:
def get_secret(key: str) -> SecretModel: def get_secret(key: str) -> SecretModel:
"""Get_secret.""" """Get_secret."""
secret = db.session.query(SecretModel).filter(SecretModel.key == key).first() secret = db.session.query(SecretModel).filter(SecretModel.key == key).first()
if secret is not None: if isinstance(secret, SecretModel):
return secret return secret
else: else:
raise ApiError( raise ApiError(

View File

@ -264,7 +264,7 @@ class UserService:
.filter(PrincipalModel.user_id == user_id) .filter(PrincipalModel.user_id == user_id)
.first() .first()
) )
if principal: if isinstance(principal, PrincipalModel):
return principal return principal
raise ApiError( raise ApiError(
error_code="no_principal_found", error_code="no_principal_found",

View File

@ -0,0 +1,49 @@
"""Process Model."""
from decimal import Decimal
from flask.app import Flask
from flask_bpmn.models.db import db
from spiffworkflow_backend.models.active_task import ActiveTaskModel
from spiffworkflow_backend.models.active_task_user import ActiveTaskUserModel
from spiffworkflow_backend.services.process_instance_processor import ProcessInstanceProcessor
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel
class TestActiveTask(BaseTest):
def test_can_create_and_delete_an_active_task (
self, app: Flask, with_db_and_bpmn_file_cleanup: None
) -> None:
process_model = load_test_spec(
"call_activity_test",
process_model_source_directory="call_activity_same_directory",
)
process_instance = self.create_process_instance_from_process_model(
process_model
)
active_task = ActiveTaskModel(
process_instance_id=process_instance.id,
process_model_display_name="my shorts",
form_file_name="my_file_name",
ui_form_file_name="",
task_id="1234",
task_name="any old thing",
task_title="",
task_type="test type",
task_status="WAITING",
lane_assignment_id=None,
)
initiator_user = self.find_or_create_user("initiator_user")
db.session.add(active_task)
db.session.commit()
active_task_user = ActiveTaskUserModel(active_task_id=active_task.id, user_id=initiator_user.id)
db.session.add(active_task_user)
db.session.commit()
processor = ProcessInstanceProcessor(process_instance)
processor.save() # This should clear out all active tasks and active task users.
assert(len(db.session.query(ActiveTaskModel).all()) == 0)