Skip to content

Commit

Permalink
Merge pull request #17 from camicroscope/develop
Browse files Browse the repository at this point in the history
Picker Updates and Deletes
  • Loading branch information
birm authored Apr 3, 2020
2 parents 0d82f31 + 55147f2 commit d80ea81
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 87 deletions.
139 changes: 79 additions & 60 deletions caracal.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,77 +55,96 @@ app.use('/loader/', loaderHandler);
// data, mongo
app.use('/data', auth.loginHandler(auth.PUBKEY));
// slide
app.use('/data/Slide/find', dataHandlers.Slide.find);
app.use('/data/Slide/find', auth.filterHandler('data', 'userFilter', 'filter'));
app.use('/data/Slide/post', permissionHandler(['Admin', 'Editor']));
app.use('/data/Slide/post', dataHandlers.Slide.add);
app.use('/data/Slide/delete', permissionHandler(['Admin', 'Editor']));
app.use('/data/Slide/delete', dataHandlers.Slide.delete);
app.use('/data/Slide/update', permissionHandler(['Admin', 'Editor']));
app.use('/data/Slide/update', dataHandlers.Slide.update);
app.get('/data/Slide/find', dataHandlers.Slide.find);
app.get('/data/Slide/find', auth.filterHandler('data', 'userFilter', 'filter'));
app.post('/data/Slide/post', permissionHandler(['Admin', 'Editor']));
app.post('/data/Slide/post', dataHandlers.Slide.add);
app.delete('/data/Slide/delete', permissionHandler(['Admin', 'Editor']));
app.delete('/data/Slide/delete', dataHandlers.Slide.find);
app.delete('/data/Slide/delete', auth.editHandler('data', 'userFilter', 'filter'));
app.delete('/data/Slide/delete', dataHandlers.Slide.delete);
app.post('/data/Slide/update', permissionHandler(['Admin', 'Editor']));
app.post('/data/Slide/update', dataHandlers.Slide.find);
app.post('/data/Slide/update', auth.editHandler('data', 'userFilter', 'filter'));
app.post('/data/Slide/update', dataHandlers.Slide.update);
// mark
app.use('/data/Mark/find', dataHandlers.Mark.find);
app.use('/data/Mark/spatial', dataHandlers.Mark.spatial);
app.use('/data/Mark/multi', dataHandlers.Mark.multi);
app.use('/data/Mark/types', dataHandlers.Mark.types);
app.use('/data/Mark/post', permissionHandler(['Admin', 'Editor']));
app.use('/data/Mark/post', dataHandlers.Mark.add);
app.use('/data/Mark/delete', permissionHandler(['Admin', 'Editor']));
app.use('/data/Mark/delete', dataHandlers.Mark.delete);
app.use('/data/Mark/update', permissionHandler(['Admin', 'Editor']));
app.use('/data/Mark/update', dataHandlers.Mark.update);
app.get('/data/Mark/find', dataHandlers.Mark.find);
app.get('/data/Mark/spatial', dataHandlers.Mark.spatial);
app.get('/data/Mark/multi', dataHandlers.Mark.multi);
app.get('/data/Mark/types', dataHandlers.Mark.types);
app.post('/data/Mark/post', permissionHandler(['Admin', 'Editor']));
app.post('/data/Mark/post', dataHandlers.Mark.add);
app.delete('/data/Mark/delete', dataHandlers.Mark.find);
app.delete('/data/Mark/delete', auth.editHandler('data'));
app.delete('/data/Mark/delete', permissionHandler(['Admin', 'Editor']));
app.delete('/data/Mark/delete', dataHandlers.Mark.delete);
app.post('/data/Mark/update', dataHandlers.Mark.find);
app.post('/data/Mark/update', auth.editHandler('data'));
app.post('/data/Mark/update', permissionHandler(['Admin', 'Editor']));
app.post('/data/Mark/update', dataHandlers.Mark.update);
// template
app.use('/data/Template/find', dataHandlers.Template.find);
app.use('/data/Template/post', permissionHandler(['Admin', 'Editor']));
app.use('/data/Template/post', dataHandlers.Template.add);
app.use('/data/Template/delete', permissionHandler(['Admin', 'Editor']));
app.use('/data/Template/delete', dataHandlers.Template.delete);
app.use('/data/Template/update', permissionHandler(['Admin', 'Editor']));
app.use('/data/Template/update', dataHandlers.Template.update);
app.get('/data/Template/find', dataHandlers.Template.find);
app.post('/data/Template/post', permissionHandler(['Admin', 'Editor']));
app.post('/data/Template/post', dataHandlers.Template.add);
app.delete('/data/Template/delete', permissionHandler(['Admin', 'Editor']));
app.delete('/data/Template/delete', dataHandlers.Template.delete);
app.post('/data/Template/update', permissionHandler(['Admin', 'Editor']));
app.post('/data/Template/update', dataHandlers.Template.update);
// heatmap
app.use('/data/Heatmap/find', dataHandlers.Heatmap.find);
app.use('/data/Heatmap/types', dataHandlers.Heatmap.types);
app.use('/data/Heatmap/post', permissionHandler(['Admin', 'Editor']));
app.use('/data/Heatmap/post', dataHandlers.Heatmap.add);
app.use('/data/Heatmap/delete', permissionHandler(['Admin', 'Editor']));
app.use('/data/Heatmap/delete', dataHandlers.Heatmap.delete);
app.use('/data/Heatmap/update', permissionHandler(['Admin', 'Editor']));
app.use('/data/Heatmap/update', dataHandlers.Heatmap.update);
app.get('/data/Heatmap/find', dataHandlers.Heatmap.find);
app.get('/data/Heatmap/types', dataHandlers.Heatmap.types);
app.post('/data/Heatmap/post', permissionHandler(['Admin', 'Editor']));
app.post('/data/Heatmap/post', dataHandlers.Heatmap.add);
app.delete('/data/Heatmap/delete', dataHandlers.Heatmap.find);
app.delete('/data/Heatmap/delete', auth.editHandler('data'));
app.delete('/data/Heatmap/delete', permissionHandler(['Admin', 'Editor']));
app.delete('/data/Heatmap/delete', dataHandlers.Heatmap.delete);
app.post('/data/Heatmap/update', dataHandlers.Heatmap.find);
app.post('/data/Heatmap/update', auth.editHandler('data'));
app.post('/data/Heatmap/update', permissionHandler(['Admin', 'Editor']));
app.post('/data/Heatmap/update', dataHandlers.Heatmap.update);
// heatmapEdit
app.use('/data/HeatmapEdit/find', dataHandlers.HeatmapEdit.find);
app.use('/data/HeatmapEdit/post', permissionHandler(['Admin', 'Editor']));
app.use('/data/HeatmapEdit/post', dataHandlers.HeatmapEdit.add);
app.use('/data/HeatmapEdit/delete', permissionHandler(['Admin', 'Editor']));
app.use('/data/HeatmapEdit/delete', dataHandlers.HeatmapEdit.delete);
app.use('/data/HeatmapEdit/update', permissionHandler(['Admin', 'Editor']));
app.use('/data/HeatmapEdit/update', dataHandlers.HeatmapEdit.update);
app.get('/data/HeatmapEdit/find', dataHandlers.HeatmapEdit.find);
app.post('/data/HeatmapEdit/post', permissionHandler(['Admin', 'Editor']));
app.post('/data/HeatmapEdit/post', dataHandlers.HeatmapEdit.add);
app.delete('/data/HeatmapEdit/delete', dataHandlers.HeatmapEdit.find);
app.delete('/data/HeatmapEdit/delete', auth.editHandler('data'));
app.delete('/data/HeatmapEdit/delete', permissionHandler(['Admin', 'Editor']));
app.delete('/data/HeatmapEdit/delete', dataHandlers.HeatmapEdit.delete);
app.post('/data/HeatmapEdit/update', dataHandlers.HeatmapEdit.find);
app.post('/data/HeatmapEdit/update', auth.editHandler('data'));
app.post('/data/HeatmapEdit/update', permissionHandler(['Admin', 'Editor']));
app.post('/data/HeatmapEdit/update', dataHandlers.HeatmapEdit.update);
// log
app.use('/data/Log/find', dataHandlers.Log.find);
app.get('/data/Log/find', dataHandlers.Log.find);
// anyone can add a log
app.use('/data/Log/post', dataHandlers.Log.add);
app.use('/data/Log/delete', permissionHandler(['Admin', 'Editor']));
app.use('/data/Log/delete', dataHandlers.Log.delete);
app.use('/data/Log/update', permissionHandler(['Admin', 'Editor']));
app.use('/data/Log/update', dataHandlers.Log.update);
app.post('/data/Log/post', dataHandlers.Log.add);
app.delete('/data/Log/delete', permissionHandler(['Admin', 'Editor']));
app.delete('/data/Log/delete', dataHandlers.Log.delete);
app.post('/data/Log/update', permissionHandler(['Admin', 'Editor']));
app.post('/data/Log/update', dataHandlers.Log.update);
// config
app.use('/data/Configuration/find', dataHandlers.Config.find);
app.use('/data/Configuration/post', permissionHandler(['Admin', 'Editor']));
app.use('/data/Configuration/post', dataHandlers.Config.add);
app.use('/data/Configuration/delete', permissionHandler(['Admin', 'Editor']));
app.use('/data/Configuration/delete', dataHandlers.Config.delete);
app.use('/data/Configuration/update', permissionHandler(['Admin', 'Editor']));
app.use('/data/Configuration/update', dataHandlers.Config.update);
app.get('/data/Configuration/find', dataHandlers.Config.find);
app.post('/data/Configuration/post', permissionHandler(['Admin', 'Editor']));
app.post('/data/Configuration/post', dataHandlers.Config.add);
app.delete('/data/Configuration/delete', permissionHandler(['Admin', 'Editor']));
app.delete('/data/Configuration/delete', dataHandlers.Config.delete);
app.post('/data/Configuration/update', permissionHandler(['Admin', 'Editor']));
app.post('/data/Configuration/update', dataHandlers.Config.update);
// user
app.use('/data/User/find', dataHandlers.User.find);
app.use('/data/User/post', permissionHandler(['Admin']));
app.use('/data/User/post', dataHandlers.User.add);
app.use('/data/User/delete', permissionHandler(['Admin']));
app.use('/data/user/delete', dataHandlers.User.delete);
app.use('/data/User/update', permissionHandler(['Admin']));
app.use('/data/User/update', dataHandlers.User.update);
app.get('/data/User/find', dataHandlers.User.find);
app.post('/data/User/post', permissionHandler(['Admin']));
app.post('/data/User/post', dataHandlers.User.add);
app.delete('/data/User/delete', permissionHandler(['Admin']));
app.delete('/data/user/delete', dataHandlers.User.delete);
app.post('/data/User/update', permissionHandler(['Admin']));
app.post('/data/User/update', dataHandlers.User.update);

