diff --git a/app.js b/app.js
index 90bb372a315..2a94b1dd3e9 100644
--- a/app.js
+++ b/app.js
@@ -29,19 +29,7 @@ function create (env, ctx) {
const enableCSP = env.secureCsp ? true : false;
- console.info('Enabled SECURE_HSTS_HEADER (HTTP Strict Transport Security)');
- const helmet = require('helmet');
- var includeSubDomainsValue = env.secureHstsHeaderIncludeSubdomains;
- var preloadValue = env.secureHstsHeaderPreload;
- app.use(helmet({
- hsts: {
- maxAge: 31536000
- , includeSubDomains: includeSubDomainsValue
- , preload: preloadValue
- }
- , frameguard: false
- , contentSecurityPolicy: enableCSP
- }));
+ let cspPolicy = false;
if (enableCSP) {
var secureCspReportOnly = env.secureCspReportOnly;
@@ -60,7 +48,7 @@ function create (env, ctx) {
}
}
- app.use(helmet.contentSecurityPolicy({ //TODO make NS work without 'unsafe-inline'
+ cspPolicy = { //TODO make NS work without 'unsafe-inline'
directives: {
defaultSrc: ["'self'"]
, styleSrc: ["'self'", 'https://fonts.googleapis.com/', 'https://fonts.gstatic.com/', "'unsafe-inline'"]
@@ -76,7 +64,26 @@ function create (env, ctx) {
, frameAncestors: frameAncestors
}
, reportOnly: secureCspReportOnly
- }));
+ };
+ }
+
+
+ console.info('Enabled SECURE_HSTS_HEADER (HTTP Strict Transport Security)');
+ const helmet = require('helmet');
+ var includeSubDomainsValue = env.secureHstsHeaderIncludeSubdomains;
+ var preloadValue = env.secureHstsHeaderPreload;
+ app.use(helmet({
+ hsts: {
+ maxAge: 31536000
+ , includeSubDomains: includeSubDomainsValue
+ , preload: preloadValue
+ }
+ , frameguard: false
+ , contentSecurityPolicy: cspPolicy
+ }));
+
+ if (enableCSP) {
+
app.use(helmet.referrerPolicy({ policy: 'no-referrer' }));
app.use(bodyParser.json({ type: ['json', 'application/csp-report'] }));
app.post('/report-violation', (req, res) => {
diff --git a/lib/authorization/storage.js b/lib/authorization/storage.js
index c032018d170..d602470add6 100644
--- a/lib/authorization/storage.js
+++ b/lib/authorization/storage.js
@@ -210,16 +210,28 @@ function init (env, ctx) {
if (!accessToken) return null;
- var split_token = accessToken.split('-');
- var prefix = split_token ? _.last(split_token) : '';
- if (prefix.length < 16) {
- return null;
- }
+ function checkToken(accessToken) {
+ var split_token = accessToken.split('-');
+ var prefix = split_token ? _.last(split_token) : '';
- return _.find(storage.subjects, function matches (subject) {
- return subject.accessTokenDigest.indexOf(accessToken) === 0 || subject.digest.indexOf(prefix) === 0;
- });
+ if (prefix.length < 16) {
+ return null;
+ }
+
+ return _.find(storage.subjects, function matches (subject) {
+ return subject.accessTokenDigest.indexOf(accessToken) === 0 || subject.digest.indexOf(prefix) === 0;
+ });
+ }
+
+ if (!Array.isArray(accessToken)) accessToken = [accessToken];
+
+ for (let i=0; i < accessToken.length; i++) {
+ const subject = checkToken(accessToken[i]);
+ if (subject) return subject;
+ }
+
+ return null;
};
storage.doesAccessTokenExist = function doesAccessTokenExist(accessToken) {
diff --git a/lib/client/clock-client.js b/lib/client/clock-client.js
index 891f10d57d5..73ac9c3baca 100644
--- a/lib/client/clock-client.js
+++ b/lib/client/clock-client.js
@@ -1,53 +1,55 @@
'use strict';
-const browserSettings = require('./browser-settings');
-
+var browserSettings = require('./browser-settings');
var client = {};
+var latestProperties = {};
client.settings = browserSettings(client, window.serverSettings, $);
-//console.log('settings', client.settings);
-// client.settings now contains all settings
-
client.query = function query () {
- console.log('query');
var parts = (location.search || '?').substring(1).split('&');
var token = '';
- parts.forEach(function (val) {
+ parts.forEach(function(val) {
if (val.startsWith('token=')) {
token = val.substring('token='.length);
}
});
var secret = localStorage.getItem('apisecrethash');
- var src = '/api/v1/entries.json?find[type]=sgv&count=3&t=' + new Date().getTime();
+ var src = '/api/v2/properties'; // Use precalculated data from the backend
if (secret) {
- src += '&secret=' + secret;
+ var s = '?secret=' + secret;
+ src += s;
} else if (token) {
- src += '&token=' + token;
+ var s2 = '?token=' + token;
+ src += s2;
}
$.ajax(src, {
- success: client.render
+ error: function gotError (err) {
+ console.error(err);
+ }
+ , success: function gotData (data) {
+ latestProperties = data;
+ client.render();
+ }
});
};
-client.render = function render (xhr) {
- console.log('got data', xhr);
+client.render = function render () {
- let rec;
- let delta;
+ if (!latestProperties.bgnow && !latestProperties.bgnow.sgvs) {
+ console.error('BG data not available');
+ return;
+ }
- // Get SGV, calculate DELTA
- xhr.forEach(element => {
- if (element.sgv && !rec) {
- rec = element;
- }
- else if (element.sgv && rec && delta==null) {
- delta = (rec.sgv - element.sgv)/((rec.date - element.date)/(5*60*1000));
- }
- });
+ let rec = latestProperties.bgnow.sgvs[0];
+ let deltaDisplayValue;
+
+ if (latestProperties.delta) {
+ deltaDisplayValue = latestProperties.delta.display;
+ }
let $errorMessage = $('#errorMessage');
let $inner = $('#inner');
@@ -71,15 +73,12 @@ client.render = function render (xhr) {
// Backward compatible
if (face === 'clock-color') {
- face = 'c' + (window.serverSettings.settings.showClockLastTime ? 'y' : 'n') + '13-sg40-' + (window.serverSettings.settings.showClockDelta ? 'dt14-' : '') + 'nl-ar30-nl-ag6';
- }
- else if (face === 'clock') {
+ face = 'c' + (window.serverSettings.settings.showClockLastTime ? 'y' : 'n') + '13-sg35-' + (window.serverSettings.settings.showClockDelta ? 'dt14-' : '') + 'nl-ar25-nl-ag6';
+ } else if (face === 'clock') {
face = 'bn0-sg40';
- }
- else if (face === 'bgclock') {
- face = 'bn0-sg30-ar18-nl-nl-tm26';
- }
- else if (face === 'config') {
+ } else if (face === 'bgclock') {
+ face = 'b' + (window.serverSettings.settings.showClockLastTime ? 'y' : 'n') + '13-sg35-' + (window.serverSettings.settings.showClockDelta ? 'dt14-' : '') + 'nl-ar25-nl-ag6';
+ } else if (face === 'config') {
face = $inner.attr('data-face-config');
$inner.empty();
}
@@ -95,46 +94,19 @@ client.render = function render (xhr) {
if (param === '0') {
bgColor = (faceParams[param].substr(0, 1) === 'c'); // do we want colorful background?
alwaysShowTime = (faceParams[param].substr(1, 1) === 'y'); // always show "stale time" text?
- staleMinutes = (faceParams[param].substr(2,2) - 0 >= 0) ? faceParams[param].substr(2,2) : 13; // threshold value (0=never)
- } else if (!clockCreated){
- let div = '
0) ? ' style="' + ((faceParams[param].substr(0,2) === 'ar') ? 'height' : 'font-size') + ':' + faceParams[param].substr(2,2) + 'vmin"' : '') + '>
';
+ staleMinutes = (faceParams[param].substr(2, 2) - 0 >= 0) ? faceParams[param].substr(2, 2) : 13; // threshold value (0=never)
+ } else if (!clockCreated) {
+ let div = ' 0) ? ' style="' + ((faceParams[param].substr(0, 2) === 'ar') ? 'height' : 'font-size') + ':' + faceParams[param].substr(2, 2) + 'vmin"' : '') + '>
';
$inner.append(div);
}
}
// Convert BG to mmol/L if necessary.
- let displayValue;
- let deltaDisplayValue;
-
- if (window.serverSettings.settings.units === 'mmol') {
- displayValue = window.Nightscout.units.mgdlToMMOL(rec.sgv);
- deltaDisplayValue = window.Nightscout.units.mgdlToMMOL(delta);
- } else {
- displayValue = rec.sgv;
- deltaDisplayValue = Math.round(delta);
- }
-
- if (deltaDisplayValue > 0) {
- deltaDisplayValue = '+' + deltaDisplayValue;
- }
+ let displayValue = rec.scaled;
// Insert the delta value text.
$('.dt').html(deltaDisplayValue);
- // Generate and insert the clock.
- let timeDivisor = parseInt(client.settings.timeFormat ? client.settings.timeFormat : 12, 10);
- let today = new Date()
- , h = today.getHours() % timeDivisor;
- if (timeDivisor === 12) {
- h = (h === 0) ? 12 : h; // In the case of 00:xx, change to 12:xx for 12h time
- }
- if (timeDivisor === 24) {
- h = (h < 10) ? ("0" + h) : h; // Pad the hours with a 0 in 24h time
- }
- let m = today.getMinutes();
- if (m < 10) m = "0" + m;
- $('.tm').html(h + ":" + m);
-
// Color background
if (bgColor) {
@@ -150,7 +122,7 @@ client.render = function render (xhr) {
let bgTargetBottom = client.settings.thresholds.bgTargetBottom;
let bgTargetTop = client.settings.thresholds.bgTargetTop;
- let bgNum = parseFloat(rec.sgv);
+ let bgNum = parseFloat(rec.mgdl);
// Threshold background coloring.
if (bgNum < bgLow) {
@@ -169,20 +141,16 @@ client.render = function render (xhr) {
$('body').css('background-color', red);
}
- }
- else {
+ } else {
$('body').css('background-color', 'black');
}
// Time before data considered stale.
let threshold = 1000 * 60 * staleMinutes;
- let last = new Date(rec.date);
- let now = new Date();
-
- let elapsedMins = Math.round(((now - last) / 1000) / 60);
-
- let thresholdReached = (now - last > threshold) && threshold > 0;
+ var elapsedms = Date.now() - rec.mills;
+ let elapsedMins = Math.floor((elapsedms / 1000) / 60);
+ let thresholdReached = (elapsedms > threshold) && threshold > 0;
// Insert the BG value text, toggle stale if necessary.
$('.sg').toggleClass('stale', thresholdReached).html(displayValue);
@@ -191,17 +159,14 @@ client.render = function render (xhr) {
let staleTimeText;
if (elapsedMins === 0) {
staleTimeText = 'Just now';
- }
- else if (elapsedMins === 1) {
+ } else if (elapsedMins === 1) {
staleTimeText = '1 minute ago';
- }
- else {
+ } else {
staleTimeText = elapsedMins + ' minutes ago';
}
$('.ag').html(staleTimeText);
- }
- else {
+ } else {
$('.ag').html('');
}
@@ -216,12 +181,33 @@ client.render = function render (xhr) {
$('body').css('color', bgColor ? 'white' : 'grey');
$('.ar').css('filter', bgColor ? 'brightness(100%)' : 'brightness(50%)').html(arrow);
}
+
+ updateClock();
+
};
+function updateClock () {
+ let timeDivisor = parseInt(client.settings.timeFormat ? client.settings.timeFormat : 12, 10);
+ let today = new Date()
+ , h = today.getHours() % timeDivisor;
+ if (timeDivisor === 12) {
+ h = (h === 0) ? 12 : h; // In the case of 00:xx, change to 12:xx for 12h time
+ }
+ if (timeDivisor === 24) {
+ h = (h < 10) ? ("0" + h) : h; // Pad the hours with a 0 in 24h time
+ }
+ let m = today.getMinutes();
+ if (m < 10) m = "0" + m;
+ $('.tm').html(h + ":" + m);
+}
+
client.init = function init () {
- console.log('init');
+ console.log('Initializing clock');
client.query();
- setInterval(client.query, 1 * 60 * 1000);
+ setInterval(client.query, 20 * 1000); // update every 20 seconds
+
+ // time update
+ setInterval(updateClock, 1000);
};
module.exports = client;
diff --git a/lib/data/dataloader.js b/lib/data/dataloader.js
index 7074b18e1fb..985ea259de5 100644
--- a/lib/data/dataloader.js
+++ b/lib/data/dataloader.js
@@ -392,7 +392,7 @@ function loadSensorAndInsulinTreatments(ddata, ctx, callback) {
function loadLatestSingle(ddata, ctx, dataType, callback) {
var dateRange = {
- $gte: new Date(ddata.lastUpdated - (constants.ONE_DAY * 32)).toISOString()
+ $gte: new Date(ddata.lastUpdated - (constants.ONE_DAY * 62)).toISOString()
};
if (ddata.page && ddata.page.frame) {
diff --git a/lib/plugins/ar2.js b/lib/plugins/ar2.js
index ab8675a0342..7a5d5e5dcfa 100644
--- a/lib/plugins/ar2.js
+++ b/lib/plugins/ar2.js
@@ -67,8 +67,10 @@ function init (ctx) {
var prop = sbx.properties.ar2;
- if (prop) {
- sbx.notifications.requestNotify({
+ console.log('ar2', prop);
+
+ if (prop && prop.level) {
+ const notify = {
level: prop.level
, title: buildTitle(prop, sbx)
, message: sbx.buildDefaultMessage()
@@ -76,7 +78,8 @@ function init (ctx) {
, pushoverSound: pushoverSound(prop, sbx.levels)
, plugin: ar2
, debug: buildDebug(prop, sbx)
- });
+ };
+ sbx.notifications.requestNotify(notify);
}
};
@@ -224,9 +227,9 @@ function selectEventType (prop, sbx) {
var eventName = '';
if (in20mins !== undefined) {
- if (in20mins > sbx.scaleMgdl(sbx.settings.thresholds.bgTargetTop)) {
+ if (sbx.settings.alarmHigh && in20mins > sbx.scaleMgdl(sbx.settings.thresholds.bgTargetTop)) {
eventName = 'high';
- } else if (in20mins < sbx.scaleMgdl(sbx.settings.thresholds.bgTargetBottom)) {
+ } else if (sbx.settings.alarmLow && in20mins < sbx.scaleMgdl(sbx.settings.thresholds.bgTargetBottom)) {
eventName = 'low';
}
}
diff --git a/lib/plugins/bgnow.js b/lib/plugins/bgnow.js
index 512a23805c2..f3d835788bf 100644
--- a/lib/plugins/bgnow.js
+++ b/lib/plugins/bgnow.js
@@ -146,12 +146,12 @@ function init (ctx) {
bgnow.calcDelta = function calcDelta (recent, previous, sbx) {
if (_.isEmpty(recent)) {
- console.info('all buckets are empty');
+ //console.info('No recent CGM data is available');
return null;
}
if (_.isEmpty(previous)) {
- console.info('previous bucket not found, not calculating delta');
+ //console.info('previous bucket not found, not calculating delta');
return null;
}
diff --git a/lib/plugins/simplealarms.js b/lib/plugins/simplealarms.js
index 9b975dddebe..17529eabee8 100644
--- a/lib/plugins/simplealarms.js
+++ b/lib/plugins/simplealarms.js
@@ -12,6 +12,7 @@ function init() {
};
simplealarms.checkNotifications = function checkNotifications(sbx) {
+
var lastSGVEntry = sbx.lastSGVEntry()
, scaledSGV = sbx.scaleEntry(lastSGVEntry)
;
@@ -37,27 +38,31 @@ function init() {
simplealarms.compareBGToTresholds = function compareBGToTresholds(scaledSGV, sbx) {
var result = { level: levels.INFO };
- if (scaledSGV > sbx.scaleMgdl(sbx.settings.thresholds.bgHigh)) {
+ if (sbx.settings.alarmUrgentHigh && scaledSGV > sbx.scaleMgdl(sbx.settings.thresholds.bgHigh)) {
result.level = levels.URGENT;
result.title = levels.toDisplay(levels.URGENT) + ' HIGH';
result.pushoverSound = 'persistent';
result.eventName = 'high';
- } else if (scaledSGV > sbx.scaleMgdl(sbx.settings.thresholds.bgTargetTop)) {
- result.level = levels.WARN;
- result.title = levels.toDisplay(levels.WARN) + ' HIGH';
- result.pushoverSound = 'climb';
- result.eventName = 'high';
- } else if (scaledSGV < sbx.scaleMgdl(sbx.settings.thresholds.bgLow)) {
+ } else
+ if (sbx.settings.alarmHigh && scaledSGV > sbx.scaleMgdl(sbx.settings.thresholds.bgTargetTop)) {
+ result.level = levels.WARN;
+ result.title = levels.toDisplay(levels.WARN) + ' HIGH';
+ result.pushoverSound = 'climb';
+ result.eventName = 'high';
+ }
+
+ if (sbx.settings.alarmUrgentLow && scaledSGV < sbx.scaleMgdl(sbx.settings.thresholds.bgLow)) {
result.level = levels.URGENT;
result.title = levels.toDisplay(levels.URGENT) + ' LOW';
result.pushoverSound = 'persistent';
result.eventName = 'low';
- } else if (scaledSGV < sbx.scaleMgdl(sbx.settings.thresholds.bgTargetBottom)) {
+ } else if (sbx.settings.alarmLow && scaledSGV < sbx.scaleMgdl(sbx.settings.thresholds.bgTargetBottom)) {
result.level = levels.WARN;
result.title = levels.toDisplay(levels.WARN) + ' LOW';
result.pushoverSound = 'falling';
result.eventName = 'low';
}
+
return result;
};
diff --git a/lib/server/bootevent.js b/lib/server/bootevent.js
index 6247645b3d2..4ee45e054d5 100644
--- a/lib/server/bootevent.js
+++ b/lib/server/bootevent.js
@@ -25,30 +25,21 @@ function boot (env, language) {
var semver = require('semver');
var nodeVersion = process.version;
- if ( semver.satisfies(nodeVersion, '^8.15.1') || semver.satisfies(nodeVersion, '^10.16.0')) {
- //Latest Node 8 LTS and Latest Node 10 LTS are recommended and supported.
+ const isLTS = process.release.lts ? true : false;
+
+ if (!isLTS) {
+ console.log( 'ERROR: Node version ' + nodeVersion + ' is not supported. Please use a secure LTS version or upgrade your Node');
+ process.exit(1);
+ }
+
+ if (semver.satisfies(nodeVersion, '^12.0.0') || semver.satisfies(nodeVersion, '^10.0.0')) {
+ //Latest Node 10 LTS and Node 12 LTS are recommended and supported.
//Require at least Node 8 LTS and Node 10 LTS without known security issues
console.debug('Node LTS version ' + nodeVersion + ' is supported');
next();
}
- else if ( semver.eq(nodeVersion, '10.15.2')) {
- //Latest Node version on Azure is tolerated, but not recommended
- console.log('WARNING: Node version v10.15.2 and Microsoft Azure are not recommended.');
- console.log('WARNING: Please migrate to another hosting provider. Your Node version is outdated and insecure');
- next();
- }
- else if ( semver.satisfies(nodeVersion, '^12.6.0')) {
- //Latest Node version
- console.debug('Node version ' + nodeVersion + ' is not a LTS version. Not recommended. Not supported');
- next();
- } else {
- // Other versions will not start
- console.log( 'ERROR: Node version ' + nodeVersion + ' is not supported. Please use a secure LTS version or upgrade your Node');
- process.exit(1);
- }
}
-
function checkEnv (ctx, next) {
ctx.language = language;
if (env.err) {
@@ -255,7 +246,7 @@ function boot (env, language) {
});
ctx.bus.on('data-loaded', function updatePlugins ( ) {
- // console.info('reloading sandbox data');
+ console.info('data loaded: reloading sandbox data and updating plugins');
var sbx = require('../sandbox')().serverInit(env, ctx);
ctx.plugins.setProperties(sbx);
ctx.notifications.initRequests();
diff --git a/lib/storage/mongo-storage.js b/lib/storage/mongo-storage.js
index 39c1a81e641..28dea49ac75 100644
--- a/lib/storage/mongo-storage.js
+++ b/lib/storage/mongo-storage.js
@@ -36,59 +36,71 @@ function init (env, cb, forceNewConnection) {
MongoClient.connect(env.storageURI, options)
.then(client => {
- console.log('Successfully established a connected to MongoDB');
-
- var dbName = env.storageURI.split('/').pop().split('?');
- dbName = dbName[0]; // drop Connection Options
- mongo.db = client.db(dbName);
- connection = mongo.db;
- mongo.client = client;
- // If there is a valid callback, then invoke the function to perform the callback
-
- if (cb && cb.call) {
- cb(null, mongo);
- }
- })
- .catch(err => {
- if (err.message && err.message.includes('AuthenticationFailed')) {
- console.log('Authentication to Mongo failed');
- cb(new Error('MongoDB authentication failed! Double check the URL has the right username and password in MONGODB_URI.'), null);
- return;
- }
-
- if (err.name && err.name === "MongoNetworkError") {
- var timeout = (i > 15) ? 60000 : i * 3000;
- console.log('Error connecting to MongoDB: %j - retrying in ' + timeout / 1000 + ' sec', err);
- setTimeout(connect_with_retry, timeout, i + 1);
- if (i == 1) cb(new Error('MongoDB connection failed! Double check the MONGODB_URI setting in Heroku.'), null);
- } else {
- cb(new Error('MONGODB_URI ' + env.storageURI + ' seems invalid: ' + err.message));
+ console.log('Successfully established a connected to MongoDB');
+
+ var dbName = env.storageURI.split('/').pop().split('?');
+ dbName = dbName[0]; // drop Connection Options
+ mongo.db = client.db(dbName);
+ connection = mongo.db;
+ mongo.client = client;
+
+ mongo.db.command({ connectionStatus: 1 }).then(
+ result => {
+ const roles = result.authInfo.authenticatedUserRoles;
+ if (roles.lenght > 0 && roles[0].role == 'read') {
+ console.error('Mongo user is read only');
+ cb(new Error('MongoDB connection is in read only mode! Go back to MongoDB configuration and check your database user has read and write access.'), null);
+ }
+
+ console.log('Mongo user role seems ok:', roles);
+
+ // If there is a valid callback, then invoke the function to perform the callback
+ if (cb && cb.call) {
+ cb(null, mongo);
+ }
}
- });
+ );
+ })
+ .catch(err => {
+ if (err.message && err.message.includes('AuthenticationFailed')) {
+ console.log('Authentication to Mongo failed');
+ cb(new Error('MongoDB authentication failed! Double check the URL has the right username and password in MONGODB_URI.'), null);
+ return;
+ }
+
+ if (err.name && err.name === "MongoNetworkError") {
+ var timeout = (i > 15) ? 60000 : i * 3000;
+ console.log('Error connecting to MongoDB: %j - retrying in ' + timeout / 1000 + ' sec', err);
+ setTimeout(connect_with_retry, timeout, i + 1);
+ if (i == 1) cb(new Error('MongoDB connection failed! Double check the MONGODB_URI setting in Heroku.'), null);
+ } else {
+ cb(new Error('MONGODB_URI ' + env.storageURI + ' seems invalid: ' + err.message));
+ }
+ });
- };
+ };
- return connect_with_retry(1);
+ return connect_with_retry(1);
- }
}
+ }
- mongo.collection = function get_collection (name) {
- return connection.collection(name);
- };
-
- mongo.ensureIndexes = function ensureIndexes (collection, fields) {
- fields.forEach(function(field) {
- console.info('ensuring index for: ' + field);
- collection.createIndex(field, { 'background': true }, function(err) {
- if (err) {
- console.error('unable to ensureIndex for: ' + field + ' - ' + err);
- }
- });
+ mongo.collection = function get_collection (name) {
+ return connection.collection(name);
+ };
+
+ mongo.ensureIndexes = function ensureIndexes (collection, fields) {
+ fields.forEach(function(field) {
+ console.info('ensuring index for: ' + field);
+ collection.createIndex(field, { 'background': true }, function(err) {
+ if (err) {
+ console.error('unable to ensureIndex for: ' + field + ' - ' + err);
+ }
});
- };
+ });
+ };
- return maybe_connect(cb);
- }
+ return maybe_connect(cb);
+}
- module.exports = init;
+module.exports = init;
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 4e143615a3d..a137dcd1533 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -3405,12 +3405,62 @@
}
},
"env-cmd": {
- "version": "8.0.2",
- "resolved": "https://registry.npmjs.org/env-cmd/-/env-cmd-8.0.2.tgz",
- "integrity": "sha512-gHX8MnQXw1iS7dc2KeJdBdxca7spIkxkNwIuORLwm8kDg6xHh5wWnv1Yv3pc64nLZR6kufQSCmwTz16sRmd/rg==",
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/env-cmd/-/env-cmd-10.1.0.tgz",
+ "integrity": "sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA==",
"dev": true,
"requires": {
- "cross-spawn": "^6.0.5"
+ "commander": "^4.0.0",
+ "cross-spawn": "^7.0.0"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+ "dev": true
+ },
+ "cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "requires": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ }
+ },
+ "path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true
+ },
+ "shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^3.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true
+ },
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ }
}
},
"errno": {
diff --git a/package.json b/package.json
index a2694ae0297..bbc6f063262 100644
--- a/package.json
+++ b/package.json
@@ -27,18 +27,18 @@
},
"scripts": {
"start": "node server.js",
- "test": "env-cmd ./my.test.env mocha --exit tests/*.test.js",
- "test-single": "env-cmd ./my.test.env mocha --exit tests/$TEST.test.js",
- "test-ci": "env-cmd ./ci.test.env nyc --reporter=lcov --reporter=text-summary mocha --exit tests/*.test.js",
+ "test": "env-cmd -f ./my.test.env mocha --exit tests/*.test.js",
+ "test-single": "env-cmd -f ./my.test.env mocha --exit tests/$TEST.test.js",
+ "test-ci": "env-cmd -f ./ci.test.env nyc --reporter=lcov --reporter=text-summary mocha --exit tests/*.test.js",
"env": "env",
"postinstall": "webpack --mode production --config webpack.config.js && npm run-script update-buster",
"bundle": "webpack --mode production --config webpack.config.js && npm run-script update-buster",
"bundle-dev": "webpack --mode development --config webpack.config.js && npm run-script update-buster",
"bundle-analyzer": "webpack --mode development --config webpack.config.js --profile --json > stats.json && webpack-bundle-analyzer stats.json",
"update-buster": "node bin/generateCacheBuster.js >tmp/cacheBusterToken",
- "coverage": "cat ./coverage/lcov.info | env-cmd ./ci.test.env codacy-coverage",
- "dev": "env-cmd ./my.env nodemon server.js 0.0.0.0",
- "prod": "env-cmd ./my.prod.env node server.js 0.0.0.0",
+ "coverage": "cat ./coverage/lcov.info | env-cmd -f ./ci.test.env codacy-coverage",
+ "dev": "env-cmd -f ./my.env nodemon server.js 0.0.0.0",
+ "prod": "env-cmd -f ./my.prod.env node server.js 0.0.0.0",
"lint": "eslint lib"
},
"main": "server.js",
@@ -57,8 +57,8 @@
}
},
"engines": {
- "node": "^10.15.2 || ^8.15.1",
- "npm": "^6.4.1"
+ "node": "^10.22.0 || ^12.18.4",
+ "npm": "^6.14.6"
},
"dependencies": {
"@babel/core": "^7.11.1",
@@ -126,7 +126,7 @@
"benv": "^3.3.0",
"codacy-coverage": "^3.4.0",
"csv-parse": "^4.12.0",
- "env-cmd": "^8.0.2",
+ "env-cmd": "^10.1.0",
"eslint": "^6.8.0",
"eslint-loader": "^2.2.1",
"mocha": "^8.1.1",
diff --git a/tests/api.entries.test.js b/tests/api.entries.test.js
index 098b5c45663..6c0c3f14e45 100644
--- a/tests/api.entries.test.js
+++ b/tests/api.entries.test.js
@@ -307,4 +307,66 @@ describe('Entries REST api', function ( ) {
});
});
+ it('post multipole entries, query, delete, verify gone', function (done) {
+ // insert a glucose entry - needs to be unique from example data
+ console.log('Inserting glucose entry')
+ request(self.app)
+ .post('/entries/')
+ .set('api-secret', self.env.api_secret || '')
+ .send([{
+ "type": "sgv", "sgv": "199", "dateString": "2014-07-20T00:44:15.000-07:00"
+ , "date": 1405791855000, "device": "dexcom", "direction": "NOT COMPUTABLE"
+ }, {
+ "type": "sgv", "sgv": "200", "dateString": "2014-07-20T00:44:15.001-07:00"
+ , "date": 1405791855001, "device": "dexcom", "direction": "NOT COMPUTABLE"
+ }])
+ .expect(200)
+ .end(function (err) {
+ if (err) {
+ done(err);
+ } else {
+ // make sure treatment was inserted successfully
+ console.log('Ensuring glucose entry was inserted successfully');
+ request(self.app)
+ .get('/entries.json?find[dateString][$gte]=2014-07-20&count=100')
+ .set('api-secret', self.env.api_secret || '')
+ .expect(200)
+ .expect(function (response) {
+ var entry = response.body[0];
+ response.body.length.should.equal(2);
+ entry.sgv.should.equal('200');
+ entry.utcOffset.should.equal(-420);
+ })
+ .end(function (err) {
+ if (err) {
+ done(err);
+ } else {
+ // delete the glucose entry
+ console.log('Deleting test glucose entry');
+ request(self.app)
+ .delete('/entries.json?find[dateString][$gte]=2014-07-20&count=100')
+ .set('api-secret', self.env.api_secret || '')
+ .expect(200)
+ .end(function (err) {
+ if (err) {
+ done(err);
+ } else {
+ // make sure it was deleted
+ console.log('Testing if glucose entries were deleted');
+ request(self.app)
+ .get('/entries.json?find[dateString][$gte]=2014-07-20&count=100')
+ .set('api-secret', self.env.api_secret || '')
+ .expect(200)
+ .expect(function (response) {
+ response.body.length.should.equal(0);
+ })
+ .end(done);
+ }
+ });
+ }
+ });
+ }
+ });
+ });
+
});
diff --git a/views/index.html b/views/index.html
index dbff801392f..8e60b30f471 100644
--- a/views/index.html
+++ b/views/index.html
@@ -730,7 +730,7 @@
reg.addEventListener('updatefound', () => {
console.log('Service worker update detected');
reg.update();
- const newWorker = reg.installing;
+ var newWorker = reg.installing;
newWorker.addEventListener('statechange', (state) => {
console.log('New worker state change', state);
window.location.reload(true);