瀏覽代碼

Removed Redis & MongoDB dependencies in favor of Loki.js

NGPixel 8 年之前
父節點
當前提交
24f90d4a17
共有 11 個文件被更改,包括 140 次插入295 次删除
  1. 4 2
      .gitignore
  2. 5 13
      config.sample.yml
  3. 6 6
      controllers/auth.js
  4. 19 18
      models/auth.js
  5. 2 151
      models/db/user.js
  6. 35 0
      models/localdata.js
  7. 60 0
      models/loki.js
  8. 0 53
      models/mongodb.js
  9. 0 41
      models/redis.js
  10. 4 7
      package.json
  11. 5 4
      server.js

+ 4 - 2
.gitignore

@@ -45,5 +45,7 @@ jspm_packages
 # Config Files
 config.yml
 
-# App Repo
-repo
+# Data directories
+/repo
+/data
+/uploads

+ 5 - 13
config.sample.yml

@@ -22,21 +22,13 @@ host: http://localhost
 port: 80
 
 # -------------------------------------------------
-# MongoDB Connection String
+# Data Directories
 # -------------------------------------------------
-# Full explanation + examples in the documentation (https://opsstatus.readme.io/)
 
-db: mongodb://localhost/wiki
-
-# -------------------------------------------------
-# Redis Connection Info
-# -------------------------------------------------
-# Full explanation + examples in the documentation (https://opsstatus.readme.io/)
-
-redis:
-  host: localhost
-  port: 6379
-  db: 0
+datadir:
+  repo: ./repo
+  db: ./data
+  uploads: ./uploads
 
 # -------------------------------------------------
 # Git Connection Info

+ 6 - 6
controllers/auth.js

@@ -2,13 +2,13 @@ var express = require('express');
 var router = express.Router();
 var passport = require('passport');
 var ExpressBrute = require('express-brute');
-var ExpressBruteRedisStore = require('express-brute-redis');
+//var ExpressBruteRedisStore = require('express-brute-redis');
 var moment = require('moment');
 
 /**
  * Setup Express-Brute
  */
