Merge branch 'dev' of github.com:sartography/cr-connect-workflow into dev

This commit is contained in:
Dan 2021-11-11 13:47:43 -05:00
commit ca5e984915
11 changed files with 112 additions and 39 deletions

47
config/logging.py Normal file
View File

@ -0,0 +1,47 @@
logging_config = {
'version': 1,
'disable_existing_loggers': False,
"loggers": {
'': { # root logger
'handlers': ['console', 'file'],
'level': 'INFO',
'propagate': True
},
'alembic.runtime.migration': {
'handlers': ['console', 'file'],
'level': 'ERROR',
'propagate': False
},
'urllib3.connectionpool': {
'handlers': ['console', 'file'],
'level': 'ERROR',
'propagate': False
},
},
"formatters": {
"simple": {
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
}
},
"root": {
"level": "DEBUG",
"handlers": [
"console",
"file",
]
},
"handlers": {
"console": {
"formatter": "simple",
"class": "logging.StreamHandler",
"stream": "ext://sys.stdout",
"level": "DEBUG"
},
"file": {
"level": "INFO",
"formatter": "simple",
"class": "logging.FileHandler",
"filename": "cr_connect.log"
}
}
}

View File

@ -1,5 +1,4 @@
import json
import logging
import logging.config
import os
import click
@ -19,9 +18,6 @@ from sentry_sdk.integrations.flask import FlaskIntegration
from apscheduler.schedulers.background import BackgroundScheduler
from werkzeug.middleware.proxy_fix import ProxyFix
logging.basicConfig(level=logging.INFO)
connexion_app = connexion.FlaskApp(__name__)
app = connexion_app.app
@ -31,9 +27,13 @@ app.config.from_object('config.default')
if "TESTING" in os.environ and os.environ["TESTING"] == "true":
app.config.from_object('config.testing')
app.config.from_pyfile('../config/testing.py')
import logging
logging.basicConfig(level=logging.INFO)
else:
app.config.root_path = app.instance_path
app.config.from_pyfile('config.py', silent=True)
from config.logging import logging_config
logging.config.dictConfig(logging_config)
db = SQLAlchemy(app)

View File

@ -41,20 +41,21 @@ class ProtocolBuilderStatus(enum.Enum):
class ProtocolBuilderStudy(object):
def __init__(
self, STUDYID: int, TITLE: str, NETBADGEID: str,
DATE_MODIFIED: str
DATE_MODIFIED: str, Q_COMPLETE: str, HSRNUMBER: str
):
self.STUDYID = STUDYID
self.TITLE = TITLE
self.NETBADGEID = NETBADGEID
self.DATE_MODIFIED = DATE_MODIFIED
self.Q_COMPLETE = Q_COMPLETE
self.HSRNUMBER = HSRNUMBER
class ProtocolBuilderStudySchema(ma.Schema):
class Meta:
model = ProtocolBuilderStudy
unknown = INCLUDE
fields = ["STUDYID", "TITLE", "NETBADGEID",
"DATE_MODIFIED"]
"DATE_MODIFIED", "Q_COMPLETE"]
@post_load
def make_pbs(self, data, **kwargs):

View File

@ -195,7 +195,11 @@ Please note this is just a few examples, ALL known document types are returned i
if cmd == 'roles':
retval = StudyService().get_investigators(study_id, all=True)
if cmd == 'details':
retval = self.pb.get_study_details(study_id)
details = self.pb.get_study_details(study_id)
if len(details) > 0:
retval = details[0]
else:
retval = None
if cmd == 'sponsors':
retval = self.pb.get_sponsors(study_id)
if cmd == 'documents':

View File

@ -38,8 +38,13 @@ class StudyService(object):
@staticmethod
def _is_valid_study(study_id):
study_info = ProtocolBuilderService().get_study_details(study_id)
if 'REVIEW_TYPE' in study_info.keys() and study_info['REVIEW_TYPE'] in [2, 3, 23, 24]:
study_info = None
study_details = ProtocolBuilderService().get_study_details(study_id)
if len(study_details) > 0:
study_info = study_details[0]
# The review types 2, 3, 23, 24 correspond to review type names
# `Full Committee`, `Expedited`, `Non-UVA IRB Full Board`, and `Non-UVA IRB Expedited`
if isinstance(study_info, dict) and 'REVIEW_TYPE' in study_info.keys() and study_info['REVIEW_TYPE'] in [2, 3, 23, 24]:
return True
return False
@ -273,8 +278,8 @@ class StudyService(object):
for code, doc in doc_dictionary.items():
doc['required'] = False
if ProtocolBuilderService.is_enabled() and doc['id']:
pb_data = next((item for item in pb_docs if int(item['AUXDOCID']) == int(doc['id'])), None)
if ProtocolBuilderService.is_enabled() and doc['id'] != '':
pb_data = next((item for item in pb_docs['AUXDOCS'] if int(item['SS_AUXILIARY_DOC_TYPE_ID']) == int(doc['id'])), None)
if pb_data:
doc['required'] = True

View File

