diff --git a/crc/scripts/study_info.py b/crc/scripts/study_info.py
index e336685d..94e35249 100644
--- a/crc/scripts/study_info.py
+++ b/crc/scripts/study_info.py
@@ -14,7 +14,7 @@ class StudyInfo(Script):
"""Please see the detailed description that is provided below. """
pb = ProtocolBuilderService()
- type_options = ['info', 'investigators', 'details', 'approvals', 'documents', 'protocol']
+ type_options = ['info', 'investigators', 'roles', 'details', 'approvals', 'documents', 'protocol']
# This is used for test/workflow validation, as well as documentation.
example_data = {
@@ -106,11 +106,20 @@ Returns the basic information such as the id and title
### Investigators ###
Returns detailed information about related personnel.
The order returned is guaranteed to match the order provided in the investigators.xslx reference file.
-If possible, detailed information is added in from LDAP about each personnel based on their user_id.
+Detailed information is added in from LDAP about each personnel based on their user_id.
```
{investigators_example}
```
+### Investigator Roles ###
+Returns a list of all investigator roles, populating any roles with additional information available from
+the Protocol Builder and LDAP. Its basically just like Investigators, but it includes all the roles, rather
+that just those that were set in Protocol Builder.
+```
+{investigators_example}
+```
+
+
### Details ###
Returns detailed information about variable keys read in from the Protocol Builder.
@@ -161,6 +170,12 @@ Returns information specific to the protocol.
"INVESTIGATORTYPEFULL": "Primary Investigator",
"NETBADGEID": "dhf8r"
},
+ "roles":
+ {
+ "INVESTIGATORTYPE": "PI",
+ "INVESTIGATORTYPEFULL": "Primary Investigator",
+ "NETBADGEID": "dhf8r"
+ },
"details":
{
"IS_IND": 0,
@@ -198,6 +213,8 @@ Returns information specific to the protocol.
self.add_data_to_task(task, {cmd: schema.dump(study)})
if cmd == 'investigators':
self.add_data_to_task(task, {cmd: StudyService().get_investigators(study_id)})
+ if cmd == 'roles':
+ self.add_data_to_task(task, {cmd: StudyService().get_investigators(study_id, all=True)})
if cmd == 'details':
self.add_data_to_task(task, {cmd: self.pb.get_study_details(study_id)})
if cmd == 'approvals':
diff --git a/crc/services/study_service.py b/crc/services/study_service.py
index 142d6166..1f7429cb 100644
--- a/crc/services/study_service.py
+++ b/crc/services/study_service.py
@@ -182,7 +182,7 @@ class StudyService(object):
return documents
@staticmethod
- def get_investigators(study_id):
+ def get_investigators(study_id, all=False):
# Loop through all known investigator types as set in the reference file
inv_dictionary = FileService.get_reference_data(FileService.INVESTIGATOR_LIST, 'code')
@@ -199,6 +199,8 @@ class StudyService(object):
else:
inv_dictionary[i_type]['user_id'] = None
+ if not all:
+ inv_dictionary = dict(filter(lambda elem: elem[1]['user_id'] is not None, inv_dictionary.items()))
return inv_dictionary
@staticmethod
diff --git a/crc/services/workflow_service.py b/crc/services/workflow_service.py
index 0faf3b76..09368610 100644
--- a/crc/services/workflow_service.py
+++ b/crc/services/workflow_service.py
@@ -207,8 +207,10 @@ class WorkflowService(object):
if spiff_task:
nav_item['task'] = WorkflowService.spiff_task_to_api_task(spiff_task, add_docs_and_forms=False)
nav_item['title'] = nav_item['task'].title # Prefer the task title.
+
else:
nav_item['task'] = None
+
if not 'is_decision' in nav_item:
nav_item['is_decision'] = False
@@ -333,10 +335,12 @@ class WorkflowService(object):
# otherwise strip off the first word of the task, as that should be following
# a BPMN standard, and should not be included in the display.
if task.properties and "display_name" in task.properties:
- task.title = task.properties['display_name']
+ try:
+ task.title = spiff_task.workflow.script_engine.evaluate_expression(spiff_task, task.properties['display_name'])
+ except Exception as e:
+ app.logger.info("Failed to set title on task due to type error." + str(e))
elif task.title and ' ' in task.title:
task.title = task.title.partition(' ')[2]
-
return task
@staticmethod
diff --git a/tests/data/multi_instance_parallel/multi_instance_parallel.bpmn b/tests/data/multi_instance_parallel/multi_instance_parallel.bpmn
index dd6215ed..9e53323f 100644
--- a/tests/data/multi_instance_parallel/multi_instance_parallel.bpmn
+++ b/tests/data/multi_instance_parallel/multi_instance_parallel.bpmn
@@ -17,6 +17,9 @@
+
+
+
SequenceFlow_1p568pp
Flow_0ugjw69
diff --git a/tests/study/test_study_api.py b/tests/study/test_study_api.py
index cdae21c5..fdf64239 100644
--- a/tests/study/test_study_api.py
+++ b/tests/study/test_study_api.py
@@ -182,8 +182,8 @@ class TestStudyApi(BaseTest):
self.assertGreater(num_db_studies_after, num_db_studies_before)
self.assertEqual(num_abandoned, 1)
self.assertEqual(num_open, 1)
- self.assertEqual(num_active, 1)
- self.assertEqual(num_incomplete, 1)
+ self.assertEqual(num_active, 2)
+ self.assertEqual(num_incomplete, 0)
self.assertEqual(len(json_data), num_db_studies_after)
self.assertEqual(num_open + num_active + num_incomplete + num_abandoned, num_db_studies_after)
diff --git a/tests/study/test_study_service.py b/tests/study/test_study_service.py
index 1c482bcb..1eb020fa 100644
--- a/tests/study/test_study_service.py
+++ b/tests/study/test_study_service.py
@@ -183,7 +183,7 @@ class TestStudyService(BaseTest):
@patch('crc.services.protocol_builder.ProtocolBuilderService.get_investigators') # mock_docs
- def test_get_personnel(self, mock_docs):
+ def test_get_personnel_roles(self, mock_docs):
self.load_example_data()
# mock out the protocol builder
@@ -191,7 +191,7 @@ class TestStudyService(BaseTest):
mock_docs.return_value = json.loads(docs_response)
workflow = self.create_workflow('docx') # The workflow really doesnt matter in this case.
- investigators = StudyService().get_investigators(workflow.study_id)
+ investigators = StudyService().get_investigators(workflow.study_id, all=True)
self.assertEqual(9, len(investigators))
@@ -207,3 +207,22 @@ class TestStudyService(BaseTest):
# No value is provided for Department Chair
self.assertIsNone(investigators['DEPT_CH']['user_id'])
+
+ @patch('crc.services.protocol_builder.ProtocolBuilderService.get_investigators') # mock_docs
+ def test_get_study_personnel(self, mock_docs):
+ self.load_example_data()
+
+ # mock out the protocol builder
+ docs_response = self.protocol_builder_response('investigators.json')
+ mock_docs.return_value = json.loads(docs_response)
+
+ workflow = self.create_workflow('docx') # The workflow really doesnt matter in this case.
+ investigators = StudyService().get_investigators(workflow.study_id, all=False)
+
+ self.assertEqual(3, len(investigators))
+
+ # dhf8r is in the ldap mock data.
+ self.assertEqual("dhf8r", investigators['PI']['user_id'])
+ self.assertEqual("Dan Funk", investigators['PI']['display_name']) # Data from ldap
+ self.assertEqual("Primary Investigator", investigators['PI']['label']) # Data from xls file.
+ self.assertEqual("Always", investigators['PI']['display']) # Data from xls file.
diff --git a/tests/test_tasks_api.py b/tests/test_tasks_api.py
index 236defdc..abbf8707 100644
--- a/tests/test_tasks_api.py
+++ b/tests/test_tasks_api.py
@@ -322,7 +322,7 @@ class TestTasksApi(BaseTest):
self.assertEqual(4, len(navigation)) # Start task, form_task, multi_task, end task
self.assertEqual("UserTask", workflow.next_task.type)
self.assertEqual(MultiInstanceType.sequential.value, workflow.next_task.multi_instance_type)
- self.assertEqual(9, workflow.next_task.multi_instance_count)
+ self.assertEqual(3, workflow.next_task.multi_instance_count)
# Assure that the names for each task are properly updated, so they aren't all the same.
self.assertEqual("Primary Investigator", workflow.next_task.properties['display_name'])
@@ -480,17 +480,23 @@ class TestTasksApi(BaseTest):
workflow = self.create_workflow('multi_instance_parallel')
workflow_api = self.get_workflow_api(workflow)
- self.assertEqual(12, len(workflow_api.navigation))
+ self.assertEqual(6, len(workflow_api.navigation))
ready_items = [nav for nav in workflow_api.navigation if nav['state'] == "READY"]
- self.assertEqual(9, len(ready_items))
+ self.assertEqual(3, len(ready_items))
self.assertEqual("UserTask", workflow_api.next_task.type)
self.assertEqual("MultiInstanceTask",workflow_api.next_task.name)
- self.assertEqual("more information", workflow_api.next_task.title)
+ self.assertEqual("Primary Investigator", workflow_api.next_task.title)
- for i in random.sample(range(9), 9):
+ for i in random.sample(range(3), 3):
task = TaskSchema().load(ready_items[i]['task'])
- data = workflow_api.next_task.data
+ rv = self.app.put('/v1.0/workflow/%i/task/%s/set_token' % (workflow.id, task.id),
+ headers=self.logged_in_headers(),
+ content_type="application/json")
+ self.assert_success(rv)
+ json_data = json.loads(rv.get_data(as_text=True))
+ workflow = WorkflowApiSchema().load(json_data)
+ data = workflow.next_task.data
data['investigator']['email'] = "dhf8r@virginia.edu"
self.complete_form(workflow, task, data)
#tasks = self.get_workflow_api(workflow).user_tasks
diff --git a/tests/workflow/test_workflow_processor_multi_instance.py b/tests/workflow/test_workflow_processor_multi_instance.py
index 76821fed..e1011223 100644
--- a/tests/workflow/test_workflow_processor_multi_instance.py
+++ b/tests/workflow/test_workflow_processor_multi_instance.py
@@ -146,6 +146,11 @@ class TestWorkflowProcessorMultiInstance(BaseTest):
api_task = WorkflowService.spiff_task_to_api_task(task)
self.assertEqual(MultiInstanceType.parallel, api_task.multi_instance_type)
+
+ # Assure navigation picks up the label of the current element variable.
+ nav = WorkflowService.processor_to_workflow_api(processor, task).navigation
+ self.assertEquals("Primary Investigator", nav[2].title)
+
task.update_data({"investigator": {"email": "dhf8r@virginia.edu"}})
processor.complete_task(task)
processor.do_engine_steps()