Merge pull request #135 from sartography/feature/multi_instance_titles
* Modifying the StudyInfo script to return both "investigators" and "…
This commit is contained in:
commit
ec40cfabda
|
@ -14,7 +14,7 @@ class StudyInfo(Script):
|
||||||
"""Please see the detailed description that is provided below. """
|
"""Please see the detailed description that is provided below. """
|
||||||
|
|
||||||
pb = ProtocolBuilderService()
|
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.
|
# This is used for test/workflow validation, as well as documentation.
|
||||||
example_data = {
|
example_data = {
|
||||||
|
@ -106,11 +106,20 @@ Returns the basic information such as the id and title
|
||||||
### Investigators ###
|
### Investigators ###
|
||||||
Returns detailed information about related personnel.
|
Returns detailed information about related personnel.
|
||||||
The order returned is guaranteed to match the order provided in the investigators.xslx reference file.
|
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}
|
{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 ###
|
### Details ###
|
||||||
Returns detailed information about variable keys read in from the Protocol Builder.
|
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",
|
"INVESTIGATORTYPEFULL": "Primary Investigator",
|
||||||
"NETBADGEID": "dhf8r"
|
"NETBADGEID": "dhf8r"
|
||||||
},
|
},
|
||||||
|
"roles":
|
||||||
|
{
|
||||||
|
"INVESTIGATORTYPE": "PI",
|
||||||
|
"INVESTIGATORTYPEFULL": "Primary Investigator",
|
||||||
|
"NETBADGEID": "dhf8r"
|
||||||
|
},
|
||||||
"details":
|
"details":
|
||||||
{
|
{
|
||||||
"IS_IND": 0,
|
"IS_IND": 0,
|
||||||
|
@ -198,6 +213,8 @@ Returns information specific to the protocol.
|
||||||
self.add_data_to_task(task, {cmd: schema.dump(study)})
|
self.add_data_to_task(task, {cmd: schema.dump(study)})
|
||||||
if cmd == 'investigators':
|
if cmd == 'investigators':
|
||||||
self.add_data_to_task(task, {cmd: StudyService().get_investigators(study_id)})
|
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':
|
if cmd == 'details':
|
||||||
self.add_data_to_task(task, {cmd: self.pb.get_study_details(study_id)})
|
self.add_data_to_task(task, {cmd: self.pb.get_study_details(study_id)})
|
||||||
if cmd == 'approvals':
|
if cmd == 'approvals':
|
||||||
|
|
|
@ -182,7 +182,7 @@ class StudyService(object):
|
||||||
return documents
|
return documents
|
||||||
|
|
||||||
@staticmethod
|
@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
|
# Loop through all known investigator types as set in the reference file
|
||||||
inv_dictionary = FileService.get_reference_data(FileService.INVESTIGATOR_LIST, 'code')
|
inv_dictionary = FileService.get_reference_data(FileService.INVESTIGATOR_LIST, 'code')
|
||||||
|
@ -199,6 +199,8 @@ class StudyService(object):
|
||||||
else:
|
else:
|
||||||
inv_dictionary[i_type]['user_id'] = None
|
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
|
return inv_dictionary
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -207,8 +207,10 @@ class WorkflowService(object):
|
||||||
if spiff_task:
|
if spiff_task:
|
||||||
nav_item['task'] = WorkflowService.spiff_task_to_api_task(spiff_task, add_docs_and_forms=False)
|
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.
|
nav_item['title'] = nav_item['task'].title # Prefer the task title.
|
||||||
|
|
||||||
else:
|
else:
|
||||||
nav_item['task'] = None
|
nav_item['task'] = None
|
||||||
|
|
||||||
if not 'is_decision' in nav_item:
|
if not 'is_decision' in nav_item:
|
||||||
nav_item['is_decision'] = False
|
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
|
# 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.
|
# a BPMN standard, and should not be included in the display.
|
||||||
if task.properties and "display_name" in task.properties:
|
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:
|
elif task.title and ' ' in task.title:
|
||||||
task.title = task.title.partition(' ')[2]
|
task.title = task.title.partition(' ')[2]
|
||||||
|
|
||||||
return task
|
return task
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
<camunda:formData>
|
<camunda:formData>
|
||||||
<camunda:formField id="email" label="Email Address:" type="string" />
|
<camunda:formField id="email" label="Email Address:" type="string" />
|
||||||
</camunda:formData>
|
</camunda:formData>
|
||||||
|
<camunda:properties>
|
||||||
|
<camunda:property name="display_name" value="investigator.label" />
|
||||||
|
</camunda:properties>
|
||||||
</bpmn:extensionElements>
|
</bpmn:extensionElements>
|
||||||
<bpmn:incoming>SequenceFlow_1p568pp</bpmn:incoming>
|
<bpmn:incoming>SequenceFlow_1p568pp</bpmn:incoming>
|
||||||
<bpmn:outgoing>Flow_0ugjw69</bpmn:outgoing>
|
<bpmn:outgoing>Flow_0ugjw69</bpmn:outgoing>
|
||||||
|
|
|
@ -182,8 +182,8 @@ class TestStudyApi(BaseTest):
|
||||||
self.assertGreater(num_db_studies_after, num_db_studies_before)
|
self.assertGreater(num_db_studies_after, num_db_studies_before)
|
||||||
self.assertEqual(num_abandoned, 1)
|
self.assertEqual(num_abandoned, 1)
|
||||||
self.assertEqual(num_open, 1)
|
self.assertEqual(num_open, 1)
|
||||||
self.assertEqual(num_active, 1)
|
self.assertEqual(num_active, 2)
|
||||||
self.assertEqual(num_incomplete, 1)
|
self.assertEqual(num_incomplete, 0)
|
||||||
self.assertEqual(len(json_data), num_db_studies_after)
|
self.assertEqual(len(json_data), num_db_studies_after)
|
||||||
self.assertEqual(num_open + num_active + num_incomplete + num_abandoned, num_db_studies_after)
|
self.assertEqual(num_open + num_active + num_incomplete + num_abandoned, num_db_studies_after)
|
||||||
|
|
||||||
|
|
|
@ -183,7 +183,7 @@ class TestStudyService(BaseTest):
|
||||||
|
|
||||||
|
|
||||||
@patch('crc.services.protocol_builder.ProtocolBuilderService.get_investigators') # mock_docs
|
@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()
|
self.load_example_data()
|
||||||
|
|
||||||
# mock out the protocol builder
|
# mock out the protocol builder
|
||||||
|
@ -191,7 +191,7 @@ class TestStudyService(BaseTest):
|
||||||
mock_docs.return_value = json.loads(docs_response)
|
mock_docs.return_value = json.loads(docs_response)
|
||||||
|
|
||||||
workflow = self.create_workflow('docx') # The workflow really doesnt matter in this case.
|
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))
|
self.assertEqual(9, len(investigators))
|
||||||
|
|
||||||
|
@ -207,3 +207,22 @@ class TestStudyService(BaseTest):
|
||||||
|
|
||||||
# No value is provided for Department Chair
|
# No value is provided for Department Chair
|
||||||
self.assertIsNone(investigators['DEPT_CH']['user_id'])
|
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.
|
||||||
|
|
|
@ -322,7 +322,7 @@ class TestTasksApi(BaseTest):
|
||||||
self.assertEqual(4, len(navigation)) # Start task, form_task, multi_task, end task
|
self.assertEqual(4, len(navigation)) # Start task, form_task, multi_task, end task
|
||||||
self.assertEqual("UserTask", workflow.next_task.type)
|
self.assertEqual("UserTask", workflow.next_task.type)
|
||||||
self.assertEqual(MultiInstanceType.sequential.value, workflow.next_task.multi_instance_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.
|
# 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'])
|
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 = self.create_workflow('multi_instance_parallel')
|
||||||
|
|
||||||
workflow_api = self.get_workflow_api(workflow)
|
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"]
|
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("UserTask", workflow_api.next_task.type)
|
||||||
self.assertEqual("MultiInstanceTask",workflow_api.next_task.name)
|
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'])
|
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"
|
data['investigator']['email'] = "dhf8r@virginia.edu"
|
||||||
self.complete_form(workflow, task, data)
|
self.complete_form(workflow, task, data)
|
||||||
#tasks = self.get_workflow_api(workflow).user_tasks
|
#tasks = self.get_workflow_api(workflow).user_tasks
|
||||||
|
|
|
@ -146,6 +146,11 @@ class TestWorkflowProcessorMultiInstance(BaseTest):
|
||||||
|
|
||||||
api_task = WorkflowService.spiff_task_to_api_task(task)
|
api_task = WorkflowService.spiff_task_to_api_task(task)
|
||||||
self.assertEqual(MultiInstanceType.parallel, api_task.multi_instance_type)
|
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"}})
|
task.update_data({"investigator": {"email": "dhf8r@virginia.edu"}})
|
||||||
processor.complete_task(task)
|
processor.complete_task(task)
|
||||||
processor.do_engine_steps()
|
processor.do_engine_steps()
|
||||||
|
|
Loading…
Reference in New Issue