Skip to content

Commit

Permalink
feat: validate temp target in Careportal (nightscout#4812)
Browse files Browse the repository at this point in the history
* Adds data validation function to the careportal
* Validate temporary targets define both low and high target and sanitize the values for obvious issues
* Removes unused logging from openaps pill
* Fixes a bug with undefined setting
  • Loading branch information
sulkaharo authored Jul 27, 2019
1 parent 7fe9fef commit fcca512
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 73 deletions.
209 changes: 137 additions & 72 deletions lib/client/careportal.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ var times = require('../times');
var Storages = require('js-storage');

function init (client, $) {
var careportal = { };
var careportal = {};

var translate = client.translate;
var storage = Storages.localStorage;
Expand All @@ -18,7 +18,7 @@ function init (client, $) {
careportal.events = _.map(careportal.allEventTypes, function each (event) {
return _.pick(event, ['val', 'name']);
});

var eventTime = $('#eventTimeValue');
var eventDate = $('#eventDateValue');

Expand All @@ -28,11 +28,11 @@ function init (client, $) {
eventDate.val(time.format('YYYY-MM-DD'));
}

function mergeDateAndTime ( ) {
function mergeDateAndTime () {
return client.utils.mergeInputTime(eventTime.val(), eventDate.val());
}

function updateTime(ele, time) {
function updateTime (ele, time) {
ele.attr('oldminutes', time.minutes());
ele.attr('oldhours', time.hours());
}
Expand All @@ -49,38 +49,38 @@ function init (client, $) {
inputMatrix[event.val] = _.pick(event, ['bg', 'insulin', 'carbs', 'protein', 'fat', 'prebolus', 'duration', 'percent', 'absolute', 'profile', 'split', 'reasons', 'targets']);
});

careportal.filterInputs = function filterInputs ( event ) {
careportal.filterInputs = function filterInputs (event) {
var eventType = $('#eventType').val();

function displayType (enabled) {
if (enabled) {
return '';
} else {
return 'none';
}
}
function resetIfHidden(visible, id) {

function resetIfHidden (visible, id) {
if (!visible) {
$(id).val('');
}
}

var reasons = inputMatrix[eventType]['reasons'];
$('#reasonLabel').css('display',displayType(reasons && reasons.length > 0));
$('#targets').css('display',displayType(inputMatrix[eventType]['targets']));

$('#bg').css('display',displayType(inputMatrix[eventType]['bg']));
$('#insulinGivenLabel').css('display',displayType(inputMatrix[eventType]['insulin']));
$('#carbsGivenLabel').css('display',displayType(inputMatrix[eventType]['carbs']));
$('#proteinGivenLabel').css('display',displayType(inputMatrix[eventType]['protein']));
$('#fatGivenLabel').css('display',displayType(inputMatrix[eventType]['fat']));
$('#durationLabel').css('display',displayType(inputMatrix[eventType]['duration']));
$('#percentLabel').css('display',displayType(inputMatrix[eventType]['percent'] && $('#absolute').val() === ''));
$('#absoluteLabel').css('display',displayType(inputMatrix[eventType]['absolute'] && $('#percent').val() === ''));
$('#profileLabel').css('display',displayType(inputMatrix[eventType]['profile']));
$('#preBolusLabel').css('display',displayType(inputMatrix[eventType]['prebolus']));
$('#insulinSplitLabel').css('display',displayType(inputMatrix[eventType]['split']));
$('#reasonLabel').css('display', displayType(reasons && reasons.length > 0));
$('#targets').css('display', displayType(inputMatrix[eventType]['targets']));

$('#bg').css('display', displayType(inputMatrix[eventType]['bg']));
$('#insulinGivenLabel').css('display', displayType(inputMatrix[eventType]['insulin']));
$('#carbsGivenLabel').css('display', displayType(inputMatrix[eventType]['carbs']));
$('#proteinGivenLabel').css('display', displayType(inputMatrix[eventType]['protein']));
$('#fatGivenLabel').css('display', displayType(inputMatrix[eventType]['fat']));
$('#durationLabel').css('display', displayType(inputMatrix[eventType]['duration']));
$('#percentLabel').css('display', displayType(inputMatrix[eventType]['percent'] && $('#absolute').val() === ''));
$('#absoluteLabel').css('display', displayType(inputMatrix[eventType]['absolute'] && $('#percent').val() === ''));
$('#profileLabel').css('display', displayType(inputMatrix[eventType]['profile']));
$('#preBolusLabel').css('display', displayType(inputMatrix[eventType]['prebolus']));
$('#insulinSplitLabel').css('display', displayType(inputMatrix[eventType]['split']));

$('#reason').empty();
_.each(reasons, function eachReason (reason) {
Expand All @@ -103,7 +103,7 @@ function init (client, $) {
maybePrevent(event);
};

careportal.reasonable = function reasonable ( ) {
careportal.reasonable = function reasonable () {
var eventType = $('#eventType').val();
var reasons = inputMatrix[eventType]['reasons'];
var selected = $('#reason').val();
Expand Down Expand Up @@ -133,10 +133,10 @@ function init (client, $) {
}
};

careportal.prepareEvents = function prepareEvents ( ) {
careportal.prepareEvents = function prepareEvents () {
$('#eventType').empty();
_.each(careportal.events, function eachEvent(event) {
$('#eventType').append('<option value="' + event.val+ '">' + translate(event.name) + '</option>');
_.each(careportal.events, function eachEvent (event) {
$('#eventType').append('<option value="' + event.val + '">' + translate(event.name) + '</option>');
});
$('#eventType').change(careportal.filterInputs);
$('#reason').change(careportal.reasonable);
Expand All @@ -148,7 +148,7 @@ function init (client, $) {
careportal.adjustSplit();
};

careportal.adjustSplit = function adjustSplit(event) {
careportal.adjustSplit = function adjustSplit (event) {
if ($(this).attr('id') === 'insulinSplitNow') {
var nowval = parseInt($('#insulinSplitNow').val()) || 0;
$('#insulinSplitExt').val(100 - nowval);
Expand All @@ -158,22 +158,22 @@ function init (client, $) {
$('#insulinSplitNow').val(100 - extval);
$('#insulinSplitExt').val(extval);
}

maybePrevent(event);
};
careportal.resolveEventName = function resolveEventName(value) {
_.each(careportal.events, function eachEvent(e) {

careportal.resolveEventName = function resolveEventName (value) {
_.each(careportal.events, function eachEvent (e) {
if (e.val === value) {
value = e.name;
}
});
return value;
};

careportal.prepare = function prepare ( ) {
careportal.prepare = function prepare () {
$('#profile').empty();
client.profilefunctions.listBasalProfiles().forEach(function (p) {
client.profilefunctions.listBasalProfiles().forEach(function(p) {
$('#profile').append('<option val="' + p + '">' + p + '</option>');
});
careportal.prepareEvents();
Expand All @@ -195,31 +195,31 @@ function init (client, $) {
setDateAndTime();
};

function gatherData ( ) {
function gatherData () {
var data = {
enteredBy: $('#enteredBy').val()
, eventType: $('#eventType').val()
, glucose: $('#glucoseValue').val().replace(',','.')
, reason: $('#reason').val()
, targetTop: $('#targetTop').val().replace(',','.')
, targetBottom: $('#targetBottom').val().replace(',','.')
, glucoseType: $('#treatment-form').find('input[name=glucoseType]:checked').val()
, carbs: $('#carbsGiven').val()
, protein: $('#proteinGiven').val()
, fat: $('#fatGiven').val()
, insulin: $('#insulinGiven').val()
, duration: times.msecs(parse_duration($('#duration').val())).mins < 1 ? $('#duration').val() : times.msecs(parse_duration($('#duration').val())).mins
, percent: $('#percent').val()
, profile: $('#profile').val()
, preBolus: parseInt($('#preBolus').val())
, notes: $('#notes').val()
, units: client.settings.units
, eventType: $('#eventType').val()
, glucose: $('#glucoseValue').val().replace(',', '.')
, reason: $('#reason').val()
, targetTop: $('#targetTop').val().replace(',', '.')
, targetBottom: $('#targetBottom').val().replace(',', '.')
, glucoseType: $('#treatment-form').find('input[name=glucoseType]:checked').val()
, carbs: $('#carbsGiven').val()
, protein: $('#proteinGiven').val()
, fat: $('#fatGiven').val()
, insulin: $('#insulinGiven').val()
, duration: times.msecs(parse_duration($('#duration').val())).mins < 1 ? $('#duration').val() : times.msecs(parse_duration($('#duration').val())).mins
, percent: $('#percent').val()
, profile: $('#profile').val()
, preBolus: parseInt($('#preBolus').val())
, notes: $('#notes').val()
, units: client.settings.units
};

if (units == "mmol") {
data.targetTop = data.targetTop * 18;
data.targetBottom = data.targetBottom * 18;
}
if (units == "mmol") {
data.targetTop = data.targetTop * 18;
data.targetBottom = data.targetBottom * 18;
}

//special handling for absolute to support temp to 0
var absolute = $('#absolute').val();
Expand All @@ -230,7 +230,7 @@ function init (client, $) {
if ($('#othertime').is(':checked')) {
data.eventTime = mergeDateAndTime().toDate();
}

if (!inputMatrix[data.eventType].profile) {
delete data.profile;
}
Expand Down Expand Up @@ -258,7 +258,59 @@ function init (client, $) {
maybePrevent(event);
};

function buildConfirmText(data) {
function validateData (data) {

let allOk = true;
let messages = [];

console.log('Validating careportal entry: ', data.eventType);

if (data.eventType == 'Temporary Target') {
if (isNaN(data.targetTop) || isNaN(data.targetBottom) || !data.targetBottom || !data.targetTop) {
console.log('Bottom or Top target missing');
allOk = false;
messages.push("Please enter a valid value for both top and bottom target to save a Temporary Target");
} else {

let targetTop = data.targetTop;
let targetBottom = data.targetBottom;

let minTarget = 4 * 18;
let maxTarget = 18 * 18;

if (units == "mmol") {
targetTop = Math.round(targetTop / 18.0 * 10) / 10;
targetBottom = Math.round(targetBottom / 18.0 * 10) / 10;
minTarget = Math.round(minTarget / 18.0 * 10) / 10;
maxTarget = Math.round(maxTarget / 18.0 * 10) / 10;
}

if (targetTop > maxTarget) {
allOk = false;
messages.push("Temporary target high is too high");
}

if (targetBottom < minTarget) {
allOk = false;
messages.push("Temporary target low is too low");
}

if (targetTop < targetBottom || targetBottom > targetTop) {
allOk = false;
messages.push("The low target must be lower than the high target and high target must be higher than the low target.");
}

}
}

return {
allOk
, messages
};

}

function buildConfirmText (data) {
var text = [
translate('Please verify that the data entered is correct') + ': '
, translate('Event Type') + ': ' + translate(careportal.resolveEventName(data.eventType))
Expand All @@ -271,22 +323,22 @@ function init (client, $) {
}

if (data.duration === 0 && data.eventType === 'Temporary Target') {
text[text.length - 1] += ' ' + translate('Cancel');
text[text.length - 1] += ' ' + translate('Cancel');
}

pushIf(data.glucose, translate('Blood Glucose') + ': ' + data.glucose);
pushIf(data.glucose, translate('Measurement Method') + ': ' + translate(data.glucoseType));

pushIf(data.reason, translate('Reason') + ': ' + data.reason);

var targetTop = data.targetTop;
var targetBottom = data.targetBottom;

if (units == "mmol") {
targetTop = Math.round(data.targetTop / 18.0 * 10) / 10;
targetBottom = Math.round(data.targetBottom / 18.0 * 10) / 10;
}
targetTop = Math.round(data.targetTop / 18.0 * 10) / 10;
targetBottom = Math.round(data.targetBottom / 18.0 * 10) / 10;
}

pushIf(data.targetTop, translate('Target Top') + ': ' + targetTop);
pushIf(data.targetBottom, translate('Target Bottom') + ': ' + targetBottom);

Expand All @@ -307,13 +359,27 @@ function init (client, $) {
return text.join('\n');
}

function confirmPost(data) {
if (window.confirm(buildConfirmText(data))) {
postTreatment(data);
function confirmPost (data) {

const validation = validateData(data);

if (!validation.allOk) {

let messages = "";

validation.messages.forEach(function(m) {
messages += translate(m) + "\n";
});

window.alert(messages);
} else {
if (window.confirm(buildConfirmText(data))) {
postTreatment(data);
}
}
}

function postTreatment(data) {
function postTreatment (data) {
if (data.eventType === 'Combo Bolus') {
data.enteredinsulin = data.insulin;
data.insulin = data.enteredinsulin * data.splitNow / 100;
Expand All @@ -322,9 +388,9 @@ function init (client, $) {

$.ajax({
method: 'POST'
, url: '/api/v1/treatments/'
, headers: client.headers()
, data: data
, url: '/api/v1/treatments/'
, headers: client.headers()
, data: data
}).done(function treatmentSaved (response) {
console.info('treatment saved', response);
}).fail(function treatmentSaveFail (response) {
Expand All @@ -336,7 +402,7 @@ function init (client, $) {

client.browserUtils.closeDrawer('#treatmentDrawer');
}

careportal.dateTimeFocus = function dateTimeFocus (event) {
$('#othertime').prop('checked', true);
updateTime($(this), mergeDateAndTime());
Expand Down Expand Up @@ -384,4 +450,3 @@ function init (client, $) {
}

module.exports = init;

5 changes: 4 additions & 1 deletion lib/plugins/openaps.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ function init (ctx) {
var retroFields = cleanList(settings.retroFields);
retroFields = isEmpty(retroFields) ? ['status-symbol', 'status-label', 'iob', 'meal-assist', 'rssi'] : retroFields;

if (typeof settings.colorPredictionLines == 'undefined') {
settings.colorPredictionLines = true;
}

var prefs = {
fields: fields
, retroFields: retroFields
Expand All @@ -59,7 +63,6 @@ function init (ctx) {

if (firstPrefs) {
firstPrefs = false;
console.info('OpenAPS Prefs:', prefs);
}

return prefs;
Expand Down

0 comments on commit fcca512

Please sign in to comment.