Skip to content

Commit

Permalink
Merge branch 'release/v23.2.6'
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-c committed Feb 6, 2023
2 parents 997eedf + e26a82e commit 5a83331
Show file tree
Hide file tree
Showing 9 changed files with 331 additions and 97 deletions.
36 changes: 34 additions & 2 deletions manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,7 @@ def present_before_after_state(user_id, external_study_id, before_state):
print(f"\t\t{item}")
print(f"\t\t\t{modified_t[item][1]} ==> {modified_t[item][0]}")

return after_qnrs, after_timeline

@app.cli.command()
@click.option(
Expand Down Expand Up @@ -877,6 +878,10 @@ def preview_site_update(org_id, retired):

# With new RP in place, cycle through patients, purge and
# refresh timeline and QNR data, and report any diffs
total_qnrs, total_qnrs_assigned = 0, 0
total_qnrs_completed_b4, total_qnrs_completed_after = 0, 0
total_qbs_completed_b4, total_qbs_completed_after = 0, 0
patients_with_fewer_assigned = 0
for patient in query:
QuestionnaireResponse.purge_qb_relationship(
subject_id=patient.id,
Expand All @@ -885,9 +890,36 @@ def preview_site_update(org_id, retired):
)
update_users_QBT(
patient.id, research_study_id=0, invalidate_existing=True)
present_before_after_state(
after_qnrs, after_timeline = present_before_after_state(
patient.id, patient.external_study_id, patient_state[patient.id])

total_qnrs += len(patient_state[patient.id]['qnrs'])
total_qbs_completed_b4 += len(
[1 for date_status in patient_state[patient.id]['timeline'].keys()
if date_status.endswith('Completed') and
not date_status.endswith('Partially Completed')])
total_qbs_completed_after += len(
[1 for date_status in after_timeline.keys()
if date_status.endswith('Completed') and
not date_status.endswith('Partially Completed')])
b4_total = sum(
[1 for qb_name in patient_state[patient.id]['qnrs'].values()
if qb_name[0] != "none of the above"])
total_qnrs_completed_b4 += b4_total
after_total = sum(
[1 for qb_name in after_qnrs.values()
if qb_name[0] != "none of the above"])
total_qnrs_completed_after += after_total
if b4_total != after_total:
patients_with_fewer_assigned += 1

print(f"{total_qnrs} QuestionnaireResponses for all patients in organization {org_id}")
print(organization.name)
print(f" Patients in organization: {len(patient_state)}")
print(f" Patients negatively affected by change: {patients_with_fewer_assigned}")
print(f" Number of those QNRs assigned to a QB before RP change: {total_qnrs_completed_b4}")
print(f" Number of those QNRs assigned to a QB after RP change: {total_qnrs_completed_after}")
print(f" Number of QuestionnaireBanks completed before RP change: {total_qbs_completed_b4}")
print(f" Number of QuestionnaireBanks completed after RP change: {total_qbs_completed_after}")
# Restore organization to pre-test RPs
db.session.delete(new_org_rp)
db.session.commit()
5 changes: 5 additions & 0 deletions portal/config/eproms/AppText.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
"name": "IRONMAN patient privacy URL",
"resourceType": "AppText"
},
{
"custom_text": "{config[LR_ORIGIN]}/c/portal/truenth/asset/mail?version=latest&uuid=890f6204-2dc8-5a5c-617e-4933fab65353&editorUrl=true",
"name": "IRONMAN newsletter",
"resourceType": "AppText"
},
{
"custom_text": "{config[LR_ORIGIN]}/c/portal/truenth/asset/detailed?version=latest&uuid=a455d641-06cb-48b7-a4fd-ddc9fe98a921&editorUrl=true",
"name": "IRONMAN patient terms and conditions URL",
Expand Down
34 changes: 4 additions & 30 deletions portal/config/eproms/Organization.json
Original file line number Diff line number Diff line change
Expand Up @@ -3784,34 +3784,6 @@
},
"resourceType": "Organization"
},
{
"extension": [
{
"timezone": "Europe/Madrid",
"url": "http://hl7.org/fhir/StructureDefinition/user-timezone"
},
{
"research_protocols": [
{"name": "IRONMAN v3"}
],
"url": "http://us.truenth.org/identity-codes/research-protocol"
}
],
"id": 146103,
"identifier": [
{
"system": "http://pcctc.org/",
"use": "secondary",
"value": "146-103"
}
],
"language": "es_ES",
"name": "Hospital Universitario Virgen de la Victoria",
"partOf": {
"reference": "api/organization/29000"
},
"resourceType": "Organization"
},
{
"extension": [
{
Expand Down Expand Up @@ -4110,7 +4082,8 @@
},
{
"research_protocols": [
{"name": "IRONMAN v3"}
{"name": "IRONMAN v3", "retired_as_of": "2023-01-06T20:00:00Z"},
{"name": "IRONMAN v5"}
],
"url": "http://us.truenth.org/identity-codes/research-protocol"
}
Expand Down Expand Up @@ -4138,7 +4111,8 @@
},
{
"research_protocols": [
{"name": "IRONMAN v3"}
{"name": "IRONMAN v3", "retired_as_of": "2023-01-06T20:00:00Z"},
{"name": "IRONMAN v5"}
],
"url": "http://us.truenth.org/identity-codes/research-protocol"
}
Expand Down
16 changes: 15 additions & 1 deletion portal/config/eproms/ScheduledJob.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,27 @@
"id": 6,
"kwargs": {
"research_study_id": 1,
"run_dates": [15, 16, 17, 18, 19, 20, 21],
"org_id": 20000
},
"name": "EMPRO site summary email",
"resourceType": "ScheduledJob",
"schedule": "r 20 20 * *",
"schedule": "r 20 * * 1",
"task": "send_questionnaire_summary"
},
{
"active": false,
"args": null,
"kwargs": {
"org_id": 22000,
"newsletter": "IRONMAN newsletter",
"research_study_id": 0
},
"name": "Send Newsletter",
"resourceType": "ScheduledJob",
"schedule": "0 0 0 0 0",
"task": "send_newsletter"
},
{
"active": true,
"args": null,
Expand Down
48 changes: 47 additions & 1 deletion portal/models/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@

from datetime import datetime
from flask import current_app
from smtplib import SMTPRecipientsRefused
from sqlalchemy.ext.hybrid import hybrid_property
from textwrap import fill

from flask_mail import Message, email_dispatched

from .app_text import MailResource, app_text
from ..audit import auditable_event
from ..database import db
from ..extensions import mail
from .user import INVITE_PREFIX, User
from .organization import OrgTree
from .user import INVITE_PREFIX, User, patients_query


def log_message(message, app):
Expand Down Expand Up @@ -198,3 +201,46 @@ def as_json(self):
'body': self.body, 'sent_at': self.sent_at,
'user_id': self.user_id}
return d


