diff --git a/crc/scripts/study_info.py b/crc/scripts/study_info.py index 90bbd866..af0c4d55 100644 --- a/crc/scripts/study_info.py +++ b/crc/scripts/study_info.py @@ -80,7 +80,12 @@ class StudyInfo(Script): 'display': 'Optional', 'unique': 'Yes', 'user_id': 'asd3v', - 'error': 'Unable to locate a user with id asd3v in LDAP'} + 'error': 'Unable to locate a user with id asd3v in LDAP'}, + 'DEPT_CH': { + 'label': 'Department Chair', + 'display': 'Always', + 'unique': 'Yes', + 'user_id': 'lb3dp'} }, "documents": { 'AD_CoCApp': {'category1': 'Ancillary Document', 'category2': 'CoC Application', 'category3': '', diff --git a/crc/services/workflow_service.py b/crc/services/workflow_service.py index cc73e383..edabd433 100644 --- a/crc/services/workflow_service.py +++ b/crc/services/workflow_service.py @@ -95,31 +95,38 @@ class WorkflowService(object): WorkflowService.delete_test_data() raise ApiError.from_workflow_exception("workflow_validation_exception", str(we), we) + count = 0 while not processor.bpmn_workflow.is_completed(): - try: - processor.bpmn_workflow.get_deep_nav_list() # Assure no errors with navigation. - processor.bpmn_workflow.do_engine_steps() - tasks = processor.bpmn_workflow.get_tasks(SpiffTask.READY) - for task in tasks: - if task.task_spec.lane is not None and task.task_spec.lane not in task.data: - raise ApiError.from_task("invalid_role", - f"This task is in a lane called '{task.task_spec.lane}', The " - f" current task data must have information mapping this role to " - f" a unique user id.", task) - task_api = WorkflowService.spiff_task_to_api_task( - task, - add_docs_and_forms=True) # Assure we try to process the documentation, and raise those errors. - # make sure forms have a form key - if hasattr(task_api, 'form') and task_api.form is not None and task_api.form.key == '': - raise ApiError(code='missing_form_key', - message='Forms must include a Form Key.', - task_id=task.id, - task_name=task.get_name()) - WorkflowService.populate_form_with_random_data(task, task_api, required_only) - processor.complete_task(task) - except WorkflowException as we: - WorkflowService.delete_test_data() - raise ApiError.from_workflow_exception("workflow_validation_exception", str(we), we) + if count < 100: # check for infinite loop + try: + processor.bpmn_workflow.get_deep_nav_list() # Assure no errors with navigation. + processor.bpmn_workflow.do_engine_steps() + tasks = processor.bpmn_workflow.get_tasks(SpiffTask.READY) + for task in tasks: + if task.task_spec.lane is not None and task.task_spec.lane not in task.data: + raise ApiError.from_task("invalid_role", + f"This task is in a lane called '{task.task_spec.lane}', The " + f" current task data must have information mapping this role to " + f" a unique user id.", task) + task_api = WorkflowService.spiff_task_to_api_task( + task, + add_docs_and_forms=True) # Assure we try to process the documentation, and raise those errors. + # make sure forms have a form key + if hasattr(task_api, 'form') and task_api.form is not None and task_api.form.key == '': + raise ApiError(code='missing_form_key', + message='Forms must include a Form Key.', + task_id=task.id, + task_name=task.get_name()) + WorkflowService.populate_form_with_random_data(task, task_api, required_only) + processor.complete_task(task) + count += 1 + except WorkflowException as we: + WorkflowService.delete_test_data() + raise ApiError.from_workflow_exception("workflow_validation_exception", str(we), we) + else: + raise ApiError.from_task(code='validation_loop', + message=f'There appears to be an infinite loop in the validation. Task is {task.task_spec.description}', + task=task) WorkflowService.delete_test_data() WorkflowService._process_documentation(processor.bpmn_workflow.last_task.parent.parent) diff --git a/crc/templates/mail_main_template.html b/crc/templates/mail_main_template.html index c8841ddc..b9f9ac7e 100644 --- a/crc/templates/mail_main_template.html +++ b/crc/templates/mail_main_template.html @@ -89,6 +89,10 @@ padding-top: 10px; } + td#logo-td { + width: 50px; + } + .footer, .header { clear: both; margin-top: 10px; @@ -361,7 +365,7 @@ -
+ diff --git a/deploy/requirements.txt b/deploy/requirements.txt index 8cca38b5..f20a4a5c 100644 --- a/deploy/requirements.txt +++ b/deploy/requirements.txt @@ -37,7 +37,7 @@ jdcal==1.4.1 jinja2==2.11.3 jsonschema==3.2.0 ldap3==2.8.1 -lxml==4.6.2 +lxml==4.6.3 mako==1.1.3 markdown==3.3.3 markupsafe==1.1.1 diff --git a/tests/data/infinite_loop/infinite_loop.bpmn b/tests/data/infinite_loop/infinite_loop.bpmn new file mode 100644 index 00000000..7fb41c13 --- /dev/null +++ b/tests/data/infinite_loop/infinite_loop.bpmn @@ -0,0 +1,97 @@ + + + + + Flow_0ldlhrt + + + + Flow_0ldlhrt + Flow_05mrx8v + Flow_0pddur1 + investigators = study_info('investigators') + + + + Investigators: {{ investigators }} + Flow_0pddur1 + Flow_03m3cuy + + + Flow_03m3cuy + Flow_05mrx8v + Flow_1212fe2 + + + + + hasattr(investigators, 'DEPT_CH') + + + Flow_14jn215 + + + + # Thank You + Flow_1212fe2 + Flow_14jn215 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/workflow/test_workflow_infinite_loop.py b/tests/workflow/test_workflow_infinite_loop.py new file mode 100644 index 00000000..a9846084 --- /dev/null +++ b/tests/workflow/test_workflow_infinite_loop.py @@ -0,0 +1,13 @@ +from tests.base_test import BaseTest +from crc import app +import json + + +class TestWorkflowInfiniteLoop(BaseTest): + + def test_workflow_infinite_loop(self): + self.load_example_data() + spec_model = self.load_test_spec('infinite_loop') + 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)) + self.assertIn('There appears to be an infinite loop', json_data[0]['message'])