index.js 10.4 KB
var express = require('express');
var nunjucks = require('nunjucks');
var session = require('express-session');
var MongoStore = require('connect-mongo/es5')(session);
var bodyParser = require('body-parser');
var mongoObjectID = require('mongodb').ObjectID;
var mongoClient = require('mongodb').MongoClient;
var crypto = require('crypto');
var strftime = require('strftime');
var querystring = require('querystring');
var morgan = require('morgan');
var FileStreamRotator = require('file-stream-rotator');
var fs = require('fs');
var os = require('os');
var monitorUtil = require('./monitor-util');

var config = require('./config.json');
var mongodb;

process.chdir(__dirname);

var logDirectory = __dirname + '/logs';
fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory);

// create a rotating write stream
var accessLogStream = FileStreamRotator.getStream({
    date_format: 'YYYYMMDD',
    filename: logDirectory + '/access-%DATE%.log',
    frequency: 'daily',
    verbose: false
});

monitorUtil.init({
    config: config
})

var controllerOptions = {
    config: config
}

var UsersController = require("./usersController");
var usersController = new UsersController(config);

var app = express();

app.use(morgan('combined', {stream: accessLogStream}));
app.use(session({
  secret: config.session_secret,
  name: 'cjkmonitor.sid',
  store: new MongoStore({url: config.mongodb.url}),
  resave: false,
  saveUninitialized: false,
}))

app.use(express.static('public', {maxAge: 24 * 3600 * 1000}));
app.use(bodyParser.urlencoded({extended: true}));

app.set('views', './views');
//app.set('view cache', false);

if (config.trust_proxy) {
    app.set('trust proxy', config.trust_proxy);
}

nunjucks.configure('views', {
    autoescape: true,
    express: app
});

function authNeeded(req, res, next) {
    if (req.session.username) {
        next();
    } else {
        res.redirect('/signin');
    }
}

function generateAutoRefreshLink(path, qs) {
    var newQs = querystring.parse(querystring.stringify(qs));

    if (qs.autorefresh == "1") {
        newQs.autorefresh = 0;
    } else {
        newQs.autorefresh = 1;
    }

    return  path + '?' + querystring.stringify(newQs); // + '#activeConditions';
}

function createPaginatorObject(total, perpage, path, qs) {
    var pageCount = Math.ceil(total / perpage);
    var pages = [];

    var newQs = querystring.parse(querystring.stringify(qs));
    delete newQs.ajax;

    for (var i = 0; i < pageCount; i++) {

        var pageNumber = i + 1;

        pages[i] = {
            'number': pageNumber,
        }

        if (pageNumber == qs.page) {
            pages[i].active = true;
        }

        newQs.page = pageNumber;
        pages[i].link =  path + '?' + querystring.stringify(newQs);

    }
    return pages;
}

function pageHome(req, res, next) {
    monitorUtil.getUserByEmail(req.session.username, function(err, activeUser) {
        _pageHome(req, res, next, activeUser)
    })
}

function _pageHome(req, res, next, activeUser) {
    var limitPerPage = 50;

    var page = 1;
    if (req.query.page) {
        page = req.query.page;
    } else {
        req.query.page = page;
    }

    var skip = (page - 1) * limitPerPage;

    var conditions = {};

    /*
    if (!req.query.trxdate) {
        req.query.trxdate = strftime('%Y-%m-%d', new Date());
    }
    */
    conditions.ts_date = req.query.trxdate;

    if (req.query.destination) {
        conditions.destination = req.query.destination.trim();
    }

    if (req.query.product) {
        conditions.product = req.query.product.trim();
    }

    if (req.query.supplier) {
        conditions.supplier = req.query.supplier.trim();
    }

    if (req.query.rc) {
        conditions.rc = req.query.rc.trim();
    }

    var _conditions = JSON.parse(JSON.stringify(conditions));
    if (!_conditions.ts_date) {
        _conditions.ts_date = strftime('%Y-%m-%d', new Date())
    }

    if (!_conditions.supplier) {
        _conditions.supplier = {$in: activeUser.suppliers}
    }

    monitorUtil.mongodb.collection('trx').find(_conditions).count(function(err, count) {

        if (err) {
            var errorMessage = 'Something wrong when retrieving number of docs on mongo: ' + err;
            console.log(errorMessage);
            res.send(errorMessage);
            return;
        }

        var pagecount = Math.ceil(count / limitPerPage);
        var paginator = createPaginatorObject(count, limitPerPage, req.path, req.query);

        monitorUtil.mongodb.collection('trx').find(_conditions).sort([['ts', -1]]).skip(skip).limit(limitPerPage).toArray(function (err, docs) {

            if (err) {
                var errorMessage = 'Something wrong when retrieving docs from mongo: ' + err;
                console.log(errorMessage);
                res.send(errorMessage);
                return;
            }

            res.render('index.html', {
                title: 'Transactions',
                config: config,
                session: req.session,
                conditions: conditions,
                trxcount: count,
                pagecount: pagecount,
                limitperpage: limitPerPage,
                paginator: paginator,
                debugmsg: JSON.stringify(paginator),
                trxs: docs,
                suppliers: activeUser.suppliers,
                autorefreshLink: generateAutoRefreshLink(req.path, req.query),
                qs: req.query,
                url: req.url,
                path: req.path,
            });
        });
    });
}