-var EBstore = new ExpressBruteRedisStore({
+/*var EBstore = new ExpressBruteRedisStore({
     prefix: 'bf:',
     client: red
 });
@@ -26,7 +26,7 @@ var bruteforce = new ExpressBrute(EBstore, {
 	    });
 		res.redirect('/login');
 	}
-});
+});*/
 
 /**
  * Login form
@@ -37,7 +37,7 @@ router.get('/login', function(req, res, next) {
 	});
 });
 
-router.post('/login', bruteforce.prevent, function(req, res, next) {
+router.post('/login', /*bruteforce.prevent,*/ function(req, res, next) {
 		passport.authenticate('local', function(err, user, info) {
 
 			if (err) { return next(err); }
@@ -54,9 +54,9 @@ router.post('/login', bruteforce.prevent, function(req, res, next) {
 
 			req.logIn(user, function(err) {
 	      if (err) { return next(err); }
-	      req.brute.reset(function () {
+	      //req.brute.reset(function () {
 				return res.redirect('/');
-			});
+			//});
 	    });
 
 		})(req, res, next);

+ 19 - 18
models/auth.js

@@ -9,11 +9,12 @@ module.exports = function(passport, appconfig) {
     });
 
     passport.deserializeUser(function(id, done) {
-        db.User.findById(id).then((user) => {
+        let user = db.User.find({ id });
+        if(user) {
             done(null, user);
-        }).catch((err) => {
+        } else {
             done(err, null);
-        });
+        }
     });
 
     // Setup local user authentication strategy
@@ -42,23 +43,23 @@ module.exports = function(passport, appconfig) {
 
     // Check for admin access
 
-    db.connectPromise.then(() => {
+    db.onReady.then(() => {
 
-        db.User.count().then((count) => {
-            if(count < 1) {
-                winston.info('No administrator account found. Creating a new one...');
-                db.User.new({
-                    email: appconfig.admin,
-                    firstName: "Admin",
-                    lastName: "Admin",
-                    password: "admin123"
-                }).then(() => {
-                    winston.info('Administrator account created successfully!');
-                }).catch((ex) => {
-                    winston.error('An error occured while creating administrator account: ' + ex);
-                });
+        if(db.User.count() < 1) {
+            winston.info('No administrator account found. Creating a new one...');
+            if(db.User.insert({
+                email: appconfig.admin,
+                firstName: "Admin",
+                lastName: "Admin",
+                password: "admin123"
+            })) {
+                winston.info('Administrator account created successfully!');
+            } else {
+                winston.error('An error occured while creating administrator account: ');
             }
-        });
+        }
+
+        return true;
 
     });
 

+ 2 - 151
models/db/user.js

@@ -1,158 +1,9 @@
 "use strict";
 
-var modb = require('mongoose');
 var bcrypt = require('bcryptjs-then');
 var Promise = require('bluebird');
 var _ = require('lodash');
 
-/**
- * User Schema
- *
- * @type       {Object}
- */
-var userSchema = modb.Schema({
+module.exports = {
 
-  email: {
-    type: String,
-    required: true,
-    index: true,
-    minlength: 6
-  },
-  password: {
-    type: String,
-    required: true
-  },
-  firstName: {
-    type: String,
-    required: true,
-    minlength: 1
-  },
-  lastName: {
-    type: String,
-    required: true,
-    minlength: 1
-  },
-  timezone: {
-    type: String,
-    required: true,
-    default: 'UTC'
-  },
-  lang: {
-    type: String,
-    required: true,
-    default: 'en'
-  },
-  rights: [{
-    type: String,
-    required: true
-  }]
-
-},
-{
-  timestamps: {}
-});
-
-/**
- * VIRTUAL - Full Name
- */
-userSchema.virtual('fullName').get(function() {
-  return this.firstName + ' ' + this.lastName;
-});
-
-/**
- * INSTANCE - Validate password against hash
- *
- * @param      {string}   uPassword  The user password
- * @return     {Promise<Boolean>}  Promise with valid / invalid boolean
- */
-userSchema.methods.validatePassword = function(uPassword) {
-  let self = this;
-  return bcrypt.compare(uPassword, self.password);
-};
-
-/**
- * MODEL - Generate hash from password
- *
- * @param      {string}   uPassword  The user password
- * @return     {Promise<String>}  Promise with generated hash
- */
-userSchema.statics.generateHash = function(uPassword) {
-    return bcrypt.hash(uPassword, 10);
-};
-
-/**
- * MODEL - Create a new user
- *
- * @param      {Object}   nUserData  User data
- * @return     {Promise}  Promise of the create operation
- */
-userSchema.statics.new = function(nUserData) {
-
-  let self = this;
-
-  return self.generateHash(nUserData.password).then((passhash) => {
-    return this.create({
-      _id: db.ObjectId(),
-      email: nUserData.email,
-      firstName: nUserData.firstName,
-      lastName: nUserData.lastName,
-      password: passhash,
-      rights: ['admin']
-    });
-  });
-  
-};
-
-/**
- * MODEL - Edit a user
- *
- * @param      {String}   userId  The user identifier
- * @param      {Object}   data    The user data
- * @return     {Promise}  Promise of the update operation
- */
-userSchema.statics.edit = function(userId, data) {
-
-  let self = this;
-
-  // Change basic info
-
-  let fdata = {
-    email: data.email,
-    firstName: data.firstName,
-    lastName: data.lastName,
-    timezone: data.timezone,
-    lang: data.lang,
-    rights: data.rights
-  };
-  let waitTask = null;
-
-  // Change password?
-
-  if(!_.isEmpty(data.password) && _.trim(data.password) !== '********') {
-    waitTask = self.generateHash(data.password).then((passhash) => {
-      fdata.password = passhash;
-      return fdata;
-    });
-  } else {
-    waitTask = Promise.resolve(fdata);
-  }
-
-  // Update user
-
-  return waitTask.then((udata) => {
-    return this.findByIdAndUpdate(userId, udata, { runValidators: true });
-  });
-
-};
-
-/**
- * MODEL - Delete a user
- *
- * @param      {String}   userId  The user ID
- * @return     {Promise}  Promise of the delete operation
- */
-userSchema.statics.erase = function(userId) {
-  return this.findByIdAndRemove(userId);
-};
-
-module.exports = modb.model('User', userSchema);
+};

+ 35 - 0
models/localdata.js

@@ -0,0 +1,35 @@
+"use strict";
+
+var fs = require('fs'),
+	_ = require('lodash');
+
+/**
+ * Local Data Storage
+ *
+ * @param      {Object}  appconfig  The application configuration
+ */
+module.exports = (appconfig) => {
+
+	// Create DB folder
+
+	try {
+		fs.mkdirSync(appconfig.datadir.db);
+	} catch (err) {
+		if(err.code !== 'EEXIST') {
+			winston.error(err);
+			process.exit(1);
+		}
+	}
+
+	// Create Uploads folder
+
+	try {
+		fs.mkdirSync(appconfig.datadir.uploads);
+	} catch (err) {
+		if(err.code !== 'EEXIST') {
+			winston.error(err);
+			process.exit(1);
+		}
+	}
+
+};

+ 60 - 0
models/loki.js

@@ -0,0 +1,60 @@
+"use strict";
+
+var loki = require('lokijs'),
+	 fs   = require("fs"),
+	 path = require("path"),
+	 Promise = require('bluebird'),
+	 _ = require('lodash');
+
+/**
+ * Loki.js module
+ *
+ * @param      {Object}  appconfig  Application config
+ * @return     {Object}  LokiJS instance
+ */
+module.exports = function(appconfig) {
+
+	let dbReadyResolve;
+	let dbReady = new Promise((resolve, reject) => {
+		dbReadyResolve = resolve;
+	});
+
+	// Initialize Loki.js
+
+	let dbModel = {
+		Store: new loki(path.join(appconfig.datadir.db, 'app.db'), {
+			env: 'NODEJS',
+			autosave: true,
+			autosaveInterval: 5000
+		}),
+		Models: {},
+		onReady: dbReady
+	};
+
+	// Load Models
+
+	let dbModelsPath = path.join(ROOTPATH, 'models/db');
+
+	dbModel.Store.loadDatabase({}, () => {
+
+		fs
+		.readdirSync(dbModelsPath)
+		.filter(function(file) {
+			return (file.indexOf(".") !== 0);
+		})
+		.forEach(function(file) {
+			let modelName = _.upperFirst(_.split(file,'.')[0]);
+			dbModel.Models[modelName] = require(path.join(dbModelsPath, file));
+			dbModel[modelName] = dbModel.Store.getCollection(modelName);
+			if(!dbModel[modelName]) {
+				dbModel[modelName] = dbModel.Store.addCollection(modelName);
+			}
+		});
+
+		dbReadyResolve();
+
+	});
+
+	return dbModel;
+
+};

+ 0 - 53
models/mongodb.js

@@ -1,53 +0,0 @@
-"use strict";
-
-var modb = require('mongoose'),
-	 fs   = require("fs"),
-	 path = require("path"),
-	 _ = require('lodash');
-
-/**
- * MongoDB module
- *
- * @param      {Object}  appconfig  Application config
- * @return     {Object}  Mongoose instance
- */
-module.exports = function(appconfig) {
-
-	modb.Promise = require('bluebird');
-
-	let dbModels = {};
-	let dbModelsPath = path.join(ROOTPATH, 'models/db');
-
-	// Event handlers
-
-	modb.connection.on('error', (err) => {
-		winston.error('Failed to connect to MongoDB instance.');
-	});
-	modb.connection.once('open', function() {
-		winston.log('Connected to MongoDB instance.');
-	});
-
-	// Store connection handle
-
-	dbModels.connection = modb.connection;
-	dbModels.ObjectId = modb.Types.ObjectId;
-
-	// Load Models
-
-	fs
-	.readdirSync(dbModelsPath)
-	.filter(function(file) {
-		return (file.indexOf(".") !== 0);
-	})
-	.forEach(function(file) {
-		let modelName = _.upperFirst(_.split(file,'.')[0]);
-		dbModels[modelName] = require(path.join(dbModelsPath, file));
-	});
-
-	// Connect
-
-	dbModels.connectPromise = modb.connect(appconfig.db);
-
-	return dbModels;
-
-};

+ 0 - 41
models/redis.js

@@ -1,41 +0,0 @@
-"use strict";
-
-var Redis = require('ioredis'),
-	_ = require('lodash');
-
-/**
- * Redis module
- *
- * @param      {Object}  appconfig  Application config
- * @return     {Redis}   Redis instance
- */
-module.exports = (appconfig) => {
-
-	let rd = null;
-
-	if(_.isArray(appconfig.redis)) {
-		rd = new Redis.Cluster(appconfig.redis, {
-			scaleReads: 'master',
-			redisOptions: {
-				lazyConnect: false
-			}
-		});
-	} else {
-		rd = new Redis(_.defaultsDeep(appconfig.redis), {
-			lazyConnect: false
-		});
-	}
-
-	// Handle connection errors
-
-	rd.on('error', (err) => {
-		winston.error('Failed to connect to Redis instance(s). [err-1]');
-	});
-
-	rd.on('node error', (err) => {
-		winston.error('Failed to connect to Redis instance(s). [err-2]');
-	});
-
-	return rd;
-
-};

+ 4 - 7
package.json

@@ -38,20 +38,20 @@
     "cheerio": "^0.20.0",
     "compression": "^1.6.2",
     "connect-flash": "^0.1.1",
+    "connect-loki": "^1.0.4",
     "connect-redis": "^3.1.0",
     "cookie-parser": "^1.4.3",
     "express": "^4.14.0",
     "express-brute": "^0.7.0-beta.0",
-    "express-brute-redis": "0.0.1",
     "express-session": "^1.14.0",
     "express-validator": "^2.20.8",
     "highlight.js": "^9.6.0",
     "i18next": "^3.4.1",
     "i18next-express-middleware": "^1.0.1",
     "i18next-node-fs-backend": "^0.1.2",
-    "ioredis": "^2.3.0",
     "js-yaml": "^3.6.1",
     "lodash": "^4.15.0",
+    "lokijs": "^1.4.1",
     "markdown-it": "^7.0.1",
     "markdown-it-abbr": "^1.0.3",
     "markdown-it-anchor": "^2.5.0",
@@ -64,8 +64,6 @@
     "markdown-it-toc-and-anchor": "^4.1.1",
     "moment": "^2.14.1",
     "moment-timezone": "^0.5.5",
-    "mongoose": "^4.5.9",
-    "mongoose-delete": "^0.3.4",
     "nodegit": "^0.14.1",
     "passport": "^0.3.2",
     "passport-local": "^1.0.0",
@@ -86,7 +84,6 @@
     "chai-as-promised": "^5.3.0",
     "codacy-coverage": "^2.0.0",
     "font-awesome": "^4.6.3",
-    "gridlex": "^2.1.1",
     "gulp": "^3.9.1",
     "gulp-babel": "^6.1.2",
     "gulp-clean-css": "^2.0.12",
@@ -99,12 +96,12 @@
     "gulp-tar": "^1.9.0",
     "gulp-uglify": "^2.0.0",
     "gulp-zip": "^3.2.0",
-    "istanbul": "^0.4.4",
+    "istanbul": "^0.4.5",
     "jquery": "^3.1.0",
     "merge-stream": "^1.0.0",
     "mocha": "^3.0.2",
     "mocha-lcov-reporter": "^1.2.0",
-    "nodemon": "^1.10.0",
+    "nodemon": "^1.10.2",
     "snyk": "^1.18.0",
     "vue": "^1.0.26"
   }

+ 5 - 4
server.js

@@ -14,8 +14,9 @@ global.winston = require('winston');
 winston.info('[SERVER] Requarks Wiki is initializing...');
 
 var appconfig = require('./models/config')('./config.yml');
-global.db = require('./models/mongodb')(appconfig);
-global.red = require('./models/redis')(appconfig);
+var lcdata = require('./models/localdata')(appconfig);
+
+global.db = require('./models/loki')(appconfig);
 global.git = require('./models/git').init(appconfig);
 global.mark = require('./models/markdown');
 
@@ -28,7 +29,7 @@ var express = require('express');
 var path = require('path');
 var favicon = require('serve-favicon');
 var session = require('express-session');
-var redisStore = require('connect-redis')(session);
+var lokiStore = require('connect-loki')(session);
 var cookieParser = require('cookie-parser');
 var bodyParser = require('body-parser');
 var flash = require('connect-flash');
@@ -68,7 +69,7 @@ var strategy = require('./models/auth')(passport, appconfig);
 app.use(cookieParser());
 app.use(session({
   name: 'requarkswiki.sid',
-  store: new redisStore({ client: red }),
+  store: new lokiStore({ path: path.join(appconfig.datadir.db, 'sessions.db') }),
   secret: appconfig.sessionSecret,
   resave: false,
   saveUninitialized: false