From fa34bee18a892a53b683995c58c2a027c7db3105 Mon Sep 17 00:00:00 2001 From: mike cullerton Date: Thu, 4 Feb 2021 11:23:05 -0500 Subject: [PATCH] First commit for cleaning up error messages for customers. This is *not* in a working state. Committing this so I can work on another ticket. --- crc/api/workflow.py | 12 +- crc/services/error_service.py | 43 ++++++ .../failing_gateway_workflow.bpmn | 133 ++++++++++++++++++ .../workflow/test_workflow_customer_error.py | 14 ++ 4 files changed, 197 insertions(+), 5 deletions(-) create mode 100644 crc/services/error_service.py create mode 100644 tests/data/failing_gateway_workflow/failing_gateway_workflow.bpmn create mode 100644 tests/workflow/test_workflow_customer_error.py diff --git a/crc/api/workflow.py b/crc/api/workflow.py index d9a0b498..e512f5bb 100644 --- a/crc/api/workflow.py +++ b/crc/api/workflow.py @@ -10,6 +10,7 @@ from crc.models.study import StudyModel, WorkflowMetadata from crc.models.task_event import TaskEventModel, TaskEvent, TaskEventSchema from crc.models.workflow import WorkflowModel, WorkflowSpecModelSchema, WorkflowSpecModel, WorkflowSpecCategoryModel, \ WorkflowSpecCategoryModelSchema +from crc.services.error_service import ValidationErrorService from crc.services.file_service import FileService from crc.services.lookup_service import LookupService from crc.services.study_service import StudyService @@ -47,15 +48,16 @@ def validate_workflow_specification(spec_id): try: WorkflowService.test_spec(spec_id) except ApiError as ae: - ae.message = "When populating all fields ... " + ae.message - errors.append(ae) + # ae.message = "When populating all fields ... \n" + ae.message + errors.append(('all', ae)) try: # Run the validation twice, the second time, just populate the required fields. WorkflowService.test_spec(spec_id, required_only=True) except ApiError as ae: - ae.message = "When populating only required fields ... " + ae.message - errors.append(ae) - return ApiErrorSchema(many=True).dump(errors) + # ae.message = "When populating only required fields ... \n" + ae.message + errors.append(('required', ae)) + interpreted_errors = ValidationErrorService.interpret_validation_errors(errors) + return ApiErrorSchema(many=True).dump(interpreted_errors) def update_workflow_specification(spec_id, body): diff --git a/crc/services/error_service.py b/crc/services/error_service.py new file mode 100644 index 00000000..85733428 --- /dev/null +++ b/crc/services/error_service.py @@ -0,0 +1,43 @@ +# known_errors +# key - something we can search for in an error message. +# both_message - human readable message return to the user if error occurs in both +# required_message - human readable message return to the user if error only occurs in required +# all_message -human readable message return to the user if error only occurs in all +# +known_errors = [{'key': 'Error is Non-default exclusive outgoing sequence flow without condition', + 'message': 'Missing condition'}] +generic_message = """Workflow validation failed. For more information about the error, see below.""" + +class ValidationErrorService(object): + + """Validation Error Service interprets messages return from api.workflow.validate_workflow_specification + Validation is run twice, + once where we try to fill in all form fields + and a second time where we only fill in the required fields. + + We get a list that contains possible errors from the validation.""" + + @staticmethod + def interpret_validation_errors(errors): + if len(errors) == 0: + return errors + hint = '' + for known_error in known_errors: + if known_error['key'] in errors[0].message: + + # in both error 0 and error 1 + if known_error['key'] in errors[1].message: + if 'both_hint' in known_error.keys(): + hint = known_error['both_hint'] + if 'both_message' in known_error.keys(): + message = known_error['both_message'] + + # just in error 0 + else: + pass + + # just in error 1 + if known_error['key'] in errors[1].message: + pass + + return errors diff --git a/tests/data/failing_gateway_workflow/failing_gateway_workflow.bpmn b/tests/data/failing_gateway_workflow/failing_gateway_workflow.bpmn new file mode 100644 index 00000000..833a92e8 --- /dev/null +++ b/tests/data/failing_gateway_workflow/failing_gateway_workflow.bpmn @@ -0,0 +1,133 @@ + + + + + Flow_065zdx1 + + + + + Flow_0xguxj8 + Flow_False + Flow_True + + + + + Flow_0enbio6 + + + + <H1>Hello</H1> + Flow_065zdx1 + Flow_067y7wi + + + Flow_067y7wi + Flow_10wcmiq + if not 'yes_no' in globals(): + yes_no = True + + + <H1>Good Bye</H1> +{% if select_one %} +<div></span>{{ name.value }}</span></div> +{% endif %} + Flow_False + Flow_0fldafi + Flow_0enbio6 + + + + + + + + Flow_True + Flow_0fldafi + + + + + + + + + + + + + + Flow_10wcmiq + Flow_0xguxj8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/workflow/test_workflow_customer_error.py b/tests/workflow/test_workflow_customer_error.py new file mode 100644 index 00000000..5a9765b8 --- /dev/null +++ b/tests/workflow/test_workflow_customer_error.py @@ -0,0 +1,14 @@ +from tests.base_test import BaseTest +import json + +class TestCustomerError(BaseTest): + + def test_customer_error(self): + # workflow = self.create_workflow('failing_workflow') + # workflow_api = self.get_workflow_api(workflow) + # first_task = workflow_api.next_task + spec_model = self.load_test_spec('failing_gateway_workflow') + rv = self.app.get('/v1.0/workflow-specification/%s/validate' % spec_model.id, headers=self.logged_in_headers()) + json_data = json.loads(rv.get_data(as_text=True)) + # + print('test_customer_error: ')