Refactoring shared code

This commit is contained in:
Carlos Lopez 2020-06-22 14:07:57 -06:00
parent e5541e4950
commit dc5ffd29d0
4 changed files with 144 additions and 102 deletions

View File

@ -90,8 +90,8 @@ def get_approvals_for_study(study_id=None):
return results return results
def get_health_attesting_csv(all_approvals=True): def get_health_attesting_csv():
records = ApprovalService.get_health_attesting_records(all_approvals) records = ApprovalService.get_health_attesting_records()
si = io.StringIO() si = io.StringIO()
cw = csv.writer(si) cw = csv.writer(si)
cw.writerows(records) cw.writerows(records)
@ -105,67 +105,10 @@ def get_health_attesting_csv(all_approvals=True):
def get_csv(): def get_csv():
"""A damn lie, it's a json file. A huge bit of a one-off for RRT, but 3 weeks of midnight work can convince a """A damn lie, it's a json file. A huge bit of a one-off for RRT, but 3 weeks of midnight work can convince a
man to do just about anything""" man to do just about anything"""
approvals = ApprovalService.get_all_approvals(include_cancelled=False) content = ApprovalService.get_not_really_csv_content()
output = []
errors = []
for approval in approvals:
try:
if approval.status != ApprovalStatus.APPROVED.value:
continue
for related_approval in approval.related_approvals:
if related_approval.status != ApprovalStatus.APPROVED.value:
continue
workflow = db.session.query(WorkflowModel).filter(WorkflowModel.id == approval.workflow_id).first()
data = json.loads(workflow.bpmn_workflow_json)
last_task = find_task(data['last_task']['__uuid__'], data['task_tree'])
personnel = extract_value(last_task, 'personnel')
training_val = extract_value(last_task, 'RequiredTraining')
pi_supervisor = extract_value(last_task, 'PISupervisor')['value']
review_complete = 'AllRequiredTraining' in training_val
pi_uid = workflow.study.primary_investigator_id
pi_details = LdapService.user_info(pi_uid)
details = []
details.append(pi_details)
for person in personnel:
uid = person['PersonnelComputingID']['value']
details.append(LdapService.user_info(uid))
for person in details: return content
record = {
"study_id": approval.study_id,
"pi_uid": pi_details.uid,
"pi": pi_details.display_name,
"name": person.display_name,
"uid": person.uid,
"email": person.email_address,
"supervisor": "",
"review_complete": review_complete,
}
# We only know the PI's supervisor.
if person.uid == pi_details.uid:
record["supervisor"] = pi_supervisor
output.append(record)
except Exception as e:
errors.append("Error pulling data for workflow #%i: %s" % (approval.workflow_id, str(e)))
return {"results": output, "errors": errors }
def extract_value(task, key):
if key in task['data']:
return pickle.loads(b64decode(task['data'][key]['__bytes__']))
else:
return ""
def find_task(uuid, task):
if task['id']['__uuid__'] == uuid:
return task
for child in task['children']:
task = find_task(uuid, child)
if task:
return task
# ----- come back to the world of the living ---- # # ----- come back to the world of the living ---- #

View File