class Newsletter(object):
"""Manages compiling newsletter content and sending out.
"""

def __init__(self, org_id, research_study_id, content_key):
self.org_id = org_id
self.research_study_id = research_study_id
self.content_key = content_key

def transmit(self):
acting_user = User.query.filter_by(email='__system__').one()
resource_url = app_text(self.content_key)
requested_orgs = (
OrgTree().here_and_below_id(organization_id=self.org_id) if self.org_id
else None)
error_emails = []
for patient in patients_query(
acting_user=acting_user,
research_study_id=self.research_study_id,
requested_orgs=requested_orgs):
if not patient.email_ready()[0]:
continue
item = MailResource(resource_url, patient.locale_code)
msg = EmailMessage(
subject=item.subject,
body=item.body,
recipients=patient.email,
sender=current_app.config['MAIL_DEFAULT_SENDER'],
user_id=acting_user.id,
recipient_id=patient.id)
try:
msg.send_message()
except SMTPRecipientsRefused as exc:
current_app.logger.error(
f"Error sending %s to %s: %s",
self.content_key, patient.email, exc)
error_emails.append(patient.email)
db.session.add(msg)

db.session.commit()
return error_emails
69 changes: 63 additions & 6 deletions portal/static/js/src/accountCreation.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import SYSTEM_IDENTIFIER_ENUM from "./modules/SYSTEM_IDENTIFIER_ENUM.js";
import OrgTool from "./modules/OrgTool.js";
import ProcApp from "./modules/Procedures.js";
import {CurrentUserObj} from "./mixins/CurrentUser.js";
import {
REQUIRED_PI_ROLES,
REQUIRED_PI_ROLES_WARNING_MESSAGE,
} from "./data/common/consts.js";

