From d76f6182b2d175339cff5f2071ae94615190bcf1 Mon Sep 17 00:00:00 2001 From: NGPixel Date: Sat, 22 Jul 2017 23:56:46 -0400 Subject: [PATCH] refactor: migrate to PostgreSQL + Sequelize --- package.json | 11 +- server/agent.js | 16 +- server/app/data.yml | 9 + server/controllers/auth.js | 18 +- server/controllers/uploads.js | 26 +- server/index.js | 128 +++-- server/libs/db.js | 63 --- server/models/_relations.js | 10 + server/models/bruteforce.js | 20 - server/models/document.js | 56 ++ server/models/entry.js | 42 -- server/models/file.js | 44 ++ server/models/folder.js | 24 + server/models/group.js | 18 + server/models/right.js | 38 ++ server/models/setting.js | 38 +- server/models/upl-file.js | 46 -- server/models/upl-folder.js | 21 - server/models/user.js | 186 +++---- server/{libs => modules}/auth.js | 116 ++-- server/{libs => modules}/config.js | 8 +- server/modules/db.js | 74 +++ server/{libs/local.js => modules/disk.js} | 60 +-- server/{libs => modules}/entries.js | 10 +- server/{libs => modules}/git.js | 64 +-- server/{libs => modules}/logger.js | 32 +- server/{libs => modules}/markdown.js | 14 +- server/modules/redis.js | 29 + server/{libs => modules}/rights.js | 6 +- .../{libs => modules}/search-index/index.js | 0 .../{libs => modules}/search-index/siUtil.js | 0 server/{libs => modules}/search.js | 20 +- server/{libs => modules}/system.js | 0 server/{libs => modules}/uploads-agent.js | 0 server/{libs => modules}/uploads.js | 42 +- .../winston-transports/bugsnag.js | 0 .../winston-transports/rollbar.js | 0 .../winston-transports/sentry.js | 0 wiki.js | 2 +- yarn.lock | 496 ++++++++++++------ 40 files changed, 1043 insertions(+), 744 deletions(-) delete mode 100644 server/libs/db.js create mode 100644 server/models/_relations.js delete mode 100644 server/models/bruteforce.js create mode 100644 server/models/document.js delete mode 100644 server/models/entry.js create mode 100644 server/models/file.js create mode 100644 server/models/folder.js create mode 100644 server/models/group.js create mode 100644 server/models/right.js delete mode 100644 server/models/upl-file.js delete mode 100644 server/models/upl-folder.js rename server/{libs => modules}/auth.js (58%) rename server/{libs => modules}/config.js (89%) create mode 100644 server/modules/db.js rename server/{libs/local.js => modules/disk.js} (59%) rename server/{libs => modules}/entries.js (97%) rename server/{libs => modules}/git.js (78%) rename server/{libs => modules}/logger.js (62%) rename server/{libs => modules}/markdown.js (96%) create mode 100644 server/modules/redis.js rename server/{libs => modules}/rights.js (94%) rename server/{libs => modules}/search-index/index.js (100%) rename server/{libs => modules}/search-index/siUtil.js (100%) rename server/{libs => modules}/search.js (88%) rename server/{libs => modules}/system.js (100%) rename server/{libs => modules}/uploads-agent.js (100%) rename server/{libs => modules}/uploads.js (81%) rename server/{libs => modules}/winston-transports/bugsnag.js (100%) rename server/{libs => modules}/winston-transports/rollbar.js (100%) rename server/{libs => modules}/winston-transports/sentry.js (100%) diff --git a/package.json b/package.json index a598f44e..d616a1e6 100644 --- a/package.json +++ b/package.json @@ -48,14 +48,14 @@ "chokidar": "~1.7.0", "compression": "~1.7.0", "connect-flash": "~0.1.1", - "connect-mongo": "~1.3.2", + "connect-redis": "~3.3.0", "cookie-parser": "~1.4.3", "cron": "~1.2.1", "diff2html": "~2.3.0", "execa": "~0.7.0", "express": "~4.15.3", "express-brute": "1.0.1", - "express-brute-mongoose": "~0.0.9", + "express-brute-redis": "~0.0.1", "express-session": "~1.15.3", "file-type": "~5.2.0", "filesize.js": "~1.0.2", @@ -67,6 +67,7 @@ "i18next-express-middleware": "~1.0.5", "i18next-node-fs-backend": "~1.0.0", "image-size": "~0.6.0", + "ioredis": "~3.1.1", "jimp": "~0.2.28", "js-yaml": "~3.9.0", "jsonwebtoken": "~7.4.1", @@ -88,8 +89,6 @@ "mime-types": "~2.1.15", "moment": "~2.18.1", "moment-timezone": "~0.5.13", - "mongodb": "~2.2.30", - "mongoose": "~4.11.1", "multer": "~1.3.0", "node-2fa": "~1.1.2", "node-graceful": "~0.2.3", @@ -104,6 +103,9 @@ "passport-slack": "0.0.7", "passport-windowslive": "~1.0.2", "passport.socketio": "~3.7.0", + "pg": "~7.0.2", + "pg-hstore": "~2.3.2", + "pg-promise": "~6.3.5", "pm2": "~2.6.1", "pug": "~2.0.0-rc.2", "read-chunk": "~2.0.0", @@ -112,6 +114,7 @@ "search-index-adder": "~0.3.9", "search-index-searcher": "~0.2.10", "semver": "~5.3.0", + "sequelize": "~4.4.2", "serve-favicon": "~2.4.3", "simplemde": "~1.11.2", "socket.io": "~2.0.2", diff --git a/server/agent.js b/server/agent.js index 38efd466..327496e8 100644 --- a/server/agent.js +++ b/server/agent.js @@ -1,6 +1,6 @@ // =========================================== // Wiki.js - Background Agent -// 1.0.0 +// 1.0.1 // Licensed under AGPLv3 // =========================================== @@ -12,7 +12,7 @@ global.ROOTPATH = ROOTPATH global.SERVERPATH = SERVERPATH const IS_DEBUG = process.env.NODE_ENV === 'development' -let appconf = require('./libs/config')() +let appconf = require('./modules/config')() global.appconfig = appconf.config global.appdata = appconf.data @@ -20,7 +20,7 @@ global.appdata = appconf.data // Load Winston // ---------------------------------------- -global.winston = require('./libs/logger')(IS_DEBUG, 'AGENT') +global.winston = require('./modules/logger')(IS_DEBUG, 'AGENT') // ---------------------------------------- // Load global modules @@ -28,12 +28,12 @@ global.winston = require('./libs/logger')(IS_DEBUG, 'AGENT') global.winston.info('Background Agent is initializing...') -global.db = require('./libs/db').init() -global.upl = require('./libs/uploads-agent').init() -global.git = require('./libs/git').init() -global.entries = require('./libs/entries').init() +global.db = require('./modules/db').init() +global.upl = require('./modules/uploads-agent').init() +global.git = require('./modules/git').init() +global.entries = require('./modules/entries').init() global.lang = require('i18next') -global.mark = require('./libs/markdown') +global.mark = require('./modules/markdown') // ---------------------------------------- // Load modules diff --git a/server/app/data.yml b/server/app/data.yml index da16577b..cd8e839d 100644 --- a/server/app/data.yml +++ b/server/app/data.yml @@ -64,6 +64,15 @@ defaults: code: dark: true colorize: true +authProviders: + - local + - microsoft + - google + - facebook + - github + - slack + - ldap + - azure colors: - red - pink diff --git a/server/controllers/auth.js b/server/controllers/auth.js index b513470e..a29e2873 100644 --- a/server/controllers/auth.js +++ b/server/controllers/auth.js @@ -1,19 +1,21 @@ 'use strict' -/* global db, lang */ +/* global wiki */ const Promise = require('bluebird') const express = require('express') const router = express.Router() const passport = require('passport') const ExpressBrute = require('express-brute') -const ExpressBruteMongooseStore = require('express-brute-mongoose') +const ExpressBruteRedisStore = require('express-brute-redis') const moment = require('moment') /** * Setup Express-Brute */ -const EBstore = new ExpressBruteMongooseStore(db.Bruteforce) +const EBstore = new ExpressBruteRedisStore({ + client: wiki.redis +}) const bruteforce = new ExpressBrute(EBstore, { freeRetries: 5, minWait: 60 * 1000, @@ -22,8 +24,8 @@ const bruteforce = new ExpressBrute(EBstore, { failCallback (req, res, next, nextValidRequestDate) { req.flash('alert', { class: 'error', - title: lang.t('auth:errors.toomanyattempts'), - message: lang.t('auth:errors.toomanyattemptsmsg', { time: moment(nextValidRequestDate).fromNow() }), + title: wiki.lang.t('auth:errors.toomanyattempts'), + message: wiki.lang.t('auth:errors.toomanyattemptsmsg', { time: moment(nextValidRequestDate).fromNow() }), iconClass: 'fa-times' }) res.redirect('/login') @@ -73,13 +75,13 @@ router.post('/login', bruteforce.prevent, function (req, res, next) { // LOGIN FAIL if (err.message === 'INVALID_LOGIN') { req.flash('alert', { - title: lang.t('auth:errors.invalidlogin'), - message: lang.t('auth:errors.invalidloginmsg') + title: wiki.lang.t('auth:errors.invalidlogin'), + message: wiki.lang.t('auth:errors.invalidloginmsg') }) return res.redirect('/login') } else { req.flash('alert', { - title: lang.t('auth:errors.loginerror'), + title: wiki.lang.t('auth:errors.loginerror'), message: err.message }) return res.redirect('/login') diff --git a/server/controllers/uploads.js b/server/controllers/uploads.js index a2a3f2f2..d7321c41 100644 --- a/server/controllers/uploads.js +++ b/server/controllers/uploads.js @@ -1,6 +1,6 @@ 'use strict' -/* global git, lang, lcdata, upl */ +/* global wiki */ const express = require('express') const router = express.Router() @@ -12,7 +12,7 @@ const fs = Promise.promisifyAll(require('fs-extra')) const path = require('path') const _ = require('lodash') -const validPathRe = new RegExp('^([a-z0-9/-' + appdata.regex.cjk + appdata.regex.arabic + ']+\\.[a-z0-9]+)$') +const validPathRe = new RegExp('^([a-z0-9/-' + wiki.data.regex.cjk + wiki.data.regex.arabic + ']+\\.[a-z0-9]+)$') const validPathThumbsRe = new RegExp('^([a-z0-9]+\\.png)$') // ========================================== @@ -28,7 +28,7 @@ router.get('/t/*', (req, res, next) => { // todo: Authentication-based access res.sendFile(fileName, { - root: lcdata.getThumbsPath(), + root: wiki.disk.getThumbsPath(), dotfiles: 'deny' }, (err) => { if (err) { @@ -37,12 +37,12 @@ router.get('/t/*', (req, res, next) => { }) }) -router.post('/img', lcdata.uploadImgHandler, (req, res, next) => { +router.post('/img', wiki.disk.uploadImgHandler, (req, res, next) => { let destFolder = _.chain(req.body.folder).trim().toLower().value() - upl.validateUploadsFolder(destFolder).then((destFolderPath) => { + wiki.upl.validateUploadsFolder(destFolder).then((destFolderPath) => { if (!destFolderPath) { - res.json({ ok: false, msg: lang.t('errors:invalidfolder') }) + res.json({ ok: false, msg: wiki.lang.t('errors:invalidfolder') }) return true } @@ -50,7 +50,7 @@ router.post('/img', lcdata.uploadImgHandler, (req, res, next) => { let destFilename = '' let destFilePath = '' - return lcdata.validateUploadsFilename(f.originalname, destFolder, true).then((fname) => { + return wiki.disk.validateUploadsFilename(f.originalname, destFolder, true).then((fname) => { destFilename = fname destFilePath = path.resolve(destFolderPath, destFilename) @@ -60,7 +60,7 @@ router.post('/img', lcdata.uploadImgHandler, (req, res, next) => { let mimeInfo = fileType(buf) if (!_.includes(['image/png', 'image/jpeg', 'image/gif', 'image/webp'], mimeInfo.mime)) { - return Promise.reject(new Error(lang.t('errors:invalidfiletype'))) + return Promise.reject(new Error(wiki.lang.t('errors:invalidfiletype'))) } return true }).then(() => { @@ -94,12 +94,12 @@ router.post('/img', lcdata.uploadImgHandler, (req, res, next) => { }) }) -router.post('/file', lcdata.uploadFileHandler, (req, res, next) => { +router.post('/file', wiki.disk.uploadFileHandler, (req, res, next) => { let destFolder = _.chain(req.body.folder).trim().toLower().value() - upl.validateUploadsFolder(destFolder).then((destFolderPath) => { + wiki.upl.validateUploadsFolder(destFolder).then((destFolderPath) => { if (!destFolderPath) { - res.json({ ok: false, msg: lang.t('errors:invalidfolder') }) + res.json({ ok: false, msg: wiki.lang.t('errors:invalidfolder') }) return true } @@ -107,7 +107,7 @@ router.post('/file', lcdata.uploadFileHandler, (req, res, next) => { let destFilename = '' let destFilePath = '' - return lcdata.validateUploadsFilename(f.originalname, destFolder, false).then((fname) => { + return wiki.disk.validateUploadsFilename(f.originalname, destFolder, false).then((fname) => { destFilename = fname destFilePath = path.resolve(destFolderPath, destFilename) @@ -150,7 +150,7 @@ router.get('/*', (req, res, next) => { // todo: Authentication-based access res.sendFile(fileName, { - root: git.getRepoPath() + '/uploads/', + root: wiki.git.getRepoPath() + '/uploads/', dotfiles: 'deny' }, (err) => { if (err) { diff --git a/server/index.js b/server/index.js index 07cc3df8..3f831aaa 100644 --- a/server/index.js +++ b/server/index.js @@ -2,47 +2,48 @@ // =========================================== // Wiki.js -// 1.0.0 +// 1.0.1 // Licensed under AGPLv3 // =========================================== const path = require('path') -const ROOTPATH = process.cwd() -const SERVERPATH = path.join(ROOTPATH, 'server') - -global.ROOTPATH = ROOTPATH -global.SERVERPATH = SERVERPATH -const IS_DEBUG = process.env.NODE_ENV === 'development' +let wiki = { + IS_DEBUG: process.env.NODE_ENV === 'development', + ROOTPATH: process.cwd(), + SERVERPATH: path.join(process.cwd(), 'server') +} +global.wiki = wiki process.env.VIPS_WARNING = false -// if (IS_DEBUG) { +// if (wiki.IS_DEBUG) { // require('@glimpse/glimpse').init() // } -let appconf = require('./libs/config')() -global.appconfig = appconf.config -global.appdata = appconf.data +let appconf = require('./modules/config')() +wiki.config = appconf.config +wiki.data = appconf.data // ---------------------------------------- // Load Winston // ---------------------------------------- -global.winston = require('./libs/logger')(IS_DEBUG, 'SERVER') -global.winston.info('Wiki.js is initializing...') +wiki.logger = require('./modules/logger')(wiki.IS_DEBUG, 'SERVER') +wiki.logger.info('Wiki.js is initializing...') // ---------------------------------------- // Load global modules // ---------------------------------------- -global.lcdata = require('./libs/local').init() -global.db = require('./libs/db').init() -global.entries = require('./libs/entries').init() -global.git = require('./libs/git').init(false) -global.lang = require('i18next') -global.mark = require('./libs/markdown') -global.search = require('./libs/search').init() -global.upl = require('./libs/uploads').init() +wiki.disk = require('./modules/disk').init() +wiki.db = require('./modules/db').init() +wiki.entries = require('./modules/entries').init() +wiki.git = require('./modules/git').init(false) +wiki.lang = require('i18next') +wiki.mark = require('./modules/markdown') +wiki.redis = require('./modules/redis').init() +wiki.search = require('./modules/search').init() +wiki.upl = require('./modules/uploads').init() // ---------------------------------------- // Load modules @@ -61,19 +62,19 @@ const i18nBackend = require('i18next-node-fs-backend') const passport = require('passport') const passportSocketIo = require('passport.socketio') const session = require('express-session') -const SessionMongoStore = require('connect-mongo')(session) +const SessionRedisStore = require('connect-redis')(session) const graceful = require('node-graceful') const socketio = require('socket.io') -var mw = autoload(path.join(SERVERPATH, '/middlewares')) -var ctrl = autoload(path.join(SERVERPATH, '/controllers')) +var mw = autoload(path.join(wiki.SERVERPATH, '/middlewares')) +var ctrl = autoload(path.join(wiki.SERVERPATH, '/controllers')) // ---------------------------------------- // Define Express App // ---------------------------------------- const app = express() -global.app = app +wiki.app = app app.use(compression()) // ---------------------------------------- @@ -86,8 +87,8 @@ app.use(mw.security) // Public Assets // ---------------------------------------- -app.use(favicon(path.join(ROOTPATH, 'assets', 'favicon.ico'))) -app.use(express.static(path.join(ROOTPATH, 'assets'), { +app.use(favicon(path.join(wiki.ROOTPATH, 'assets', 'favicon.ico'))) +app.use(express.static(path.join(wiki.ROOTPATH, 'assets'), { index: false, maxAge: '7d' })) @@ -96,20 +97,19 @@ app.use(express.static(path.join(ROOTPATH, 'assets'), { // Passport Authentication // ---------------------------------------- -require('./libs/auth')(passport) -global.rights = require('./libs/rights') -global.rights.init() +require('./modules/auth')(passport) +wiki.rights = require('./modules/rights') +wiki.rights.init() -let sessionStore = new SessionMongoStore({ - mongooseConnection: global.db.connection, - touchAfter: 15 +let sessionStore = new SessionRedisStore({ + client: wiki.redis }) app.use(cookieParser()) app.use(session({ name: 'wikijs.sid', store: sessionStore, - secret: appconfig.sessionSecret, + secret: wiki.config.sessionSecret, resave: false, saveUninitialized: false })) @@ -127,26 +127,24 @@ app.use(mw.seo) // Localization Engine // ---------------------------------------- -global.lang - .use(i18nBackend) - .init({ - load: 'languageOnly', - ns: ['common', 'admin', 'auth', 'errors', 'git'], - defaultNS: 'common', - saveMissing: false, - preload: [appconfig.lang], - lng: appconfig.lang, - fallbackLng: 'en', - backend: { - loadPath: path.join(SERVERPATH, 'locales/{{lng}}/{{ns}}.json') - } - }) +wiki.lang.use(i18nBackend).init({ + load: 'languageOnly', + ns: ['common', 'admin', 'auth', 'errors', 'git'], + defaultNS: 'common', + saveMissing: false, + preload: [wiki.config.lang], + lng: wiki.config.lang, + fallbackLng: 'en', + backend: { + loadPath: path.join(wiki.SERVERPATH, 'locales/{{lng}}/{{ns}}.json') + } +}) // ---------------------------------------- // View Engine Setup // ---------------------------------------- -app.set('views', path.join(SERVERPATH, 'views')) +app.set('views', path.join(wiki.SERVERPATH, 'views')) app.set('view engine', 'pug') app.use(bodyParser.json({ limit: '1mb' })) @@ -157,10 +155,10 @@ app.use(bodyParser.urlencoded({ extended: false, limit: '1mb' })) // ---------------------------------------- app.locals._ = require('lodash') -app.locals.t = global.lang.t.bind(global.lang) +app.locals.t = wiki.lang.t.bind(wiki.lang) app.locals.moment = require('moment') -app.locals.moment.locale(appconfig.lang) -app.locals.appconfig = appconfig +app.locals.moment.locale(wiki.config.lang) +app.locals.appconfig = wiki.config app.use(mw.flash) // ---------------------------------------- @@ -187,7 +185,7 @@ app.use(function (err, req, res, next) { res.status(err.status || 500) res.render('error', { message: err.message, - error: IS_DEBUG ? err : {} + error: wiki.IS_DEBUG ? err : {} }) }) @@ -195,13 +193,13 @@ app.use(function (err, req, res, next) { // Start HTTP server // ---------------------------------------- -global.winston.info('Starting HTTP/WS server on port ' + appconfig.port + '...') +wiki.logger.info('Starting HTTP/WS server on port ' + wiki.config.port + '...') -app.set('port', appconfig.port) +app.set('port', wiki.config.port) var server = http.createServer(app) var io = socketio(server) -server.listen(appconfig.port) +server.listen(wiki.config.port) server.on('error', (error) => { if (error.syscall !== 'listen') { throw error @@ -210,10 +208,10 @@ server.on('error', (error) => { // handle specific listen errors with friendly messages switch (error.code) { case 'EACCES': - global.winston.error('Listening on port ' + appconfig.port + ' requires elevated privileges!') + wiki.logger.error('Listening on port ' + wiki.config.port + ' requires elevated privileges!') return process.exit(1) case 'EADDRINUSE': - global.winston.error('Port ' + appconfig.port + ' is already in use!') + wiki.logger.error('Port ' + wiki.config.port + ' is already in use!') return process.exit(1) default: throw error @@ -221,7 +219,7 @@ server.on('error', (error) => { }) server.on('listening', () => { - global.winston.info('HTTP/WS server started successfully! [RUNNING]') + wiki.logger.info('HTTP/WS server started successfully! [RUNNING]') }) // ---------------------------------------- @@ -231,7 +229,7 @@ server.on('listening', () => { io.use(passportSocketIo.authorize({ key: 'wikijs.sid', store: sessionStore, - secret: appconfig.sessionSecret, + secret: wiki.config.sessionSecret, cookieParser, success: (data, accept) => { accept() @@ -247,7 +245,7 @@ io.on('connection', ctrl.ws) // Start child processes // ---------------------------------------- -let bgAgent = fork(path.join(SERVERPATH, 'agent.js')) +let bgAgent = fork(path.join(wiki.SERVERPATH, 'agent.js')) bgAgent.on('message', m => { if (!m.action) { @@ -256,7 +254,7 @@ bgAgent.on('message', m => { switch (m.action) { case 'searchAdd': - global.search.add(m.content) + wiki.search.add(m.content) break } }) @@ -266,11 +264,11 @@ bgAgent.on('message', m => { // ---------------------------------------- graceful.on('exit', () => { - global.winston.info('- SHUTTING DOWN - Terminating Background Agent...') + wiki.logger.info('- SHUTTING DOWN - Terminating Background Agent...') bgAgent.kill() - global.winston.info('- SHUTTING DOWN - Performing git sync...') + wiki.logger.info('- SHUTTING DOWN - Performing git sync...') return global.git.resync().then(() => { - global.winston.info('- SHUTTING DOWN - Git sync successful. Now safe to exit.') + wiki.logger.info('- SHUTTING DOWN - Git sync successful. Now safe to exit.') process.exit() }) }) diff --git a/server/libs/db.js b/server/libs/db.js deleted file mode 100644 index 733d28a2..00000000 --- a/server/libs/db.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict' - -/* global ROOTPATH, appconfig, winston */ - -const modb = require('mongoose') -const fs = require('fs') -const path = require('path') -const _ = require('lodash') - -/** - * MongoDB module - * - * @return {Object} MongoDB wrapper instance - */ -module.exports = { - - /** - * Initialize DB - * - * @return {Object} DB instance - */ - init() { - let self = this - - let dbModelsPath = path.join(SERVERPATH, 'models') - - modb.Promise = require('bluebird') - - // Event handlers - - modb.connection.on('error', err => { - winston.error('Failed to connect to MongoDB instance.') - return err - }) - modb.connection.once('open', function () { - winston.log('Connected to MongoDB instance.') - }) - - // Store connection handle - - self.connection = modb.connection - self.ObjectId = modb.Types.ObjectId - - // Load DB Models - - fs - .readdirSync(dbModelsPath) - .filter(function (file) { - return (file.indexOf('.') !== 0) - }) - .forEach(function (file) { - let modelName = _.upperFirst(_.camelCase(_.split(file, '.')[0])) - self[modelName] = require(path.join(dbModelsPath, file)) - }) - - // Connect - - self.onReady = modb.connect(appconfig.db, { useMongoClient: true }) - - return self - } - -} diff --git a/server/models/_relations.js b/server/models/_relations.js new file mode 100644 index 00000000..1f2f373f --- /dev/null +++ b/server/models/_relations.js @@ -0,0 +1,10 @@ +'use strict' + +/** + * Associate DB Model relations + */ +module.exports = db => { + db.User.belongsToMany(db.Group, { through: 'UserGroups' }) + db.Group.hasMany(db.Right, { as: 'GroupRights' }) + db.File.belongsTo(db.Folder) +} diff --git a/server/models/bruteforce.js b/server/models/bruteforce.js deleted file mode 100644 index 76981fd7..00000000 --- a/server/models/bruteforce.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict' - -const Mongoose = require('mongoose') - -/** - * BruteForce schema - * - * @type {} - */ -var bruteForceSchema = Mongoose.Schema({ - _id: { type: String, index: 1 }, - data: { - count: Number, - lastRequest: Date, - firstRequest: Date - }, - expires: { type: Date, index: { expires: '1d' } } -}) - -module.exports = Mongoose.model('Bruteforce', bruteForceSchema) diff --git a/server/models/document.js b/server/models/document.js new file mode 100644 index 00000000..e742d492 --- /dev/null +++ b/server/models/document.js @@ -0,0 +1,56 @@ +'use strict' + +/** + * Document schema + */ +module.exports = (sequelize, DataTypes) => { + let documentSchema = sequelize.define('setting', { + path: { + type: DataTypes.STRING, + allowNull: false + }, + title: { + type: DataTypes.STRING, + allowNull: false, + validate: { + len: [2, 255] + } + }, + subtitle: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: '' + }, + parentPath: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: '' + }, + parentTitle: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: '' + }, + isDirectory: { + type: DataTypes.BOOLEAN, + allowNull: false, + defaultValue: false + }, + isEntry: { + type: DataTypes.BOOLEAN, + allowNull: false, + defaultValue: false + } + }, { + timestamps: true, + version: true, + indexes: [ + { + unique: true, + fields: ['path'] + } + ] + }) + + return documentSchema +} diff --git a/server/models/entry.js b/server/models/entry.js deleted file mode 100644 index 746d6d28..00000000 --- a/server/models/entry.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict' - -const Mongoose = require('mongoose') - -/** - * Entry schema - * - * @type {} - */ -var entrySchema = Mongoose.Schema({ - _id: String, - - title: { - type: String, - required: true, - minlength: 2 - }, - subtitle: { - type: String, - default: '' - }, - parentTitle: { - type: String, - default: '' - }, - parentPath: { - type: String, - default: '' - }, - isDirectory: { - type: Boolean, - default: false - }, - isEntry: { - type: Boolean, - default: false - } -}, { - timestamps: {} -}) - -module.exports = Mongoose.model('Entry', entrySchema) diff --git a/server/models/file.js b/server/models/file.js new file mode 100644 index 00000000..9dea525b --- /dev/null +++ b/server/models/file.js @@ -0,0 +1,44 @@ +'use strict' + +/** + * File schema + */ +module.exports = (sequelize, DataTypes) => { + let fileSchema = sequelize.define('file', { + category: { + type: DataTypes.ENUM('binary', 'image'), + allowNull: false, + defaultValue: 'binary' + }, + mime: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: 'application/octet-stream' + }, + extra: { + type: DataTypes.JSONB, + allowNull: true + }, + filename: { + type: DataTypes.STRING, + allowNull: false + }, + basename: { + type: DataTypes.STRING, + allowNull: false + }, + filesize: { + type: DataTypes.INTEGER, + allowNull: false, + validate: { + isInt: true, + min: 0 + } + } + }, { + timestamps: true, + version: true + }) + + return fileSchema +} diff --git a/server/models/folder.js b/server/models/folder.js new file mode 100644 index 00000000..ea873100 --- /dev/null +++ b/server/models/folder.js @@ -0,0 +1,24 @@ +'use strict' + +/** + * Folder schema + */ +module.exports = (sequelize, DataTypes) => { + let folderSchema = sequelize.define('folder', { + name: { + type: DataTypes.STRING, + allowNull: false + } + }, { + timestamps: true, + version: true, + indexes: [ + { + unique: true, + fields: ['name'] + } + ] + }) + + return folderSchema +} diff --git a/server/models/group.js b/server/models/group.js new file mode 100644 index 00000000..436d845b --- /dev/null +++ b/server/models/group.js @@ -0,0 +1,18 @@ +'use strict' + +/** + * Group schema + */ +module.exports = (sequelize, DataTypes) => { + let groupSchema = sequelize.define('group', { + name: { + type: DataTypes.STRING, + allowNull: false + } + }, { + timestamps: true, + version: true + }) + + return groupSchema +} diff --git a/server/models/right.js b/server/models/right.js new file mode 100644 index 00000000..22306370 --- /dev/null +++ b/server/models/right.js @@ -0,0 +1,38 @@ +'use strict' + +/** + * Right schema + */ +module.exports = (sequelize, DataTypes) => { + let rightSchema = sequelize.define('right', { + path: { + type: DataTypes.STRING, + allowNull: false + }, + role: { + type: DataTypes.ENUM('read', 'write', 'manage'), + allowNull: false, + defaultValue: 'read' + }, + exact: { + type: DataTypes.BOOLEAN, + allowNull: false, + defaultValue: false + }, + allow: { + type: DataTypes.BOOLEAN, + allowNull: false, + defaultValue: false + } + }, { + timestamps: true, + version: true, + indexes: [ + { + fields: ['path'] + } + ] + }) + + return rightSchema +} diff --git a/server/models/setting.js b/server/models/setting.js index 73686af2..28cef993 100644 --- a/server/models/setting.js +++ b/server/models/setting.js @@ -1,22 +1,28 @@ 'use strict' -const Mongoose = require('mongoose') - /** * Settings schema - * - * @type {} */ -var settingSchema = Mongoose.Schema({ - key: { - type: String, - required: true, - index: true - }, - value: { - type: String, - required: true - } -}, { timestamps: {} }) +module.exports = (sequelize, DataTypes) => { + let settingSchema = sequelize.define('setting', { + key: { + type: DataTypes.STRING, + allowNull: false + }, + config: { + type: DataTypes.JSONB, + allowNull: false + } + }, { + timestamps: true, + version: true, + indexes: [ + { + unique: true, + fields: ['key'] + } + ] + }) -module.exports = Mongoose.model('Setting', settingSchema) + return settingSchema +} diff --git a/server/models/upl-file.js b/server/models/upl-file.js deleted file mode 100644 index a48602bb..00000000 --- a/server/models/upl-file.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict' - -const Mongoose = require('mongoose') - -/** - * Upload File schema - * - * @type {} - */ -var uplFileSchema = Mongoose.Schema({ - - _id: String, - - category: { - type: String, - required: true, - default: 'binary' - }, - mime: { - type: String, - required: true, - default: 'application/octet-stream' - }, - extra: { - type: Object - }, - folder: { - type: String, - ref: 'UplFolder' - }, - filename: { - type: String, - required: true - }, - basename: { - type: String, - required: true - }, - filesize: { - type: Number, - required: true - } - -}, { timestamps: {} }) - -module.exports = Mongoose.model('UplFile', uplFileSchema) diff --git a/server/models/upl-folder.js b/server/models/upl-folder.js deleted file mode 100644 index 80028b6f..00000000 --- a/server/models/upl-folder.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict' - -const Mongoose = require('mongoose') - -/** - * Upload Folder schema - * - * @type {} - */ -var uplFolderSchema = Mongoose.Schema({ - - _id: String, - - name: { - type: String, - index: true - } - -}, { timestamps: {} }) - -module.exports = Mongoose.model('UplFolder', uplFolderSchema) diff --git a/server/models/user.js b/server/models/user.js index be3ab360..1a9bc05e 100644 --- a/server/models/user.js +++ b/server/models/user.js @@ -1,109 +1,113 @@ 'use strict' -/* global db, lang */ +/* global wiki */ -const Mongoose = require('mongoose') const Promise = require('bluebird') const bcrypt = require('bcryptjs-then') const _ = require('lodash') /** * Users schema - * - * @type {} */ -var userSchema = Mongoose.Schema({ - - email: { - type: String, - required: true, - index: true - }, - - provider: { - type: String, - required: true - }, - - providerId: { - type: String - }, - - password: { - type: String - }, - - name: { - type: String - }, - - rights: [{ - role: String, - path: String, - exact: Boolean, - deny: Boolean - }] - -}, { timestamps: {} }) +module.exports = (sequelize, DataTypes) => { + let userSchema = sequelize.define('user', { + email: { + type: DataTypes.STRING, + allowNull: false, + validate: { + isEmail: true + } + }, + provider: { + type: DataTypes.ENUM(wiki.data.authProviders), + allowNull: false + }, + providerId: { + type: DataTypes.STRING, + allowNull: true + }, + password: { + type: DataTypes.STRING, + allowNull: true + }, + name: { + type: DataTypes.STRING, + allowNull: true + }, + role: { + type: DataTypes.ENUM('admin', 'user', 'guest'), + allowNull: false + } + }, { + timestamps: true, + version: true, + indexes: [ + { + unique: true, + fields: ['provider', 'email'] + } + ] + }) -userSchema.statics.processProfile = (profile) => { - let primaryEmail = '' - if (_.isArray(profile.emails)) { - let e = _.find(profile.emails, ['primary', true]) - primaryEmail = (e) ? e.value : _.first(profile.emails).value - } else if (_.isString(profile.email) && profile.email.length > 5) { - primaryEmail = profile.email - } else if (_.isString(profile.mail) && profile.mail.length > 5) { - primaryEmail = profile.mail - } else if (profile.user && profile.user.email && profile.user.email.length > 5) { - primaryEmail = profile.user.email - } else { - return Promise.reject(new Error(lang.t('auth:errors.invaliduseremail'))) + userSchema.prototype.validatePassword = function (rawPwd) { + return bcrypt.compare(rawPwd, this.password).then((isValid) => { + return (isValid) ? true : Promise.reject(new Error(wiki.lang.t('auth:errors:invalidlogin'))) + }) } - profile.provider = _.lowerCase(profile.provider) - primaryEmail = _.toLower(primaryEmail) + userSchema.processProfile = (profile) => { + let primaryEmail = '' + if (_.isArray(profile.emails)) { + let e = _.find(profile.emails, ['primary', true]) + primaryEmail = (e) ? e.value : _.first(profile.emails).value + } else if (_.isString(profile.email) && profile.email.length > 5) { + primaryEmail = profile.email + } else if (_.isString(profile.mail) && profile.mail.length > 5) { + primaryEmail = profile.mail + } else if (profile.user && profile.user.email && profile.user.email.length > 5) { + primaryEmail = profile.user.email + } else { + return Promise.reject(new Error(wiki.lang.t('auth:errors.invaliduseremail'))) + } - return db.User.findOneAndUpdate({ - email: primaryEmail, - provider: profile.provider - }, { - email: primaryEmail, - provider: profile.provider, - providerId: profile.id, - name: profile.displayName || _.split(primaryEmail, '@')[0] - }, { - new: true - }).then((user) => { - // Handle unregistered accounts - if (!user && profile.provider !== 'local' && (appconfig.auth.defaultReadAccess || profile.provider === 'ldap' || profile.provider === 'azure')) { - let nUsr = { - email: primaryEmail, - provider: profile.provider, - providerId: profile.id, - password: '', - name: profile.displayName || profile.name || profile.cn, - rights: [{ - role: 'read', - path: '/', - exact: false, - deny: false - }] + profile.provider = _.lowerCase(profile.provider) + primaryEmail = _.toLower(primaryEmail) + + return wiki.db.User.findOneAndUpdate({ + email: primaryEmail, + provider: profile.provider + }, { + email: primaryEmail, + provider: profile.provider, + providerId: profile.id, + name: profile.displayName || _.split(primaryEmail, '@')[0] + }, { + new: true + }).then((user) => { + // Handle unregistered accounts + if (!user && profile.provider !== 'local' && (appconfig.auth.defaultReadAccess || profile.provider === 'ldap' || profile.provider === 'azure')) { + let nUsr = { + email: primaryEmail, + provider: profile.provider, + providerId: profile.id, + password: '', + name: profile.displayName || profile.name || profile.cn, + rights: [{ + role: 'read', + path: '/', + exact: false, + deny: false + }] + } + return db.User.create(nUsr) } - return db.User.create(nUsr) - } - return user || Promise.reject(new Error(lang.t('auth:errors:notyetauthorized'))) - }) -} + return user || Promise.reject(new Error(wiki.lang.t('auth:errors:notyetauthorized'))) + }) + } -userSchema.statics.hashPassword = (rawPwd) => { - return bcrypt.hash(rawPwd) -} + userSchema.hashPassword = (rawPwd) => { + return bcrypt.hash(rawPwd) + } -userSchema.methods.validatePassword = function (rawPwd) { - return bcrypt.compare(rawPwd, this.password).then((isValid) => { - return (isValid) ? true : Promise.reject(new Error(lang.t('auth:errors:invalidlogin'))) - }) + return userSchema } - -module.exports = Mongoose.model('User', userSchema) diff --git a/server/libs/auth.js b/server/modules/auth.js similarity index 58% rename from server/libs/auth.js rename to server/modules/auth.js index 34271ccc..2b0a408d 100644 --- a/server/libs/auth.js +++ b/server/modules/auth.js @@ -1,6 +1,6 @@ 'use strict' -/* global appconfig, appdata, db, lang, winston */ +/* global wiki */ const fs = require('fs') @@ -12,11 +12,11 @@ module.exports = function (passport) { }) passport.deserializeUser(function (id, done) { - db.User.findById(id).then((user) => { + wiki.db.User.findById(id).then((user) => { if (user) { done(null, user) } else { - done(new Error(lang.t('auth:errors:usernotfound')), null) + done(new Error(wiki.lang.t('auth:errors:usernotfound')), null) } return true }).catch((err) => { @@ -26,14 +26,14 @@ module.exports = function (passport) { // Local Account - if (appconfig.auth.local && appconfig.auth.local.enabled) { + if (wiki.config.auth.local && wiki.config.auth.local.enabled) { const LocalStrategy = require('passport-local').Strategy passport.use('local', new LocalStrategy({ usernameField: 'email', passwordField: 'password' }, (uEmail, uPassword, done) => { - db.User.findOne({ email: uEmail, provider: 'local' }).then((user) => { + wiki.db.User.findOne({ email: uEmail, provider: 'local' }).then((user) => { if (user) { return user.validatePassword(uPassword).then(() => { return done(null, user) || true @@ -52,15 +52,15 @@ module.exports = function (passport) { // Google ID - if (appconfig.auth.google && appconfig.auth.google.enabled) { + if (wiki.config.auth.google && wiki.config.auth.google.enabled) { const GoogleStrategy = require('passport-google-oauth20').Strategy passport.use('google', new GoogleStrategy({ - clientID: appconfig.auth.google.clientId, - clientSecret: appconfig.auth.google.clientSecret, - callbackURL: appconfig.host + '/login/google/callback' + clientID: wiki.config.auth.google.clientId, + clientSecret: wiki.config.auth.google.clientSecret, + callbackURL: wiki.config.host + '/login/google/callback' }, (accessToken, refreshToken, profile, cb) => { - db.User.processProfile(profile).then((user) => { + wiki.db.User.processProfile(profile).then((user) => { return cb(null, user) || true }).catch((err) => { return cb(err, null) || true @@ -71,15 +71,15 @@ module.exports = function (passport) { // Microsoft Accounts - if (appconfig.auth.microsoft && appconfig.auth.microsoft.enabled) { + if (wiki.config.auth.microsoft && wiki.config.auth.microsoft.enabled) { const WindowsLiveStrategy = require('passport-windowslive').Strategy passport.use('windowslive', new WindowsLiveStrategy({ - clientID: appconfig.auth.microsoft.clientId, - clientSecret: appconfig.auth.microsoft.clientSecret, - callbackURL: appconfig.host + '/login/ms/callback' + clientID: wiki.config.auth.microsoft.clientId, + clientSecret: wiki.config.auth.microsoft.clientSecret, + callbackURL: wiki.config.host + '/login/ms/callback' }, function (accessToken, refreshToken, profile, cb) { - db.User.processProfile(profile).then((user) => { + wiki.db.User.processProfile(profile).then((user) => { return cb(null, user) || true }).catch((err) => { return cb(err, null) || true @@ -90,16 +90,16 @@ module.exports = function (passport) { // Facebook - if (appconfig.auth.facebook && appconfig.auth.facebook.enabled) { + if (wiki.config.auth.facebook && wiki.config.auth.facebook.enabled) { const FacebookStrategy = require('passport-facebook').Strategy passport.use('facebook', new FacebookStrategy({ - clientID: appconfig.auth.facebook.clientId, - clientSecret: appconfig.auth.facebook.clientSecret, - callbackURL: appconfig.host + '/login/facebook/callback', + clientID: wiki.config.auth.facebook.clientId, + clientSecret: wiki.config.auth.facebook.clientSecret, + callbackURL: wiki.config.host + '/login/facebook/callback', profileFields: ['id', 'displayName', 'email'] }, function (accessToken, refreshToken, profile, cb) { - db.User.processProfile(profile).then((user) => { + wiki.db.User.processProfile(profile).then((user) => { return cb(null, user) || true }).catch((err) => { return cb(err, null) || true @@ -110,16 +110,16 @@ module.exports = function (passport) { // GitHub - if (appconfig.auth.github && appconfig.auth.github.enabled) { + if (wiki.config.auth.github && wiki.config.auth.github.enabled) { const GitHubStrategy = require('passport-github2').Strategy passport.use('github', new GitHubStrategy({ - clientID: appconfig.auth.github.clientId, - clientSecret: appconfig.auth.github.clientSecret, - callbackURL: appconfig.host + '/login/github/callback', + clientID: wiki.config.auth.github.clientId, + clientSecret: wiki.config.auth.github.clientSecret, + callbackURL: wiki.config.host + '/login/github/callback', scope: ['user:email'] }, (accessToken, refreshToken, profile, cb) => { - db.User.processProfile(profile).then((user) => { + wiki.db.User.processProfile(profile).then((user) => { return cb(null, user) || true }).catch((err) => { return cb(err, null) || true @@ -130,15 +130,15 @@ module.exports = function (passport) { // Slack - if (appconfig.auth.slack && appconfig.auth.slack.enabled) { + if (wiki.config.auth.slack && wiki.config.auth.slack.enabled) { const SlackStrategy = require('passport-slack').Strategy passport.use('slack', new SlackStrategy({ - clientID: appconfig.auth.slack.clientId, - clientSecret: appconfig.auth.slack.clientSecret, - callbackURL: appconfig.host + '/login/slack/callback' + clientID: wiki.config.auth.slack.clientId, + clientSecret: wiki.config.auth.slack.clientSecret, + callbackURL: wiki.config.host + '/login/slack/callback' }, (accessToken, refreshToken, profile, cb) => { - db.User.processProfile(profile).then((user) => { + wiki.db.User.processProfile(profile).then((user) => { return cb(null, user) || true }).catch((err) => { return cb(err, null) || true @@ -149,20 +149,20 @@ module.exports = function (passport) { // LDAP - if (appconfig.auth.ldap && appconfig.auth.ldap.enabled) { + if (wiki.config.auth.ldap && wiki.config.auth.ldap.enabled) { const LdapStrategy = require('passport-ldapauth').Strategy passport.use('ldapauth', new LdapStrategy({ server: { - url: appconfig.auth.ldap.url, - bindDn: appconfig.auth.ldap.bindDn, - bindCredentials: appconfig.auth.ldap.bindCredentials, - searchBase: appconfig.auth.ldap.searchBase, - searchFilter: appconfig.auth.ldap.searchFilter, + url: wiki.config.auth.ldap.url, + bindDn: wiki.config.auth.ldap.bindDn, + bindCredentials: wiki.config.auth.ldap.bindCredentials, + searchBase: wiki.config.auth.ldap.searchBase, + searchFilter: wiki.config.auth.ldap.searchFilter, searchAttributes: ['displayName', 'name', 'cn', 'mail'], - tlsOptions: (appconfig.auth.ldap.tlsEnabled) ? { + tlsOptions: (wiki.config.auth.ldap.tlsEnabled) ? { ca: [ - fs.readFileSync(appconfig.auth.ldap.tlsCertPath) + fs.readFileSync(wiki.config.auth.ldap.tlsCertPath) ] } : {} }, @@ -171,7 +171,7 @@ module.exports = function (passport) { }, (profile, cb) => { profile.provider = 'ldap' profile.id = profile.dn - db.User.processProfile(profile).then((user) => { + wiki.db.User.processProfile(profile).then((user) => { return cb(null, user) || true }).catch((err) => { return cb(err, null) || true @@ -182,21 +182,21 @@ module.exports = function (passport) { // AZURE AD - if (appconfig.auth.azure && appconfig.auth.azure.enabled) { + if (wiki.config.auth.azure && wiki.config.auth.azure.enabled) { const AzureAdOAuth2Strategy = require('passport-azure-ad-oauth2').Strategy const jwt = require('jsonwebtoken') passport.use('azure_ad_oauth2', new AzureAdOAuth2Strategy({ - clientID: appconfig.auth.azure.clientId, - clientSecret: appconfig.auth.azure.clientSecret, - callbackURL: appconfig.host + '/login/azure/callback', - resource: appconfig.auth.azure.resource, - tenant: appconfig.auth.azure.tenant + clientID: wiki.config.auth.azure.clientId, + clientSecret: wiki.config.auth.azure.clientSecret, + callbackURL: wiki.config.host + '/login/azure/callback', + resource: wiki.config.auth.azure.resource, + tenant: wiki.config.auth.azure.tenant }, (accessToken, refreshToken, params, profile, cb) => { let waadProfile = jwt.decode(params.id_token) waadProfile.id = waadProfile.oid waadProfile.provider = 'azure' - db.User.processProfile(waadProfile).then((user) => { + wiki.db.User.processProfile(waadProfile).then((user) => { return cb(null, user) || true }).catch((err) => { return cb(err, null) || true @@ -207,12 +207,12 @@ module.exports = function (passport) { // Create users for first-time - db.onReady.then(() => { - return db.User.findOne({ provider: 'local', email: 'guest' }).then((c) => { + wiki.db.onReady.then(() => { + return wiki.db.User.findOne({ provider: 'local', email: 'guest' }).then((c) => { if (c < 1) { // Create guest account - return db.User.create({ + return wiki.db.User.create({ provider: 'local', email: 'guest', name: 'Guest', @@ -221,22 +221,22 @@ module.exports = function (passport) { role: 'read', path: '/', exact: false, - deny: !appconfig.public + deny: !wiki.config.public }] }).then(() => { - winston.info('[AUTH] Guest account created successfully!') + wiki.logger.info('[AUTH] Guest account created successfully!') }).catch((err) => { - winston.error('[AUTH] An error occured while creating guest account:') - winston.error(err) + wiki.logger.error('[AUTH] An error occured while creating guest account:') + wiki.logger.error(err) }) } }).then(() => { if (process.env.WIKI_JS_HEROKU) { - return db.User.findOne({ provider: 'local', email: process.env.WIKI_ADMIN_EMAIL }).then((c) => { + return wiki.db.User.findOne({ provider: 'local', email: process.env.WIKI_ADMIN_EMAIL }).then((c) => { if (c < 1) { // Create root admin account (HEROKU ONLY) - return db.User.create({ + return wiki.db.User.create({ provider: 'local', email: process.env.WIKI_ADMIN_EMAIL, name: 'Administrator', @@ -248,10 +248,10 @@ module.exports = function (passport) { deny: false }] }).then(() => { - winston.info('[AUTH] Root admin account created successfully!') + wiki.logger.info('[AUTH] Root admin account created successfully!') }).catch((err) => { - winston.error('[AUTH] An error occured while creating root admin account:') - winston.error(err) + wiki.logger.error('[AUTH] An error occured while creating root admin account:') + wiki.logger.error(err) }) } else { return true } }) diff --git a/server/libs/config.js b/server/modules/config.js similarity index 89% rename from server/libs/config.js rename to server/modules/config.js index 92eac339..4c120338 100644 --- a/server/libs/config.js +++ b/server/modules/config.js @@ -1,5 +1,7 @@ 'use strict' +/* global wiki */ + const fs = require('fs') const yaml = require('js-yaml') const _ = require('lodash') @@ -14,9 +16,9 @@ const cfgHelper = require('../helpers/config') */ module.exports = (confPaths) => { confPaths = _.defaults(confPaths, { - config: path.join(ROOTPATH, 'config.yml'), - data: path.join(SERVERPATH, 'app/data.yml'), - dataRegex: path.join(SERVERPATH, 'app/regex.js') + config: path.join(wiki.ROOTPATH, 'config.yml'), + data: path.join(wiki.SERVERPATH, 'app/data.yml'), + dataRegex: path.join(wiki.SERVERPATH, 'app/regex.js') }) let appconfig = {} diff --git a/server/modules/db.js b/server/modules/db.js new file mode 100644 index 00000000..42e83eb3 --- /dev/null +++ b/server/modules/db.js @@ -0,0 +1,74 @@ +'use strict' + +/* global wiki */ + +const fs = require('fs') +const path = require('path') +const _ = require('lodash') + +/** + * PostgreSQL DB module + */ +module.exports = { + + Sequelize: require('sequelize'), + + /** + * Initialize DB + * + * @return {Object} DB instance + */ + init() { + let self = this + + let dbModelsPath = path.join(wiki.SERVERPATH, 'models') + + // Define Sequelize instance + + self.inst = new self.Sequelize(wiki.config.db.db, wiki.config.db.user, wiki.config.db.pass, { + host: wiki.config.db.host, + port: wiki.config.db.port, + dialect: 'postgres', + pool: { + max: 10, + min: 0, + idle: 10000 + } + }) + + // Attempt to connect and authenticate to DB + + self.inst.authenticate().then(() => { + wiki.logger.info('Connected to PostgreSQL database.') + }).catch(err => { + wiki.logger.error('Failed to connect to MongoDB instance.') + return err + }) + + // Load DB Models + + fs + .readdirSync(dbModelsPath) + .filter(function (file) { + return (file.indexOf('.') !== 0 && file.indexOf('_') !== 0) + }) + .forEach(function (file) { + let modelName = _.upperFirst(_.camelCase(_.split(file, '.')[0])) + self[modelName] = self.inst.import(path.join(dbModelsPath, file)) + }) + + // Associate DB Models + + require(path.join(dbModelsPath, '_relations.js'))(self) + + // Sync DB + + self.onReady = self.inst.sync({ + force: false, + logging: wiki.logger.verbose + }) + + return self + } + +} diff --git a/server/libs/local.js b/server/modules/disk.js similarity index 59% rename from server/libs/local.js rename to server/modules/disk.js index 3053e63b..9e919229 100644 --- a/server/libs/local.js +++ b/server/modules/disk.js @@ -1,6 +1,6 @@ 'use strict' -/* global lang, winston */ +/* global wiki */ const path = require('path') const Promise = require('bluebird') @@ -10,7 +10,7 @@ const os = require('os') const _ = require('lodash') /** - * Local Data Storage + * Local Disk Storage */ module.exports = { @@ -21,29 +21,24 @@ module.exports = { /** * Initialize Local Data Storage model - * - * @return {Object} Local Data Storage model instance */ init () { - this._uploadsPath = path.resolve(ROOTPATH, appconfig.paths.repo, 'uploads') - this._uploadsThumbsPath = path.resolve(ROOTPATH, appconfig.paths.data, 'thumbs') + this._uploadsPath = path.resolve(wiki.ROOTPATH, wiki.config.paths.repo, 'uploads') + this._uploadsThumbsPath = path.resolve(wiki.ROOTPATH, wiki.config.paths.data, 'thumbs') - this.createBaseDirectories(appconfig) - this.initMulter(appconfig) + this.createBaseDirectories() + this.initMulter() return this }, /** * Init Multer upload handlers - * - * @param {Object} appconfig The application config - * @return {boolean} Void */ - initMulter (appconfig) { + initMulter () { let maxFileSizes = { - img: appconfig.uploads.maxImageFileSize * 1024 * 1024, - file: appconfig.uploads.maxOtherFileSize * 1024 * 1024 + img: wiki.config.uploads.maxImageFileSize * 1024 * 1024, + file: wiki.config.uploads.maxOtherFileSize * 1024 * 1024 } // -> IMAGES @@ -51,7 +46,7 @@ module.exports = { this.uploadImgHandler = multer({ storage: multer.diskStorage({ destination: (req, f, cb) => { - cb(null, path.resolve(ROOTPATH, appconfig.paths.data, 'temp-upload')) + cb(null, path.resolve(wiki.ROOTPATH, wiki.config.paths.data, 'temp-upload')) } }), fileFilter: (req, f, cb) => { @@ -76,7 +71,7 @@ module.exports = { this.uploadFileHandler = multer({ storage: multer.diskStorage({ destination: (req, f, cb) => { - cb(null, path.resolve(ROOTPATH, appconfig.paths.data, 'temp-upload')) + cb(null, path.resolve(wiki.ROOTPATH, wiki.config.paths.data, 'temp-upload')) } }), fileFilter: (req, f, cb) => { @@ -95,35 +90,32 @@ module.exports = { /** * Creates a base directories (Synchronous). - * - * @param {Object} appconfig The application config - * @return {Void} Void */ - createBaseDirectories (appconfig) { - winston.info('Checking data directories...') + createBaseDirectories () { + wiki.logger.info('Checking data directories...') try { - fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.data)) - fs.emptyDirSync(path.resolve(ROOTPATH, appconfig.paths.data)) - fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.data, './cache')) - fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.data, './thumbs')) - fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.data, './temp-upload')) + fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data)) + fs.emptyDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data)) + fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data, './cache')) + fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data, './thumbs')) + fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data, './temp-upload')) if (os.type() !== 'Windows_NT') { - fs.chmodSync(path.resolve(ROOTPATH, appconfig.paths.data, './temp-upload'), '755') + fs.chmodSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data, './temp-upload'), '755') } - fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.repo)) - fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.repo, './uploads')) + fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.repo)) + fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.repo, './uploads')) if (os.type() !== 'Windows_NT') { - fs.chmodSync(path.resolve(ROOTPATH, appconfig.paths.repo, './uploads'), '755') + fs.chmodSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.repo, './uploads'), '755') } } catch (err) { - winston.error(err) + wiki.logger.error(err) } - winston.info('Data and Repository directories are OK.') + wiki.logger.info('Data and Repository directories are OK.') }, /** @@ -154,7 +146,7 @@ module.exports = { */ validateUploadsFilename (f, fld, isImage) { let fObj = path.parse(f) - let fname = _.chain(fObj.name).trim().toLower().kebabCase().value().replace(new RegExp('[^a-z0-9-' + appdata.regex.cjk + appdata.regex.arabic + ']', 'g'), '') + let fname = _.chain(fObj.name).trim().toLower().kebabCase().value().replace(new RegExp('[^a-z0-9-' + wiki.data.regex.cjk + wiki.data.regex.arabic + ']', 'g'), '') let fext = _.toLower(fObj.ext) if (isImage && !_.includes(['.jpg', '.jpeg', '.png', '.gif', '.webp'], fext)) { @@ -165,7 +157,7 @@ module.exports = { let fpath = path.resolve(this._uploadsPath, fld, f) return fs.statAsync(fpath).then((s) => { - throw new Error(lang.t('errors:fileexists', { path: f })) + throw new Error(wiki.lang.t('errors:fileexists', { path: f })) }).catch((err) => { if (err.code === 'ENOENT') { return f diff --git a/server/libs/entries.js b/server/modules/entries.js similarity index 97% rename from server/libs/entries.js rename to server/modules/entries.js index a5e7b830..802d0d6d 100644 --- a/server/libs/entries.js +++ b/server/modules/entries.js @@ -1,6 +1,6 @@ 'use strict' -/* global db, git, lang, mark, rights, search, winston */ +/* global wiki */ const Promise = require('bluebird') const path = require('path') @@ -25,10 +25,10 @@ module.exports = { init() { let self = this - self._repoPath = path.resolve(ROOTPATH, appconfig.paths.repo) - self._cachePath = path.resolve(ROOTPATH, appconfig.paths.data, 'cache') - appdata.repoPath = self._repoPath - appdata.cachePath = self._cachePath + self._repoPath = path.resolve(wiki.ROOTPATH, wiki.config.paths.repo) + self._cachePath = path.resolve(wiki.ROOTPATH, wiki.config.paths.data, 'cache') + wiki.data.repoPath = self._repoPath + wiki.data.cachePath = self._cachePath return self }, diff --git a/server/libs/git.js b/server/modules/git.js similarity index 78% rename from server/libs/git.js rename to server/modules/git.js index 2f86fbb2..b0155ce9 100644 --- a/server/libs/git.js +++ b/server/modules/git.js @@ -1,6 +1,6 @@ 'use strict' -/* global lang, winston */ +/* global wiki */ const Git = require('git-wrapper2-promise') const Promise = require('bluebird') @@ -43,20 +43,20 @@ module.exports = { // -> Build repository path - if (_.isEmpty(appconfig.paths.repo)) { - self._repo.path = path.join(ROOTPATH, 'repo') + if (_.isEmpty(wiki.config.paths.repo)) { + self._repo.path = path.join(wiki.ROOTPATH, 'repo') } else { - self._repo.path = appconfig.paths.repo + self._repo.path = wiki.config.paths.repo } // -> Initialize repository - self.onReady = self._initRepo(appconfig) + self.onReady = self._initRepo() // Define signature - if (appconfig.git) { - self._signature.email = appconfig.git.serverEmail || 'wiki@example.com' + if (wiki.config.git) { + self._signature.email = wiki.config.git.serverEmail || 'wiki@example.com' } return self @@ -65,19 +65,19 @@ module.exports = { /** * Initialize Git repository * - * @param {Object} appconfig The application config + * @param {Object} wiki.config The application config * @return {Object} Promise */ - _initRepo(appconfig) { + _initRepo() { let self = this - winston.info('Checking Git repository...') + wiki.logger.info('Checking Git repository...') // -> Check if path is accessible return fs.mkdirAsync(self._repo.path).catch((err) => { if (err.code !== 'EEXIST') { - winston.error('Invalid Git repository path or missing permissions.') + wiki.logger.error('Invalid Git repository path or missing permissions.') } }).then(() => { self._git = new Git({ 'git-dir': self._repo.path }) @@ -91,28 +91,28 @@ module.exports = { self._repo.exists = false }) }).then(() => { - if (appconfig.git === false) { - winston.info('Remote Git syncing is disabled. Not recommended!') + if (wiki.config.git === false) { + wiki.logger.info('Remote Git syncing is disabled. Not recommended!') return Promise.resolve(true) } // Initialize remote - let urlObj = URL.parse(appconfig.git.url) - if (appconfig.git.auth.type !== 'ssh') { - urlObj.auth = appconfig.git.auth.username + ':' + appconfig.git.auth.password + let urlObj = URL.parse(wiki.config.git.url) + if (wiki.config.git.auth.type !== 'ssh') { + urlObj.auth = wiki.config.git.auth.username + ':' + wiki.config.git.auth.password } self._url = URL.format(urlObj) let gitConfigs = [ () => { return self._git.exec('config', ['--local', 'user.name', 'Wiki']) }, () => { return self._git.exec('config', ['--local', 'user.email', self._signature.email]) }, - () => { return self._git.exec('config', ['--local', '--bool', 'http.sslVerify', _.toString(appconfig.git.auth.sslVerify)]) } + () => { return self._git.exec('config', ['--local', '--bool', 'http.sslVerify', _.toString(wiki.config.git.auth.sslVerify)]) } ] - if (appconfig.git.auth.type === 'ssh') { + if (wiki.config.git.auth.type === 'ssh') { gitConfigs.push(() => { - return self._git.exec('config', ['--local', 'core.sshCommand', 'ssh -i "' + appconfig.git.auth.privateKey + '" -o StrictHostKeyChecking=no']) + return self._git.exec('config', ['--local', 'core.sshCommand', 'ssh -i "' + wiki.config.git.auth.privateKey + '" -o StrictHostKeyChecking=no']) }) } @@ -125,14 +125,14 @@ module.exports = { return self._git.exec('remote', ['set-url', 'origin', self._url]) } }).catch(err => { - winston.error(err) + wiki.logger.error(err) }) }) }).catch((err) => { - winston.error('Git remote error!') + wiki.logger.error('Git remote error!') throw err }).then(() => { - winston.info('Git repository is OK.') + wiki.logger.info('Git repository is OK.') return true }) }, @@ -143,7 +143,7 @@ module.exports = { * @return {String} The repo path. */ getRepoPath() { - return this._repo.path || path.join(ROOTPATH, 'repo') + return this._repo.path || path.join(wiki.ROOTPATH, 'repo') }, /** @@ -156,18 +156,18 @@ module.exports = { // Is git remote disabled? - if (appconfig.git === false) { + if (wiki.config.git === false) { return Promise.resolve(true) } // Fetch - winston.info('Performing pull from remote Git repository...') + wiki.logger.info('Performing pull from remote Git repository...') return self._git.pull('origin', self._repo.branch).then((cProc) => { - winston.info('Git Pull completed.') + wiki.logger.info('Git Pull completed.') }) .catch((err) => { - winston.error('Unable to fetch from git origin!') + wiki.logger.error('Unable to fetch from git origin!') throw err }) .then(() => { @@ -177,19 +177,19 @@ module.exports = { let out = cProc.stdout.toString() if (_.includes(out, 'commit')) { - winston.info('Performing push to remote Git repository...') + wiki.logger.info('Performing push to remote Git repository...') return self._git.push('origin', self._repo.branch).then(() => { - return winston.info('Git Push completed.') + return wiki.logger.info('Git Push completed.') }) } else { - winston.info('Git Push skipped. Repository is already in sync.') + wiki.logger.info('Git Push skipped. Repository is already in sync.') } return true }) }) .catch((err) => { - winston.error('Unable to push changes to remote Git repository!') + wiki.logger.error('Unable to push changes to remote Git repository!') throw err }) }, @@ -209,7 +209,7 @@ module.exports = { let out = cProc.stdout.toString() return _.includes(out, gitFilePath) }).then((isTracked) => { - commitMsg = (isTracked) ? lang.t('git:updated', { path: gitFilePath }) : lang.t('git:added', { path: gitFilePath }) + commitMsg = (isTracked) ? wiki.lang.t('git:updated', { path: gitFilePath }) : wiki.lang.t('git:added', { path: gitFilePath }) return self._git.add(gitFilePath) }).then(() => { let commitUsr = securityHelper.sanitizeCommitUser(author) diff --git a/server/libs/logger.js b/server/modules/logger.js similarity index 62% rename from server/libs/logger.js rename to server/modules/logger.js index 4a6f7884..d45a3ec4 100644 --- a/server/libs/logger.js +++ b/server/modules/logger.js @@ -1,6 +1,8 @@ 'use strict' -module.exports = (isDebug, processName) => { +/* global wiki */ + +module.exports = (processName) => { let winston = require('winston') if (typeof processName === 'undefined') { @@ -10,10 +12,10 @@ module.exports = (isDebug, processName) => { // Console let logger = new (winston.Logger)({ - level: (isDebug) ? 'debug' : 'info', + level: (wiki.IS_DEBUG) ? 'debug' : 'info', transports: [ new (winston.transports.Console)({ - level: (isDebug) ? 'debug' : 'info', + level: (wiki.IS_DEBUG) ? 'debug' : 'info', prettyPrint: true, colorize: true, silent: false, @@ -28,48 +30,48 @@ module.exports = (isDebug, processName) => { // External services - if (appconfig.externalLogging.bugsnag) { + if (wiki.config.externalLogging.bugsnag) { const bugsnagTransport = require('./winston-transports/bugsnag') logger.add(bugsnagTransport, { level: 'warn', - key: appconfig.externalLogging.bugsnag + key: wiki.config.externalLogging.bugsnag }) } - if (appconfig.externalLogging.loggly) { + if (wiki.config.externalLogging.loggly) { require('winston-loggly-bulk') logger.add(winston.transports.Loggly, { - token: appconfig.externalLogging.loggly.token, - subdomain: appconfig.externalLogging.loggly.subdomain, + token: wiki.config.externalLogging.loggly.token, + subdomain: wiki.config.externalLogging.loggly.subdomain, tags: ['wiki-js'], level: 'warn', json: true }) } - if (appconfig.externalLogging.papertrail) { + if (wiki.config.externalLogging.papertrail) { require('winston-papertrail').Papertrail // eslint-disable-line no-unused-expressions logger.add(winston.transports.Papertrail, { - host: appconfig.externalLogging.papertrail.host, - port: appconfig.externalLogging.papertrail.port, + host: wiki.config.externalLogging.papertrail.host, + port: wiki.config.externalLogging.papertrail.port, level: 'warn', program: 'wiki.js' }) } - if (appconfig.externalLogging.rollbar) { + if (wiki.config.externalLogging.rollbar) { const rollbarTransport = require('./winston-transports/rollbar') logger.add(rollbarTransport, { level: 'warn', - key: appconfig.externalLogging.rollbar + key: wiki.config.externalLogging.rollbar }) } - if (appconfig.externalLogging.sentry) { + if (wiki.config.externalLogging.sentry) { const sentryTransport = require('./winston-transports/sentry') logger.add(sentryTransport, { level: 'warn', - key: appconfig.externalLogging.sentry + key: wiki.config.externalLogging.sentry }) } diff --git a/server/libs/markdown.js b/server/modules/markdown.js similarity index 96% rename from server/libs/markdown.js rename to server/modules/markdown.js index 14b0c887..c88266d7 100644 --- a/server/libs/markdown.js +++ b/server/modules/markdown.js @@ -1,6 +1,6 @@ 'use strict' -/* global winston */ +/* global wiki */ const Promise = require('bluebird') const md = require('markdown-it') @@ -23,11 +23,11 @@ const mdRemove = require('remove-markdown') var mkdown = md({ html: true, - breaks: appconfig.features.linebreaks, + breaks: wiki.config.features.linebreaks, linkify: true, typography: true, highlight(str, lang) { - if (appconfig.theme.code.colorize && lang && hljs.getLanguage(lang)) { + if (wiki.config.theme.code.colorize && lang && hljs.getLanguage(lang)) { try { return '
' + hljs.highlight(lang, str, true).value + '
' } catch (err) { @@ -57,7 +57,7 @@ var mkdown = md({ }) .use(mdAttrs) -if (appconfig.features.mathjax) { +if (wiki.config.features.mathjax) { mkdown.use(mdMathjax) } @@ -94,7 +94,7 @@ const videoRules = [ // Regex -const textRegex = new RegExp('\\b[a-z0-9-.,' + appdata.regex.cjk + appdata.regex.arabic + ']+\\b', 'g') +const textRegex = new RegExp('\\b[a-z0-9-.,' + wiki.data.regex.cjk + wiki.data.regex.arabic + ']+\\b', 'g') const mathRegex = [ { format: 'TeX', @@ -301,7 +301,7 @@ const parseContent = (content) => { // Mathjax Post-processor - if (appconfig.features.mathjax) { + if (wiki.config.features.mathjax) { return processMathjax(cr.html()) } else { return Promise.resolve(cr.html()) @@ -339,7 +339,7 @@ const processMathjax = (content) => { resolve(result.svg) } else { resolve(currentMatch[0]) - winston.warn(result.errors.join(', ')) + wiki.logger.warn(result.errors.join(', ')) } }) }) diff --git a/server/modules/redis.js b/server/modules/redis.js new file mode 100644 index 00000000..284c93d3 --- /dev/null +++ b/server/modules/redis.js @@ -0,0 +1,29 @@ +'use strict' + +/* global wiki */ + +const Redis = require('ioredis') +const { isPlainObject } = require('lodash') + +/** + * Redis module + * + * @return {Object} Redis client wrapper instance + */ +module.exports = { + + /** + * Initialize Redis client + * + * @return {Object} Redis client instance + */ + init() { + if (isPlainObject(wiki.config.redis)) { + return new Redis(wiki.config.redis) + } else { + wiki.logger.error('Invalid Redis configuration!') + process.exit(1) + } + } + +} diff --git a/server/libs/rights.js b/server/modules/rights.js similarity index 94% rename from server/libs/rights.js rename to server/modules/rights.js index ce82882b..d06de758 100644 --- a/server/libs/rights.js +++ b/server/modules/rights.js @@ -1,6 +1,6 @@ 'use strict' -/* global db */ +/* global wiki */ const _ = require('lodash') @@ -32,8 +32,8 @@ module.exports = { init () { let self = this - db.onReady.then(() => { - db.User.findOne({ provider: 'local', email: 'guest' }).then((u) => { + wiki.db.onReady.then(() => { + wiki.db.User.findOne({ provider: 'local', email: 'guest' }).then((u) => { if (u) { self.guest = u } diff --git a/server/libs/search-index/index.js b/server/modules/search-index/index.js similarity index 100% rename from server/libs/search-index/index.js rename to server/modules/search-index/index.js diff --git a/server/libs/search-index/siUtil.js b/server/modules/search-index/siUtil.js similarity index 100% rename from server/libs/search-index/siUtil.js rename to server/modules/search-index/siUtil.js diff --git a/server/libs/search.js b/server/modules/search.js similarity index 88% rename from server/libs/search.js rename to server/modules/search.js index 7c446b17..d2978aa2 100644 --- a/server/libs/search.js +++ b/server/modules/search.js @@ -1,13 +1,13 @@ 'use strict' -/* global winston */ +/* global wiki */ const Promise = require('bluebird') const _ = require('lodash') const searchIndex = require('./search-index') const stopWord = require('stopword') const streamToPromise = require('stream-to-promise') -const searchAllowedChars = new RegExp('[^a-z0-9' + appdata.regex.cjk + appdata.regex.arabic + ' ]', 'g') +const searchAllowedChars = new RegExp('[^a-z0-9' + wiki.data.regex.cjk + wiki.data.regex.arabic + ' ]', 'g') module.exports = { @@ -27,15 +27,15 @@ module.exports = { fieldedSearch: true, indexPath: 'wiki', logLevel: 'error', - stopwords: _.get(stopWord, appconfig.lang, []) + stopwords: _.get(stopWord, wiki.config.lang, []) }, (err, si) => { if (err) { - winston.error('Failed to initialize search index.', err) + wiki.logger.error('Failed to initialize search index.', err) reject(err) } else { self._si = Promise.promisifyAll(si) self._si.flushAsync().then(() => { - winston.info('Search index flushed and ready.') + wiki.logger.info('Search index flushed and ready.') resolve(true) }) } @@ -95,13 +95,13 @@ module.exports = { parent: content.parent || '', content: content.text || '' }]).then(() => { - winston.log('verbose', 'Entry ' + content._id + ' added/updated to search index.') + wiki.logger.log('verbose', 'Entry ' + content._id + ' added/updated to search index.') return true }).catch((err) => { - winston.error(err) + wiki.logger.error(err) }) }).catch((err) => { - winston.error(err) + wiki.logger.error(err) }) }) }, @@ -131,7 +131,7 @@ module.exports = { if (err.type === 'NotFoundError') { return true } else { - winston.error(err) + wiki.logger.error(err) } }) }) @@ -204,7 +204,7 @@ module.exports = { suggest: [] } } else { - winston.error(err) + wiki.logger.error(err) } }) } diff --git a/server/libs/system.js b/server/modules/system.js similarity index 100% rename from server/libs/system.js rename to server/modules/system.js diff --git a/server/libs/uploads-agent.js b/server/modules/uploads-agent.js similarity index 100% rename from server/libs/uploads-agent.js rename to server/modules/uploads-agent.js diff --git a/server/libs/uploads.js b/server/modules/uploads.js similarity index 81% rename from server/libs/uploads.js rename to server/modules/uploads.js index 2bee6322..f56ecab3 100644 --- a/server/libs/uploads.js +++ b/server/modules/uploads.js @@ -1,6 +1,6 @@ 'use strict' -/* global db, lang, lcdata, upl, winston */ +/* global wiki */ const path = require('path') const Promise = require('bluebird') @@ -27,8 +27,8 @@ module.exports = { * @return {Object} Uploads model instance */ init () { - this._uploadsPath = path.resolve(ROOTPATH, appconfig.paths.repo, 'uploads') - this._uploadsThumbsPath = path.resolve(ROOTPATH, appconfig.paths.data, 'thumbs') + this._uploadsPath = path.resolve(wiki.ROOTPATH, wiki.config.paths.repo, 'uploads') + this._uploadsThumbsPath = path.resolve(wiki.ROOTPATH, wiki.config.paths.data, 'thumbs') return this }, @@ -48,7 +48,7 @@ module.exports = { * @return {Array} The uploads folders. */ getUploadsFolders () { - return db.UplFolder.find({}, 'name').sort('name').exec().then((results) => { + return wiki.db.Folder.find({}, 'name').sort('name').exec().then((results) => { return (results) ? _.map(results, 'name') : [{ name: '' }] }) }, @@ -69,7 +69,7 @@ module.exports = { } return fs.ensureDirAsync(path.join(self._uploadsPath, folderName)).then(() => { - return db.UplFolder.findOneAndUpdate({ + return wiki.db.UplFolder.findOneAndUpdate({ _id: 'f:' + folderName }, { name: folderName @@ -88,7 +88,7 @@ module.exports = { * @return {Boolean} True if valid */ validateUploadsFolder (folderName) { - return db.UplFolder.findOne({ name: folderName }).then((f) => { + return wiki.db.UplFolder.findOne({ name: folderName }).then((f) => { return (f) ? path.resolve(this._uploadsPath, folderName) : false }) }, @@ -101,7 +101,7 @@ module.exports = { */ addUploadsFiles (arrFiles) { if (_.isArray(arrFiles) || _.isPlainObject(arrFiles)) { - // this._uploadsDb.Files.insert(arrFiles); + // this._uploadswiki.Db.Files.insert(arrFiles); } }, @@ -113,7 +113,7 @@ module.exports = { * @return {Array} The files matching the query */ getUploadsFiles (cat, fld) { - return db.UplFile.find({ + return wiki.db.UplFile.find({ category: cat, folder: 'f:' + fld }).sort('filename').exec() @@ -128,7 +128,7 @@ module.exports = { deleteUploadsFile (uid) { let self = this - return db.UplFile.findOneAndRemove({ _id: uid }).then((f) => { + return wiki.db.UplFile.findOneAndRemove({ _id: uid }).then((f) => { if (f) { return self.deleteUploadsFileTry(f, 0) } @@ -150,7 +150,7 @@ module.exports = { return self.deleteUploadsFileTry(f, attempt + 1) }) } else { - winston.warn('Unable to delete uploads file ' + f.filename + '. File is locked by another process and multiple attempts failed.') + wiki.logger.warn('Unable to delete uploads file ' + f.filename + '. File is locked by another process and multiple attempts failed.') return true } }) @@ -168,12 +168,12 @@ module.exports = { let fUrlFilename = _.last(_.split(fUrlObj.pathname, '/')) let destFolder = _.chain(fFolder).trim().toLower().value() - return upl.validateUploadsFolder(destFolder).then((destFolderPath) => { + return wiki.upl.validateUploadsFolder(destFolder).then((destFolderPath) => { if (!destFolderPath) { - return Promise.reject(new Error(lang.t('errors:invalidfolder'))) + return Promise.reject(new Error(wiki.lang.t('errors:invalidfolder'))) } - return lcdata.validateUploadsFilename(fUrlFilename, destFolder).then((destFilename) => { + return wiki.disk.validateUploadsFilename(fUrlFilename, destFolder).then((destFilename) => { let destFilePath = path.resolve(destFolderPath, destFilename) return new Promise((resolve, reject) => { @@ -194,7 +194,7 @@ module.exports = { rq.abort() destFileStream.destroy() fs.remove(destFilePath) - reject(new Error(lang.t('errors:remotetoolarge'))) + reject(new Error(wiki.lang.t('errors:remotetoolarge'))) } }).on('error', (err) => { destFileStream.destroy() @@ -223,15 +223,15 @@ module.exports = { moveUploadsFile (uid, fld, nFilename) { let self = this - return db.UplFolder.findById('f:' + fld).then((folder) => { + return wiki.db.UplFolder.finwiki.dById('f:' + fld).then((folder) => { if (folder) { - return db.UplFile.findById(uid).then((originFile) => { + return wiki.db.UplFile.finwiki.dById(uid).then((originFile) => { // -> Check if rename is valid let nameCheck = null if (nFilename) { let originFileObj = path.parse(originFile.filename) - nameCheck = lcdata.validateUploadsFilename(nFilename + originFileObj.ext, folder.name) + nameCheck = wiki.disk.validateUploadsFilename(nFilename + originFileObj.ext, folder.name) } else { nameCheck = Promise.resolve(originFile.filename) } @@ -245,12 +245,12 @@ module.exports = { // -> Check for invalid operations if (sourceFilePath === destFilePath) { - return Promise.reject(new Error(lang.t('errors:invalidoperation'))) + return Promise.reject(new Error(wiki.lang.t('errors:invalidoperation'))) } - // -> Delete DB entry + // -> Delete wiki.DB entry - preMoveOps.push(db.UplFile.findByIdAndRemove(uid)) + preMoveOps.push(wiki.db.UplFile.finwiki.dByIdAndRemove(uid)) // -> Move thumbnail ahead to avoid re-generation @@ -273,7 +273,7 @@ module.exports = { }) }) } else { - return Promise.reject(new Error(lang.t('errors:invaliddestfolder'))) + return Promise.reject(new Error(wiki.lang.t('errors:invaliddestfolder'))) } }) } diff --git a/server/libs/winston-transports/bugsnag.js b/server/modules/winston-transports/bugsnag.js similarity index 100% rename from server/libs/winston-transports/bugsnag.js rename to server/modules/winston-transports/bugsnag.js diff --git a/server/libs/winston-transports/rollbar.js b/server/modules/winston-transports/rollbar.js similarity index 100% rename from server/libs/winston-transports/rollbar.js rename to server/modules/winston-transports/rollbar.js diff --git a/server/libs/winston-transports/sentry.js b/server/modules/winston-transports/sentry.js similarity index 100% rename from server/libs/winston-transports/sentry.js rename to server/modules/winston-transports/sentry.js diff --git a/wiki.js b/wiki.js index fcfb1358..faa38b0d 100644 --- a/wiki.js +++ b/wiki.js @@ -3,7 +3,7 @@ // =========================================== // Wiki.js -// 1.0.0 +// 1.0.1 // Licensed under AGPLv3 // =========================================== diff --git a/yarn.lock b/yarn.lock index 60ff1355..3094beea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -72,6 +72,10 @@ "@types/express-serve-static-core" "*" "@types/serve-static" "*" +"@types/geojson@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-1.0.2.tgz#b02d10ab028e2928ac592a051aaa4981a1941d03" + "@types/ldapjs@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/ldapjs/-/ldapjs-1.0.0.tgz#d940cb412140caec14edaa9c76d5b92799dab495" @@ -86,7 +90,7 @@ version "8.0.14" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.14.tgz#4a19dc6bb61d16c01cbadc7b30ac23518fff176b" -"@types/node@^6.0.46": +"@types/node@^6.0.46", "@types/node@^6.0.48": version "6.0.84" resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.84.tgz#193ffe5a9f42864d425ffd9739d95b753c6a1eab" @@ -288,6 +292,10 @@ anymatch@^1.3.0: arrify "^1.0.0" micromatch "^2.1.5" +ap@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ap/-/ap-0.2.0.tgz#ae0942600b29912f0d2b14ec60c45e8f330b6110" + app-root-path@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-1.4.0.tgz#6335d865c9640d0fad99004e5a79232238e92dfa" @@ -412,12 +420,6 @@ async@1.5, async@^1.4.0, async@^1.5: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/async/-/async-2.1.4.tgz#2d2160c7788032e4dd6cbe2502f1f9a2c8f6cde4" - dependencies: - lodash "^4.14.0" - async@^2.1.4, async@^2.3.0, async@^2.5: version "2.5.0" resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" @@ -986,6 +988,10 @@ bindings@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11" +bisection@: + version "0.0.3" + resolved "https://registry.yarnpkg.com/bisection/-/bisection-0.0.3.tgz#9891d506d86ec7d50910c5157bb592dbb03f33db" + bl@^1.0.0: version "1.2.1" resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.1.tgz#cac328f7bee45730d404b692203fcb590e172d5e" @@ -1006,11 +1012,7 @@ block-stream@*: dependencies: inherits "~2.0.0" -bluebird@2.10.2: - version "2.10.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.10.2.tgz#024a5517295308857f14f91f1106fc3b555f446b" - -bluebird@^3.0, bluebird@^3.1.1, bluebird@^3.4.1, bluebird@~3.5.0: +bluebird@^3.1.1, bluebird@^3.3.4, bluebird@^3.4.1, bluebird@^3.4.6, bluebird@~3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" @@ -1082,10 +1084,6 @@ bser@^2.0.0: dependencies: node-int64 "^0.4.0" -bson@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/bson/-/bson-1.0.4.tgz#93c10d39eaa5b58415cbc4052f3e53e562b0b72c" - buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" @@ -1094,9 +1092,9 @@ buffer-equal@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b" -buffer-shims@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" +buffer-writer@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-1.0.1.tgz#22a936901e3029afcd7547eb4487ceb697a3bf08" builtin-modules@^1.0.0, builtin-modules@^1.1.1: version "1.1.1" @@ -1323,6 +1321,17 @@ closure-compiler@0.2.12: dependencies: google-closure-compiler "20150901.x" +cls-bluebird@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/cls-bluebird/-/cls-bluebird-2.0.1.tgz#c259a480ae02c0e506134307bb13db30446ee2e7" + dependencies: + is-bluebird "^1.0.2" + shimmer "^1.1.0" + +cluster-key-slot@^1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.0.8.tgz#7654556085a65330932a2e8b5976f8e2d0b3e414" + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -1453,12 +1462,12 @@ connect-flash@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/connect-flash/-/connect-flash-0.1.1.tgz#d8630f26d95a7f851f9956b1e8cc6732f3b6aa30" -connect-mongo@~1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/connect-mongo/-/connect-mongo-1.3.2.tgz#7cbf58dfff26760e5e00e017d0a85b4bc90b9d37" +connect-redis@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/connect-redis/-/connect-redis-3.3.0.tgz#c9510c1a567ff710eb2510e6a7509fa92b2232df" dependencies: - bluebird "^3.0" - mongodb ">= 1.2.0 <3.0.0" + debug "^2.2.0" + redis "^2.1.0" console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" @@ -1563,6 +1572,13 @@ cron@1.2.1, cron@~1.2.1: dependencies: moment-timezone "^0.5.x" +cross-env@^3.1.2: + version "3.2.4" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-3.2.4.tgz#9e0585f277864ed421ce756f81a980ff0d698aba" + dependencies: + cross-spawn "^5.1.0" + is-windows "^1.0.0" + cross-spawn@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" @@ -1638,7 +1654,7 @@ de-indent@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" -debug@*, debug@2.6.8, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.4.5, debug@^2.6, debug@^2.6.3, debug@^2.6.8, debug@~2.6.4, debug@~2.6.6: +debug@*, debug@2.6.8, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.0, debug@^2.4.5, debug@^2.6, debug@^2.6.3, debug@^2.6.8, debug@~2.6.4, debug@~2.6.6: version "2.6.8" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" dependencies: @@ -1716,7 +1732,11 @@ delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" -depd@1.1.0, depd@~1.1.0: +denque@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.1.1.tgz#10229c2b88eec1bd15ff82c5fde356e7beb6db9e" + +depd@1.1.0, depd@^1.1.0, depd@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" @@ -1814,6 +1834,14 @@ domutils@^1.5.1: dom-serializer "0" domelementtype "1" +dottie@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dottie/-/dottie-2.0.0.tgz#da191981c8b8d713ca0115d5898cf397c2f0ddd0" + +double-ended-queue@^2.1.0-0: + version "2.1.0-0" + resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c" + dtrace-provider@^0.7.0: version "0.7.1" resolved "https://registry.yarnpkg.com/dtrace-provider/-/dtrace-provider-0.7.1.tgz#c06b308f2f10d5d5838aec9c571e5d588dc71d04" @@ -1949,6 +1977,12 @@ entities@^1.1.1, entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" +env-cmd@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/env-cmd/-/env-cmd-5.1.0.tgz#0236db393c3f033005204fcd0a92ee40723a9c9e" + dependencies: + cross-spawn "^5.0.1" + errno@^0.1.4, errno@~0.1.1: version "0.1.4" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" @@ -1961,10 +1995,6 @@ error-ex@^1.2.0: dependencies: is-arrayish "^0.2.1" -es6-promise@3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.2.1.tgz#ec56233868032909207170c39448e24449dd1fc4" - es6-promise@^3.0.2: version "3.3.1" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" @@ -2208,13 +2238,13 @@ expand-template@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-1.0.3.tgz#6c303323177a62b1b22c070279f7861287b69b1a" -express-brute-mongoose@~0.0.9: - version "0.0.9" - resolved "https://registry.yarnpkg.com/express-brute-mongoose/-/express-brute-mongoose-0.0.9.tgz#7f8001c9548f78b705e6810be06f4c1e85745bd2" +express-brute-redis@~0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/express-brute-redis/-/express-brute-redis-0.0.1.tgz#0f4c833a5c3c2505c0c5c9ba55108e224a247ef8" dependencies: - express-brute "~0.5.0" - moment "^2.18.1" - mongoose "*" + express-brute "~0.4.2" + redis "~0.10.0" + underscore "~1.5.1" express-brute@1.0.1: version "1.0.1" @@ -2223,10 +2253,11 @@ express-brute@1.0.1: long-timeout "~0.1.1" underscore "~1.8.3" -express-brute@~0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/express-brute/-/express-brute-0.5.3.tgz#0c8aabafe09dd722666587916f471b976f0c2a48" +express-brute@~0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/express-brute/-/express-brute-0.4.2.tgz#3bc34fb01252b8f47e737bf72dd01ff4df1d9c07" dependencies: + memcached "~0.2.4" underscore "~1.5.1" express-session@~1.15.3: @@ -2486,6 +2517,10 @@ flat-cache@^1.2.1: graceful-fs "^4.1.2" write "^0.2.1" +flexbuffer@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/flexbuffer/-/flexbuffer-0.0.6.tgz#039fdf23f8823e440c38f3277e6fef1174215b30" + fliplog@^0.3.13: version "0.3.13" resolved "https://registry.yarnpkg.com/fliplog/-/fliplog-0.3.13.tgz#dd0d786e821822aae272e0ddc84012596a96154c" @@ -2653,6 +2688,14 @@ gaze@^1.0.0: dependencies: globule "^1.0.0" +generic-pool@2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-2.4.3.tgz#780c36f69dfad05a5a045dd37be7adca11a4f6ff" + +generic-pool@^3.1.6: + version "3.1.7" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.1.7.tgz#dac22b2c7a7a04e41732f7d8d2d25a303c88f662" + get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" @@ -2894,6 +2937,13 @@ has@^1.0.1: dependencies: function-bind "^1.0.2" +hashring@0.0.x: + version "0.0.8" + resolved "https://registry.yarnpkg.com/hashring/-/hashring-0.0.8.tgz#203ab13c364119f10106526d2eaf7bd42b484c31" + dependencies: + bisection "" + simple-lru-cache "0.0.x" + hawk@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" @@ -2929,10 +2979,6 @@ home-or-tmp@^2.0.0: os-homedir "^1.0.0" os-tmpdir "^1.0.1" -hooks-fixed@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/hooks-fixed/-/hooks-fixed-2.0.0.tgz#a01d894d52ac7f6599bbb1f63dfc9c411df70cba" - hosted-git-info@^2.1.4: version "2.5.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" @@ -3053,6 +3099,10 @@ infinity-agent@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/infinity-agent/-/infinity-agent-2.0.3.tgz#45e0e2ff7a9eb030b27d62b74b3744b7a7ac4216" +inflection@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.10.0.tgz#5bffcb1197ad3e81050f8e17e21668087ee9eb2f" + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -3127,6 +3177,19 @@ invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" +ioredis@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-3.1.1.tgz#cc2f1d3232b8c95cc153046bce168f2baa1186e8" + dependencies: + bluebird "^3.3.4" + cluster-key-slot "^1.0.6" + debug "^2.2.0" + denque "^1.1.0" + flexbuffer "0.0.6" + lodash "^4.8.2" + redis-commands "^1.2.0" + redis-parser "^2.4.0" + ip-regex@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-1.0.3.tgz#dc589076f659f419c222039a33316f1c7387effd" @@ -3149,6 +3212,10 @@ is-binary-path@^1.0.0: dependencies: binary-extensions "^1.0.0" +is-bluebird@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-bluebird/-/is-bluebird-1.0.2.tgz#096439060f4aa411abee19143a84d6a55346d6e2" + is-buffer@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" @@ -3307,6 +3374,10 @@ is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" +is-windows@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.1.tgz#310db70f742d259a16a369202b51af84233310d9" + is@^3.2.0: version "3.2.1" resolved "https://registry.yarnpkg.com/is/-/is-3.2.1.tgz#d0ac2ad55eb7b0bec926a5266f6c662aaa83dca5" @@ -3411,6 +3482,12 @@ isurl@^1.0.0-alpha5: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" +jackpot@>=0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/jackpot/-/jackpot-0.0.6.tgz#3cff064285cbf66f4eab2593c90bce816a821849" + dependencies: + retry "0.6.0" + jest-changed-files@^20.0.3: version "20.0.3" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-20.0.3.tgz#9394d5cc65c438406149bef1bf4d52b68e03e3f8" @@ -3862,10 +3939,6 @@ jws@^3.1.4: jwa "^1.1.4" safe-buffer "^5.0.1" -kareem@1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/kareem/-/kareem-1.4.2.tgz#3b4af5dbfaf3ac1c08b8e5518fdd81ba90c2ab72" - keygrip@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.1.tgz#b02fa4816eef21a8c4b35ca9e52921ffc89a30e9" @@ -4182,7 +4255,7 @@ lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" -lodash@4.17.4, lodash@^4.0.0, lodash@^4.1.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@~4.17.4: +lodash@4.17.4, lodash@^4.0.0, lodash@^4.1.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.1, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.8.2, lodash@~4.17.4: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -4238,6 +4311,10 @@ makeerror@1.0.x: dependencies: tmpl "1.0.x" +manakin@0.4: + version "0.4.7" + resolved "https://registry.yarnpkg.com/manakin/-/manakin-0.4.7.tgz#41ca449b55bea9c4c4fecec393b9c4d63818fc3f" + map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" @@ -4325,6 +4402,13 @@ mem@^1.1.0: dependencies: mimic-fn "^1.0.0" +memcached@~0.2.4: + version "0.2.8" + resolved "https://registry.yarnpkg.com/memcached/-/memcached-0.2.8.tgz#ffbf9498cbc30779625b77e77770bd50dc525212" + dependencies: + hashring "0.0.x" + jackpot ">=0.0.6" + memdown@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/memdown/-/memdown-1.2.4.tgz#cd9a34aaf074d53445a271108eb4b8dd4ec0f27f" @@ -4456,80 +4540,16 @@ mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: dependencies: minimist "0.0.8" -moment-timezone@^0.5.x, moment-timezone@~0.5.13: +moment-timezone@^0.5.4, moment-timezone@^0.5.x, moment-timezone@~0.5.13: version "0.5.13" resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.13.tgz#99ce5c7d827262eb0f1f702044177f60745d7b90" dependencies: moment ">= 2.9.0" -moment@2.x.x, "moment@>= 2.9.0", moment@^2.10.6, moment@^2.16.1, moment@^2.18, moment@^2.18.1, moment@~2.18.1: +moment@2.x.x, "moment@>= 2.9.0", moment@^2.10.6, moment@^2.13.0, moment@^2.16.1, moment@^2.18, moment@~2.18.1: version "2.18.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" -mongodb-core@2.1.11: - version "2.1.11" - resolved "https://registry.yarnpkg.com/mongodb-core/-/mongodb-core-2.1.11.tgz#1c38776ceb174997a99c28860eed9028da9b3e1a" - dependencies: - bson "~1.0.4" - require_optional "~1.0.0" - -mongodb-core@2.1.14: - version "2.1.14" - resolved "https://registry.yarnpkg.com/mongodb-core/-/mongodb-core-2.1.14.tgz#13cba2764226b5be3d18992af0c963ce5ea0f0fd" - dependencies: - bson "~1.0.4" - require_optional "~1.0.0" - -mongodb@2.2.27: - version "2.2.27" - resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-2.2.27.tgz#34122034db66d983bcf6ab5adb26a24a70fef6e6" - dependencies: - es6-promise "3.2.1" - mongodb-core "2.1.11" - readable-stream "2.2.7" - -"mongodb@>= 1.2.0 <3.0.0", mongodb@~2.2.30: - version "2.2.30" - resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-2.2.30.tgz#8ccd801f676c8172040c2f2b47e9602a0d5634ab" - dependencies: - es6-promise "3.2.1" - mongodb-core "2.1.14" - readable-stream "2.2.7" - -mongoose@*, mongoose@~4.11.1: - version "4.11.3" - resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-4.11.3.tgz#f93d427b282c2e798b0fe1532fb41a7dde6e98d3" - dependencies: - async "2.1.4" - bson "~1.0.4" - hooks-fixed "2.0.0" - kareem "1.4.2" - mongodb "2.2.27" - mpath "0.3.0" - mpromise "0.5.5" - mquery "2.3.1" - ms "2.0.0" - muri "1.2.2" - regexp-clone "0.0.1" - sliced "1.0.1" - -mpath@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.3.0.tgz#7a58f789e9b5fd3c94520634157960f26bd5ef44" - -mpromise@0.5.5: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mpromise/-/mpromise-0.5.5.tgz#f5b24259d763acc2257b0a0c8c6d866fd51732e6" - -mquery@2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/mquery/-/mquery-2.3.1.tgz#9ab36749714800ff0bb53a681ce4bc4d5f07c87b" - dependencies: - bluebird "2.10.2" - debug "2.6.8" - regexp-clone "0.0.1" - sliced "0.0.5" - ms@0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" @@ -4555,10 +4575,6 @@ multer@~1.3.0: type-is "^1.6.4" xtend "^4.0.0" -muri@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/muri/-/muri-1.2.2.tgz#63198132650db08a04cc79ccd00dd389afd2631c" - mustache@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" @@ -4811,6 +4827,10 @@ oauth@0.9.x: version "0.9.15" resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" +object-assign@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + object-assign@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" @@ -4979,6 +4999,10 @@ package-json@^1.0.0: got "^3.2.0" registry-url "^3.0.0" +packet-reader@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-0.3.1.tgz#cd62e60af8d7fea8a705ec4ff990871c46871f27" + parse-bmfont-ascii@^1.0.3: version "1.0.6" resolved "https://registry.yarnpkg.com/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz#11ac3c3ff58f7c2020ab22769079108d4dfa0285" @@ -5214,6 +5238,80 @@ performance-now@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" +pg-connection-string@0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-0.1.3.tgz#da1847b20940e42ee1492beaf65d49d91b245df7" + +pg-hstore@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/pg-hstore/-/pg-hstore-2.3.2.tgz#f7ef053e7b9b892ae986af2f7cbe86432dfcf24f" + dependencies: + underscore "^1.7.0" + +pg-minify@0.4: + version "0.4.2" + resolved "https://registry.yarnpkg.com/pg-minify/-/pg-minify-0.4.2.tgz#c75b4b5878960fb09c3b9a4d4eb1036aea7ea0e3" + +pg-pool@1.*: + version "1.8.0" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-1.8.0.tgz#f7ec73824c37a03f076f51bfdf70e340147c4f37" + dependencies: + generic-pool "2.4.3" + object-assign "4.1.0" + +pg-pool@2.*: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-2.0.1.tgz#8b12541df271b57f7020c50a3f5566471f82c77e" + +pg-promise@~6.3.5: + version "6.3.5" + resolved "https://registry.yarnpkg.com/pg-promise/-/pg-promise-6.3.5.tgz#61db54e4cd269d6c7c789ee8989ae5b0aa778caa" + dependencies: + manakin "0.4" + pg "^6.4.0" + pg-minify "0.4" + spex "1.2" + +pg-types@1.*: + version "1.12.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-1.12.0.tgz#8ad3b7b897e3fd463e62de241ad5fc640b4a66f0" + dependencies: + ap "~0.2.0" + postgres-array "~1.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.0" + postgres-interval "^1.1.0" + +pg@^6.4.0: + version "6.4.1" + resolved "https://registry.yarnpkg.com/pg/-/pg-6.4.1.tgz#3eabd8ca056814437c769f17ff7a0c36ac7023c5" + dependencies: + buffer-writer "1.0.1" + packet-reader "0.3.1" + pg-connection-string "0.1.3" + pg-pool "1.*" + pg-types "1.*" + pgpass "1.*" + semver "4.3.2" + +pg@~7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/pg/-/pg-7.0.2.tgz#b9c2fe8168e7edfe9343aebe6fc48591e766ada7" + dependencies: + buffer-writer "1.0.1" + packet-reader "0.3.1" + pg-connection-string "0.1.3" + pg-pool "2.*" + pg-types "1.*" + pgpass "1.x" + semver "4.3.2" + +pgpass@1.*, pgpass@1.x: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.2.tgz#2a7bb41b6065b67907e91da1b07c1847c877b306" + dependencies: + split "^1.0.0" + pidusage@^1.1.0: version "1.1.5" resolved "https://registry.yarnpkg.com/pidusage/-/pidusage-1.1.5.tgz#b8c8d32bdfaf36212ca9e741028876ea33217e66" @@ -5335,6 +5433,24 @@ postcss@^6.0.1: source-map "^0.5.6" supports-color "^4.2.0" +postgres-array@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-1.0.2.tgz#8e0b32eb03bf77a5c0a7851e0441c169a256a238" + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + +postgres-date@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.3.tgz#e2d89702efdb258ff9d9cee0fe91bd06975257a8" + +postgres-interval@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.1.1.tgz#acdb0f897b4b1c6e496d9d4e0a853e1c428f06f0" + dependencies: + xtend "^4.0.0" + prebuild-install@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-2.2.0.tgz#55934756a32bac8747390ca44ff663cee8b99b69" @@ -5704,18 +5820,6 @@ readable-stream@1.1.x, readable-stream@^1.0.33: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@2.2.7: - version "2.2.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.7.tgz#07057acbe2467b22042d36f98c5ad507054e95b1" - dependencies: - buffer-shims "~1.0.0" - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~1.0.0" - util-deprecate "~1.0.1" - readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2: version "2.3.3" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" @@ -5757,6 +5861,26 @@ redent@^1.0.0: indent-string "^2.1.0" strip-indent "^1.0.1" +redis-commands@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.3.1.tgz#81d826f45fa9c8b2011f4cd7a0fe597d241d442b" + +redis-parser@^2.4.0, redis-parser@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-2.6.0.tgz#52ed09dacac108f1a631c07e9b69941e7a19504b" + +redis@^2.1.0: + version "2.7.1" + resolved "https://registry.yarnpkg.com/redis/-/redis-2.7.1.tgz#7d56f7875b98b20410b71539f1d878ed58ebf46a" + dependencies: + double-ended-queue "^2.1.0-0" + redis-commands "^1.2.0" + redis-parser "^2.5.0" + +redis@~0.10.0: + version "0.10.3" + resolved "https://registry.yarnpkg.com/redis/-/redis-0.10.3.tgz#8927fe2110ee39617bcf3fd37b89d8e123911bb6" + regenerate@^1.2.1: version "1.3.2" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" @@ -5780,10 +5904,6 @@ regex-cache@^0.4.2: is-equal-shallow "^0.1.3" is-primitive "^2.0.0" -regexp-clone@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-0.0.1.tgz#a7c2e09891fdbf38fbb10d376fb73003e68ac589" - regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" @@ -5878,21 +5998,10 @@ require-uncached@^1.0.3: caller-path "^0.1.0" resolve-from "^1.0.0" -require_optional@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e" - dependencies: - resolve-from "^2.0.0" - semver "^5.1.0" - resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" -resolve-from@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" - resolve@1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" @@ -5910,6 +6019,18 @@ restore-cursor@^2.0.0: onetime "^2.0.0" signal-exit "^3.0.2" +retry-as-promised@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/retry-as-promised/-/retry-as-promised-2.2.0.tgz#b0463d7fd3cf5b2fed64500ab6e8b8a49c5b8e6c" + dependencies: + bluebird "^3.4.6" + cross-env "^3.1.2" + debug "^2.2.0" + +retry@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.6.0.tgz#1c010713279a6fd1e8def28af0c3ff1871caa537" + right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" @@ -6036,6 +6157,10 @@ semver-diff@^2.0.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" +semver@4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7" + semver@~5.1.0: version "5.1.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.1.1.tgz#a3292a373e6f3e0798da0b20641b9a9c5bc47e19" @@ -6092,6 +6217,29 @@ send@0.15.3: range-parser "~1.2.0" statuses "~1.3.1" +sequelize@~4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-4.4.2.tgz#95292e0a752e2586ec92a0e72362b76e4fcb8eae" + dependencies: + bluebird "^3.4.6" + cls-bluebird "^2.0.1" + debug "^2.3.0" + depd "^1.1.0" + dottie "^2.0.0" + env-cmd "^5.0.0" + generic-pool "^3.1.6" + inflection "1.10.0" + lodash "^4.17.1" + moment "^2.13.0" + moment-timezone "^0.5.4" + retry-as-promised "^2.0.0" + semver "^5.0.1" + terraformer-wkt-parser "^1.1.2" + toposort-class "^1.0.1" + uuid "^3.0.0" + validator "^6.3.0" + wkx "^0.4.1" + serve-favicon@~2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/serve-favicon/-/serve-favicon-2.4.3.tgz#5986b17b0502642b641c21f818b1acce32025d23" @@ -6177,6 +6325,10 @@ simple-get@^1.4.2: unzip-response "^1.0.0" xtend "^4.0.0" +simple-lru-cache@0.0.x: + version "0.0.2" + resolved "https://registry.yarnpkg.com/simple-lru-cache/-/simple-lru-cache-0.0.2.tgz#d59cc3a193c1a5d0320f84ee732f6e4713e511dd" + simplemde@~1.11.2: version "1.11.2" resolved "https://registry.yarnpkg.com/simplemde/-/simplemde-1.11.2.tgz#a23a35d978d2c40ef07dec008c92f070d8e080e3" @@ -6193,14 +6345,6 @@ slice-ansi@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" -sliced@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/sliced/-/sliced-0.0.5.tgz#5edc044ca4eb6f7816d50ba2fc63e25d8fe4707f" - -sliced@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" - slide@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" @@ -6291,12 +6435,22 @@ spdx-license-ids@^1.0.2: version "1.2.2" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" +spex@1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/spex/-/spex-1.2.0.tgz#6264b3b8acbc444477f06dbb66d425c0ee1074c0" + split@0.3: version "0.3.3" resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" dependencies: through "2" +split@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/split/-/split-1.0.0.tgz#c4395ce683abcd254bc28fe1dabb6e5c27dcffae" + dependencies: + through "2" + sprintf-js@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c" @@ -6408,7 +6562,7 @@ string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" -string_decoder@~1.0.0, string_decoder@~1.0.3: +string_decoder@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" dependencies: @@ -6543,6 +6697,18 @@ term-vector@^0.1.2: dependencies: lodash.isequal "^4.1.3" +terraformer-wkt-parser@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/terraformer-wkt-parser/-/terraformer-wkt-parser-1.1.2.tgz#336a0c8fc82094a5aff83288f69aedecd369bf0c" + dependencies: + terraformer "~1.0.5" + +terraformer@~1.0.5: + version "1.0.8" + resolved "https://registry.yarnpkg.com/terraformer/-/terraformer-1.0.8.tgz#51e0ad89746fcf2161dc6f65aa70e42377c8b593" + dependencies: + "@types/geojson" "^1.0.0" + test-exclude@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.1.1.tgz#4d84964b0966b0087ecc334a2ce002d3d9341e26" @@ -6620,6 +6786,10 @@ topo@1.x.x: dependencies: hoek "2.x.x" +toposort-class@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988" + touch@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/touch/-/touch-1.0.0.tgz#449cbe2dbae5a8c8038e30d71fa0ff464947c4de" @@ -6760,14 +6930,14 @@ undefsafe@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-0.0.3.tgz#ecca3a03e56b9af17385baac812ac83b994a962f" +underscore@^1.7.0, underscore@~1.8.3: + version "1.8.3" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" + underscore@~1.5.1: version "1.5.2" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.5.2.tgz#1335c5e4f5e6d33bbb4b006ba8c86a00f556de08" -underscore@~1.8.3: - version "1.8.3" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" - universalify@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" @@ -6874,6 +7044,10 @@ validator@^5.5.0: version "5.7.0" resolved "https://registry.yarnpkg.com/validator/-/validator-5.7.0.tgz#7a87a58146b695ac486071141c0c49d67da05e5c" +validator@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-6.3.0.tgz#47ce23ed8d4eaddfa9d4b8ef0071b6cf1078d7c8" + validator@~8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/validator/-/validator-8.0.0.tgz#00d6ec230ab5d3353ab1174162a96462b947bdbd" @@ -7072,6 +7246,12 @@ with@^5.0.0: acorn "^3.1.0" acorn-globals "^3.0.0" +wkx@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.4.1.tgz#2fc171b5e9cb55c6256fef4bde1f21be413befee" + dependencies: + "@types/node" "^6.0.48" + wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"