function pageTrxView(req, res, next) {

    monitorUtil.mongodb.collection('trx').find({requestId: req.params.id}).limit(1).next(function(err, doc) {
        res.render(
            'trx.view.html',
            {
                title: 'Transaction #' + req.params.id,
                trx: doc
            }
        );

    });

}

function pageSigninForm(req, res, next) {
    if (req.session.username) {
        res.redirect('/');
        return;
    }

    res.render('signin.html');
}

function pageSigninPost(req, res, next) {
    var passwordHash = crypto.createHash('sha256').update(req.body.password).digest().toString('hex');
    monitorUtil.mongodb.collection('users').findOne({email: req.body.username, password: passwordHash}, function(err, doc) {
        if (err) {
            res.redirect('/signin');
            return;
        }

        if (!doc) {
            res.redirect('/signin');
            return;
        }

        req.session.username = req.body.username;
        monitorUtil.invalidateCacheUserByEmail(doc.email);

        if (doc.roles) {

            req.session.roles = doc.roles;
            req.session.isAdmin = (doc.roles.indexOf('admin') >= 0);

        } else {
            req.session.roles = [];
            req.session.isAdmin = 0;
        }

        res.redirect('/');

    });
}

function pageUsersChangePassword(req, res, next) {
    monitorUtil.mongodb.collection('users').find({_id: new mongoObjectID(req.params.id)}).limit(1).next(function(err, doc) {
        if (err) {
            res.send("Error retrieving data");
            return;
        }

        res.render(
            'users.change-password.html',
            {
                title: 'Change Password',
                session: req.session,
                user: doc
            }
        );
    });
}

function pageUsersChangePasswordPost(req, res, next) {
    if (req.body.passwod1 && (req.body.password1 != req.body.password2)) {
        res.redirect("/users/change-password/" + req.body._id);
        return;
    }

    var _id = new mongoObjectID(req.body._id);
    var passwordHash = crypto.createHash('sha256').update(req.body.password1).digest().toString('hex');

    monitorUtil.mongodb.collection('users').updateOne({_id: _id}, {$set: {password: passwordHash}}, function(err, r) {
        res.redirect("/users/view/" + req.body._id);
        return;
    });
}

function adminNeeded(req, res, next) {
    if (req.session.isAdmin) {
        next();
    }
    else {
        res.redirect('/');
    }
}

function logout(req, res, next) {
    req.session.username = null;
    res.redirect('/signin');
}

function pageRuntimeInfo(req, res, next) {
    var os_info = {
        uptime: os.uptime(),
        loadavg: os.loadavg(),
        hostname: os.hostname(),
        type: os.type(),
        platform: os.platform(),
        arch: os.arch(),
        release: os.release(),
        totalmem: os.totalmem(),
    }

    res.render(
        'runtime-info.html',
        {
            title: 'Runtime Info',
            session: req.session,
            config: JSON.stringify(config, null, 2),
            nodejs_versions: JSON.stringify(process.versions, null, 2),
            memory_usage: JSON.stringify(process.memoryUsage(), null, 2),
            uptime: process.uptime(),
            os_info: JSON.stringify(os_info, null, 2),
            net_ifaces: JSON.stringify(os.networkInterfaces(), null, 2),
        }
    );
}

app.all('/', authNeeded, pageHome);
app.get('/signin', pageSigninForm);
app.post('/signin', pageSigninPost);
app.get('/logout', logout);

app.get('/runtime-info', authNeeded, adminNeeded, pageRuntimeInfo);

app.get('/trx/view/:id', authNeeded, pageTrxView);

app.get('/users', authNeeded, adminNeeded, usersController.index);
app.get('/users/view/:id', authNeeded, adminNeeded, usersController.view);
app.get('/users/add', authNeeded, adminNeeded, usersController.addForm);
app.post('/users/add', authNeeded, adminNeeded, usersController.addSave);
app.get('/users/change-password/:id', authNeeded, adminNeeded, pageUsersChangePassword);
app.post('/users/change-password/:id', authNeeded, adminNeeded, pageUsersChangePasswordPost);

app.get('/users/:capability/delete-confirmation/:user_id/:user_email/:value_to_delete', authNeeded, adminNeeded, usersController.deleteCapabilityConfirmation);
app.get('/users/:capability/delete-confirmation/:user_id/:user_email/', authNeeded, adminNeeded, usersController.deleteCapabilityConfirmation);
app.get('/users/:capability/delete/:user_id/:value_to_delete', authNeeded, adminNeeded, usersController.deleteCapability);
app.get('/users/:capability/delete/:user_id/', authNeeded, adminNeeded, usersController.deleteCapability);

app.get('/users/:capability/add/:user_id/:user_email', authNeeded, adminNeeded, usersController.addCapabilityForm);
app.post('/users/:capability/add/:user_id/:user_email', authNeeded, adminNeeded, usersController.addCapability);

app.listen(config.listen_port, function () {
  console.log('Example app listening on port ' + config.listen_port);
});