(function() {
var AccountCreationObj = window.AccountCreationObj = function (dependencies) { /*global $ tnthDates Utility*/
Expand Down Expand Up @@ -336,6 +340,17 @@ import {CurrentUserObj} from "./mixins/CurrentUser.js";
}
};

this.hasErrorText = function() {
var hasError = false;
$("#createProfileForm " + HELP_BLOCK_IDENTIFIER).each(function () {
if (hasError) {
return false;
}
hasError = $(this).text() !== "";
});
return hasError;
}

this.__checkFields = function() {

var hasError = false;
Expand All @@ -362,12 +377,7 @@ import {CurrentUserObj} from "./mixins/CurrentUser.js";

/* finally check fields to make sure there isn't error, e.g. due to validation error */
if (!hasError) {
$("#createProfileForm " + HELP_BLOCK_IDENTIFIER).each(function() {
if (hasError) {
return false;
}
hasError = ($(this).text() !== "");
});
hasError = this.hasErrorText();
}

if (hasError) {
Expand All @@ -379,11 +389,20 @@ import {CurrentUserObj} from "./mixins/CurrentUser.js";
return hasError;
};


this.isRoleChecked = function(role) {
if (!role) return false;
return $(`#createProfileForm .input-role[data-role='${role}']`).is(
":checked"
);
};

this.initFieldEvents = function() {
let self = this;
Utility.convertToNumericField($("#date, #year, #phone, #altPhone"));

$("#createProfileForm [required]").on("change", function() {
if (self.hasErrorText()) return;
$("#updateProfile").attr("disabled", false);
setTimeout(function() { self.clearError(); }, 600);
});
Expand All @@ -396,6 +415,44 @@ import {CurrentUserObj} from "./mixins/CurrentUser.js";
$("#createProfileForm input[type='checkbox']").on("change", function() {
$(this).closest(".profile-section").find(HELP_BLOCK_IDENTIFIER).text("").removeClass("error-message");
});

$("#createProfileForm .input-role").on("change", function() {
// PI role checked
var primaryInvestatorRoleChecked = self.isRoleChecked(
"primary_investigator"
);

if (!primaryInvestatorRoleChecked) {
$(this)
.closest(".profile-section")
.find(HELP_BLOCK_IDENTIFIER)
.text("")
.removeClass("error-message");
$("#updateProfile").attr("disabled", false);
return;
}
var requiredRolesChecked = REQUIRED_PI_ROLES.filter((role) =>
self.isRoleChecked(role)
).length > 0;

if (!requiredRolesChecked) {
$(this)
.closest(".profile-section")
.find(HELP_BLOCK_IDENTIFIER)
.html(REQUIRED_PI_ROLES_WARNING_MESSAGE)
.addClass("error-message");
$("#updateProfile").attr("disabled", true);
} else {
$(this)
.closest(".profile-section")
.find(HELP_BLOCK_IDENTIFIER)
.html("")
.addClass("error-message");
$("#updateProfile").attr("disabled", false);
}


});
};

this.setDefaultRoles = function() {
Expand Down
24 changes: 21 additions & 3 deletions portal/static/js/src/data/common/consts.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,27 @@ export var EPROMS_MAIN_STUDY_ID = 0;
export var EPROMS_SUBSTUDY_ID = 1;
export var EPROMS_SUBSTUDY_SHORT_TITLE = "EMPRO";
export var EPROMS_SUBSTUDY_TITLE = i18next.t("IRONMAN EMPRO study");
export var EMPRO_TRIGGER_PROCCESSED_STATES = ["processed", "triggered", "resolved"];
export var EMPRO_TRIGGER_UNPROCCESSED_STATES = ["due", "inprocess", "unstarted"];
export var EMPRO_TRIGGER_PROCCESSED_STATES = [
"processed",
"triggered",
"resolved",
];
export var EMPRO_TRIGGER_UNPROCCESSED_STATES = [
"due",
"inprocess",
"unstarted",
];
export var EPROMS_SUBSTUDY_QUESTIONNAIRE_IDENTIFIER = "ironman_ss";
export var EMPRO_POST_TX_QUESTIONNAIRE_IDENTIFIER = "ironman_ss_post_tx";
//pre-existing translated text
export var DEFAULT_SERVER_DATA_ERROR = i18next.t("Error retrieving data from server");
export var DEFAULT_SERVER_DATA_ERROR = i18next.t(
"Error retrieving data from server"
);
export var REQUIRED_PI_ROLES = ["staff", "staff_admin", "clinician"];
export var REQUIRED_PI_ROLES_WARNING_MESSAGE =
i18next.t(`<p>An account with a Primary Investigator role must also have at least ONE of the following roles:</p>
<ul>
<li><b>Staff</b></li>
<li><b>Admin Staff</b></li>
<li><b>Clinician</b></li>
</ul>`);
Loading

0 comments on commit 5a83331

Please sign in to comment.