// render mongo returns/data
app.use('/data', function(req, res, next) {
if (!req.data) {
res.status(404).json({});
}
res.json(req.data);
});

Expand Down
52 changes: 33 additions & 19 deletions handlers/authHandlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');
var atob = require('atob');
var fs = require('fs');
var filterFunction = require('./filterFunction.js');

var JWK_URL = process.env.JWK_URL;
var DISABLE_SEC = process.env.DISABLE_SEC || false;
Expand Down Expand Up @@ -193,29 +194,41 @@ function loginHandler(checkKey) {
// use filter handler AFTER data handler
function filterHandler(dataField, filterField, attrField) {
return function(req, res, next) {
// do nothing if sec disabled, or if filter contains "**"
// all docs with no set attrField are passed too
var filter = req[filterField];
// make filter an array
if (!Array.isArray(filter)) {
filter = [filter];
req[dataField] = filterFunction(req[filterField], req[dataField], attrField, '**');
next();
};
}

// use edit handler AFTER a find route to populate data, but BEFORE the edit itself
function editHandler(dataField, filterField, attrField) {
return function(req, res, next) {
if (filterField && attrField) {
req[dataField] = filterFunction(req[filterField], req[dataField], attrField, '**');
}
if (filter.indexOf('**') == -1) {
// filter data in dataField if attrField in filterField
var data = req[dataField];
// is data an array?
if (Array.isArray(data)) {
// remove ones where does not match
req[dataField] = data.filter((x) => (!x[attrField] || filter.indexOf(x[attrField]) >= 0) );
} else {
if (!data[attrField] || filter.indexOf(data[attrField]) >= 0) {
req[dataField] = data;
} else {
req[dataField] = {};
if (!Array.isArray(req[dataField])) {
req[dataField] = [req[dataField]];
}
// edit routes should operate on one object
if (req[dataField].length == 1) {
// DESTROY query
for (let n in req.query) {
if (req.query.hasOwnProperty(n)) {
delete req.query[n];
}
}
req.query = {_id: req[dataField][0]._id['$oid']};
next();
} else if (req[dataField].length == 0) {
let errorMessage = {};
errorMessage.error = 'Nothing applicable to change.';
errorMessage.statusCode = 400;
next(errorMessage);
} else {
let errorMessage = {};
errorMessage.error = 'At most one document may be changed at once.';
errorMessage.statusCode = 400;
next(errorMessage);
}
next();
};
}

Expand All @@ -224,6 +237,7 @@ auth.jwkTokenTrade = jwkTokenTrade;
auth.tokenTrade = tokenTrade;
auth.filterHandler = filterHandler;
auth.loginHandler = loginHandler;
auth.editHandler = editHandler;
auth.CLIENT = CLIENT;
auth.PRIKEY = PRIKEY;
auth.PUBKEY = PUBKEY;
Expand Down
5 changes: 3 additions & 2 deletions handlers/dataHandlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ function mongoDelete(collection, query) {
if (err) {
rej(err);
}
delete result.connection;
res(result);
db.close();
});
Expand Down Expand Up @@ -130,6 +131,7 @@ function mongoUpdate(collection, query, newVals) {
if (err) {
rej(err);
}
delete result.connection;
res(result);
db.close();
});
Expand All @@ -142,7 +144,6 @@ function mongoUpdate(collection, query, newVals) {
});
}


var Slide = {};
Slide.find = function(req, res, next) {
// slide, specimen, study, location
Expand Down Expand Up @@ -176,7 +177,7 @@ Slide.update = function(req, res, next) {
var newVals = {
$set: JSON.parse(req.body),
};
mongoUpdate('slide', query).then((x) => {
mongoUpdate('slide', query, newVals).then((x) => {
req.data = x;
next();
}).catch((e) => next(e));
Expand Down
23 changes: 23 additions & 0 deletions handlers/filterFunction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
function filterFunction(filter, data, attr, wildcard) {
// make filter an array
if (!Array.isArray(filter)) {
filter = [filter];
}
if (filter.indexOf(wildcard) == -1) {
// is data an array?
if (Array.isArray(data)) {
// remove ones where does not match
data = data.filter((x) => (!x[attr] || filter.indexOf(x[attr]) >= 0) );
} else {
if (!data[attr] || filter.indexOf(data[attr]) >= 0) {
data = data;
} else {
data = {};
}
}
}
return data;
}


module.exports = filterFunction;
8 changes: 2 additions & 6 deletions test/functional/slide_lifecycle.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,9 @@ describe('Slide Lifecycle Step 1', function() {
describe('Slide Lifecycle Step 2', function() {
it('Finds the Slide', function(done) {
this.timeout(5000);
var slideData = {'name': 'TEST', 'specimen': '', 'study': '', 'location': '/images/sample.svs', 'mpp': 0.499};
chai.request(server)
.post(findurl)
.get(findurl + '?name=TEST')
.set('Content-Type', 'application/json; charset=utf-8')
.send(slideData)
.end(function(err, res) {
(res).should.have.status(200);
(res.body).should.be.an('array');
Expand All @@ -48,11 +46,9 @@ describe('Slide Lifecycle Step 2', function() {
describe('Slide Lifecycle Step 3', function() {
it('Deletes a Slide', function(done) {
this.timeout(5000);
var slideData = {'name': 'TEST', 'specimen': '', 'study': '', 'location': '/images/sample.svs', 'mpp': 0.499};
chai.request(server)
.post(deleteurl)
.delete(deleteurl + '?name=TEST')
.set('Content-Type', 'application/json; charset=utf-8')
.send(slideData)
.end(function(err, res) {
(res).should.have.status(200);
(res.body).should.be.a('object');
Expand Down

0 comments on commit d80ea81

Please sign in to comment.