@ -1,3 +1,6 @@
import json
import pickle
from base64 import b64decode
from datetime import datetime, timedelta from datetime import datetime, timedelta
from sqlalchemy import desc, func from sqlalchemy import desc, func
@ -110,19 +113,51 @@ class ApprovalService(object):
return [Approval.from_model(approval_model) for approval_model in db_approvals] return [Approval.from_model(approval_model) for approval_model in db_approvals]
@staticmethod @staticmethod
def get_health_attesting_records(all_approvals=True): def get_approval_details(approval):
"""Return a list with prepared information related to all approvals """Returns a list of packed approval details, obtained from
approved or filtered by today """ the task data sent during the workflow """
if all_approvals: def extract_value(task, key):
approvals = session.query(ApprovalModel).filter( if key in task['data']:
ApprovalModel.status==ApprovalStatus.APPROVED.value return pickle.loads(b64decode(task['data'][key]['__bytes__']))
) else:
else: return ""
today = datetime.now().date()
approvals = session.query(ApprovalModel).filter( def find_task(uuid, task):
func.date(ApprovalModel.date_created)==today, if task['id']['__uuid__'] == uuid:
ApprovalModel.status==ApprovalStatus.APPROVED.value return task
) for child in task['children']:
task = find_task(uuid, child)
if task:
return task
if approval.status != ApprovalStatus.APPROVED.value:
return {}
for related_approval in approval.related_approvals:
if related_approval.status != ApprovalStatus.APPROVED.value:
continue
workflow = db.session.query(WorkflowModel).filter(WorkflowModel.id == approval.workflow_id).first()
data = json.loads(workflow.bpmn_workflow_json)
last_task = find_task(data['last_task']['__uuid__'], data['task_tree'])
personnel = extract_value(last_task, 'personnel')
training_val = extract_value(last_task, 'RequiredTraining')
pi_supervisor = extract_value(last_task, 'PISupervisor')['value']
review_complete = 'AllRequiredTraining' in training_val
pi_uid = workflow.study.primary_investigator_id
pi_details = LdapService.user_info(pi_uid)
details = {'Supervisor': pi_supervisor}
details['person_details'] = []
details['person_details'].append(pi_details)
for person in personnel:
uid = person['PersonnelComputingID']['value']
details['person_details'].append(LdapService.user_info(uid))
return details
@staticmethod
def get_health_attesting_records():
"""Return a list with prepared information related to all approvals """
approvals = ApprovalService.get_all_approvals(include_cancelled=False)
health_attesting_rows = [ health_attesting_rows = [
['university_computing_id', ['university_computing_id',
@ -132,22 +167,60 @@ class ApprovalService(object):
'job_title', 'job_title',
'supervisor_university_computing_id'] 'supervisor_university_computing_id']
] ]
for approval in approvals: for approval in approvals:
pi_info = LdapService.user_info(approval.study.primary_investigator_id) try:
approver_info = LdapService.user_info(approval.approver_uid) details = ApprovalService.get_approval_details(approval)
first_name = pi_info.given_name if not details:
last_name = pi_info.display_name.replace(first_name, '').strip() continue
health_attesting_rows.append([
pi_info.uid, for person in details['person_details']:
last_name, first_name = person.given_name
first_name, last_name = person.display_name.replace(first_name, '').strip()
'', record = [
'Academic Researcher', person.uid,
approver_info.uid last_name,
]) first_name,
'',
'Academic Researcher',
details['Supervisor'] if person.uid == details['person_details'][0].uid else 'askresearch'
]
if record not in health_attesting_rows:
health_attesting_rows.append(record)
except Exception as e:
app.logger.error("Error pulling data for workflow #%i: %s" % (approval.workflow_id, str(e)))
return health_attesting_rows return health_attesting_rows
@staticmethod
def get_not_really_csv_content():
approvals = ApprovalService.get_all_approvals(include_cancelled=False)
output = []
errors = []
for approval in approvals:
try:
details = ApprovalService.get_approval_details(approval)
for person in details['person_details']:
record = {
"study_id": approval.study_id,
"pi_uid": pi_details.uid,
"pi": pi_details.display_name,
"name": person.display_name,
"uid": person.uid,
"email": person.email_address,
"supervisor": details['Supervisor'] if person.uid == details['person_details'][0].uid else "",
"review_complete": review_complete,
}
output.append(record)
except Exception as e:
errors.append("Error pulling data for workflow #%i: %s" % (approval.workflow_id, str(e)))
return {"results": output, "errors": errors }
@staticmethod @staticmethod
def update_approval(approval_id, approver_uid): def update_approval(approval_id, approver_uid):
"""Update a specific approval """Update a specific approval

View File

