index.js 9.21 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 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
});

function initMongoClient() {
    if (!config.mongodb || !config.mongodb.url) {
        return;
    }

    try {
        var url = config.mongodb.url;

        mongoClient.connect(url, function(err, db) {
            if (err) {
                console.log('Failed to connect to mongodb');
                return;
            }
            mongodb = db;
            console.log('MongoDB connected');
        });
    }
    catch(err) {
        console.log('Exception when connecting to mongodb');
    }
}
initMongoClient();

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);

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) {
    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;
    }

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

    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);

        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: config.suppliers,
                autorefreshLink: generateAutoRefreshLink(req.path, req.query),
                qs: req.query,
                url: req.url,
                path: req.path,
            });
        });
    });
}

function pageTrxView(req, res, next) {

    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');
    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;

        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) {
    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');

    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');
}

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

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);
});