Merge pull request #135 from sartography/feature/multi_instance_titles

* Modifying the StudyInfo script to return both "investigators" and "…
This commit is contained in:
Carlos López 2020-07-06 10:18:33 -06:00 committed by GitHub
commit ec40cfabda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 71 additions and 15 deletions

View File

@ -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':

View File

@ -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

View File

@ -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

View File

@ -17,6 +17,9 @@
<camunda:formData>
<camunda:formField id="email" label="Email Address:" type="string" />
</camunda:formData>
<camunda:properties>
<camunda:property name="display_name" value="investigator.label" />
</camunda:properties>
</bpmn:extensionElements>
<bpmn:incoming>SequenceFlow_1p568pp</bpmn:incoming>
<bpmn:outgoing>Flow_0ugjw69</bpmn:outgoing>

View File

@ -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)

View File

@ -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.

View File

@ -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

View File

@ -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()