attempt to save again if deadlock given for draft data save w/ burnettk (#410)
Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
parent
58cc0d9c14
commit
148bf386e3
|
@ -14,6 +14,7 @@ from flask import jsonify
|
||||||
from flask import make_response
|
from flask import make_response
|
||||||
from flask import stream_with_context
|
from flask import stream_with_context
|
||||||
from flask.wrappers import Response
|
from flask.wrappers import Response
|
||||||
|
from MySQLdb import OperationalError # type: ignore
|
||||||
from SpiffWorkflow.bpmn.exceptions import WorkflowTaskException # type: ignore
|
from SpiffWorkflow.bpmn.exceptions import WorkflowTaskException # type: ignore
|
||||||
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow # type: ignore
|
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow # type: ignore
|
||||||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||||
|
@ -586,13 +587,21 @@ def task_save_draft(
|
||||||
principal = _find_principal_or_raise()
|
principal = _find_principal_or_raise()
|
||||||
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||||
if not process_instance.can_submit_task():
|
if not process_instance.can_submit_task():
|
||||||
raise ApiError(
|
return Response(
|
||||||
error_code="process_instance_not_runnable",
|
json.dumps(
|
||||||
message=(
|
{
|
||||||
|
"ok": True,
|
||||||
|
"saved": False,
|
||||||
|
"message": (
|
||||||
f"Process Instance ({process_instance.id}) has status "
|
f"Process Instance ({process_instance.id}) has status "
|
||||||
f"{process_instance.status} which does not allow draft data to be saved."
|
f"{process_instance.status} which does not allow draft data to be saved."
|
||||||
),
|
),
|
||||||
status_code=400,
|
"process_model_identifier": process_instance.process_model_identifier,
|
||||||
|
"process_instance_id": process_instance_id,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
status=200,
|
||||||
|
mimetype="application/json",
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -610,12 +619,30 @@ def task_save_draft(
|
||||||
if json_data_dict is not None:
|
if json_data_dict is not None:
|
||||||
JsonDataModel.insert_or_update_json_data_dict(json_data_dict)
|
JsonDataModel.insert_or_update_json_data_dict(json_data_dict)
|
||||||
db.session.add(task_draft_data)
|
db.session.add(task_draft_data)
|
||||||
|
try:
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
except OperationalError as exception:
|
||||||
|
db.session.rollback()
|
||||||
|
if "Deadlock" in str(exception):
|
||||||
|
task_draft_data = TaskService.task_draft_data_from_task_model(task_model)
|
||||||
|
# if we do not find a task_draft_data record, that means it was deleted when the form was submitted
|
||||||
|
# and we therefore have no need to save draft data
|
||||||
|
if task_draft_data is not None:
|
||||||
|
json_data_dict = TaskService.update_task_data_on_task_model_and_return_dict_if_updated(
|
||||||
|
task_draft_data, body, "saved_form_data_hash"
|
||||||
|
)
|
||||||
|
if json_data_dict is not None:
|
||||||
|
JsonDataModel.insert_or_update_json_data_dict(json_data_dict)
|
||||||
|
db.session.add(task_draft_data)
|
||||||
|
db.session.commit()
|
||||||
|
else:
|
||||||
|
raise exception
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
json.dumps(
|
json.dumps(
|
||||||
{
|
{
|
||||||
"ok": True,
|
"ok": True,
|
||||||
|
"saved": True,
|
||||||
"process_model_identifier": process_instance.process_model_identifier,
|
"process_model_identifier": process_instance.process_model_identifier,
|
||||||
"process_instance_id": process_instance_id,
|
"process_instance_id": process_instance_id,
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ import {
|
||||||
modifyProcessIdentifierForPathParam,
|
modifyProcessIdentifierForPathParam,
|
||||||
recursivelyChangeNullAndUndefined,
|
recursivelyChangeNullAndUndefined,
|
||||||
} from '../helpers';
|
} from '../helpers';
|
||||||
import { ErrorForDisplay, EventDefinition, Task } from '../interfaces';
|
import { EventDefinition, Task } from '../interfaces';
|
||||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||||
import InstructionsForEndUser from '../components/InstructionsForEndUser';
|
import InstructionsForEndUser from '../components/InstructionsForEndUser';
|
||||||
import TypeaheadWidget from '../rjsf/custom_widgets/TypeaheadWidget/TypeaheadWidget';
|
import TypeaheadWidget from '../rjsf/custom_widgets/TypeaheadWidget/TypeaheadWidget';
|
||||||
|
@ -77,17 +77,6 @@ export default function TaskShow() {
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [params]);
|
}, [params]);
|
||||||
|
|
||||||
const handleAutoSaveError = (error: ErrorForDisplay) => {
|
|
||||||
if (
|
|
||||||
error.error_code &&
|
|
||||||
error.error_code === 'process_instance_not_runnable'
|
|
||||||
) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
addError(error);
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Before we auto-saved form data, we remembered what data was in the form, and then created a synthetic submit event
|
// Before we auto-saved form data, we remembered what data was in the form, and then created a synthetic submit event
|
||||||
// in order to implement a "Save and close" button. That button no longer saves (since we have auto-save), but the crazy
|
// in order to implement a "Save and close" button. That button no longer saves (since we have auto-save), but the crazy
|
||||||
// frontend code to support that Save and close button is here, in case we need to reference that someday:
|
// frontend code to support that Save and close button is here, in case we need to reference that someday:
|
||||||
|
@ -106,7 +95,6 @@ export default function TaskShow() {
|
||||||
postBody: formData,
|
postBody: formData,
|
||||||
httpMethod: 'POST',
|
httpMethod: 'POST',
|
||||||
successCallback: successCallbackToUse,
|
successCallback: successCallbackToUse,
|
||||||
failureCallback: handleAutoSaveError,
|
|
||||||
});
|
});
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue