Merge branch 'master' into feature/protocol_status
This commit is contained in:
commit
28d5727851
|
@ -608,7 +608,7 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/Workflow"
|
$ref: "#/components/schemas/Workflow"
|
||||||
delete:
|
delete:
|
||||||
operationId: crc.api.workflow.delete
|
operationId: crc.api.workflow.delete_workflow
|
||||||
summary: Removes an existing workflow
|
summary: Removes an existing workflow
|
||||||
tags:
|
tags:
|
||||||
- Workflows and Tasks
|
- Workflows and Tasks
|
||||||
|
|
|
@ -9,6 +9,7 @@ from crc.models.stats import WorkflowStatsModel, TaskEventModel
|
||||||
from crc.models.workflow import WorkflowModel, WorkflowSpecModelSchema, WorkflowSpecModel, WorkflowSpecCategoryModel, \
|
from crc.models.workflow import WorkflowModel, WorkflowSpecModelSchema, WorkflowSpecModel, WorkflowSpecCategoryModel, \
|
||||||
WorkflowSpecCategoryModelSchema
|
WorkflowSpecCategoryModelSchema
|
||||||
from crc.services.file_service import FileService
|
from crc.services.file_service import FileService
|
||||||
|
from crc.services.study_service import StudyService
|
||||||
from crc.services.workflow_processor import WorkflowProcessor
|
from crc.services.workflow_processor import WorkflowProcessor
|
||||||
from crc.services.workflow_service import WorkflowService
|
from crc.services.workflow_service import WorkflowService
|
||||||
|
|
||||||
|
@ -78,8 +79,8 @@ def delete_workflow_specification(spec_id):
|
||||||
FileService.delete_file(file.id)
|
FileService.delete_file(file.id)
|
||||||
|
|
||||||
# Delete all stats and workflow models related to this specification
|
# Delete all stats and workflow models related to this specification
|
||||||
session.query(WorkflowStatsModel).filter_by(workflow_spec_id=spec_id).delete()
|
for workflow in session.query(WorkflowModel).filter_by(workflow_spec_id=spec_id):
|
||||||
session.query(WorkflowModel).filter_by(workflow_spec_id=spec_id).delete()
|
StudyService.delete_workflow(workflow)
|
||||||
session.query(WorkflowSpecModel).filter_by(id=spec_id).delete()
|
session.query(WorkflowSpecModel).filter_by(id=spec_id).delete()
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
|
@ -115,11 +116,8 @@ def get_workflow(workflow_id, soft_reset=False, hard_reset=False):
|
||||||
return WorkflowApiSchema().dump(workflow_api_model)
|
return WorkflowApiSchema().dump(workflow_api_model)
|
||||||
|
|
||||||
|
|
||||||
def delete(workflow_id):
|
def delete_workflow(workflow_id):
|
||||||
session.query(TaskEventModel).filter_by(workflow_id=workflow_id).delete()
|
StudyService.delete_workflow(workflow_id)
|
||||||
session.query(WorkflowStatsModel).filter_by(workflow_id=workflow_id).delete()
|
|
||||||
session.query(WorkflowModel).filter_by(id=workflow_id).delete()
|
|
||||||
session.commit()
|
|
||||||
|
|
||||||
def set_current_task(workflow_id, task_id):
|
def set_current_task(workflow_id, task_id):
|
||||||
workflow_model = session.query(WorkflowModel).filter_by(id=workflow_id).first()
|
workflow_model = session.query(WorkflowModel).filter_by(id=workflow_id).first()
|
||||||
|
|
|
@ -52,12 +52,21 @@ class StudyService(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def delete_study(study_id):
|
def delete_study(study_id):
|
||||||
session.query(WorkflowStatsModel).filter_by(study_id=study_id).delete()
|
|
||||||
session.query(TaskEventModel).filter_by(study_id=study_id).delete()
|
session.query(TaskEventModel).filter_by(study_id=study_id).delete()
|
||||||
session.query(WorkflowModel).filter_by(study_id=study_id).delete()
|
session.query(WorkflowStatsModel).filter_by(study_id=study_id).delete()
|
||||||
|
for workflow in session.query(WorkflowModel).filter_by(study_id=study_id):
|
||||||
|
StudyService.delete_workflow(workflow.id)
|
||||||
session.query(StudyModel).filter_by(id=study_id).delete()
|
session.query(StudyModel).filter_by(id=study_id).delete()
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def delete_workflow(workflow_id):
|
||||||
|
for file in session.query(FileModel).filter_by(workflow_id=workflow_id).all():
|
||||||
|
FileService.delete_file(file.id)
|
||||||
|
session.query(TaskEventModel).filter_by(workflow_id=workflow_id).delete()
|
||||||
|
session.query(WorkflowStatsModel).filter_by(workflow_id=workflow_id).delete()
|
||||||
|
session.query(WorkflowModel).filter_by(id=workflow_id).delete()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_categories():
|
def get_categories():
|
||||||
"""Returns a list of category objects, in the correct order."""
|
"""Returns a list of category objects, in the correct order."""
|
||||||
|
|
|
@ -164,6 +164,11 @@ class TestTasksApi(BaseTest):
|
||||||
json_data = json.loads(rv.get_data(as_text=True))
|
json_data = json.loads(rv.get_data(as_text=True))
|
||||||
files = FileModelSchema(many=True).load(json_data, session=session)
|
files = FileModelSchema(many=True).load(json_data, session=session)
|
||||||
self.assertTrue(len(files) == 1)
|
self.assertTrue(len(files) == 1)
|
||||||
|
# Assure we can still delete the study even when there is a file attached to a workflow.
|
||||||
|
rv = self.app.delete('/v1.0/study/%i' % workflow.study_id, headers=self.logged_in_headers())
|
||||||
|
self.assert_success(rv)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_documentation_populated_in_end(self):
|
def test_get_documentation_populated_in_end(self):
|
||||||
self.load_example_data()
|
self.load_example_data()
|
||||||
|
|
|
@ -1,22 +1,13 @@
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import string
|
|
||||||
import random
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from SpiffWorkflow.bpmn.specs.EndEvent import EndEvent
|
from crc import session
|
||||||
|
|
||||||
from crc import session, db, app
|
|
||||||
from crc.api.common import ApiError
|
|
||||||
from crc.models.api_models import MultiInstanceType
|
from crc.models.api_models import MultiInstanceType
|
||||||
from crc.models.file import FileModel, FileDataModel, CONTENT_TYPES
|
|
||||||
from crc.models.study import StudyModel
|
from crc.models.study import StudyModel
|
||||||
from crc.models.workflow import WorkflowSpecModel, WorkflowStatus, WorkflowModel
|
from crc.models.workflow import WorkflowStatus
|
||||||
from crc.services.file_service import FileService
|
|
||||||
from crc.services.study_service import StudyService
|
from crc.services.study_service import StudyService
|
||||||
|
from crc.services.workflow_processor import WorkflowProcessor
|
||||||
from crc.services.workflow_service import WorkflowService
|
from crc.services.workflow_service import WorkflowService
|
||||||
from tests.base_test import BaseTest
|
from tests.base_test import BaseTest
|
||||||
from crc.services.workflow_processor import WorkflowProcessor
|
|
||||||
|
|
||||||
|
|
||||||
class TestWorkflowProcessorMultiInstance(BaseTest):
|
class TestWorkflowProcessorMultiInstance(BaseTest):
|
||||||
|
@ -96,3 +87,66 @@ class TestWorkflowProcessorMultiInstance(BaseTest):
|
||||||
task.data['StudyInfo']['investigators'])
|
task.data['StudyInfo']['investigators'])
|
||||||
|
|
||||||
self.assertEqual(WorkflowStatus.complete, processor.get_status())
|
self.assertEqual(WorkflowStatus.complete, processor.get_status())
|
||||||
|
|
||||||
|
|
||||||
|
@patch('crc.services.protocol_builder.requests.get')
|
||||||
|
def test_create_and_complete_workflow_parallel(self, mock_get):
|
||||||
|
"""Unlike the test above, the parallel task allows us to complete the items in any order."""
|
||||||
|
|
||||||
|
mock_get.return_value.ok = True
|
||||||
|
mock_get.return_value.text = self.protocol_builder_response('investigators.json')
|
||||||
|
|
||||||
|
self.load_example_data()
|
||||||
|
workflow_spec_model = self.load_test_spec("multi_instance_parallel")
|
||||||
|
study = session.query(StudyModel).first()
|
||||||
|
processor = self.get_processor(study, workflow_spec_model)
|
||||||
|
processor.bpmn_workflow.do_engine_steps()
|
||||||
|
|
||||||
|
# In the Parallel instance, there should be three tasks, all of them in the ready state.
|
||||||
|
next_user_tasks = processor.next_user_tasks()
|
||||||
|
self.assertEqual(3, len(next_user_tasks))
|
||||||
|
|
||||||
|
# We can complete the tasks out of order.
|
||||||
|
task = next_user_tasks[2]
|
||||||
|
|
||||||
|
self.assertEquals(
|
||||||
|
{
|
||||||
|
'DC': {'user_id': 'asd3v', 'type_full': 'Department Contact'},
|
||||||
|
'IRBC': {'user_id': 'asdf32', 'type_full': 'IRB Coordinator'},
|
||||||
|
'PI': {'user_id': 'dhf8r', 'type_full': 'Primary Investigator'}
|
||||||
|
},
|
||||||
|
task.data['StudyInfo']['investigators'])
|
||||||
|
|
||||||
|
self.assertEqual(WorkflowStatus.user_input_required, processor.get_status())
|
||||||
|
self.assertEquals("dhf8r", task.data["investigator"]["user_id"]) # The last of the tasks
|
||||||
|
|
||||||
|
api_task = WorkflowService.spiff_task_to_api_task(task)
|
||||||
|
self.assertEquals(MultiInstanceType.parallel, api_task.mi_type)
|
||||||
|
task.update_data({"email":"dhf8r@virginia.edu"})
|
||||||
|
processor.complete_task(task)
|
||||||
|
processor.do_engine_steps()
|
||||||
|
|
||||||
|
task = next_user_tasks[0]
|
||||||
|
api_task = WorkflowService.spiff_task_to_api_task(task)
|
||||||
|
self.assertEqual("MutiInstanceTask", api_task.name)
|
||||||
|
task.update_data({"email":"asd3v@virginia.edu"})
|
||||||
|
processor.complete_task(task)
|
||||||
|
processor.do_engine_steps()
|
||||||
|
|
||||||
|
task = next_user_tasks[1]
|
||||||
|
api_task = WorkflowService.spiff_task_to_api_task(task)
|
||||||
|
self.assertEqual("MutiInstanceTask", task.get_name())
|
||||||
|
task.update_data({"email":"asdf32@virginia.edu"})
|
||||||
|
processor.complete_task(task)
|
||||||
|
processor.do_engine_steps()
|
||||||
|
|
||||||
|
# Completing the tasks out of order, still provides the correct information.
|
||||||
|
self.assertEquals(
|
||||||
|
{
|
||||||
|
'DC': {'user_id': 'asd3v', 'type_full': 'Department Contact', 'email': 'asd3v@virginia.edu'},
|
||||||
|
'IRBC': {'user_id': 'asdf32', 'type_full': 'IRB Coordinator', "email": "asdf32@virginia.edu"},
|
||||||
|
'PI': {'user_id': 'dhf8r', 'type_full': 'Primary Investigator', "email": "dhf8r@virginia.edu"}
|
||||||
|
},
|
||||||
|
task.data['StudyInfo']['investigators'])
|
||||||
|
|
||||||
|
self.assertEqual(WorkflowStatus.complete, processor.get_status())
|
||||||
|
|
Loading…
Reference in New Issue