@ -57,6 +57,32 @@ class TestApprovalsService(BaseTest):
self.assertEqual(1, models[0].version) self.assertEqual(1, models[0].version)
self.assertEqual(2, models[1].version) self.assertEqual(2, models[1].version)
def test_get_health_attesting_records(self):
self.load_example_data()
self.create_reference_document()
workflow = self.create_workflow('empty_workflow')
FileService.add_workflow_file(workflow_id=workflow.id,
name="anything.png", content_type="text",
binary_data=b'5678', irb_doc_code="AD_CoCAppr")
ApprovalService.add_approval(study_id=workflow.study_id, workflow_id=workflow.id, approver_uid="dhf8r")
records = ApprovalService.get_health_attesting_records()
self.assertEqual(len(records), 1)
def test_get_not_really_csv_content(self):
self.load_example_data()
self.create_reference_document()
workflow = self.create_workflow('empty_workflow')
FileService.add_workflow_file(workflow_id=workflow.id,
name="anything.png", content_type="text",
binary_data=b'5678', irb_doc_code="AD_CoCAppr")
ApprovalService.add_approval(study_id=workflow.study_id, workflow_id=workflow.id, approver_uid="dhf8r")
records = ApprovalService.get_not_really_csv_content()
self.assertEqual(len(records), 1)
def test_new_approval_sends_proper_emails(self): def test_new_approval_sends_proper_emails(self):
self.assertEqual(1, 1) self.assertEqual(1, 1)

View File

@ -47,7 +47,7 @@ class TestTasksApi(BaseTest):
# The total number of tasks may change over time, as users move through gateways # The total number of tasks may change over time, as users move through gateways
# branches may be pruned. As we hit parallel Multi-Instance new tasks may be created... # branches may be pruned. As we hit parallel Multi-Instance new tasks may be created...
self.assertIsNotNone(workflow.total_tasks) self.assertIsNotNone(workflow.total_tasks)
self.assertEquals(prev_completed_task_count + 1, workflow.completed_tasks) self.assertEqual(prev_completed_task_count + 1, workflow.completed_tasks)
# Assure a record exists in the Task Events # Assure a record exists in the Task Events
task_events = session.query(TaskEventModel) \ task_events = session.query(TaskEventModel) \
.filter_by(workflow_id=workflow.id) \ .filter_by(workflow_id=workflow.id) \
@ -56,25 +56,25 @@ class TestTasksApi(BaseTest):
self.assertGreater(len(task_events), 0) self.assertGreater(len(task_events), 0)
event = task_events[0] event = task_events[0]
self.assertIsNotNone(event.study_id) self.assertIsNotNone(event.study_id)
self.assertEquals("dhf8r", event.user_uid) self.assertEqual("dhf8r", event.user_uid)
self.assertEquals(workflow.id, event.workflow_id) self.assertEqual(workflow.id, event.workflow_id)
self.assertEquals(workflow.workflow_spec_id, event.workflow_spec_id) self.assertEqual(workflow.workflow_spec_id, event.workflow_spec_id)
self.assertEquals(workflow.spec_version, event.spec_version) self.assertEqual(workflow.spec_version, event.spec_version)
self.assertEquals(WorkflowService.TASK_ACTION_COMPLETE, event.action) self.assertEqual(WorkflowService.TASK_ACTION_COMPLETE, event.action)
self.assertEquals(task_in.id, task_id) self.assertEqual(task_in.id, task_id)
self.assertEquals(task_in.name, event.task_name) self.assertEqual(task_in.name, event.task_name)
self.assertEquals(task_in.title, event.task_title) self.assertEqual(task_in.title, event.task_title)
self.assertEquals(task_in.type, event.task_type) self.assertEqual(task_in.type, event.task_type)
self.assertEquals("COMPLETED", event.task_state) self.assertEqual("COMPLETED", event.task_state)
# Not sure what vodoo is happening inside of marshmallow to get me in this state. # Not sure what vodoo is happening inside of marshmallow to get me in this state.
if isinstance(task_in.multi_instance_type, MultiInstanceType): if isinstance(task_in.multi_instance_type, MultiInstanceType):
self.assertEquals(task_in.multi_instance_type.value, event.mi_type) self.assertEqual(task_in.multi_instance_type.value, event.mi_type)
else: else:
self.assertEquals(task_in.multi_instance_type, event.mi_type) self.assertEqual(task_in.multi_instance_type, event.mi_type)
self.assertEquals(task_in.multi_instance_count, event.mi_count) self.assertEqual(task_in.multi_instance_count, event.mi_count)
self.assertEquals(task_in.multi_instance_index, event.mi_index) self.assertEqual(task_in.multi_instance_index, event.mi_index)
self.assertEquals(task_in.process_name, event.process_name) self.assertEqual(task_in.process_name, event.process_name)
self.assertIsNotNone(event.date) self.assertIsNotNone(event.date)
# Assure that there is data in the form_data # Assure that there is data in the form_data