2020-03-26 16:51:53 +00:00
|
|
|
from typing import List
|
2020-02-26 23:06:51 +00:00
|
|
|
|
2019-12-18 19:02:17 +00:00
|
|
|
from connexion import NoContent
|
2020-02-26 23:06:51 +00:00
|
|
|
from flask import g
|
2020-03-09 19:12:40 +00:00
|
|
|
from sqlalchemy.exc import IntegrityError
|
2019-12-18 19:02:17 +00:00
|
|
|
|
Refactor the document details scripts. Now there is one script, it returns data in a consistent format, and has all the details required. The script is located in StudyInfo, with the argument documents. Make note that it returns a dictionary of ALL the documents, with a field to mark which ones are required according to the protocol builder. Others may become required if a workflow determines such, in which case the workflow will enforce this, and the document will have a count > 0, and additional details in a list of files within the document. I modified the XLS file to use lower case variable names, because it disturbed me, and we have to reference them frequently. Removed devious "as_object" variable on get_required_docs, so it behaves like the other methods all the time, and returns a dictionary. All the core business logic for finding the documents list now resides in the StudyService.
Because this changes the endpoint for all existing document details, I've modified all the test and static bpmn files to use the new format.
Shorting up the SponsorsList.xls file makes for slightly faster tests. seems senseless to load 5000 everytime we reset the data.
Tried to test all of this carefully in the test_study_details_documents.py test.
2020-04-29 19:08:11 +00:00
|
|
|
from crc import session
|
2019-12-27 18:50:03 +00:00
|
|
|
from crc.api.common import ApiError, ApiErrorSchema
|
2020-02-27 16:17:58 +00:00
|
|
|
from crc.models.protocol_builder import ProtocolBuilderStatus, ProtocolBuilderStudy
|
Created a "StudyService" and moved all complex logic around study manipulation out of the study api, and this service, as things were getting complicated. The Workflow Processor no longer creates the WorkflowModel, the study object handles that, and only passes the model into the workflow processor when it is ready to start the workflow.
Created a Study object (seperate from the StudyModel) that can cronstructed on request, and contains a different data structure than we store in the DB. This allows us to return underlying Categories and Workflows in a clean way.
Added a new status to workflows called "not_started", meaning we have not yet instantiated a processor or created a BPMN, they have no version yet and no stored data, just the possiblity of being started.
The Top Level Workflow or "Master" workflow is now a part of the sample data, and loaded at all times.
Removed the ability to "add a workflow to a study" and "remove a workflow from a study", a study contains all possible workflows by definition.
Example data no longer creates users or studies, it just creates the specs.
2020-03-30 12:00:16 +00:00
|
|
|
from crc.models.study import StudySchema, StudyModel, Study
|
2020-02-27 16:17:58 +00:00
|
|
|
from crc.services.protocol_builder import ProtocolBuilderService
|
Created a "StudyService" and moved all complex logic around study manipulation out of the study api, and this service, as things were getting complicated. The Workflow Processor no longer creates the WorkflowModel, the study object handles that, and only passes the model into the workflow processor when it is ready to start the workflow.
Created a Study object (seperate from the StudyModel) that can cronstructed on request, and contains a different data structure than we store in the DB. This allows us to return underlying Categories and Workflows in a clean way.
Added a new status to workflows called "not_started", meaning we have not yet instantiated a processor or created a BPMN, they have no version yet and no stored data, just the possiblity of being started.
The Top Level Workflow or "Master" workflow is now a part of the sample data, and loaded at all times.
Removed the ability to "add a workflow to a study" and "remove a workflow from a study", a study contains all possible workflows by definition.
Example data no longer creates users or studies, it just creates the specs.
2020-03-30 12:00:16 +00:00
|
|
|
from crc.services.study_service import StudyService
|
2019-12-18 19:02:17 +00:00
|
|
|
|
|
|
|
|
2020-01-03 16:44:24 +00:00
|
|
|
def add_study(body):
|
Created a "StudyService" and moved all complex logic around study manipulation out of the study api, and this service, as things were getting complicated. The Workflow Processor no longer creates the WorkflowModel, the study object handles that, and only passes the model into the workflow processor when it is ready to start the workflow.
Created a Study object (seperate from the StudyModel) that can cronstructed on request, and contains a different data structure than we store in the DB. This allows us to return underlying Categories and Workflows in a clean way.
Added a new status to workflows called "not_started", meaning we have not yet instantiated a processor or created a BPMN, they have no version yet and no stored data, just the possiblity of being started.
The Top Level Workflow or "Master" workflow is now a part of the sample data, and loaded at all times.
Removed the ability to "add a workflow to a study" and "remove a workflow from a study", a study contains all possible workflows by definition.
Example data no longer creates users or studies, it just creates the specs.
2020-03-30 12:00:16 +00:00
|
|
|
"""This should never get called, and is subject to deprication. Studies
|
|
|
|
should be added through the protocol builder only."""
|
|
|
|
study: Study = StudySchema().load(body)
|
|
|
|
study_model = StudyModel(**study.model_args())
|
|
|
|
session.add(study_model)
|
|
|
|
errors = StudyService._add_all_workflow_specs_to_study(study)
|
2020-01-14 16:45:12 +00:00
|
|
|
session.commit()
|
Created a "StudyService" and moved all complex logic around study manipulation out of the study api, and this service, as things were getting complicated. The Workflow Processor no longer creates the WorkflowModel, the study object handles that, and only passes the model into the workflow processor when it is ready to start the workflow.
Created a Study object (seperate from the StudyModel) that can cronstructed on request, and contains a different data structure than we store in the DB. This allows us to return underlying Categories and Workflows in a clean way.
Added a new status to workflows called "not_started", meaning we have not yet instantiated a processor or created a BPMN, they have no version yet and no stored data, just the possiblity of being started.
The Top Level Workflow or "Master" workflow is now a part of the sample data, and loaded at all times.
Removed the ability to "add a workflow to a study" and "remove a workflow from a study", a study contains all possible workflows by definition.
Example data no longer creates users or studies, it just creates the specs.
2020-03-30 12:00:16 +00:00
|
|
|
study_data = StudySchema().dump(study)
|
2020-03-27 15:55:36 +00:00
|
|
|
study_data["errors"] = ApiErrorSchema(many=True).dump(errors)
|
|
|
|
return study_data
|
2020-01-03 16:44:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
def update_study(study_id, body):
|
|
|
|
if study_id is None:
|
2020-03-23 16:22:26 +00:00
|
|
|
raise ApiError('unknown_study', 'Please provide a valid Study ID.')
|
2020-01-03 16:44:24 +00:00
|
|
|
|
Created a "StudyService" and moved all complex logic around study manipulation out of the study api, and this service, as things were getting complicated. The Workflow Processor no longer creates the WorkflowModel, the study object handles that, and only passes the model into the workflow processor when it is ready to start the workflow.
Created a Study object (seperate from the StudyModel) that can cronstructed on request, and contains a different data structure than we store in the DB. This allows us to return underlying Categories and Workflows in a clean way.
Added a new status to workflows called "not_started", meaning we have not yet instantiated a processor or created a BPMN, they have no version yet and no stored data, just the possiblity of being started.
The Top Level Workflow or "Master" workflow is now a part of the sample data, and loaded at all times.
Removed the ability to "add a workflow to a study" and "remove a workflow from a study", a study contains all possible workflows by definition.
Example data no longer creates users or studies, it just creates the specs.
2020-03-30 12:00:16 +00:00
|
|
|
study_model = session.query(StudyModel).filter_by(id=study_id).first()
|
|
|
|
if study_model is None:
|
2020-03-23 16:22:26 +00:00
|
|
|
raise ApiError('unknown_study', 'The study "' + study_id + '" is not recognized.')
|
2020-01-03 16:44:24 +00:00
|
|
|
|
Created a "StudyService" and moved all complex logic around study manipulation out of the study api, and this service, as things were getting complicated. The Workflow Processor no longer creates the WorkflowModel, the study object handles that, and only passes the model into the workflow processor when it is ready to start the workflow.
Created a Study object (seperate from the StudyModel) that can cronstructed on request, and contains a different data structure than we store in the DB. This allows us to return underlying Categories and Workflows in a clean way.
Added a new status to workflows called "not_started", meaning we have not yet instantiated a processor or created a BPMN, they have no version yet and no stored data, just the possiblity of being started.
The Top Level Workflow or "Master" workflow is now a part of the sample data, and loaded at all times.
Removed the ability to "add a workflow to a study" and "remove a workflow from a study", a study contains all possible workflows by definition.
Example data no longer creates users or studies, it just creates the specs.
2020-03-30 12:00:16 +00:00
|
|
|
study: Study = StudySchema().load(body)
|
|
|
|
study.update_model(study_model)
|
|
|
|
session.add(study_model)
|
2020-01-14 16:45:12 +00:00
|
|
|
session.commit()
|
Created a "StudyService" and moved all complex logic around study manipulation out of the study api, and this service, as things were getting complicated. The Workflow Processor no longer creates the WorkflowModel, the study object handles that, and only passes the model into the workflow processor when it is ready to start the workflow.
Created a Study object (seperate from the StudyModel) that can cronstructed on request, and contains a different data structure than we store in the DB. This allows us to return underlying Categories and Workflows in a clean way.
Added a new status to workflows called "not_started", meaning we have not yet instantiated a processor or created a BPMN, they have no version yet and no stored data, just the possiblity of being started.
The Top Level Workflow or "Master" workflow is now a part of the sample data, and loaded at all times.
Removed the ability to "add a workflow to a study" and "remove a workflow from a study", a study contains all possible workflows by definition.
Example data no longer creates users or studies, it just creates the specs.
2020-03-30 12:00:16 +00:00
|
|
|
return StudySchema().dump(study)
|
2020-01-03 16:44:24 +00:00
|
|
|
|
|
|
|
|
2019-12-18 19:02:17 +00:00
|
|
|
def get_study(study_id):
|
Created a "StudyService" and moved all complex logic around study manipulation out of the study api, and this service, as things were getting complicated. The Workflow Processor no longer creates the WorkflowModel, the study object handles that, and only passes the model into the workflow processor when it is ready to start the workflow.
Created a Study object (seperate from the StudyModel) that can cronstructed on request, and contains a different data structure than we store in the DB. This allows us to return underlying Categories and Workflows in a clean way.
Added a new status to workflows called "not_started", meaning we have not yet instantiated a processor or created a BPMN, they have no version yet and no stored data, just the possiblity of being started.
The Top Level Workflow or "Master" workflow is now a part of the sample data, and loaded at all times.
Removed the ability to "add a workflow to a study" and "remove a workflow from a study", a study contains all possible workflows by definition.
Example data no longer creates users or studies, it just creates the specs.
2020-03-30 12:00:16 +00:00
|
|
|
study_service = StudyService()
|
|
|
|
study = study_service.get_study(study_id)
|
2020-04-08 17:39:42 +00:00
|
|
|
if(study is None):
|
2020-04-08 17:28:43 +00:00
|
|
|
raise ApiError("Study not found", status_code=404)
|
Created a "StudyService" and moved all complex logic around study manipulation out of the study api, and this service, as things were getting complicated. The Workflow Processor no longer creates the WorkflowModel, the study object handles that, and only passes the model into the workflow processor when it is ready to start the workflow.
Created a Study object (seperate from the StudyModel) that can cronstructed on request, and contains a different data structure than we store in the DB. This allows us to return underlying Categories and Workflows in a clean way.
Added a new status to workflows called "not_started", meaning we have not yet instantiated a processor or created a BPMN, they have no version yet and no stored data, just the possiblity of being started.
The Top Level Workflow or "Master" workflow is now a part of the sample data, and loaded at all times.
Removed the ability to "add a workflow to a study" and "remove a workflow from a study", a study contains all possible workflows by definition.
Example data no longer creates users or studies, it just creates the specs.
2020-03-30 12:00:16 +00:00
|
|
|
schema = StudySchema()
|
2019-12-18 19:02:17 +00:00
|
|
|
return schema.dump(study)
|
|
|
|
|
2020-02-26 23:06:51 +00:00
|
|
|
|
2020-03-09 19:12:40 +00:00
|
|
|
def delete_study(study_id):
|
|
|
|
try:
|
Created a "StudyService" and moved all complex logic around study manipulation out of the study api, and this service, as things were getting complicated. The Workflow Processor no longer creates the WorkflowModel, the study object handles that, and only passes the model into the workflow processor when it is ready to start the workflow.
Created a Study object (seperate from the StudyModel) that can cronstructed on request, and contains a different data structure than we store in the DB. This allows us to return underlying Categories and Workflows in a clean way.
Added a new status to workflows called "not_started", meaning we have not yet instantiated a processor or created a BPMN, they have no version yet and no stored data, just the possiblity of being started.
The Top Level Workflow or "Master" workflow is now a part of the sample data, and loaded at all times.
Removed the ability to "add a workflow to a study" and "remove a workflow from a study", a study contains all possible workflows by definition.
Example data no longer creates users or studies, it just creates the specs.
2020-03-30 12:00:16 +00:00
|
|
|
StudyService.delete_study(study_id)
|
2020-03-09 19:12:40 +00:00
|
|
|
except IntegrityError as ie:
|
|
|
|
session.rollback()
|
Created a "StudyService" and moved all complex logic around study manipulation out of the study api, and this service, as things were getting complicated. The Workflow Processor no longer creates the WorkflowModel, the study object handles that, and only passes the model into the workflow processor when it is ready to start the workflow.
Created a Study object (seperate from the StudyModel) that can cronstructed on request, and contains a different data structure than we store in the DB. This allows us to return underlying Categories and Workflows in a clean way.
Added a new status to workflows called "not_started", meaning we have not yet instantiated a processor or created a BPMN, they have no version yet and no stored data, just the possiblity of being started.
The Top Level Workflow or "Master" workflow is now a part of the sample data, and loaded at all times.
Removed the ability to "add a workflow to a study" and "remove a workflow from a study", a study contains all possible workflows by definition.
Example data no longer creates users or studies, it just creates the specs.
2020-03-30 12:00:16 +00:00
|
|
|
message = "Failed to delete Study #%i due to an Integrity Error: %s" % (study_id, str(ie))
|
|
|
|
raise ApiError(code="study_integrity_error", message=message)
|
2020-03-09 19:12:40 +00:00
|
|
|
|
2020-02-27 15:30:16 +00:00
|
|
|
|
2020-03-26 16:51:53 +00:00
|
|
|
def all_studies():
|
|
|
|
"""Returns all the studies associated with the current user. Assures we are
|
|
|
|
in sync with values read in from the protocol builder. """
|
Created a "StudyService" and moved all complex logic around study manipulation out of the study api, and this service, as things were getting complicated. The Workflow Processor no longer creates the WorkflowModel, the study object handles that, and only passes the model into the workflow processor when it is ready to start the workflow.
Created a Study object (seperate from the StudyModel) that can cronstructed on request, and contains a different data structure than we store in the DB. This allows us to return underlying Categories and Workflows in a clean way.
Added a new status to workflows called "not_started", meaning we have not yet instantiated a processor or created a BPMN, they have no version yet and no stored data, just the possiblity of being started.
The Top Level Workflow or "Master" workflow is now a part of the sample data, and loaded at all times.
Removed the ability to "add a workflow to a study" and "remove a workflow from a study", a study contains all possible workflows by definition.
Example data no longer creates users or studies, it just creates the specs.
2020-03-30 12:00:16 +00:00
|
|
|
StudyService.synch_all_studies_with_protocol_builder(g.user)
|
|
|
|
studies = StudyService.get_studies_for_user(g.user)
|
|
|
|
results = StudySchema(many=True).dump(studies)
|
2020-02-28 16:14:30 +00:00
|
|
|
return results
|
2020-02-26 23:06:51 +00:00
|
|
|
|
2020-02-28 16:14:30 +00:00
|
|
|
|
2019-12-18 19:02:17 +00:00
|
|
|
def post_update_study_from_protocol_builder(study_id):
|
2020-02-27 15:30:16 +00:00
|
|
|
"""Update a single study based on data received from
|
2020-02-20 18:30:04 +00:00
|
|
|
the protocol builder."""
|
|
|
|
|
2020-03-26 16:51:53 +00:00
|
|
|
db_study = session.query(StudyModel).filter_by(study_id=study_id).all()
|
2020-03-27 18:27:50 +00:00
|
|
|
pb_studies: List[ProtocolBuilderStudy] = ProtocolBuilderService.get_studies(g.user.uid)
|
2020-03-26 16:51:53 +00:00
|
|
|
pb_study = next((pbs for pbs in pb_studies if pbs.STUDYID == study_id), None)
|
|
|
|
if pb_study:
|
|
|
|
db_study.update_from_protocol_builder(pb_study)
|
|
|
|
else:
|
|
|
|
db_study.inactive = True
|
2020-04-21 21:13:30 +00:00
|
|
|
db_study.protocol_builder_status = ProtocolBuilderStatus.ABANDONED
|
2020-02-28 16:14:30 +00:00
|
|
|
|
2019-12-18 19:02:17 +00:00
|
|
|
return NoContent, 304
|
|
|
|
|
|
|
|
|
2020-03-30 14:12:10 +00:00
|
|
|
|
2020-03-15 19:54:13 +00:00
|
|
|
|
|
|
|
|