Adds user to example data. Requires login before adding/updating a study.

This commit is contained in:
Aaron Louie 2020-02-27 10:30:16 -05:00
parent 27d7afb656
commit f3068e68db
5 changed files with 119 additions and 86 deletions

View File

@ -12,6 +12,7 @@ from models.protocol_builder import ProtocolBuilderStatus, ProtocolBuilderStudy
from crc.models.workflow import WorkflowModel, WorkflowApiSchema, WorkflowSpecModel
from crc.services import protocol_builder
from crc.services.workflow_processor import WorkflowProcessor
from services.protocol_builder import ProtocolBuilderService
@auth.login_required
@ -19,38 +20,24 @@ def all_studies():
user = g.user
""":type: crc.models.user.UserModel"""
# Get studies matching this user from Protocol Builder
pb_studies: List[ProtocolBuilderStudy] = protocol_builder.get_studies(user.uid)
schema = StudyModelSchema(many=True)
update_from_protocol_builder()
db_studies = session.query(StudyModel).filter_by(user_uid=user.uid).all()
db_study_ids = list(map(lambda s: s.id, db_studies))
for pb_study in pb_studies:
if pb_study['HSRNUMBER'] not in db_study_ids:
status = ProtocolBuilderStatus.complete._value_ if pb_study['Q_COMPLETE'] else ProtocolBuilderStatus.in_process._value_
add_study({
'id': pb_study['HSRNUMBER'],
'title': pb_study['TITLE'],
'protocol_builder_status': status,
'user_uid': pb_study['NETBADGEID'],
'last_updated': pb_study['DATE_MODIFIED']
})
db_studies = session.query(StudyModel).filter_by(user_uid=user.uid).all()
return schema.dump(db_studies)
return StudyModelSchema(many=True).dump(db_studies)
@auth.login_required
def add_study(body):
study = StudyModelSchema().load(body, session=session)
session.add(study)
session.commit()
# FIXME: We need to ask the protocol builder what workflows to add to the study, not just add them all.
for spec in session.query(WorkflowSpecModel).all():
WorkflowProcessor.create(study.id, spec.id)
return StudyModelSchema().dump(study)
@auth.login_required
def update_study(study_id, body):
if study_id is None:
error = ApiError('unknown_study', 'Please provide a valid Study ID.')
@ -68,6 +55,7 @@ def update_study(study_id, body):
return StudyModelSchema().dump(study)
@auth.login_required
def get_study(study_id):
study = session.query(StudyModel).filter_by(id=study_id).first()
schema = StudyModelSchema()
@ -76,12 +64,34 @@ def get_study(study_id):
return schema.dump(study)
@auth.login_required
def update_from_protocol_builder():
"""Call the """
"""Updates the list of known studies for a given user based on data received from
the protocol builder."""
user = g.user
""":type: crc.models.user.UserModel"""
# Get studies matching this user from Protocol Builder
pb_studies: List[ProtocolBuilderStudy] = ProtocolBuilderService.get_studies(user.uid)
db_studies = session.query(StudyModel).filter_by(user_uid=user.uid).all()
db_study_ids = list(map(lambda s: s.id, db_studies))
for pb_study in pb_studies:
if pb_study['HSRNUMBER'] not in db_study_ids:
status = ProtocolBuilderStatus.complete._value_ if pb_study['Q_COMPLETE'] else ProtocolBuilderStatus.in_process._value_
add_study({
'id': pb_study['HSRNUMBER'],
'title': pb_study['TITLE'],
'protocol_builder_status': status,
'user_uid': pb_study['NETBADGEID'],
'last_updated': pb_study['DATE_MODIFIED']
})
def post_update_study_from_protocol_builder(study_id):
"""This will update the list of known studies based on data received from
"""Update a single study based on data received from
the protocol builder."""
# todo: Actually get data from an external service here

View File

@ -1,16 +1,31 @@
import datetime
import glob
import os
import xml.etree.ElementTree as ElementTree
from crc import app, db, session
from crc.models.file import FileType, FileModel, FileDataModel
from crc.models.study import StudyModel
from crc.models.user import UserModel
from crc.models.workflow import WorkflowSpecModel
import xml.etree.ElementTree as ElementTree
from crc.services.workflow_processor import WorkflowProcessor
class ExampleDataLoader:
def make_data(self):
users = [
UserModel(
uid='dhf8r',
email_address='dhf8r@virginia.EDU',
display_name='Daniel Harold Funk',
affiliation='staff@virginia.edu;member@virginia.edu',
eppn='dhf8r@virginia.edu',
first_name='Daniel',
last_name='Funk',
title='SOFTWARE ENGINEER V'
)
]
studies = [
StudyModel(
id=1,
@ -19,7 +34,8 @@ class ExampleDataLoader:
protocol_builder_status='in_process',
primary_investigator_id='dhf8r',
sponsor='Sartography Pharmaceuticals',
ind_number='1234'
ind_number='1234',
user_uid='dhf8r'
),
StudyModel(
id=2,
@ -28,7 +44,8 @@ class ExampleDataLoader:
protocol_builder_status='in_process',
primary_investigator_id='dhf8r',
sponsor='Makerspace & Co.',
ind_number='5678'
ind_number='5678',
user_uid='dhf8r'
),
]
@ -69,11 +86,11 @@ class ExampleDataLoader:
description='How to take different paths based on input.')
workflow_specifications += \
self.create_spec(id="docx",
name="docx",
display_name="Form with document generation",
description='the name says it all')
name="docx",
display_name="Form with document generation",
description='the name says it all')
all_data = studies + workflow_specifications
all_data = users + studies + workflow_specifications
return all_data
def create_spec(self, id, name, display_name="", description="", filepath=None):
@ -112,7 +129,7 @@ class ExampleDataLoader:
try:
file = open(file_path, "rb")
data = file.read()
if(is_primary):
if (is_primary):
bpmn: ElementTree.Element = ElementTree.fromstring(data)
spec.primary_process_id = WorkflowProcessor.get_process_id(bpmn)
print("Locating Process Id for " + filename + " " + spec.primary_process_id)
@ -121,7 +138,6 @@ class ExampleDataLoader:
file.close()
return models
@staticmethod
def clean_db():
session.flush() # Clear out any transactions before deleting it all to avoid spurious errors.

View File

@ -3,11 +3,13 @@
import json
import os
import unittest
import urllib.parse
os.environ["TESTING"] = "true"
from crc.models.file import FileModel, FileDataModel
from crc.models.workflow import WorkflowSpecModel
os.environ["TESTING"] = "true"
from crc.models.user import UserModel
from crc import app, db, session
from example_data import ExampleDataLoader
@ -18,14 +20,13 @@ from example_data import ExampleDataLoader
# logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
# Great class to inherit from, as it sets up and tears down
# classes efficiently when we have a database in place.
class BaseTest(unittest.TestCase):
""" Great class to inherit from, as it sets up and tears down classes
efficiently when we have a database in place.
"""
auths = {}
test_uid = "dhf8r"
@classmethod
def setUpClass(cls):
@ -48,6 +49,25 @@ class BaseTest(unittest.TestCase):
self.ctx.pop()
self.auths = {}
def logged_in_headers(self, user=None, redirect_url='http://some/frontend/url'):
if user is None:
uid = self.test_uid
user_info = {'uid': self.test_uid, 'first_name': 'Daniel', 'last_name': 'Funk',
'email_address': 'dhf8r@virginia.edu'}
else:
uid = user.uid
user_info = {'uid': user.uid, 'first_name': user.first_name, 'last_name': user.last_name,
'email_address': user.email_address}
query_string = self.user_info_to_query_string(user_info, redirect_url)
rv = self.app.get("/v1.0/sso_backdoor%s" % query_string, follow_redirects=False)
self.assertTrue(rv.status_code == 302)
self.assertTrue(str.startswith(rv.location, redirect_url))
user_model = session.query(UserModel).filter_by(uid=uid).first()
self.assertIsNotNone(user_model.display_name)
return dict(Authorization='Bearer ' + user_model.encode_auth_token().decode())
def load_example_data(self):
from example_data import ExampleDataLoader
ExampleDataLoader.clean_db()
@ -66,7 +86,8 @@ class BaseTest(unittest.TestCase):
self.assertIsNotNone(file_data)
self.assertGreater(len(file_data), 0)
def load_test_spec(self, dir_name):
@staticmethod
def load_test_spec(dir_name):
"""Loads a spec into the database based on a directory in /tests/data"""
if session.query(WorkflowSpecModel).filter_by(id=dir_name).count() > 0:
return
@ -81,7 +102,8 @@ class BaseTest(unittest.TestCase):
session.flush()
return spec
def protocol_builder_response(self, file_name):
@staticmethod
def protocol_builder_response(file_name):
filepath = os.path.join(app.root_path, '..', 'tests', 'data', 'pb_responses', file_name)
with open(filepath, 'r') as myfile:
data = myfile.read()
@ -102,3 +124,16 @@ class BaseTest(unittest.TestCase):
"Incorrect Valid Response:" + rv.status + ".")
if code != 0:
self.assertEqual(code, rv.status_code)
@staticmethod
def user_info_to_query_string(user_info, redirect_url):
query_string_list = []
items = user_info.items()
for key, value in items:
query_string_list.append('%s=%s' % (key, urllib.parse.quote(value)))
query_string_list.append('redirect_url=%s' % redirect_url)
return '?%s' % '&'.join(query_string_list)

View File

@ -1,31 +1,9 @@
import urllib.parse
from crc import db
from crc.models.user import UserModel
from tests.base_test import BaseTest
class TestAuthentication(BaseTest):
test_uid = "dhf8r"
def logged_in_headers(self, user=None, redirect_url='http://some/frontend/url'):
if user is None:
uid = self.test_uid
user_info = {'uid': self.test_uid, 'first_name': 'Daniel', 'last_name': 'Funk',
'email_address': 'dhf8r@virginia.edu'}
else:
uid = user.uid
user_info = {'uid': user.uid, 'first_name': user.first_name, 'last_name': user.last_name,
'email_address': user.email_address}
query_string = self.user_info_to_query_string(user_info, redirect_url)
rv = self.app.get("/v1.0/sso_backdoor%s" % query_string, follow_redirects=False)
self.assertTrue(rv.status_code == 302)
self.assertTrue(str.startswith(rv.location, redirect_url))
user_model = UserModel.query.filter_by(uid=uid).first()
self.assertIsNotNone(user_model.display_name)
return dict(Authorization='Bearer ' + user_model.encode_auth_token().decode())
def test_auth_token(self):
self.load_example_data()
@ -35,12 +13,13 @@ class TestAuthentication(BaseTest):
self.assertEqual("dhf8r", user.decode_auth_token(auth_token))
def test_auth_creates_user(self):
new_uid = 'czn1z';
self.load_example_data()
user = db.session.query(UserModel).filter(UserModel.uid == self.test_uid).first()
user = db.session.query(UserModel).filter(UserModel.uid == new_uid).first()
self.assertIsNone(user)
user_info = {'uid': self.test_uid, 'first_name': 'Daniel', 'last_name': 'Funk',
'email_address': 'dhf8r@virginia.edu'}
user_info = {'uid': new_uid, 'first_name': 'Cordi', 'last_name': 'Nator',
'email_address': 'czn1z@virginia.edu'}
redirect_url = 'http://worlds.best.website/admin'
query_string = self.user_info_to_query_string(user_info, redirect_url)
url = '/v1.0/sso_backdoor%s' % query_string
@ -48,7 +27,7 @@ class TestAuthentication(BaseTest):
self.assertTrue(rv_1.status_code == 302)
self.assertTrue(str.startswith(rv_1.location, redirect_url))
user = db.session.query(UserModel).filter(UserModel.uid == self.test_uid).first()
user = db.session.query(UserModel).filter(UserModel.uid == new_uid).first()
self.assertIsNotNone(user)
self.assertIsNotNone(user.display_name)
self.assertIsNotNone(user.email_address)
@ -69,15 +48,3 @@ class TestAuthentication(BaseTest):
user = UserModel(uid="ajl2j", first_name='Aaron', last_name='Louie', email_address='ajl2j@virginia.edu')
rv = self.app.get('/v1.0/user', headers=self.logged_in_headers(user, redirect_url='http://omg.edu/lolwut'))
self.assert_success(rv)
def user_info_to_query_string(self, user_info, redirect_url):
query_string_list = []
items = user_info.items()
for key, value in items:
query_string_list.append('%s=%s' % (key, urllib.parse.quote(value)))
query_string_list.append('redirect_url=%s' % redirect_url)
return '?%s' % '&'.join(query_string_list)

View File

@ -1,8 +1,7 @@
import json
from datetime import datetime, tzinfo, timezone
from datetime import datetime, timezone
from crc import session
from crc.models.file import FileModel
from crc.models.study import StudyModel, StudyModelSchema
from models.protocol_builder import ProtocolBuilderStatus
from crc.models.workflow import WorkflowSpecModel, WorkflowSpecModelSchema, WorkflowModel, WorkflowStatus, \
@ -21,7 +20,8 @@ class TestStudyApi(BaseTest):
self.load_example_data()
study = {
"id": 12345,
"title": "Phase III Trial of Genuine People Personalities (GPP) Autonomous Intelligent Emotional Agents for Interstellar Spacecraft",
"title": "Phase III Trial of Genuine People Personalities (GPP) Autonomous Intelligent Emotional Agents "
"for Interstellar Spacecraft",
"last_updated": datetime.now(tz=timezone.utc),
"protocol_builder_status": ProtocolBuilderStatus.in_process,
"primary_investigator_id": "tricia.marie.mcmillan@heartofgold.edu",
@ -30,6 +30,7 @@ class TestStudyApi(BaseTest):
}
rv = self.app.post('/v1.0/study',
content_type="application/json",
headers=self.logged_in_headers(),
data=json.dumps(StudyModelSchema().dump(study)))
self.assert_success(rv)
db_study = session.query(StudyModel).filter_by(id=12345).first()
@ -41,16 +42,15 @@ class TestStudyApi(BaseTest):
self.assertEqual(study["sponsor"], db_study.sponsor)
self.assertEqual(study["ind_number"], db_study.ind_number)
def test_update_study(self):
self.load_example_data()
study: StudyModel = session.query(StudyModel).first()
study.title = "Pilot Study of Fjord Placement for Single Fraction Outcomes to Cortisol Susceptibility"
study.protocol_builder_status = ProtocolBuilderStatus.complete
rv = self.app.put('/v1.0/study/%i' % study.id,
content_type="application/json",
data=json.dumps(StudyModelSchema().dump(study)))
content_type="application/json",
headers=self.logged_in_headers(),
data=json.dumps(StudyModelSchema().dump(study)))
self.assert_success(rv)
db_study = session.query(StudyModel).filter_by(id=study.id).first()
self.assertIsNotNone(db_study)
@ -62,6 +62,7 @@ class TestStudyApi(BaseTest):
study = session.query(StudyModel).first()
rv = self.app.get('/v1.0/study/%i' % study.id,
follow_redirects=True,
headers=self.logged_in_headers(),
content_type="application/json")
self.assert_success(rv)
json_data = json.loads(rv.get_data(as_text=True))
@ -80,7 +81,9 @@ class TestStudyApi(BaseTest):
study = session.query(StudyModel).first()
self.assertEqual(0, session.query(WorkflowModel).count())
spec = session.query(WorkflowSpecModel).first()
rv = self.app.post('/v1.0/study/%i/workflows' % study.id, content_type="application/json",
rv = self.app.post('/v1.0/study/%i/workflows' % study.id,
content_type="application/json",
headers=self.logged_in_headers(),
data=json.dumps(WorkflowSpecModelSchema().dump(spec)))
self.assert_success(rv)
self.assertEqual(1, session.query(WorkflowModel).count())
@ -98,7 +101,9 @@ class TestStudyApi(BaseTest):
self.load_example_data()
study = session.query(StudyModel).first()
spec = session.query(WorkflowSpecModel).first()
rv = self.app.post('/v1.0/study/%i/workflows' % study.id, content_type="application/json",
rv = self.app.post('/v1.0/study/%i/workflows' % study.id,
content_type="application/json",
headers=self.logged_in_headers(),
data=json.dumps(WorkflowSpecModelSchema().dump(spec)))
self.assertEqual(1, session.query(WorkflowModel).count())
json_data = json.loads(rv.get_data(as_text=True))