Files
dougal-software/lib/www/server/api/index.js

256 lines
6.3 KiB
JavaScript
Raw Normal View History

2020-08-08 23:59:13 +02:00
const http = require('http');
const express = require('express');
const cookieParser = require('cookie-parser')
const maybeSendAlert = require("../lib/alerts");
2020-08-08 23:59:13 +02:00
const mw = require('./middleware');
const app = express();
const verbose = process.env.NODE_ENV != 'test';
app.map = function(a, route){
route = route || '';
for (var key in a) {
switch (typeof a[key]) {
// { '/path': { ... }}
case 'object':
if (!Array.isArray(a[key])) {
app.map(a[key], route + key);
break;
} // else drop through
// get: function(){ ... }
case 'function':
if (verbose) console.log('%s %s', key, route);
app[key](route, a[key]);
break;
}
}
};
app.use(express.json({type: "application/json", strict: false, limit: '10mb'}));
2020-08-08 23:59:13 +02:00
app.use(express.urlencoded({ type: "application/x-www-form-urlencoded", extended: true }));
app.use(express.text({type: "text/*", limit: '10mb'}));
2020-08-08 23:59:13 +02:00
app.use((req, res, next) => {
res.set("Access-Control-Allow-Origin", "*");
res.set("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PUT, PATCH, DELETE");
res.set("Access-Control-Allow-Headers", "Content-Type");
next();
});
app.use(cookieParser());
app.use(mw.auth.jwt);
// app.use(mw.auth.access({path: {allow:["^/login", "^/user$"]}}));
// Adds arbitrary information to the request object
const meta = (key, value) => {
return (req, res, next) => {
if (!req.meta) {
req.meta = {};
}
if (key) {
req.meta[key] = value;
}
next();
}
};
// Short for adding meta to all methods
const allMeta = (key, value) => {
return { all: [ meta(key, value) ] };
};
// These routes do not require authentication
2020-08-08 23:59:13 +02:00
app.map({
'*': { all: [ meta() ] }, // Create the req.meta object
'/login': {
post: [ mw.user.login ]
},
'/logout': {
get: [ mw.user.logout ],
post: [ mw.user.logout ]
},
'/': {
get: [ mw.openapi.get ]
}
});
app.use(mw.auth.authentify);
// We must be authenticated before we can access these
app.map({
2020-08-08 23:59:13 +02:00
'/project': {
get: [ mw.project.list ], // Get list of projects
},
'/project/:project': {
get: [ mw.project.get ], // Get project data
},
'/project/:project/summary': {
get: [ mw.project.get ],
},
'/project/:project/gis': {
get: [ mw.gis.project.bbox ]
},
'/project/:project/gis/preplot': {
get: [ mw.gis.project.preplot ]
},
'/project/:project/gis/preplot/:featuretype(line|point)': {
get: [ mw.gis.project.preplot ]
},
'/project/:project/gis/raw/:featuretype(line|point)': {
get: [ mw.gis.project.raw ]
},
'/project/:project/gis/final/:featuretype(line|point)': {
get: [ mw.gis.project.final ]
},
'/project/:project/line/': {
get: [ mw.line.list ],
},
'/project/:project/line/:line': {
2020-08-08 23:59:13 +02:00
// get: [ mw.line.get ],
patch: [ mw.auth.access.write, mw.line.patch ],
},
2020-08-08 23:59:13 +02:00
'/project/:project/sequence/': {
get: [ mw.sequence.list ],
},
'/project/:project/sequence/:sequence': {
2020-08-08 23:59:13 +02:00
// get: [ mw.sequence.get ],
patch: [ mw.auth.access.write, mw.sequence.patch ],
},
2020-10-08 16:36:15 +02:00
'/project/:project/plan/': {
get: [ mw.plan.list ],
put: [ mw.auth.access.write, mw.plan.put ],
post: [ mw.auth.access.write, mw.plan.post ]
2020-10-08 16:36:15 +02:00
},
'/project/:project/plan/:sequence': {
// get: [ mw.plan.get ],
patch: [ mw.auth.access.write, mw.plan.patch ],
delete: [ mw.auth.access.write, mw.plan.delete ]
2020-10-08 16:36:15 +02:00
},
2020-08-08 23:59:13 +02:00
//
'/project/:project/event/': {
get: [ mw.event.cache.get, mw.event.list, mw.event.cache.save ],
post: [ mw.auth.access.write, mw.event.post ],
put: [ mw.auth.access.write, mw.event.put ],
delete: [ mw.auth.access.write, mw.event.delete ],
2020-08-22 20:33:43 +02:00
':type/': {
':id/': {
// get: [ mw.event.get ],
put: [ mw.auth.access.write, mw.event.put ],
delete: [mw.auth.access.write, mw.event.delete ]
2020-08-22 20:33:43 +02:00
}
},
},
'/project/:project/label/': {
get: [ mw.label.list ],
// post: [ mw.label.post ],
},
'/project/:project/configuration/:path(*)?': {
get: [ mw.configuration.get ],
// post: [ mw.auth.access.admin, mw.label.post ],
},
'/project/:project/info/:path(*)': {
get: [ mw.info.get ],
// post: [ mw.info.post ],
},
'/project/:project/meta/': {
put: [ mw.meta.put ],
},
'/project/:project/meta/:path(*)': {
// Path examples:
// GET:
// `/raw/sequences/qc/missing_shots`,
// `/final/points/qc/sync_warn/results
get: [ mw.meta.get ],
// // PUT:
// // `/raw/qc/missing_shots` ← { sequence: …, value: … }
// put: [ mw.meta.put ]
},
2020-08-08 23:59:13 +02:00
//
// '/project/:id/permissions/:mode(read|write)?': {
// get: [ mw.permissions.get ],
// put: [ mw.permissions.put ],
// // post: [ mw.permissions.post ],
// // delete: [ mw.permissions.delete ]
// },
'/navdata/': {
get: [ mw.navdata.get ],
'gis/:featuretype(line|point)': {
get: [ mw.gis.navdata.get ]
}
2020-10-11 17:51:31 +02:00
},
'/rss/': {
get: [ mw.rss.get ]
}
2020-08-08 23:59:13 +02:00
//
// '/user': {
// get: [ mw.user.get ],
// post: [ mw.user.put ]
// },
// '/user/:user': {
// get: [ mw.user.get ],
// put: [ mw.user.put ],
// // delete: [ mw.user.delete ]
// },
//
});
// Generic error handler. Stops stack dumps
// being sent to clients.
app.use(function (err, req, res, next) {
const title = `HTTP backend error at ${req.method} ${req.originalUrl}`;
const description = err.message;
const message = err.message;
const alert = {title, message, description, error: err};
2020-08-08 23:59:13 +02:00
console.log("Error:", err);
2020-08-08 23:59:13 +02:00
if (err instanceof Error && err.name != "UnauthorizedError") {
console.error(err.stack);
res.status(500).send('General internal error');
maybeSendAlert(alert);
2020-08-08 23:59:13 +02:00
} else if (typeof err === 'string') {
res.status(500).send({message: err});
maybeSendAlert(alert);
2020-08-08 23:59:13 +02:00
} else {
res.status(err.status || 500).send({message: err.message || (err.inner && err.inner.message) || "Internal error"});
if (!res.status) {
maybeSendAlert(alert);
}
2020-08-08 23:59:13 +02:00
}
});
app.disable('x-powered-by');
app.enable('trust proxy');
console.log('trust proxy is ' + (app.get('trust proxy')? 'on' : 'off'));
const addr = "127.0.0.1";
if (!module.parent) {
var port = process.env.HTTP_PORT || 3000;
var server = http.createServer(app).listen(port, addr);
console.log('API started on port ' + port);
} else {
app.start = function (port = 3000, path) {
var root = app;
if (path) {
root = express();
['x-powered-by', 'trust proxy'].forEach(k => root.set(k, app.get(k)));
root.use(path, app);
}
const server = http.createServer(root).listen(port, addr);
if (server) {
console.log(`API started on port ${port}, prefix: ${path || "/"}`);
}
return server;
}
module.exports = app;
}