2020-02-26 23:06:51 +00:00
|
|
|
import json
|
2020-06-15 16:26:53 +00:00
|
|
|
from json import JSONDecodeError
|
2020-02-27 14:54:46 +00:00
|
|
|
from typing import List, Optional
|
2020-02-26 23:06:51 +00:00
|
|
|
|
2020-02-20 18:30:04 +00:00
|
|
|
import requests
|
|
|
|
|
|
|
|
from crc import app
|
2020-03-03 18:50:22 +00:00
|
|
|
from crc.api.common import ApiError
|
2020-05-25 16:29:05 +00:00
|
|
|
from crc.models.protocol_builder import ProtocolBuilderStudySchema, ProtocolBuilderRequiredDocument
|
2020-02-27 14:54:46 +00:00
|
|
|
|
|
|
|
class ProtocolBuilderService(object):
|
|
|
|
STUDY_URL = app.config['PB_USER_STUDIES_URL']
|
|
|
|
INVESTIGATOR_URL = app.config['PB_INVESTIGATORS_URL']
|
|
|
|
REQUIRED_DOCS_URL = app.config['PB_REQUIRED_DOCS_URL']
|
|
|
|
STUDY_DETAILS_URL = app.config['PB_STUDY_DETAILS_URL']
|
2020-11-04 19:34:10 +00:00
|
|
|
SPONSORS_URL = app.config['PB_SPONSORS_URL']
|
2021-05-01 19:20:47 +00:00
|
|
|
IRB_INFO_URL = app.config['PB_IRB_INFO_URL']
|
2021-07-02 19:25:33 +00:00
|
|
|
CHECK_STUDY_URL = app.config['PB_CHECK_STUDY_URL']
|
2020-02-27 14:54:46 +00:00
|
|
|
|
2020-05-27 02:42:49 +00:00
|
|
|
@staticmethod
|
|
|
|
def is_enabled():
|
2020-05-27 03:38:57 +00:00
|
|
|
if isinstance(app.config['PB_ENABLED'], str):
|
|
|
|
return app.config['PB_ENABLED'].lower() == "true"
|
|
|
|
else:
|
2020-05-27 13:47:44 +00:00
|
|
|
return app.config['PB_ENABLED'] is True
|
2020-05-27 02:42:49 +00:00
|
|
|
|
2020-02-27 14:54:46 +00:00
|
|
|
@staticmethod
|
2020-04-03 20:24:38 +00:00
|
|
|
def get_studies(user_id) -> {}:
|
2020-05-22 18:37:49 +00:00
|
|
|
ProtocolBuilderService.__enabled_or_raise()
|
2020-03-03 18:50:22 +00:00
|
|
|
if not isinstance(user_id, str):
|
2020-06-03 19:03:22 +00:00
|
|
|
raise ApiError("protocol_builder_error", "This user id is invalid: " + str(user_id))
|
2020-06-15 16:26:53 +00:00
|
|
|
url = ProtocolBuilderService.STUDY_URL % user_id
|
|
|
|
response = requests.get(url)
|
2020-02-27 14:54:46 +00:00
|
|
|
if response.ok and response.text:
|
2020-06-15 16:26:53 +00:00
|
|
|
try:
|
|
|
|
pb_studies = ProtocolBuilderStudySchema(many=True).loads(response.text)
|
|
|
|
return pb_studies
|
|
|
|
except JSONDecodeError as err:
|
|
|
|
raise ApiError("protocol_builder_error",
|
|
|
|
"Received an invalid response from the protocol builder. The response is not "
|
|
|
|
"valid json. Url: %s, Response: %s, error: %s" %
|
|
|
|
(url, response.text, err.msg))
|
2020-02-27 14:54:46 +00:00
|
|
|
else:
|
2020-03-03 18:50:22 +00:00
|
|
|
raise ApiError("protocol_builder_error",
|
|
|
|
"Received an invalid response from the protocol builder (status %s): %s" %
|
|
|
|
(response.status_code, response.text))
|
2020-02-27 14:54:46 +00:00
|
|
|
|
|
|
|
@staticmethod
|
2020-04-03 20:24:38 +00:00
|
|
|
def get_investigators(study_id) -> {}:
|
2020-05-22 18:37:49 +00:00
|
|
|
return ProtocolBuilderService.__make_request(study_id, ProtocolBuilderService.INVESTIGATOR_URL)
|
2020-02-27 14:54:46 +00:00
|
|
|
|
|
|
|
@staticmethod
|
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
|
|
|
def get_required_docs(study_id) -> Optional[List[ProtocolBuilderRequiredDocument]]:
|
2020-05-22 18:37:49 +00:00
|
|
|
return ProtocolBuilderService.__make_request(study_id, ProtocolBuilderService.REQUIRED_DOCS_URL)
|
2020-02-27 14:54:46 +00:00
|
|
|
|
|
|
|
@staticmethod
|
2020-04-03 20:24:38 +00:00
|
|
|
def get_study_details(study_id) -> {}:
|
2020-05-22 18:37:49 +00:00
|
|
|
return ProtocolBuilderService.__make_request(study_id, ProtocolBuilderService.STUDY_DETAILS_URL)
|
|
|
|
|
2020-08-25 14:30:46 +00:00
|
|
|
@staticmethod
|
2021-05-01 19:20:47 +00:00
|
|
|
def get_irb_info(study_id) -> {}:
|
|
|
|
return ProtocolBuilderService.__make_request(study_id, ProtocolBuilderService.IRB_INFO_URL)
|
|
|
|
|
|
|
|
@staticmethod
|
2020-08-25 14:30:46 +00:00
|
|
|
def get_sponsors(study_id) -> {}:
|
|
|
|
return ProtocolBuilderService.__make_request(study_id, ProtocolBuilderService.SPONSORS_URL)
|
|
|
|
|
2021-07-02 19:25:33 +00:00
|
|
|
@staticmethod
|
|
|
|
def check_study(study_id) -> {}:
|
|
|
|
return ProtocolBuilderService.__make_request(study_id, ProtocolBuilderService.CHECK_STUDY_URL)
|
|
|
|
|
2020-05-22 18:37:49 +00:00
|
|
|
@staticmethod
|
|
|
|
def __enabled_or_raise():
|
2020-05-27 02:42:49 +00:00
|
|
|
if not ProtocolBuilderService.is_enabled():
|
2020-05-22 18:37:49 +00:00
|
|
|
raise ApiError("protocol_builder_disabled", "The Protocol Builder Service is currently disabled.")
|
2020-03-03 18:50:22 +00:00
|
|
|
|
|
|
|
@staticmethod
|
2020-05-22 18:37:49 +00:00
|
|
|
def __make_request(study_id, url):
|
|
|
|
ProtocolBuilderService.__enabled_or_raise()
|
2020-03-03 18:50:22 +00:00
|
|
|
if not isinstance(study_id, int):
|
|
|
|
raise ApiError("invalid_study_id", "This study id is invalid: " + str(study_id))
|
2020-05-22 18:37:49 +00:00
|
|
|
response = requests.get(url % study_id)
|
|
|
|
if response.ok and response.text:
|
|
|
|
return json.loads(response.text)
|
|
|
|
else:
|
|
|
|
raise ApiError("protocol_builder_error",
|
|
|
|
"Received an invalid response from the protocol builder (status %s): %s when calling "
|
|
|
|
"url '%s'." %
|
|
|
|
(response.status_code, response.text, url))
|