UNPKG

openkb

Version:

openKB is an Open Source Nodejs Markdown based knowledge base/FAQ/Wiki app with powerful lunr search

324 lines (296 loc) 10.9 kB
var express = require('express'); var path = require('path'); var logger = require('morgan'); var handlebars = require('express-handlebars'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var Nedb = require('nedb'); var session = require('express-session'); var bcrypt = require('bcrypt-nodejs'); var markdownit = require('markdown-it')({html: true, linkify: true, typographer: true}); var moment = require('moment'); var fs = require('fs'); var Nedb_store = require('nedb-session-store')(session); var remove_md = require('remove-markdown'); var common = require('./routes/common'); var config = common.read_config(); var MongoClient = require('mongodb').MongoClient; var expstate = require('express-state'); var compression = require('compression'); // require the routes var index = require('./routes/index'); var api = require('./routes/api'); var app = express(); // setup the translation var i18n = new (require('i18n-2'))({ locales: ['en', 'de', 'da', 'es', 'cn', 'ru', 'pt-br'], directory: path.join(__dirname, 'locales/'), defaultLocale: 'en', cookieName: 'locale' }); if(config.settings.locale){ i18n.setLocale(config.settings.locale); i18n.setLocaleFromCookie(); } // compress all requests app.use(compression()); // setup express-state expstate.extend(app); // add the config items we want to expose to the client common.config_expose(app); // check theme directory exists if set if(config.settings.theme){ if(!fs.existsSync(path.join(__dirname, '/public/themes/', config.settings.theme))){ console.error('Theme folder does not exist. Please check theme in /routes/config.json'); process.exit(); } } // view engine setup app.set('views', path.join(__dirname, '/views')); app.engine('hbs', handlebars({extname: 'hbs', layoutsDir: path.join(__dirname, '/views/layouts'), defaultLayout: 'layout.hbs', partialsDir: 'public/themes/'})); app.set('view engine', 'hbs'); // helpers for the handlebar templating platform handlebars = handlebars.create({ helpers: { __: function (value){ return i18n.__(value); }, split_keywords: function (keywords){ var app_context = config.settings.app_context; if(app_context !== ''){ app_context = '/' + app_context; } if(keywords){ var array = keywords.split(','); var links = ''; for(var i = 0; i < array.length; i++){ if(array[i].trim() !== ''){ links += '<a href="' + app_context + '/search/' + array[i].trim() + '">' + array[i].trim() + '</a> <span class="keywordSeporator">|</span> '; } }return links.substring(0, links.length - 1); } return keywords; }, encodeURI: function(url){ return encodeURI(url); }, removeEmail: function(user){ return user.replace(/ - ([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/, ''); }, checked_state: function (state){ if(state === true || state === 'true'){ return'checked'; } return''; }, select_state: function (value, option){ if(value === option){ return'selected'; }return''; }, if_null: function (val1, val2){ if(val1){ return val1; } return val2; }, substring: function (val, length){ if(val.length > length){ return val.substring(0, length); } return val; }, strip_md: function(md){ if(md !== null && md !== ''){ return remove_md(md); } return md; }, view_count: function(value){ if(value === '' || value === undefined){ return'0'; } return value; }, ifBoth: function(val1, val2, options){ if(val1 && val2){ return options.fn(this); } return options.inverse(this); }, format_date: function(date){ if(config.settings.date_format){ return moment(date).format(config.settings.date_format); } return moment(date).format('DD/MM/YYYY h:mmA'); }, app_context: function (){ if(config.settings.app_context !== undefined && config.settings.app_context !== ''){ return'/' + config.settings.app_context; }return''; }, ifCond: function(v1, operator, v2, options){ switch(operator){ case'==': return(v1 === v2) ? options.fn(this) : options.inverse(this); case'!=': return(v1 !== v2) ? options.fn(this) : options.inverse(this); case'===': return(v1 === v2) ? options.fn(this) : options.inverse(this); case'<': return(v1 < v2) ? options.fn(this) : options.inverse(this); case'<=': return(v1 <= v2) ? options.fn(this) : options.inverse(this); case'>': return(v1 > v2) ? options.fn(this) : options.inverse(this); case'>=': return(v1 >= v2) ? options.fn(this) : options.inverse(this); case'&&': return(v1 && v2) ? options.fn(this) : options.inverse(this); case'||': return(v1 || v2) ? options.fn(this) : options.inverse(this); default: return options.inverse(this); } }, is_an_admin: function (value, options){ if(value === 'true'){ return options.fn(this); } return options.inverse(this); } } }); app.enable('trust proxy'); app.set('port', process.env.PORT || 4444); app.set('bind', process.env.BIND || '0.0.0.0'); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: false})); app.use(cookieParser('5TOCyfH3HuszKGzFZntk')); app.use(session({ resave: false, saveUninitialized: true, secret: 'pAgGxo8Hzg7PFlv1HpO8Eg0Y6xtP7zYx', cookie: { path: '/', httpOnly: true, maxAge: 3600000 * 24 }, store: new Nedb_store({ filename: 'data/sessions.db' }) })); // setup the app context var app_context = ''; if(config.settings.app_context !== undefined && config.settings.app_context !== ''){ app_context = '/' + config.settings.app_context; } // frontend modules loaded from NPM app.use(app_context + '/static', express.static(path.join(__dirname, 'public/'))); app.use(app_context + '/uploads', express.static(path.join(__dirname, 'public', 'uploads'))); app.use(app_context + '/font-awesome', express.static(path.join(__dirname, 'node_modules/font-awesome/'))); app.use(app_context + '/jquery', express.static(path.join(__dirname, 'node_modules/jquery/dist/'))); app.use(app_context + '/bootstrap', express.static(path.join(__dirname, 'node_modules/bootstrap/dist/'))); app.use(app_context + '/bootstrapTabs', express.static(path.join(__dirname, 'node_modules/bootstrap/js/'))); app.use(app_context + '/simplemde', express.static(path.join(__dirname, 'node_modules/simplemde/dist/'))); app.use(app_context + '/markdown-it', express.static(path.join(__dirname, 'node_modules/markdown-it/dist/'))); app.use(app_context + '/stylesheets', express.static(path.join(__dirname, 'public/stylesheets'))); app.use(app_context + '/fonts', express.static(path.join(__dirname, 'public/fonts'))); app.use(app_context + '/javascripts', express.static(path.join(__dirname, 'public/javascripts'))); app.use(app_context + '/lunr', express.static(path.join(__dirname, 'node_modules/lunr'))); app.use(app_context + '/favicon.png', express.static(path.join(__dirname, 'public/favicon.png'))); // serving static content app.use(express.static(path.join(__dirname, 'public'))); // Make stuff accessible to our router app.use(function (req, res, next){ req.markdownit = markdownit; req.handlebars = handlebars.helpers; req.bcrypt = bcrypt; req.i18n = i18n; req.app_context = app_context; req.i18n.setLocaleFromCookie(); next(); }); // setup the routes if(app_context !== ''){ app.use(app_context, index); app.use(app_context, api); }else{ app.use('/', index); app.use('/', api); } // catch 404 and forward to error handler app.use(function(req, res, next){ var err = new Error('Not Found'); err.status = 404; next(err); }); // === Error handlers === // development error handler // will print stacktrace if(app.get('env') === 'development'){ app.use(function (err, req, res, next){ console.error(err.stack); res.status(err.status || 500); res.render('error', { message: err.message, error: err, helpers: handlebars.helpers, config: config }); }); } // production error handler // no stacktraces leaked to user app.use(function (err, req, res, next){ console.error(err.stack); res.status(err.status || 500); res.render('error', { message: err.message, error: {}, helpers: handlebars.helpers, config: config }); }); // sets up the databse depending on whether it's embedded (NeDB) or MongoDB if(config.settings.database.type === 'embedded'){ // setup the db's var db = new Nedb(); db = {}; db.users = new Nedb({filename: path.join(__dirname, '/data/users.db'), autoload: true}); db.kb = new Nedb({filename: path.join(__dirname, '/data/kb.db'), autoload: true}); db.votes = new Nedb({filename: path.join(__dirname, '/data/votes.db'), autoload: true}); // add db to app for routes app.db = db; // add articles to index common.buildIndex(db, function(err){ // lift the app app.listen(app.get('port'), app.get('bind'), function (){ console.log('openKB running on host: http://' + app.get('bind') + ':' + app.get('port')); app.emit('openKBstarted'); }); }); }else{ MongoClient.connect(config.settings.database.connection_string, {}, function(err, db){ // On connection error we display then exit if(err){ console.error('Error connecting to MongoDB: ' + err); process.exit(); } // setup the collections db.users = db.collection('users'); db.kb = db.collection('kb'); db.votes = db.collection('votes'); // add db to app for routes app.db = db; // add articles to index common.buildIndex(db, function(err){ // lift the app app.listen(app.get('port'), app.get('bind'), function (){ console.log('openKB running on host: http://' + app.get('bind') + ':' + app.get('port')); app.emit('openKBstarted'); }); }); }); } module.exports = app;