@ -1,22 +1,26 @@
[
{
"AUXDOC": "Cancer Center's PRC Approval Form",
"AUXDOCID": 6
{
"AUXDOCS": [ {
"AUXILIARY_DOC": "Cancer Center's PRC Approval Form",
"SS_AUXILIARY_DOC_TYPE_ID": 6
},
{
"AUXDOC": "InfoSec Approval",
"AUXDOCID": "24"
"AUXILIARY_DOC": "InfoSec Approval",
"SS_AUXILIARY_DOC_TYPE_ID": "24"
},
{
"AUXDOC": "Scientific Pre-review Documentation",
"AUXDOCID": "25"
"AUXILIARY_DOC": "Scientific Pre-review Documentation",
"SS_AUXILIARY_DOC_TYPE_ID": "25"
},
{
"AUXDOC": "GMEC Approval",
"AUXDOCID": "45"
"AUXILIARY_DOC": "GMEC Approval",
"SS_AUXILIARY_DOC_TYPE_ID": "45"
},
{
"AUXDOC": "Laser Safety Officer Approval",
"AUXDOCID": "57"
"AUXILIARY_DOC": "Laser Safety Officer Approval",
"SS_AUXILIARY_DOC_TYPE_ID": "57"
}
]
],
"OTHERDOCS": [],
"TEMPLATEDOCS": []
}

View File

@ -1,4 +1,4 @@
{
[{
"DSMB": 1,
"DSMB_FREQUENCY": 2,
"GCRC_NUMBER": "9",
@ -64,4 +64,4 @@
"SPONSORS_PROTOCOL_REVISION_DATE": "2021-04-20",
"UPLOAD_COMPLETE": null,
"REVIEW_TYPE": 2
}
}]

View File

@ -1,4 +1,4 @@
{
[{
"DSMB": 1,
"DSMB_FREQUENCY": 2,
"GCRC_NUMBER": "9",
@ -64,4 +64,4 @@
"SPONSORS_PROTOCOL_REVISION_DATE": "2021-04-20",
"UPLOAD_COMPLETE": null,
"REVIEW_TYPE": 99
}
}]

View File

@ -3,18 +3,24 @@
"DATE_MODIFIED": "2020-02-19T14:26:49.127756",
"NETBADGEID": "dhf8r",
"STUDYID": 54321,
"TITLE": "Another study about the effect of a naked mannequin on software productivity"
"TITLE": "Another study about the effect of a naked mannequin on software productivity",
"Q_COMPLETE": 0,
"HSRNUMBER": null
},
{
"DATE_MODIFIED": "2020-02-19T14:24:55.101695",
"NETBADGEID": "dhf8r",
"STUDYID": 65432,
"TITLE": "Peanut butter consumption among quiet dogs"
"TITLE": "Peanut butter consumption among quiet dogs",
"Q_COMPLETE": 0,
"HSRNUMBER": null
},
{
"DATE_MODIFIED": "2020-02-19T14:24:55.101695",
"NETBADGEID": "dhf8r",
"STUDYID": 1,
"TITLE": "Efficacy of xenomorph bio-augmented circuits on dexterity of cybernetic prostheses"
"TITLE": "Efficacy of xenomorph bio-augmented circuits on dexterity of cybernetic prostheses",
"Q_COMPLETE": 0,
"HSRNUMBER": null
}
]

View File

@ -35,16 +35,17 @@ class TestProtocolBuilder(BaseTest):
mock_get.return_value.ok = True
mock_get.return_value.text = self.protocol_builder_response('required_docs.json')
response = ProtocolBuilderService.get_required_docs(self.test_study_id)
self.assertIsNotNone(response)
self.assertEqual(5, len(response))
self.assertEqual(6, response[0]['AUXDOCID'])
auxdocs = response['AUXDOCS']
self.assertIsNotNone(auxdocs)
self.assertEqual(5, len(auxdocs))
self.assertEqual(6, auxdocs[0]['SS_AUXILIARY_DOC_TYPE_ID'])
@patch('crc.services.protocol_builder.requests.get')
def test_get_details(self, mock_get):
app.config['PB_ENABLED'] = True
mock_get.return_value.ok = True
mock_get.return_value.text = self.protocol_builder_response('study_details.json')
response = ProtocolBuilderService.get_study_details(self.test_study_id)
response = ProtocolBuilderService.get_study_details(self.test_study_id)[0]
self.assertIsNotNone(response)
self.assertEqual(65, len(response))
self.assertEqual('1234', response['IND_1'])

View File

@ -76,7 +76,7 @@ class TestStudyInfoScript(BaseTest):
app.config['PB_ENABLED'] = True
mock_get.return_value.ok = True
mock_get.return_value.text = self.protocol_builder_response('study_details.json')
response = ProtocolBuilderService.get_study_details(self.test_study_id)
response = ProtocolBuilderService.get_study_details(self.test_study_id)[0]
study_info, second_task = self.do_work(info_type='details')
self.assertEqual(response['IBC_NUMBER'], second_task.data['info']['IBC_NUMBER'])
self.assertEqual(response['IDE'], second_task.data['info']['IDE'])
@ -84,7 +84,12 @@ class TestStudyInfoScript(BaseTest):
self.assertEqual(response['IND_2'], second_task.data['info']['IND_2'])
self.assertEqual(response['IND_3'], second_task.data['info']['IND_3'])
def test_info_script_documents(self):
@patch('crc.services.protocol_builder.requests.get')
def test_info_script_documents(self, mock_get):
app.config['PB_ENABLED'] = True
mock_get.return_value.ok = True
mock_get.return_value.text = self.protocol_builder_response('required_docs.json')
response = ProtocolBuilderService.get_required_docs(self.test_study_id)
study_info, second_task = self.do_work(info_type='documents')
self.assertEqual(study_info, second_task.data['info'])
self.assertEqual(0, len(study_info['Grant_App']['files']), "Grant_App has not files yet.")