def set_current_task(workflow_id, task_id): workflow_model = session.query(WorkflowModel).filter_by( id=workflow_id).first() processor = WorkflowProcessor(workflow_model) task_id = uuid.UUID(task_id) spiff_task = processor.bpmn_workflow.get_task(task_id) _verify_user_and_role(processor, spiff_task) user_uid = g.user.uid if spiff_task.state != spiff_task.COMPLETED and spiff_task.state != spiff_task.READY: raise ApiError( "invalid_state", "You may not move the token to a task who's state is not " "currently set to COMPLETE or READY.") # Only reset the token if the task doesn't already have it. if spiff_task.state == spiff_task.COMPLETED: spiff_task.reset_token( reset_data=True ) # Don't try to copy the existing data back into this task. processor.save() WorkflowService.log_task_action(user_uid, processor, spiff_task, WorkflowService.TASK_ACTION_TOKEN_RESET) WorkflowService.update_task_assignments(processor) workflow_api_model = WorkflowService.processor_to_workflow_api( processor, spiff_task) return WorkflowApiSchema().dump(workflow_api_model)
def get_workflow_from_spec(spec_id): workflow_model = WorkflowService.get_workflow_from_spec(spec_id, g.user) processor = WorkflowProcessor(workflow_model) processor.do_engine_steps() processor.save() WorkflowService.update_task_assignments(processor) workflow_api_model = WorkflowService.processor_to_workflow_api(processor) return WorkflowApiSchema().dump(workflow_api_model)
def test_total_tasks_updated(self, mock_docs): """Assure that as a users progress is available when getting a list of studies for that user.""" app.config['PB_ENABLED'] = True docs_response = self.protocol_builder_response('required_docs.json') mock_docs.return_value = json.loads(docs_response) user = self.create_user_with_study_and_workflow() # The load example data script should set us up a user and at least one study, one category, and one workflow. studies = StudyService.get_studies_for_user(user) self.assertTrue(len(studies) == 1) self.assertTrue(len(studies[0].categories) == 1) self.assertTrue(len(studies[0].categories[0].workflows) == 1) workflow = next(iter( studies[0].categories[0].workflows)) # Workflows is a set. # workflow should not be started, and it should have 0 completed tasks, and 0 total tasks. self.assertEqual(WorkflowStatus.not_started, workflow.status) self.assertEqual(0, workflow.total_tasks) self.assertEqual(0, workflow.completed_tasks) # Initialize the Workflow with the workflow processor. workflow_model = db.session.query(WorkflowModel).filter( WorkflowModel.id == workflow.id).first() processor = WorkflowProcessor(workflow_model) # Assure the workflow is now started, and knows the total and completed tasks. studies = StudyService.get_studies_for_user(user) workflow = next(iter( studies[0].categories[0].workflows)) # Workflows is a set. # self.assertEqual(WorkflowStatus.user_input_required, workflow.status) self.assertTrue(workflow.total_tasks > 0) self.assertEqual(0, workflow.completed_tasks) self.assertIsNotNone(workflow.spec_version) # Complete a task task = processor.next_task() processor.complete_task(task) processor.save() # Assure the workflow has moved on to the next task. studies = StudyService.get_studies_for_user(user) workflow = next(iter( studies[0].categories[0].workflows)) # Workflows is a set. self.assertEqual(1, workflow.completed_tasks) # Get approvals approvals = StudyService.get_approvals(studies[0].id) self.assertGreater(len(approvals), 0) self.assertIsNotNone(approvals[0]['display_order'])
def get_workflow(workflow_id, do_engine_steps=True): """Retrieve workflow based on workflow_id, and return it in the last saved State. If do_engine_steps is False, return the workflow without running any engine tasks or logging any events. """ workflow_model: WorkflowModel = session.query(WorkflowModel).filter_by( id=workflow_id).first() processor = WorkflowProcessor(workflow_model) if do_engine_steps: processor.do_engine_steps() processor.save() WorkflowService.update_task_assignments(processor) workflow_api_model = WorkflowService.processor_to_workflow_api(processor) return WorkflowApiSchema().dump(workflow_api_model)
def test_timer_event(self): workflow = self.create_workflow('timer_event') processor = WorkflowProcessor(workflow) processor.do_engine_steps() task = processor.next_task() processor.complete_task(task) tasks = processor.get_ready_user_tasks() self.assertEqual(tasks, []) processor.save() time.sleep(.3) # our timer is at .25 sec so we have to wait for it # get done waiting WorkflowService.do_waiting() wf = db.session.query(WorkflowModel).filter( WorkflowModel.id == workflow.id).first() self.assertTrue(wf.status != WorkflowStatus.waiting)
def test_waiting_event_error(self): workflow = self.create_workflow('timer_event_error') processor = WorkflowProcessor(workflow) processor.do_engine_steps() processor.save() time.sleep(.3) # our timer is at .25 sec so we have to wait for it # get done waiting wf = db.session.query(WorkflowModel).filter( WorkflowModel.id == workflow.id).first() self.assertTrue(wf.status == WorkflowStatus.waiting) with self.assertLogs('crc', level='ERROR') as cm: WorkflowService.do_waiting() self.assertEqual(1, len(cm.output)) self.assertRegex(cm.output[0], f"workflow #%i" % workflow.id) self.assertRegex(cm.output[0], f"study #%i" % workflow.study_id) self.assertTrue(wf.status == WorkflowStatus.erroring)
def test_load_irb_from_db(self, mock_study_service): # This depends on getting a list of investigators back from the protocol builder. mock_study_service.return_value = self.mock_investigator_response self.load_example_data() workflow_spec_model = self.create_workflow("irb_api_personnel") study = session.query(StudyModel).first() processor = WorkflowProcessor(workflow_spec_model) processor.do_engine_steps() task_list = processor.get_ready_user_tasks() processor.complete_task(task_list[0]) processor.do_engine_steps() nav_list = processor.bpmn_workflow.get_flat_nav_list() processor.save() # reload after save processor = WorkflowProcessor(workflow_spec_model) nav_list2 = processor.bpmn_workflow.get_flat_nav_list() self.assertEqual(nav_list, nav_list2)
def update_task(workflow_id, task_id, body, terminate_loop=None): workflow_model = session.query(WorkflowModel).filter_by( id=workflow_id).first() if workflow_model is None: raise ApiError("invalid_workflow_id", "The given workflow id is not valid.", status_code=404) elif workflow_model.study is None: raise ApiError("invalid_study", "There is no study associated with the given workflow.", status_code=404) processor = WorkflowProcessor(workflow_model) task_id = uuid.UUID(task_id) spiff_task = processor.bpmn_workflow.get_task(task_id) _verify_user_and_role(processor, spiff_task) if not spiff_task: raise ApiError("empty_task", "Processor failed to obtain task.", status_code=404) if spiff_task.state != spiff_task.READY: raise ApiError( "invalid_state", "You may not update a task unless it is in the READY state. " "Consider calling a token reset to make this task Ready.") if terminate_loop: spiff_task.terminate_loop() spiff_task.update_data(body) processor.complete_task(spiff_task) processor.do_engine_steps() processor.save() # Log the action, and any pending task assignments in the event of lanes in the workflow. WorkflowService.log_task_action(g.user.uid, processor, spiff_task, WorkflowService.TASK_ACTION_COMPLETE) WorkflowService.update_task_assignments(processor) workflow_api_model = WorkflowService.processor_to_workflow_api(processor) return WorkflowApiSchema().dump(workflow_api_model)