gouldi.js
require('app-module-path').addPath(__dirname);
const express = require('express');
const app = express();
const path = require("path");
const yaml = require('js-yaml');
const BBPromise = require('bluebird');
const preq = require('preq');
const fs = BBPromise.promisifyAll(require('fs'));
const mathoidcfg = yaml.safeLoad(fs.readFileSync('config.yaml'));
//var readme = fs.readFileSync('views/README.md').toString();
require('app-module-path').addPath(path.join(__dirname + '/node_modules/vmext'));
const bodyParser = require('body-parser');
app.use(bodyParser.json({limit: "50mb"}));
app.use(bodyParser.urlencoded({limit: "50mb", extended: true, parameterLimit:50000}));
const GithubContent = require('github-content');
const Github = require('github-base');
require('mathoid/server.js');
const githubChangeRemoteFile = require('github-change-remote-file');
const mergeHelper = require('helper/merge.js');
const dataHelper = require('helper/dataHelper.js')
// add middleware to:
// 1) Allow CORS
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});
// need to specify a view because of
// --> app.use('/', require('./node_modules/vmext/routes/routes'));
// therefore we need ejs and set the view to html --> switch main.html to view/index.html
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
// needed subpath gold because it is the new subpath of the GUI
app.use('/node_modules', express.static(path.join(__dirname + '/node_modules')));
app.use('/scripts', express.static(path.join(__dirname + '/scripts')));
app.use('/styles', express.static(path.join(__dirname + '/styles')));
app.use('/widgets', express.static(path.join(__dirname + '/node_modules/vmext/public/widgets')));
app.use('/vendor', express.static(path.join(__dirname + '/node_modules/vmext/public/vendor')));
app.use('/assets', express.static(path.join(__dirname + '/assets')));
app.use('/readme', express.static(path.join(__dirname + '/views/README.md')));
app.use('/datasetSources', express.static(path.join(__dirname + '/views/dataSources.csv')));
app.use('/api', require("./node_modules/vmext/api/versions.js"));
app.use('/', require('./node_modules/vmext/routes/routes'));
app.post('/get-model', function (req, res) {
const body = req.body;
const gc = new GithubContent(body);
gc.file(body.filename, function (err, file) {
try {
const json = JSON.parse(file.contents.toString());
res.send(json);
} catch (e) {
res.status(400).send('Invalid JSON string');
}
});
});
app.post('/write-model', function (req, res) {
const body = req.body;
console.log("Update file on GitHub: " + body.filename);
console.log(body);
body.transform = function (x) {
body.message = body.data.commitMsg || `Update item ${body.data.qID} \n\n[ci skip]`;
delete body.data.commitMsg;
delete body.data.qID;
return JSON.stringify(body.data, null, 2);
};
githubChangeRemoteFile(body)
.then(function (inner_res) {
res.send( inner_res );
})
.catch(function (err) {
throw err;
});
});
app.post('/write-model-create', function(req, res) {
const body = req.body;
const path = '/repos/'+body.owner+'/'+body.repo+'/contents/'+body.path;
const github = new Github({token: body.token});
console.log("Push new file to github: " + body.path);
body.message = body.content.commitMsg || `Create new item ${body.content.qID} \n\n[ci skip]`;
delete body.token;
body.content = Buffer.from(JSON.stringify(body.content, null, 2)).toString('base64');
github.put(path, body)
.then(innerRes => {
res.send(innerRes.body);
})
.catch(function (err) {
throw err;
});
});
app.post('/render-math', function (req, res){
preq.post(
{
uri: 'http://localhost:10044/svg/',
encoding: null,
body: {q: req.body.input, nospeech: true}
}
).then( function(inner_res) {
res.send( inner_res.body.toString() );
}).catch( function(e){
res.status(400).send('Error while render SVG: ' + e.message);
} );
});
app.post('/latexml', function(req, res){
preq.post(
{
uri: 'http://vmext-demo.wmflabs.org/math/',
query: {
latex: req.body.latex
}
}
).then( function(inner_res){
res.send( inner_res.body.result );
}).catch( function(e){
res.status(400).send('Error while request LaTeXML: ' + e.message);
});
});
app.get('/dataset', function(req, res){
res.sendFile( "views/dataSourcesTemplate.html", { root: __dirname } );
});
app.get('/about', function(req, res, next) {
res.sendFile( "views/aboutPage.html", { root: __dirname } );
});
app.post('/numberOfItems', function(req, res){
const github = new Github(req.body);
github.get('/repos/ag-gipp/mathmlben/contents/data', {})
.then(innerRes => {
const number = innerRes.body.filter(entry => entry.type === 'file').length;
console.log("Number of files remote: " + number)
res.send({numberOfEntries: number});
})
.catch(err => {
console.log("Unable to retrieve number of entries from GitHub. Load local savings instead.");
res.send( {numberOfEntries: dataHelper.numberOfEntries()} );
})
});
app.get('/getDefaultEntry', function(req, res){
res.sendFile( 'data/default/default.json', {root: __dirname} );
});
app.get('/rawdata/:qid', function(req, res){
const qid = req.params.qid;
const maxNum = dataHelper.numberOfEntries();
if ( /^([0-9]\d*)$/g.test(qid) ){
const num = parseInt(qid);
if ( num < 1 || maxNum <= num ){
res.status(400).send( 'Invalid QID request: ' + qid + ' is out of range. Must be between 1 and ' + maxNum + '.' );
}
else {
console.log("Requesting single raw file of QID: " + num);
res.sendFile( "data/"+qid+".json", { root: __dirname } );
}
} else if ( qid.match(/^all$/g) ){
console.log("Requesting complete dataset!");
console.dir(req.headers); // provide request information
mergeHelper.mergeAllGoldFiles()
.then(() => {
console.log("Done, send entire gold standard.");
res.send(mergeHelper.merged);
});
} else {
res.status(400).send('Invalid QID request: ' + qid + ' is not a number! For the entire gold standard call "rawdata/all-gen"');
}
});
app.all('/*', function(req, res, next) {
// Just send the index.html for other files to support HTML5Mode
res.sendFile('views/index.html', { root: __dirname });
});
app.use('/', function(req, res){
res.redirect('about');
});
const port = 34512; //process.env.GOULDI_PORT | mathoidcfg.gouldi.port;
app.listen( port, function () {
console.log('Started GoUldI on ' + port);
});