Skip to content

Commit

Permalink
Merge pull request nightscout#8 from nightscout/dev
Browse files Browse the repository at this point in the history
Refresh dev from nightscout
  • Loading branch information
lixgbg authored May 28, 2018
2 parents c69357e + 019ce15 commit fafd01a
Show file tree
Hide file tree
Showing 41 changed files with 5,252 additions and 1,236 deletions.
5 changes: 3 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ language: node_js
sudo: required
dist: trusty
node_js:
- "8.9.3"
before_install: if [[ `npm --version` != "5.6" ]]; then npm install -g npm@latest; npm --version; fi
- "8"
- "9"
before_install: if [[ `npm --version` != "5.8.0" ]]; then npm install -g npm@latest; npm --version; fi
matrix:
fast_finish: true
services:
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ Community maintained fork of the

Requirements:

- [Node.js](http://nodejs.org/) 8.9.0 LTS (use [Install instructions for Node](https://nodejs.org/en/download/package-manager/) or `setup.sh`)
- [Node.js](http://nodejs.org/) 8.11.0 LTS or later or [Node.js](http://nodejs.org/) 9.10.0 or later. Use [Install instructions for Node](https://nodejs.org/en/download/package-manager/) or `setup.sh`)
- [MongoDB](https://www.mongodb.com/download-center?jmp=nav#community) 3.x. MongoDB 2.4 is only supported for Raspberry Pi.

Clone this repo then install dependencies into the root of the project:

Expand Down Expand Up @@ -215,6 +216,7 @@ To learn more about the Nightscout API, visit https://YOUR-SITE.com/api-docs.htm
* `MONGO_DEVICESTATUS_COLLECTION`(`devicestatus`) - The collection used to store device status information such as uploader battery
* `MONGO_PROFILE_COLLECTION`(`profile`) - The collection used to store your profiles
* `MONGO_FOOD_COLLECTION`(`food`) - The collection used to store your food database
* `MONGO_ACTIVITY_COLLECTION`(`activity`) - The collection used to store activity data
* `PORT` (`1337`) - The port that the node.js application will listen on.
* `HOSTNAME` - The hostname that the node.js application will listen on, null by default for any hostname for IPv6 you may need to use `::`.
* `SSL_KEY` - Path to your ssl key file, so that ssl(https) can be enabled directly in node.js
Expand Down
13 changes: 10 additions & 3 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ function create(env, ctx) {
// pebble data
app.get('/pebble', ctx.pebble);

// expose swagger.yaml
app.get('/swagger.yaml', function(req, res) {
res.sendFile(__dirname + '/swagger.yaml');
// expose swagger.json
app.get('/swagger.json', function(req, res) {
res.sendFile(__dirname + '/swagger.json');
});

/*
Expand Down Expand Up @@ -141,6 +141,13 @@ function create(env, ctx) {
// serve the static content
app.use(staticFiles);

var swaggerFiles = express.static(env.swagger_files, {
maxAge: maxAge
});

// serve the static content
app.use('/swagger-ui-dist', swaggerFiles);

var tmpFiles = express.static('tmp', {
maxAge: maxAge
});
Expand Down
4 changes: 2 additions & 2 deletions bundle/bundle.source.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import '../static/css/drawer.css';
import '../static/css/dropdown.css';
import '../static/css/sgv.css';
import '../node_modules/jquery.tipsy/src/jquery.tipsy.css';
import '../node_modules/jquery.tooltips/css/jquery.tooltips.css';


$ = require("jquery");
Expand All @@ -11,7 +11,7 @@ require('jquery-ui-bundle');
window._ = require('lodash');
window.d3 = require('d3');

require('jquery.tipsy');
require('jquery.tooltips');

window.Storage = require('js-storage');

Expand Down
2 changes: 2 additions & 0 deletions env.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ function config ( ) {
env.HOSTNAME = readENV('HOSTNAME', null);
env.IMPORT_CONFIG = readENV('IMPORT_CONFIG', null);
env.static_files = readENV('NIGHTSCOUT_STATIC_FILES', __dirname + '/static/');
env.swagger_files = readENV('NIGHTSCOUT_SWAGGER_FILES', __dirname + '/node_modules/swagger-ui-dist/');
env.debug = {
minify: readENVTruthy('DEBUG_MINIFY', true)
};
Expand Down Expand Up @@ -105,6 +106,7 @@ function setStorage() {
env.profile_collection = readENV('MONGO_PROFILE_COLLECTION', 'profile');
env.devicestatus_collection = readENV('MONGO_DEVICESTATUS_COLLECTION', 'devicestatus');
env.food_collection = readENV('MONGO_FOOD_COLLECTION', 'food');
env.activity_collection = readENV('MONGO_ACTIVITY_COLLECTION', 'activity');

// TODO: clean up a bit
// Some people prefer to use a json configuration file instead.
Expand Down
127 changes: 127 additions & 0 deletions lib/api/activity/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
'use strict';

var _ = require('lodash');
var consts = require('../../constants');
var moment = require('moment');

function configure(app, wares, ctx) {
var express = require('express')
, api = express.Router();

api.use(wares.compression());
api.use(wares.bodyParser({
limit: 1048576 * 50
}));
// text body types get handled as raw buffer stream
api.use(wares.bodyParser.raw({
limit: 1048576
}));
// json body types get handled as parsed json
api.use(wares.bodyParser.json({
limit: 1048576
}));
// also support url-encoded content-type
api.use(wares.bodyParser.urlencoded({
limit: 1048576
, extended: true
}));
// invoke common middleware
api.use(wares.sendJSONStatus);

api.use(ctx.authorization.isPermitted('api:activity:read'));

// List activity data available
api.get('/activity', function(req, res) {
var ifModifiedSince = req.get('If-Modified-Since');
ctx.activity.list(req.query, function(err, results) {
var d1 = null;

_.forEach(results, function clean(t) {

var d2 = null;

if (t.hasOwnProperty('created_at')) {
d2 = new Date(t.created_at);
} else {
if (t.hasOwnProperty('timestamp')) {
d2 = new Date(t.timestamp);
}
}

if (d2 == null) { return; }

if (d1 == null || d2.getTime() > d1.getTime()) {
d1 = d2;
}
});

if (!_.isNil(d1)) res.setHeader('Last-Modified', d1.toUTCString());

if (ifModifiedSince && d1.getTime() <= moment(ifModifiedSince).valueOf()) {
res.status(304).send({
status: 304
, message: 'Not modified'
, type: 'internal'
});
return;
} else {
return res.json(results);
}
});
});

function config_authed(app, api, wares, ctx) {

function post_response(req, res) {
var activity = req.body;

if (!_.isArray(activity)) {
activity = [activity];
};

ctx.activity.create(activity, function(err, created) {
if (err) {
console.log('Error adding activity data', err);
res.sendJSONStatus(res, consts.HTTP_INTERNAL_ERROR, 'Mongo Error', err);
} else {
console.log('Activity measure created');
res.json(created);
}
});
}

api.post('/activity/', wares.bodyParser({
limit: 1048576 * 50
}), ctx.authorization.isPermitted('api:activity:create'), post_response);

api.delete('/activity/:_id', ctx.authorization.isPermitted('api:activity:delete'), function(req, res) {
ctx.activity.remove(req.params._id, function() {
res.json({});
});
});

// update record
api.put('/activity/', ctx.authorization.isPermitted('api:activity:update'), function(req, res) {
var data = req.body;
ctx.activity.save(data, function(err, created) {
if (err) {
res.sendJSONStatus(res, consts.HTTP_INTERNAL_ERROR, 'Mongo Error', err);
console.log('Error saving activity');
console.log(err);
} else {
res.json(created);
console.log('Activity measure saved', data);
}
});
});
}

if (app.enabled('api') && app.enabled('careportal')) {
config_authed(app, api, wares, ctx);
}

return api;
}

module.exports = configure;

38 changes: 37 additions & 1 deletion lib/api/entries/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,11 @@ function configure (app, wares, ctx) {
res.setHeader('Last-Modified', lastEntryDate.toUTCString());
}

var ifModifiedSince = req.get('If-Modified-Since');
var ifModifiedSince = req.get('If-Modified-Since');
if (!ifModifiedSince) { return next(); }

console.log("CGM Entry request with If-Modified-Since: ", ifModifiedSince);

if (lastEntryDate.getTime() <= new Date(ifModifiedSince).getTime()) {
res.status(304).send({status:304, message: 'Not modified', type:'internal'});
return;
Expand Down Expand Up @@ -114,6 +116,40 @@ function configure (app, wares, ctx) {
if (res.entries_err) {
return res.sendJSONStatus(res, consts.HTTP_INTERNAL_ERROR, 'Mongo Error', res.entries_err);
}

// IF-Modified-Since support

function compare(a,b) {
var a_field = a.mills ? a.mills : a.date;
var b_field = b.mills ? b.mills : b.date;

if (a_field < b_field)
return -1;
if (a_field > b_field)
return 1;
return 0;
}

res.entries.sort(compare);

var lastEntry = _.last(res.entries);
var lastEntryDate = null;

if (!_.isNil(lastEntry)) {
if (lastEntry.mills) lastEntryDate = new Date(lastEntry.mills);
if (!lastEntry.mills && lastEntry.date ) lastEntryDate = new Date(lastEntry.date);
res.setHeader('Last-Modified', lastEntryDate.toUTCString());
}

var ifModifiedSince = req.get('If-Modified-Since');

console.log('If-Modified-Since: ' + new Date(ifModifiedSince) + ' Last-Modified', lastEntryDate);

if (lastEntryDate !== null && ifModifiedSince !== null && lastEntryDate.getTime() <= new Date(ifModifiedSince).getTime()) {
res.status(304).send({status:304, message: 'Not modified', type:'internal'});
return;
}

// if no error, format the payload
// The general pattern here is to create an output stream that reformats
// the data correctly into the desired representation.
Expand Down
2 changes: 2 additions & 0 deletions lib/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ function create (env, ctx) {
app.all('/devicestatus*', require('./devicestatus/')(app, wares, ctx));
app.all('/notifications*', require('./notifications-api')(app, wares, ctx));

app.all('/activity*', require('./activity/')(app, wares, ctx));

app.use('/', wares.sendJSONStatus, require('./verifyauth')(ctx));
app.all('/food*', require('./food/')(app, wares, ctx));

Expand Down
1 change: 1 addition & 0 deletions lib/authorization/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ function init (env, ctx) {
, { name: 'readable', permissions: [ '*:*:read' ] }
, { name: 'careportal', permissions: [ 'api:treatments:create' ] }
, { name: 'devicestatus-upload', permissions: [ 'api:devicestatus:create' ] }
, { name: 'activity', permissions: [ 'api:activity:create' ] }
];

storage.reload = function reload (callback) {
Expand Down
6 changes: 3 additions & 3 deletions lib/client/browser-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ function init ($) {

// Tooltips can remain in the way on touch screens.
if (!isTouch()) {
$('.tip').tipsy();
$('.tip').tooltip();
} else {
// Drawer info tips should be displayed on touchscreens.
$('#drawer').find('.tip').tipsy();
$('#drawer').find('.tip').tooltip();
}
$.fn.tipsy.defaults = {
$.fn.tooltip.defaults = {
fade: true,
gravity: 'n',
opacity: 0.75
Expand Down
1 change: 1 addition & 0 deletions lib/client/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,7 @@ function init (client, d3) {
renderer.drawTreatments = function drawTreatments(client) {

var treatmentCount = 0;
chart().focus.selectAll('.draggable-treatment').remove();

_.forEach(client.ddata.treatments, function eachTreatment (d) {
if (Number(d.insulin) > 0 || Number(d.carbs) > 0) { treatmentCount += 1; };
Expand Down
Loading

0 comments on commit fafd01a

Please sign in to comment.