Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TN-3324 robust handling of unsortable patient list attributes #4414

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 46 additions & 42 deletions portal/models/patient_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,49 +53,53 @@ def patient_list_update_patient(patient_id, research_study_id=None):
if not user.has_role(ROLE.PATIENT.value):
return

patient = PatientList.query.get(patient_id)
new_record = False
if not patient:
new_record = True
patient = PatientList(userid=patient_id)
db.session.add(patient)
from ..timeout_lock import TimeoutLock
# async possibility, only allow one thread at a time
key = f"patient_list_update_patient:{patient_id}"
with TimeoutLock(key, expires=60, timeout=60):
patient = PatientList.query.get(patient_id)
new_record = False
if not patient:
new_record = True
patient = PatientList(userid=patient_id)
db.session.add(patient)

if research_study_id is None or new_record:
patient.study_id = user.external_study_id
patient.firstname = user.first_name
patient.lastname = user.last_name
patient.email = user.email
patient.birthdate = user.birthdate
patient.deleted = user.deleted_id is not None
patient.test_role = True if user.has_role(ROLE.TEST.value) else False
patient.org_id = user.organizations[0].id if user.organizations else None
patient.org_name = user.organizations[0].name if user.organizations else None
if research_study_id is None or new_record:
patient.study_id = user.external_study_id
patient.firstname = user.first_name
patient.lastname = user.last_name
patient.email = user.email
patient.birthdate = user.birthdate
patient.deleted = user.deleted_id is not None
patient.test_role = True if user.has_role(ROLE.TEST.value) else False
patient.org_id = user.organizations[0].id if user.organizations else None
patient.org_name = user.organizations[0].name if user.organizations else None

# necessary to avoid recursive loop via some update paths
now = datetime.utcnow()
if patient.last_updated and patient.last_updated + timedelta(seconds=10) > now:
db.session.commit()
return
# necessary to avoid recursive loop via some update paths
now = datetime.utcnow()
if patient.last_updated and patient.last_updated + timedelta(seconds=10) > now:
db.session.commit()
return

patient.last_updated = now
if research_study_id == BASE_RS_ID or research_study_id is None:
rs_id = BASE_RS_ID
qb_status = qb_status_visit_name(
patient.userid, research_study_id=rs_id, as_of_date=now)
patient.questionnaire_status = str(qb_status['status'])
patient.visit = qb_status['visit_name']
patient.consentdate, _ = consent_withdrawal_dates(user=user, research_study_id=rs_id)
patient.last_updated = now
if research_study_id == BASE_RS_ID or research_study_id is None:
rs_id = BASE_RS_ID
qb_status = qb_status_visit_name(
patient.userid, research_study_id=rs_id, as_of_date=now)
patient.questionnaire_status = str(qb_status['status'])
patient.visit = qb_status['visit_name']
patient.consentdate, _ = consent_withdrawal_dates(user=user, research_study_id=rs_id)

if (research_study_id == EMPRO_RS_ID or research_study_id is None) and user.clinicians:
rs_id = EMPRO_RS_ID
patient.clinician = '; '.join(
(clinician_name_map().get(c.id, "not in map") for c in user.clinicians)) or ""
qb_status = qb_status_visit_name(
patient.userid, research_study_id=rs_id, as_of_date=now)
patient.empro_status = str(qb_status['status'])
patient.empro_visit = qb_status['visit_name']
patient.action_state = qb_status['action_state'].title() \
if qb_status['action_state'] else ""
patient.empro_consentdate, _ = consent_withdrawal_dates(
user=user, research_study_id=rs_id)
db.session.commit()
if (research_study_id == EMPRO_RS_ID or research_study_id is None) and user.clinicians:
rs_id = EMPRO_RS_ID
patient.clinician = '; '.join(
(clinician_name_map().get(c.id, "not in map") for c in user.clinicians)) or ""
qb_status = qb_status_visit_name(
patient.userid, research_study_id=rs_id, as_of_date=now)
patient.empro_status = str(qb_status['status'])
patient.empro_visit = qb_status['visit_name']
patient.action_state = qb_status['action_state'].title() \
if qb_status['action_state'] else ""
patient.empro_consentdate, _ = consent_withdrawal_dates(
user=user, research_study_id=rs_id)
db.session.commit()
4 changes: 2 additions & 2 deletions portal/models/qb_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ def _sync_timeline(self):

completed = QBT.query.filter(QBT.user_id == self.user.id).filter(
QBT.research_study_id == self.research_study_id).filter(
QBT.status == OverallStatus.completed).count()
self.at_least_one_completed = completed > 0
QBT.status == OverallStatus.completed).with_entities(QBT.id).first()
self.at_least_one_completed = completed is not None

# Obtain withdrawal date if applicable
withdrawn = QBT.query.filter(QBT.user_id == self.user.id).filter(
Expand Down
3 changes: 2 additions & 1 deletion portal/static/js/src/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -1323,7 +1323,8 @@ let requestTimerId = 0;
) {
var tnthAjax = this.getDependency("tnthAjax");
tableName = tableName || this.tableIdentifier;
if (!tableName) {
if (!tableName || !document.querySelector("#adminTable")) {
if (callback) callback();
return false;
}
userId = userId || this.userId;
Expand Down
10 changes: 10 additions & 0 deletions portal/static/js/src/modules/TnthAjax.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ export default { /*global $ */
$.ajax("/api/me").done(
function() {
console.log("user authorized");
if ((typeof CsrfTokenChecker !== "undefined") &&
!CsrfTokenChecker.checkTokenValidity()) {
//if CSRF Token not valid, return error
if (callback) {
callback({"error": DEFAULT_SERVER_DATA_ERROR});
fieldHelper.showError(targetField);
}
return;
}

ajaxCall();
}
).fail(function() {
Expand Down
2 changes: 2 additions & 0 deletions portal/templates/admin/admin_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@
// custom ajax request here
function patientDataAjaxRequest(params) {
loadIntervalId = setInterval(() => {
//document DOM not ready, don't make ajax call yet
if (!document.querySelector("#adminTable")) return;
if (typeof window.AdminObj === "undefined") return;
window.AdminObj.getRemotePatientListData(params);
clearInterval(loadIntervalId);
Expand Down
4 changes: 4 additions & 0 deletions portal/views/patients.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ def filter_query(query, filter_field, filter_value):
# ignore requests to filter by unknown column
return query

if filter_field in ('birthdate', 'consentdate', 'empro_consentdate'):
# these are not filterable (partial strings on date complexity) - ignore such a request
return query

if filter_field == 'userid':
query = query.filter(PatientList.userid == int(filter_value))
return query
Expand Down
2 changes: 0 additions & 2 deletions requirements.dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ pyparsing==2.4.7 # via packaging
pytest >= 6.1.0
pytest-flask==0.15.1
pytest-timeout==1.4.2
selenium==3.141.0
snowballstemmer==2.0.0 # via sphinx
sphinx-rtd-theme==0.5.1
sphinx==3.3.1
Expand All @@ -36,5 +35,4 @@ virtualenv==20.4.2 # via tox
waitress==1.4.3 # via webtest
webob==1.8.5 # via webtest
webtest==2.0.33 # via flask-webtest
xvfbwrapper==0.2.9
--editable .
141 changes: 0 additions & 141 deletions tests/integration_tests/__init__.py

This file was deleted.

8 changes: 0 additions & 8 deletions tests/integration_tests/pages.py

This file was deleted.

64 changes: 0 additions & 64 deletions tests/integration_tests/test_login.py

This file was deleted.

Loading