Commit d76f6182 authored by NGPixel's avatar NGPixel

refactor: migrate to PostgreSQL + Sequelize

parent 8da98ce7
...@@ -48,14 +48,14 @@ ...@@ -48,14 +48,14 @@
"chokidar": "~1.7.0", "chokidar": "~1.7.0",
"compression": "~1.7.0", "compression": "~1.7.0",
"connect-flash": "~0.1.1", "connect-flash": "~0.1.1",
"connect-mongo": "~1.3.2", "connect-redis": "~3.3.0",
"cookie-parser": "~1.4.3", "cookie-parser": "~1.4.3",
"cron": "~1.2.1", "cron": "~1.2.1",
"diff2html": "~2.3.0", "diff2html": "~2.3.0",
"execa": "~0.7.0", "execa": "~0.7.0",
"express": "~4.15.3", "express": "~4.15.3",
"express-brute": "1.0.1", "express-brute": "1.0.1",
"express-brute-mongoose": "~0.0.9", "express-brute-redis": "~0.0.1",
"express-session": "~1.15.3", "express-session": "~1.15.3",
"file-type": "~5.2.0", "file-type": "~5.2.0",
"filesize.js": "~1.0.2", "filesize.js": "~1.0.2",
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
"i18next-express-middleware": "~1.0.5", "i18next-express-middleware": "~1.0.5",
"i18next-node-fs-backend": "~1.0.0", "i18next-node-fs-backend": "~1.0.0",
"image-size": "~0.6.0", "image-size": "~0.6.0",
"ioredis": "~3.1.1",
"jimp": "~0.2.28", "jimp": "~0.2.28",
"js-yaml": "~3.9.0", "js-yaml": "~3.9.0",
"jsonwebtoken": "~7.4.1", "jsonwebtoken": "~7.4.1",
...@@ -88,8 +89,6 @@ ...@@ -88,8 +89,6 @@
"mime-types": "~2.1.15", "mime-types": "~2.1.15",
"moment": "~2.18.1", "moment": "~2.18.1",
"moment-timezone": "~0.5.13", "moment-timezone": "~0.5.13",
"mongodb": "~2.2.30",
"mongoose": "~4.11.1",
"multer": "~1.3.0", "multer": "~1.3.0",
"node-2fa": "~1.1.2", "node-2fa": "~1.1.2",
"node-graceful": "~0.2.3", "node-graceful": "~0.2.3",
...@@ -104,6 +103,9 @@ ...@@ -104,6 +103,9 @@
"passport-slack": "0.0.7", "passport-slack": "0.0.7",
"passport-windowslive": "~1.0.2", "passport-windowslive": "~1.0.2",
"passport.socketio": "~3.7.0", "passport.socketio": "~3.7.0",
"pg": "~7.0.2",
"pg-hstore": "~2.3.2",
"pg-promise": "~6.3.5",
"pm2": "~2.6.1", "pm2": "~2.6.1",
"pug": "~2.0.0-rc.2", "pug": "~2.0.0-rc.2",
"read-chunk": "~2.0.0", "read-chunk": "~2.0.0",
...@@ -112,6 +114,7 @@ ...@@ -112,6 +114,7 @@
"search-index-adder": "~0.3.9", "search-index-adder": "~0.3.9",
"search-index-searcher": "~0.2.10", "search-index-searcher": "~0.2.10",
"semver": "~5.3.0", "semver": "~5.3.0",
"sequelize": "~4.4.2",
"serve-favicon": "~2.4.3", "serve-favicon": "~2.4.3",
"simplemde": "~1.11.2", "simplemde": "~1.11.2",
"socket.io": "~2.0.2", "socket.io": "~2.0.2",
......
// =========================================== // ===========================================
// Wiki.js - Background Agent // Wiki.js - Background Agent
// 1.0.0 // 1.0.1
// Licensed under AGPLv3 // Licensed under AGPLv3
// =========================================== // ===========================================
...@@ -12,7 +12,7 @@ global.ROOTPATH = ROOTPATH ...@@ -12,7 +12,7 @@ global.ROOTPATH = ROOTPATH
global.SERVERPATH = SERVERPATH global.SERVERPATH = SERVERPATH
const IS_DEBUG = process.env.NODE_ENV === 'development' const IS_DEBUG = process.env.NODE_ENV === 'development'
let appconf = require('./libs/config')() let appconf = require('./modules/config')()
global.appconfig = appconf.config global.appconfig = appconf.config
global.appdata = appconf.data global.appdata = appconf.data
...@@ -20,7 +20,7 @@ global.appdata = appconf.data ...@@ -20,7 +20,7 @@ global.appdata = appconf.data
// Load Winston // Load Winston
// ---------------------------------------- // ----------------------------------------
global.winston = require('./libs/logger')(IS_DEBUG, 'AGENT') global.winston = require('./modules/logger')(IS_DEBUG, 'AGENT')
// ---------------------------------------- // ----------------------------------------
// Load global modules // Load global modules
...@@ -28,12 +28,12 @@ global.winston = require('./libs/logger')(IS_DEBUG, 'AGENT') ...@@ -28,12 +28,12 @@ global.winston = require('./libs/logger')(IS_DEBUG, 'AGENT')
global.winston.info('Background Agent is initializing...') global.winston.info('Background Agent is initializing...')
global.db = require('./libs/db').init() global.db = require('./modules/db').init()
global.upl = require('./libs/uploads-agent').init() global.upl = require('./modules/uploads-agent').init()
global.git = require('./libs/git').init() global.git = require('./modules/git').init()
global.entries = require('./libs/entries').init() global.entries = require('./modules/entries').init()
global.lang = require('i18next') global.lang = require('i18next')
global.mark = require('./libs/markdown') global.mark = require('./modules/markdown')
// ---------------------------------------- // ----------------------------------------
// Load modules // Load modules
......
...@@ -64,6 +64,15 @@ defaults: ...@@ -64,6 +64,15 @@ defaults:
code: code:
dark: true dark: true
colorize: true colorize: true
authProviders:
- local
- microsoft
- google
- facebook
- github
- slack
- ldap
- azure
colors: colors:
- red - red
- pink - pink
......
'use strict' 'use strict'
/* global db, lang */ /* global wiki */
const Promise = require('bluebird') const Promise = require('bluebird')
const express = require('express') const express = require('express')
const router = express.Router() const router = express.Router()
const passport = require('passport') const passport = require('passport')
const ExpressBrute = require('express-brute') const ExpressBrute = require('express-brute')
const ExpressBruteMongooseStore = require('express-brute-mongoose') const ExpressBruteRedisStore = require('express-brute-redis')
const moment = require('moment') const moment = require('moment')
/** /**
* Setup Express-Brute * Setup Express-Brute
*/ */
const EBstore = new ExpressBruteMongooseStore(db.Bruteforce) const EBstore = new ExpressBruteRedisStore({
client: wiki.redis
})
const bruteforce = new ExpressBrute(EBstore, { const bruteforce = new ExpressBrute(EBstore, {
freeRetries: 5, freeRetries: 5,
minWait: 60 * 1000, minWait: 60 * 1000,
...@@ -22,8 +24,8 @@ const bruteforce = new ExpressBrute(EBstore, { ...@@ -22,8 +24,8 @@ const bruteforce = new ExpressBrute(EBstore, {
failCallback (req, res, next, nextValidRequestDate) { failCallback (req, res, next, nextValidRequestDate) {
req.flash('alert', { req.flash('alert', {
class: 'error', class: 'error',
title: lang.t('auth:errors.toomanyattempts'), title: wiki.lang.t('auth:errors.toomanyattempts'),
message: lang.t('auth:errors.toomanyattemptsmsg', { time: moment(nextValidRequestDate).fromNow() }), message: wiki.lang.t('auth:errors.toomanyattemptsmsg', { time: moment(nextValidRequestDate).fromNow() }),
iconClass: 'fa-times' iconClass: 'fa-times'
}) })
res.redirect('/login') res.redirect('/login')
...@@ -73,13 +75,13 @@ router.post('/login', bruteforce.prevent, function (req, res, next) { ...@@ -73,13 +75,13 @@ router.post('/login', bruteforce.prevent, function (req, res, next) {
// LOGIN FAIL // LOGIN FAIL
if (err.message === 'INVALID_LOGIN') { if (err.message === 'INVALID_LOGIN') {
req.flash('alert', { req.flash('alert', {
title: lang.t('auth:errors.invalidlogin'), title: wiki.lang.t('auth:errors.invalidlogin'),
message: lang.t('auth:errors.invalidloginmsg') message: wiki.lang.t('auth:errors.invalidloginmsg')
}) })
return res.redirect('/login') return res.redirect('/login')
} else { } else {
req.flash('alert', { req.flash('alert', {
title: lang.t('auth:errors.loginerror'), title: wiki.lang.t('auth:errors.loginerror'),
message: err.message message: err.message
}) })
return res.redirect('/login') return res.redirect('/login')
......
'use strict' 'use strict'
/* global git, lang, lcdata, upl */ /* global wiki */
const express = require('express') const express = require('express')
const router = express.Router() const router = express.Router()
...@@ -12,7 +12,7 @@ const fs = Promise.promisifyAll(require('fs-extra')) ...@@ -12,7 +12,7 @@ const fs = Promise.promisifyAll(require('fs-extra'))
const path = require('path') const path = require('path')
const _ = require('lodash') 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)$') const validPathThumbsRe = new RegExp('^([a-z0-9]+\\.png)$')
// ========================================== // ==========================================
...@@ -28,7 +28,7 @@ router.get('/t/*', (req, res, next) => { ...@@ -28,7 +28,7 @@ router.get('/t/*', (req, res, next) => {
// todo: Authentication-based access // todo: Authentication-based access
res.sendFile(fileName, { res.sendFile(fileName, {
root: lcdata.getThumbsPath(), root: wiki.disk.getThumbsPath(),
dotfiles: 'deny' dotfiles: 'deny'
}, (err) => { }, (err) => {
if (err) { if (err) {
...@@ -37,12 +37,12 @@ router.get('/t/*', (req, res, next) => { ...@@ -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() let destFolder = _.chain(req.body.folder).trim().toLower().value()
upl.validateUploadsFolder(destFolder).then((destFolderPath) => { wiki.upl.validateUploadsFolder(destFolder).then((destFolderPath) => {
if (!destFolderPath) { if (!destFolderPath) {
res.json({ ok: false, msg: lang.t('errors:invalidfolder') }) res.json({ ok: false, msg: wiki.lang.t('errors:invalidfolder') })
return true return true
} }
...@@ -50,7 +50,7 @@ router.post('/img', lcdata.uploadImgHandler, (req, res, next) => { ...@@ -50,7 +50,7 @@ router.post('/img', lcdata.uploadImgHandler, (req, res, next) => {
let destFilename = '' let destFilename = ''
let destFilePath = '' let destFilePath = ''
return lcdata.validateUploadsFilename(f.originalname, destFolder, true).then((fname) => { return wiki.disk.validateUploadsFilename(f.originalname, destFolder, true).then((fname) => {
destFilename = fname destFilename = fname
destFilePath = path.resolve(destFolderPath, destFilename) destFilePath = path.resolve(destFolderPath, destFilename)
...@@ -60,7 +60,7 @@ router.post('/img', lcdata.uploadImgHandler, (req, res, next) => { ...@@ -60,7 +60,7 @@ router.post('/img', lcdata.uploadImgHandler, (req, res, next) => {
let mimeInfo = fileType(buf) let mimeInfo = fileType(buf)
if (!_.includes(['image/png', 'image/jpeg', 'image/gif', 'image/webp'], mimeInfo.mime)) { 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 return true
}).then(() => { }).then(() => {
...@@ -94,12 +94,12 @@ router.post('/img', lcdata.uploadImgHandler, (req, res, next) => { ...@@ -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() let destFolder = _.chain(req.body.folder).trim().toLower().value()
upl.validateUploadsFolder(destFolder).then((destFolderPath) => { wiki.upl.validateUploadsFolder(destFolder).then((destFolderPath) => {
if (!destFolderPath) { if (!destFolderPath) {
res.json({ ok: false, msg: lang.t('errors:invalidfolder') }) res.json({ ok: false, msg: wiki.lang.t('errors:invalidfolder') })
return true return true
} }
...@@ -107,7 +107,7 @@ router.post('/file', lcdata.uploadFileHandler, (req, res, next) => { ...@@ -107,7 +107,7 @@ router.post('/file', lcdata.uploadFileHandler, (req, res, next) => {
let destFilename = '' let destFilename = ''
let destFilePath = '' let destFilePath = ''
return lcdata.validateUploadsFilename(f.originalname, destFolder, false).then((fname) => { return wiki.disk.validateUploadsFilename(f.originalname, destFolder, false).then((fname) => {
destFilename = fname destFilename = fname
destFilePath = path.resolve(destFolderPath, destFilename) destFilePath = path.resolve(destFolderPath, destFilename)
...@@ -150,7 +150,7 @@ router.get('/*', (req, res, next) => { ...@@ -150,7 +150,7 @@ router.get('/*', (req, res, next) => {
// todo: Authentication-based access // todo: Authentication-based access
res.sendFile(fileName, { res.sendFile(fileName, {
root: git.getRepoPath() + '/uploads/', root: wiki.git.getRepoPath() + '/uploads/',
dotfiles: 'deny' dotfiles: 'deny'
}, (err) => { }, (err) => {
if (err) { if (err) {
......
...@@ -2,47 +2,48 @@ ...@@ -2,47 +2,48 @@
// =========================================== // ===========================================
// Wiki.js // Wiki.js
// 1.0.0 // 1.0.1
// Licensed under AGPLv3 // Licensed under AGPLv3
// =========================================== // ===========================================
const path = require('path') const path = require('path')
const ROOTPATH = process.cwd() let wiki = {
const SERVERPATH = path.join(ROOTPATH, 'server') IS_DEBUG: process.env.NODE_ENV === 'development',
ROOTPATH: process.cwd(),
global.ROOTPATH = ROOTPATH SERVERPATH: path.join(process.cwd(), 'server')
global.SERVERPATH = SERVERPATH }
const IS_DEBUG = process.env.NODE_ENV === 'development' global.wiki = wiki
process.env.VIPS_WARNING = false process.env.VIPS_WARNING = false
// if (IS_DEBUG) { // if (wiki.IS_DEBUG) {
// require('@glimpse/glimpse').init() // require('@glimpse/glimpse').init()
// } // }
let appconf = require('./libs/config')() let appconf = require('./modules/config')()
global.appconfig = appconf.config wiki.config = appconf.config
global.appdata = appconf.data wiki.data = appconf.data
// ---------------------------------------- // ----------------------------------------
// Load Winston // Load Winston
// ---------------------------------------- // ----------------------------------------
global.winston = require('./libs/logger')(IS_DEBUG, 'SERVER') wiki.logger = require('./modules/logger')(wiki.IS_DEBUG, 'SERVER')
global.winston.info('Wiki.js is initializing...') wiki.logger.info('Wiki.js is initializing...')
// ---------------------------------------- // ----------------------------------------
// Load global modules // Load global modules
// ---------------------------------------- // ----------------------------------------
global.lcdata = require('./libs/local').init() wiki.disk = require('./modules/disk').init()
global.db = require('./libs/db').init() wiki.db = require('./modules/db').init()
global.entries = require('./libs/entries').init() wiki.entries = require('./modules/entries').init()
global.git = require('./libs/git').init(false) wiki.git = require('./modules/git').init(false)
global.lang = require('i18next') wiki.lang = require('i18next')
global.mark = require('./libs/markdown') wiki.mark = require('./modules/markdown')
global.search = require('./libs/search').init() wiki.redis = require('./modules/redis').init()
global.upl = require('./libs/uploads').init() wiki.search = require('./modules/search').init()
wiki.upl = require('./modules/uploads').init()
// ---------------------------------------- // ----------------------------------------
// Load modules // Load modules
...@@ -61,19 +62,19 @@ const i18nBackend = require('i18next-node-fs-backend') ...@@ -61,19 +62,19 @@ const i18nBackend = require('i18next-node-fs-backend')
const passport = require('passport') const passport = require('passport')
const passportSocketIo = require('passport.socketio') const passportSocketIo = require('passport.socketio')
const session = require('express-session') const session = require('express-session')
const SessionMongoStore = require('connect-mongo')(session) const SessionRedisStore = require('connect-redis')(session)
const graceful = require('node-graceful') const graceful = require('node-graceful')
const socketio = require('socket.io') const socketio = require('socket.io')
var mw = autoload(path.join(SERVERPATH, '/middlewares')) var mw = autoload(path.join(wiki.SERVERPATH, '/middlewares'))
var ctrl = autoload(path.join(SERVERPATH, '/controllers')) var ctrl = autoload(path.join(wiki.SERVERPATH, '/controllers'))
// ---------------------------------------- // ----------------------------------------
// Define Express App // Define Express App
// ---------------------------------------- // ----------------------------------------
const app = express() const app = express()
global.app = app wiki.app = app
app.use(compression()) app.use(compression())
// ---------------------------------------- // ----------------------------------------
...@@ -86,8 +87,8 @@ app.use(mw.security) ...@@ -86,8 +87,8 @@ app.use(mw.security)
// Public Assets // Public Assets
// ---------------------------------------- // ----------------------------------------
app.use(favicon(path.join(ROOTPATH, 'assets', 'favicon.ico'))) app.use(favicon(path.join(wiki.ROOTPATH, 'assets', 'favicon.ico')))
app.use(express.static(path.join(ROOTPATH, 'assets'), { app.use(express.static(path.join(wiki.ROOTPATH, 'assets'), {
index: false, index: false,
maxAge: '7d' maxAge: '7d'
})) }))
...@@ -96,20 +97,19 @@ app.use(express.static(path.join(ROOTPATH, 'assets'), { ...@@ -96,20 +97,19 @@ app.use(express.static(path.join(ROOTPATH, 'assets'), {
// Passport Authentication // Passport Authentication
// ---------------------------------------- // ----------------------------------------
require('./libs/auth')(passport) require('./modules/auth')(passport)
global.rights = require('./libs/rights') wiki.rights = require('./modules/rights')
global.rights.init() wiki.rights.init()
let sessionStore = new SessionMongoStore({ let sessionStore = new SessionRedisStore({
mongooseConnection: global.db.connection, client: wiki.redis
touchAfter: 15
}) })
app.use(cookieParser()) app.use(cookieParser())
app.use(session({ app.use(session({
name: 'wikijs.sid', name: 'wikijs.sid',
store: sessionStore, store: sessionStore,
secret: appconfig.sessionSecret, secret: wiki.config.sessionSecret,
resave: false, resave: false,
saveUninitialized: false saveUninitialized: false
})) }))
...@@ -127,26 +127,24 @@ app.use(mw.seo) ...@@ -127,26 +127,24 @@ app.use(mw.seo)
// Localization Engine // Localization Engine
// ---------------------------------------- // ----------------------------------------
global.lang wiki.lang.use(i18nBackend).init({
.use(i18nBackend)
.init({
load: 'languageOnly', load: 'languageOnly',
ns: ['common', 'admin', 'auth', 'errors', 'git'], ns: ['common', 'admin', 'auth', 'errors', 'git'],
defaultNS: 'common', defaultNS: 'common',
saveMissing: false, saveMissing: false,
preload: [appconfig.lang], preload: [wiki.config.lang],
lng: appconfig.lang, lng: wiki.config.lang,
fallbackLng: 'en', fallbackLng: 'en',
backend: { backend: {
loadPath: path.join(SERVERPATH, 'locales/{{lng}}/{{ns}}.json') loadPath: path.join(wiki.SERVERPATH, 'locales/{{lng}}/{{ns}}.json')
} }
}) })
// ---------------------------------------- // ----------------------------------------
// View Engine Setup // View Engine Setup
// ---------------------------------------- // ----------------------------------------
app.set('views', path.join(SERVERPATH, 'views')) app.set('views', path.join(wiki.SERVERPATH, 'views'))
app.set('view engine', 'pug') app.set('view engine', 'pug')
app.use(bodyParser.json({ limit: '1mb' })) app.use(bodyParser.json({ limit: '1mb' }))
...@@ -157,10 +155,10 @@ app.use(bodyParser.urlencoded({ extended: false, limit: '1mb' })) ...@@ -157,10 +155,10 @@ app.use(bodyParser.urlencoded({ extended: false, limit: '1mb' }))
// ---------------------------------------- // ----------------------------------------
app.locals._ = require('lodash') 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 = require('moment')
app.locals.moment.locale(appconfig.lang) app.locals.moment.locale(wiki.config.lang)
app.locals.appconfig = appconfig app.locals.appconfig = wiki.config
app.use(mw.flash) app.use(mw.flash)
// ---------------------------------------- // ----------------------------------------
...@@ -187,7 +185,7 @@ app.use(function (err, req, res, next) { ...@@ -187,7 +185,7 @@ app.use(function (err, req, res, next) {
res.status(err.status || 500) res.status(err.status || 500)
res.render('error', { res.render('error', {
message: err.message, message: err.message,
error: IS_DEBUG ? err : {} error: wiki.IS_DEBUG ? err : {}
}) })
}) })
...@@ -195,13 +193,13 @@ app.use(function (err, req, res, next) { ...@@ -195,13 +193,13 @@ app.use(function (err, req, res, next) {
// Start HTTP server // 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 server = http.createServer(app)
var io = socketio(server) var io = socketio(server)
server.listen(appconfig.port) server.listen(wiki.config.port)
server.on('error', (error) => { server.on('error', (error) => {
if (error.syscall !== 'listen') { if (error.syscall !== 'listen') {
throw error throw error
...@@ -210,10 +208,10 @@ server.on('error', (error) => { ...@@ -210,10 +208,10 @@ server.on('error', (error) => {
// handle specific listen errors with friendly messages // handle specific listen errors with friendly messages
switch (error.code) { switch (error.code) {
case 'EACCES': 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) return process.exit(1)
case 'EADDRINUSE': 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) return process.exit(1)
default: default:
throw error throw error
...@@ -221,7 +219,7 @@ server.on('error', (error) => { ...@@ -221,7 +219,7 @@ server.on('error', (error) => {
}) })
server.on('listening', () => { 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', () => { ...@@ -231,7 +229,7 @@ server.on('listening', () => {
io.use(passportSocketIo.authorize({ io.use(passportSocketIo.authorize({
key: 'wikijs.sid', key: 'wikijs.sid',
store: sessionStore, store: sessionStore,
secret: appconfig.sessionSecret, secret: wiki.config.sessionSecret,
cookieParser, cookieParser,
success: (data, accept) => { success: (data, accept) => {
accept() accept()
...@@ -247,7 +245,7 @@ io.on('connection', ctrl.ws) ...@@ -247,7 +245,7 @@ io.on('connection', ctrl.ws)
// Start child processes // Start child processes
// ---------------------------------------- // ----------------------------------------
let bgAgent = fork(path.join(SERVERPATH, 'agent.js')) let bgAgent = fork(path.join(wiki.SERVERPATH, 'agent.js'))
bgAgent.on('message', m => { bgAgent.on('message', m => {
if (!m.action) { if (!m.action) {
...@@ -256,7 +254,7 @@ bgAgent.on('message', m => { ...@@ -256,7 +254,7 @@ bgAgent.on('message', m => {
switch (m.action) { switch (m.action) {
case 'searchAdd': case 'searchAdd':
global.search.add(m.content) wiki.search.add(m.content)
break break
} }
}) })
...@@ -266,11 +264,11 @@ bgAgent.on('message', m => { ...@@ -266,11 +264,11 @@ bgAgent.on('message', m => {
// ---------------------------------------- // ----------------------------------------
graceful.on('exit', () => { graceful.on('exit', () => {
global.winston.info('- SHUTTING DOWN - Terminating Background Agent...') wiki.logger.info('- SHUTTING DOWN - Terminating Background Agent...')
bgAgent.kill() bgAgent.kill()
global.winston.info('- SHUTTING DOWN - Performing git sync...') wiki.logger.info('- SHUTTING DOWN - Performing git sync...')
return global.git.resync().then(() => { 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() process.exit()
}) })
}) })
'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)
}
'use strict'
const Mongoose = require('mongoose')
/**
* BruteForce schema
*
* @type {<Mongoose.Schema>}
*/
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)
'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
}
'use strict'
const Mongoose = require('mongoose')
/**
* Entry schema
*
* @type {<Mongoose.Schema>}
*/
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)
'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
}
'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
}
'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
}
'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
}
'use strict' 'use strict'
const Mongoose = require('mongoose')
/** /**
* Settings schema * Settings schema
*
* @type {<Mongoose.Schema>}
*/ */
var settingSchema = Mongoose.Schema({ module.exports = (sequelize, DataTypes) => {
let settingSchema = sequelize.define('setting', {
key: { key: {
type: String, type: DataTypes.STRING,
required: true, allowNull: false
index: true
}, },
value: { config: {
type: String, type: DataTypes.JSONB,
required: true allowNull: false
}
}, {
timestamps: true,
version: true,
indexes: [
{
unique: true,
fields: ['key']
} }
}, { timestamps: {} }) ]
})
module.exports = Mongoose.model('Setting', settingSchema) return settingSchema
}
'use strict'
const Mongoose = require('mongoose')
/**
* Upload File schema
*
* @type {<Mongoose.Schema>}
*/
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)
'use strict'
const Mongoose = require('mongoose')
/**
* Upload Folder schema
*
* @type {<Mongoose.Schema>}
*/
var uplFolderSchema = Mongoose.Schema({
_id: String,
name: {
type: String,
index: true
}
}, { timestamps: {} })
module.exports = Mongoose.model('UplFolder', uplFolderSchema)
'use strict' 'use strict'
/* global db, lang */ /* global wiki */
const Mongoose = require('mongoose')
const Promise = require('bluebird') const Promise = require('bluebird')
const bcrypt = require('bcryptjs-then') const bcrypt = require('bcryptjs-then')
const _ = require('lodash') const _ = require('lodash')
/** /**
* Users schema * Users schema
*
* @type {<Mongoose.Schema>}
*/ */
var userSchema = Mongoose.Schema({ module.exports = (sequelize, DataTypes) => {
let userSchema = sequelize.define('user', {
email: { email: {
type: String, type: DataTypes.STRING,
required: true, allowNull: false,
index: true validate: {
isEmail: true
}
}, },
provider: { provider: {
type: String, type: DataTypes.ENUM(wiki.data.authProviders),
required: true allowNull: false
}, },
providerId: { providerId: {
type: String type: DataTypes.STRING,
allowNull: true
}, },
password: { password: {
type: String type: DataTypes.STRING,
allowNull: true
}, },
name: { name: {
type: String type: DataTypes.STRING,
allowNull: true
}, },
role: {
type: DataTypes.ENUM('admin', 'user', 'guest'),
allowNull: false
}
}, {
timestamps: true,
version: true,
indexes: [
{
unique: true,
fields: ['provider', 'email']
}
]
})
rights: [{ userSchema.prototype.validatePassword = function (rawPwd) {
role: String, return bcrypt.compare(rawPwd, this.password).then((isValid) => {
path: String, return (isValid) ? true : Promise.reject(new Error(wiki.lang.t('auth:errors:invalidlogin')))
exact: Boolean, })
deny: Boolean }
}]
}, { timestamps: {} })
userSchema.statics.processProfile = (profile) => { userSchema.processProfile = (profile) => {
let primaryEmail = '' let primaryEmail = ''
if (_.isArray(profile.emails)) { if (_.isArray(profile.emails)) {
let e = _.find(profile.emails, ['primary', true]) let e = _.find(profile.emails, ['primary', true])
...@@ -58,13 +67,13 @@ userSchema.statics.processProfile = (profile) => { ...@@ -58,13 +67,13 @@ userSchema.statics.processProfile = (profile) => {
} else if (profile.user && profile.user.email && profile.user.email.length > 5) { } else if (profile.user && profile.user.email && profile.user.email.length > 5) {
primaryEmail = profile.user.email primaryEmail = profile.user.email
} else { } else {
return Promise.reject(new Error(lang.t('auth:errors.invaliduseremail'))) return Promise.reject(new Error(wiki.lang.t('auth:errors.invaliduseremail')))
} }
profile.provider = _.lowerCase(profile.provider) profile.provider = _.lowerCase(profile.provider)
primaryEmail = _.toLower(primaryEmail) primaryEmail = _.toLower(primaryEmail)
return db.User.findOneAndUpdate({ return wiki.db.User.findOneAndUpdate({
email: primaryEmail, email: primaryEmail,
provider: profile.provider provider: profile.provider
}, { }, {
...@@ -92,18 +101,13 @@ userSchema.statics.processProfile = (profile) => { ...@@ -92,18 +101,13 @@ userSchema.statics.processProfile = (profile) => {
} }
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) => { userSchema.hashPassword = (rawPwd) => {
return bcrypt.hash(rawPwd) return bcrypt.hash(rawPwd)
} }
userSchema.methods.validatePassword = function (rawPwd) { return userSchema
return bcrypt.compare(rawPwd, this.password).then((isValid) => {
return (isValid) ? true : Promise.reject(new Error(lang.t('auth:errors:invalidlogin')))
})
} }
module.exports = Mongoose.model('User', userSchema)
'use strict' 'use strict'
/* global wiki */
const fs = require('fs') const fs = require('fs')
const yaml = require('js-yaml') const yaml = require('js-yaml')
const _ = require('lodash') const _ = require('lodash')
...@@ -14,9 +16,9 @@ const cfgHelper = require('../helpers/config') ...@@ -14,9 +16,9 @@ const cfgHelper = require('../helpers/config')
*/ */
module.exports = (confPaths) => { module.exports = (confPaths) => {
confPaths = _.defaults(confPaths, { confPaths = _.defaults(confPaths, {
config: path.join(ROOTPATH, 'config.yml'), config: path.join(wiki.ROOTPATH, 'config.yml'),
data: path.join(SERVERPATH, 'app/data.yml'), data: path.join(wiki.SERVERPATH, 'app/data.yml'),
dataRegex: path.join(SERVERPATH, 'app/regex.js') dataRegex: path.join(wiki.SERVERPATH, 'app/regex.js')
}) })
let appconfig = {} let appconfig = {}
......
'use strict' 'use strict'
/* global ROOTPATH, appconfig, winston */ /* global wiki */
const modb = require('mongoose')
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
const _ = require('lodash') const _ = require('lodash')
/** /**
* MongoDB module * PostgreSQL DB module
*
* @return {Object} MongoDB wrapper instance
*/ */
module.exports = { module.exports = {
Sequelize: require('sequelize'),
/** /**
* Initialize DB * Initialize DB
* *
...@@ -22,40 +21,52 @@ module.exports = { ...@@ -22,40 +21,52 @@ module.exports = {
init() { init() {
let self = this let self = this
let dbModelsPath = path.join(SERVERPATH, 'models') let dbModelsPath = path.join(wiki.SERVERPATH, 'models')
modb.Promise = require('bluebird')
// Event handlers // Define Sequelize instance
modb.connection.on('error', err => { self.inst = new self.Sequelize(wiki.config.db.db, wiki.config.db.user, wiki.config.db.pass, {
winston.error('Failed to connect to MongoDB instance.') host: wiki.config.db.host,
return err port: wiki.config.db.port,
}) dialect: 'postgres',
modb.connection.once('open', function () { pool: {
winston.log('Connected to MongoDB instance.') max: 10,
min: 0,
idle: 10000
}
}) })
// Store connection handle // Attempt to connect and authenticate to DB
self.connection = modb.connection self.inst.authenticate().then(() => {
self.ObjectId = modb.Types.ObjectId wiki.logger.info('Connected to PostgreSQL database.')
}).catch(err => {
wiki.logger.error('Failed to connect to MongoDB instance.')
return err
})
// Load DB Models // Load DB Models
fs fs
.readdirSync(dbModelsPath) .readdirSync(dbModelsPath)
.filter(function (file) { .filter(function (file) {
return (file.indexOf('.') !== 0) return (file.indexOf('.') !== 0 && file.indexOf('_') !== 0)
}) })
.forEach(function (file) { .forEach(function (file) {
let modelName = _.upperFirst(_.camelCase(_.split(file, '.')[0])) let modelName = _.upperFirst(_.camelCase(_.split(file, '.')[0]))
self[modelName] = require(path.join(dbModelsPath, file)) self[modelName] = self.inst.import(path.join(dbModelsPath, file))
}) })
// Connect // Associate DB Models
require(path.join(dbModelsPath, '_relations.js'))(self)
self.onReady = modb.connect(appconfig.db, { useMongoClient: true }) // Sync DB
self.onReady = self.inst.sync({
force: false,
logging: wiki.logger.verbose
})
return self return self
} }
......
'use strict' 'use strict'
/* global lang, winston */ /* global wiki */
const path = require('path') const path = require('path')
const Promise = require('bluebird') const Promise = require('bluebird')
...@@ -10,7 +10,7 @@ const os = require('os') ...@@ -10,7 +10,7 @@ const os = require('os')
const _ = require('lodash') const _ = require('lodash')
/** /**
* Local Data Storage * Local Disk Storage
*/ */
module.exports = { module.exports = {
...@@ -21,29 +21,24 @@ module.exports = { ...@@ -21,29 +21,24 @@ module.exports = {
/** /**
* Initialize Local Data Storage model * Initialize Local Data Storage model
*
* @return {Object} Local Data Storage model instance
*/ */
init () { init () {
this._uploadsPath = path.resolve(ROOTPATH, appconfig.paths.repo, 'uploads') this._uploadsPath = path.resolve(wiki.ROOTPATH, wiki.config.paths.repo, 'uploads')
this._uploadsThumbsPath = path.resolve(ROOTPATH, appconfig.paths.data, 'thumbs') this._uploadsThumbsPath = path.resolve(wiki.ROOTPATH, wiki.config.paths.data, 'thumbs')
this.createBaseDirectories(appconfig) this.createBaseDirectories()
this.initMulter(appconfig) this.initMulter()
return this return this
}, },
/** /**
* Init Multer upload handlers * Init Multer upload handlers
*
* @param {Object} appconfig The application config
* @return {boolean} Void
*/ */
initMulter (appconfig) { initMulter () {
let maxFileSizes = { let maxFileSizes = {
img: appconfig.uploads.maxImageFileSize * 1024 * 1024, img: wiki.config.uploads.maxImageFileSize * 1024 * 1024,
file: appconfig.uploads.maxOtherFileSize * 1024 * 1024 file: wiki.config.uploads.maxOtherFileSize * 1024 * 1024
} }
// -> IMAGES // -> IMAGES
...@@ -51,7 +46,7 @@ module.exports = { ...@@ -51,7 +46,7 @@ module.exports = {
this.uploadImgHandler = multer({ this.uploadImgHandler = multer({
storage: multer.diskStorage({ storage: multer.diskStorage({
destination: (req, f, cb) => { 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) => { fileFilter: (req, f, cb) => {
...@@ -76,7 +71,7 @@ module.exports = { ...@@ -76,7 +71,7 @@ module.exports = {
this.uploadFileHandler = multer({ this.uploadFileHandler = multer({
storage: multer.diskStorage({ storage: multer.diskStorage({
destination: (req, f, cb) => { 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) => { fileFilter: (req, f, cb) => {
...@@ -95,35 +90,32 @@ module.exports = { ...@@ -95,35 +90,32 @@ module.exports = {
/** /**
* Creates a base directories (Synchronous). * Creates a base directories (Synchronous).
*
* @param {Object} appconfig The application config
* @return {Void} Void
*/ */
createBaseDirectories (appconfig) { createBaseDirectories () {
winston.info('Checking data directories...') wiki.logger.info('Checking data directories...')
try { try {
fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.data)) fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data))
fs.emptyDirSync(path.resolve(ROOTPATH, appconfig.paths.data)) fs.emptyDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data))
fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.data, './cache')) fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data, './cache'))
fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.data, './thumbs')) fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data, './thumbs'))
fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.data, './temp-upload')) fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.data, './temp-upload'))
if (os.type() !== 'Windows_NT') { 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(wiki.ROOTPATH, wiki.config.paths.repo))
fs.ensureDirSync(path.resolve(ROOTPATH, appconfig.paths.repo, './uploads')) fs.ensureDirSync(path.resolve(wiki.ROOTPATH, wiki.config.paths.repo, './uploads'))
if (os.type() !== 'Windows_NT') { 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) { } 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 = { ...@@ -154,7 +146,7 @@ module.exports = {
*/ */
validateUploadsFilename (f, fld, isImage) { validateUploadsFilename (f, fld, isImage) {
let fObj = path.parse(f) 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) let fext = _.toLower(fObj.ext)
if (isImage && !_.includes(['.jpg', '.jpeg', '.png', '.gif', '.webp'], fext)) { if (isImage && !_.includes(['.jpg', '.jpeg', '.png', '.gif', '.webp'], fext)) {
...@@ -165,7 +157,7 @@ module.exports = { ...@@ -165,7 +157,7 @@ module.exports = {
let fpath = path.resolve(this._uploadsPath, fld, f) let fpath = path.resolve(this._uploadsPath, fld, f)
return fs.statAsync(fpath).then((s) => { 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) => { }).catch((err) => {
if (err.code === 'ENOENT') { if (err.code === 'ENOENT') {
return f return f
......
'use strict' 'use strict'
/* global db, git, lang, mark, rights, search, winston */ /* global wiki */
const Promise = require('bluebird') const Promise = require('bluebird')
const path = require('path') const path = require('path')
...@@ -25,10 +25,10 @@ module.exports = { ...@@ -25,10 +25,10 @@ module.exports = {
init() { init() {
let self = this let self = this
self._repoPath = path.resolve(ROOTPATH, appconfig.paths.repo) self._repoPath = path.resolve(wiki.ROOTPATH, wiki.config.paths.repo)
self._cachePath = path.resolve(ROOTPATH, appconfig.paths.data, 'cache') self._cachePath = path.resolve(wiki.ROOTPATH, wiki.config.paths.data, 'cache')
appdata.repoPath = self._repoPath wiki.data.repoPath = self._repoPath
appdata.cachePath = self._cachePath wiki.data.cachePath = self._cachePath
return self return self
}, },
......
'use strict' 'use strict'
/* global lang, winston */ /* global wiki */
const Git = require('git-wrapper2-promise') const Git = require('git-wrapper2-promise')
const Promise = require('bluebird') const Promise = require('bluebird')
...@@ -43,20 +43,20 @@ module.exports = { ...@@ -43,20 +43,20 @@ module.exports = {
// -> Build repository path // -> Build repository path
if (_.isEmpty(appconfig.paths.repo)) { if (_.isEmpty(wiki.config.paths.repo)) {
self._repo.path = path.join(ROOTPATH, 'repo') self._repo.path = path.join(wiki.ROOTPATH, 'repo')
} else { } else {
self._repo.path = appconfig.paths.repo self._repo.path = wiki.config.paths.repo
} }
// -> Initialize repository // -> Initialize repository
self.onReady = self._initRepo(appconfig) self.onReady = self._initRepo()
// Define signature // Define signature
if (appconfig.git) { if (wiki.config.git) {
self._signature.email = appconfig.git.serverEmail || 'wiki@example.com' self._signature.email = wiki.config.git.serverEmail || 'wiki@example.com'
} }
return self return self
...@@ -65,19 +65,19 @@ module.exports = { ...@@ -65,19 +65,19 @@ module.exports = {
/** /**
* Initialize Git repository * Initialize Git repository
* *
* @param {Object} appconfig The application config * @param {Object} wiki.config The application config
* @return {Object} Promise * @return {Object} Promise
*/ */
_initRepo(appconfig) { _initRepo() {
let self = this let self = this
winston.info('Checking Git repository...') wiki.logger.info('Checking Git repository...')
// -> Check if path is accessible // -> Check if path is accessible
return fs.mkdirAsync(self._repo.path).catch((err) => { return fs.mkdirAsync(self._repo.path).catch((err) => {
if (err.code !== 'EEXIST') { if (err.code !== 'EEXIST') {
winston.error('Invalid Git repository path or missing permissions.') wiki.logger.error('Invalid Git repository path or missing permissions.')
} }
}).then(() => { }).then(() => {
self._git = new Git({ 'git-dir': self._repo.path }) self._git = new Git({ 'git-dir': self._repo.path })
...@@ -91,28 +91,28 @@ module.exports = { ...@@ -91,28 +91,28 @@ module.exports = {
self._repo.exists = false self._repo.exists = false
}) })
}).then(() => { }).then(() => {
if (appconfig.git === false) { if (wiki.config.git === false) {
winston.info('Remote Git syncing is disabled. Not recommended!') wiki.logger.info('Remote Git syncing is disabled. Not recommended!')
return Promise.resolve(true) return Promise.resolve(true)
} }
// Initialize remote // Initialize remote
let urlObj = URL.parse(appconfig.git.url) let urlObj = URL.parse(wiki.config.git.url)
if (appconfig.git.auth.type !== 'ssh') { if (wiki.config.git.auth.type !== 'ssh') {
urlObj.auth = appconfig.git.auth.username + ':' + appconfig.git.auth.password urlObj.auth = wiki.config.git.auth.username + ':' + wiki.config.git.auth.password
} }
self._url = URL.format(urlObj) self._url = URL.format(urlObj)
let gitConfigs = [ let gitConfigs = [
() => { return self._git.exec('config', ['--local', 'user.name', 'Wiki']) }, () => { 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', '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(() => { 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 = { ...@@ -125,14 +125,14 @@ module.exports = {
return self._git.exec('remote', ['set-url', 'origin', self._url]) return self._git.exec('remote', ['set-url', 'origin', self._url])
} }
}).catch(err => { }).catch(err => {
winston.error(err) wiki.logger.error(err)
}) })
}) })
}).catch((err) => { }).catch((err) => {
winston.error('Git remote error!') wiki.logger.error('Git remote error!')
throw err throw err
}).then(() => { }).then(() => {
winston.info('Git repository is OK.') wiki.logger.info('Git repository is OK.')
return true return true
}) })
}, },
...@@ -143,7 +143,7 @@ module.exports = { ...@@ -143,7 +143,7 @@ module.exports = {
* @return {String} The repo path. * @return {String} The repo path.
*/ */
getRepoPath() { getRepoPath() {
return this._repo.path || path.join(ROOTPATH, 'repo') return this._repo.path || path.join(wiki.ROOTPATH, 'repo')
}, },
/** /**
...@@ -156,18 +156,18 @@ module.exports = { ...@@ -156,18 +156,18 @@ module.exports = {
// Is git remote disabled? // Is git remote disabled?
if (appconfig.git === false) { if (wiki.config.git === false) {
return Promise.resolve(true) return Promise.resolve(true)
} }
// Fetch // 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) => { return self._git.pull('origin', self._repo.branch).then((cProc) => {
winston.info('Git Pull completed.') wiki.logger.info('Git Pull completed.')
}) })
.catch((err) => { .catch((err) => {
winston.error('Unable to fetch from git origin!') wiki.logger.error('Unable to fetch from git origin!')
throw err throw err
}) })
.then(() => { .then(() => {
...@@ -177,19 +177,19 @@ module.exports = { ...@@ -177,19 +177,19 @@ module.exports = {
let out = cProc.stdout.toString() let out = cProc.stdout.toString()
if (_.includes(out, 'commit')) { 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 self._git.push('origin', self._repo.branch).then(() => {
return winston.info('Git Push completed.') return wiki.logger.info('Git Push completed.')
}) })
} else { } else {
winston.info('Git Push skipped. Repository is already in sync.') wiki.logger.info('Git Push skipped. Repository is already in sync.')
} }
return true return true
}) })
}) })
.catch((err) => { .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 throw err
}) })
}, },
...@@ -209,7 +209,7 @@ module.exports = { ...@@ -209,7 +209,7 @@ module.exports = {
let out = cProc.stdout.toString() let out = cProc.stdout.toString()
return _.includes(out, gitFilePath) return _.includes(out, gitFilePath)
}).then((isTracked) => { }).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) return self._git.add(gitFilePath)
}).then(() => { }).then(() => {
let commitUsr = securityHelper.sanitizeCommitUser(author) let commitUsr = securityHelper.sanitizeCommitUser(author)
......
'use strict' 'use strict'
module.exports = (isDebug, processName) => { /* global wiki */
module.exports = (processName) => {
let winston = require('winston') let winston = require('winston')
if (typeof processName === 'undefined') { if (typeof processName === 'undefined') {
...@@ -10,10 +12,10 @@ module.exports = (isDebug, processName) => { ...@@ -10,10 +12,10 @@ module.exports = (isDebug, processName) => {
// Console // Console
let logger = new (winston.Logger)({ let logger = new (winston.Logger)({
level: (isDebug) ? 'debug' : 'info', level: (wiki.IS_DEBUG) ? 'debug' : 'info',
transports: [ transports: [
new (winston.transports.Console)({ new (winston.transports.Console)({
level: (isDebug) ? 'debug' : 'info', level: (wiki.IS_DEBUG) ? 'debug' : 'info',
prettyPrint: true, prettyPrint: true,
colorize: true, colorize: true,
silent: false, silent: false,
...@@ -28,48 +30,48 @@ module.exports = (isDebug, processName) => { ...@@ -28,48 +30,48 @@ module.exports = (isDebug, processName) => {
// External services // External services
if (appconfig.externalLogging.bugsnag) { if (wiki.config.externalLogging.bugsnag) {
const bugsnagTransport = require('./winston-transports/bugsnag') const bugsnagTransport = require('./winston-transports/bugsnag')
logger.add(bugsnagTransport, { logger.add(bugsnagTransport, {
level: 'warn', level: 'warn',
key: appconfig.externalLogging.bugsnag key: wiki.config.externalLogging.bugsnag
}) })
} }
if (appconfig.externalLogging.loggly) { if (wiki.config.externalLogging.loggly) {
require('winston-loggly-bulk') require('winston-loggly-bulk')
logger.add(winston.transports.Loggly, { logger.add(winston.transports.Loggly, {
token: appconfig.externalLogging.loggly.token, token: wiki.config.externalLogging.loggly.token,
subdomain: appconfig.externalLogging.loggly.subdomain, subdomain: wiki.config.externalLogging.loggly.subdomain,
tags: ['wiki-js'], tags: ['wiki-js'],
level: 'warn', level: 'warn',
json: true json: true
}) })
} }
if (appconfig.externalLogging.papertrail) { if (wiki.config.externalLogging.papertrail) {
require('winston-papertrail').Papertrail // eslint-disable-line no-unused-expressions require('winston-papertrail').Papertrail // eslint-disable-line no-unused-expressions
logger.add(winston.transports.Papertrail, { logger.add(winston.transports.Papertrail, {
host: appconfig.externalLogging.papertrail.host, host: wiki.config.externalLogging.papertrail.host,
port: appconfig.externalLogging.papertrail.port, port: wiki.config.externalLogging.papertrail.port,
level: 'warn', level: 'warn',
program: 'wiki.js' program: 'wiki.js'
}) })
} }
if (appconfig.externalLogging.rollbar) { if (wiki.config.externalLogging.rollbar) {
const rollbarTransport = require('./winston-transports/rollbar') const rollbarTransport = require('./winston-transports/rollbar')
logger.add(rollbarTransport, { logger.add(rollbarTransport, {
level: 'warn', 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') const sentryTransport = require('./winston-transports/sentry')
logger.add(sentryTransport, { logger.add(sentryTransport, {
level: 'warn', level: 'warn',
key: appconfig.externalLogging.sentry key: wiki.config.externalLogging.sentry
}) })
} }
......
'use strict' 'use strict'
/* global winston */ /* global wiki */
const Promise = require('bluebird') const Promise = require('bluebird')
const md = require('markdown-it') const md = require('markdown-it')
...@@ -23,11 +23,11 @@ const mdRemove = require('remove-markdown') ...@@ -23,11 +23,11 @@ const mdRemove = require('remove-markdown')
var mkdown = md({ var mkdown = md({
html: true, html: true,
breaks: appconfig.features.linebreaks, breaks: wiki.config.features.linebreaks,
linkify: true, linkify: true,
typography: true, typography: true,
highlight(str, lang) { highlight(str, lang) {
if (appconfig.theme.code.colorize && lang && hljs.getLanguage(lang)) { if (wiki.config.theme.code.colorize && lang && hljs.getLanguage(lang)) {
try { try {
return '<pre class="hljs"><code>' + hljs.highlight(lang, str, true).value + '</code></pre>' return '<pre class="hljs"><code>' + hljs.highlight(lang, str, true).value + '</code></pre>'
} catch (err) { } catch (err) {
...@@ -57,7 +57,7 @@ var mkdown = md({ ...@@ -57,7 +57,7 @@ var mkdown = md({
}) })
.use(mdAttrs) .use(mdAttrs)
if (appconfig.features.mathjax) { if (wiki.config.features.mathjax) {
mkdown.use(mdMathjax) mkdown.use(mdMathjax)
} }
...@@ -94,7 +94,7 @@ const videoRules = [ ...@@ -94,7 +94,7 @@ const videoRules = [
// Regex // 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 = [ const mathRegex = [
{ {
format: 'TeX', format: 'TeX',
...@@ -301,7 +301,7 @@ const parseContent = (content) => { ...@@ -301,7 +301,7 @@ const parseContent = (content) => {
// Mathjax Post-processor // Mathjax Post-processor
if (appconfig.features.mathjax) { if (wiki.config.features.mathjax) {
return processMathjax(cr.html()) return processMathjax(cr.html())
} else { } else {
return Promise.resolve(cr.html()) return Promise.resolve(cr.html())
...@@ -339,7 +339,7 @@ const processMathjax = (content) => { ...@@ -339,7 +339,7 @@ const processMathjax = (content) => {
resolve(result.svg) resolve(result.svg)
} else { } else {
resolve(currentMatch[0]) resolve(currentMatch[0])
winston.warn(result.errors.join(', ')) wiki.logger.warn(result.errors.join(', '))
} }
}) })
}) })
......
'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)
}
}
}
'use strict' 'use strict'
/* global db */ /* global wiki */
const _ = require('lodash') const _ = require('lodash')
...@@ -32,8 +32,8 @@ module.exports = { ...@@ -32,8 +32,8 @@ module.exports = {
init () { init () {
let self = this let self = this
db.onReady.then(() => { wiki.db.onReady.then(() => {
db.User.findOne({ provider: 'local', email: 'guest' }).then((u) => { wiki.db.User.findOne({ provider: 'local', email: 'guest' }).then((u) => {
if (u) { if (u) {
self.guest = u self.guest = u
} }
......
'use strict' 'use strict'
/* global winston */ /* global wiki */
const Promise = require('bluebird') const Promise = require('bluebird')
const _ = require('lodash') const _ = require('lodash')
const searchIndex = require('./search-index') const searchIndex = require('./search-index')
const stopWord = require('stopword') const stopWord = require('stopword')
const streamToPromise = require('stream-to-promise') 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 = { module.exports = {
...@@ -27,15 +27,15 @@ module.exports = { ...@@ -27,15 +27,15 @@ module.exports = {
fieldedSearch: true, fieldedSearch: true,
indexPath: 'wiki', indexPath: 'wiki',
logLevel: 'error', logLevel: 'error',
stopwords: _.get(stopWord, appconfig.lang, []) stopwords: _.get(stopWord, wiki.config.lang, [])
}, (err, si) => { }, (err, si) => {
if (err) { if (err) {
winston.error('Failed to initialize search index.', err) wiki.logger.error('Failed to initialize search index.', err)
reject(err) reject(err)
} else { } else {
self._si = Promise.promisifyAll(si) self._si = Promise.promisifyAll(si)
self._si.flushAsync().then(() => { self._si.flushAsync().then(() => {
winston.info('Search index flushed and ready.') wiki.logger.info('Search index flushed and ready.')
resolve(true) resolve(true)
}) })
} }
...@@ -95,13 +95,13 @@ module.exports = { ...@@ -95,13 +95,13 @@ module.exports = {
parent: content.parent || '', parent: content.parent || '',
content: content.text || '' content: content.text || ''
}]).then(() => { }]).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 return true
}).catch((err) => { }).catch((err) => {
winston.error(err) wiki.logger.error(err)
}) })
}).catch((err) => { }).catch((err) => {
winston.error(err) wiki.logger.error(err)
}) })
}) })
}, },
...@@ -131,7 +131,7 @@ module.exports = { ...@@ -131,7 +131,7 @@ module.exports = {
if (err.type === 'NotFoundError') { if (err.type === 'NotFoundError') {
return true return true
} else { } else {
winston.error(err) wiki.logger.error(err)
} }
}) })
}) })
...@@ -204,7 +204,7 @@ module.exports = { ...@@ -204,7 +204,7 @@ module.exports = {
suggest: [] suggest: []
} }
} else { } else {
winston.error(err) wiki.logger.error(err)
} }
}) })
} }
......
'use strict' 'use strict'
/* global db, lang, lcdata, upl, winston */ /* global wiki */
const path = require('path') const path = require('path')
const Promise = require('bluebird') const Promise = require('bluebird')
...@@ -27,8 +27,8 @@ module.exports = { ...@@ -27,8 +27,8 @@ module.exports = {
* @return {Object} Uploads model instance * @return {Object} Uploads model instance
*/ */
init () { init () {
this._uploadsPath = path.resolve(ROOTPATH, appconfig.paths.repo, 'uploads') this._uploadsPath = path.resolve(wiki.ROOTPATH, wiki.config.paths.repo, 'uploads')
this._uploadsThumbsPath = path.resolve(ROOTPATH, appconfig.paths.data, 'thumbs') this._uploadsThumbsPath = path.resolve(wiki.ROOTPATH, wiki.config.paths.data, 'thumbs')
return this return this
}, },
...@@ -48,7 +48,7 @@ module.exports = { ...@@ -48,7 +48,7 @@ module.exports = {
* @return {Array<String>} The uploads folders. * @return {Array<String>} The uploads folders.
*/ */
getUploadsFolders () { 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: '' }] return (results) ? _.map(results, 'name') : [{ name: '' }]
}) })
}, },
...@@ -69,7 +69,7 @@ module.exports = { ...@@ -69,7 +69,7 @@ module.exports = {
} }
return fs.ensureDirAsync(path.join(self._uploadsPath, folderName)).then(() => { return fs.ensureDirAsync(path.join(self._uploadsPath, folderName)).then(() => {
return db.UplFolder.findOneAndUpdate({ return wiki.db.UplFolder.findOneAndUpdate({
_id: 'f:' + folderName _id: 'f:' + folderName
}, { }, {
name: folderName name: folderName
...@@ -88,7 +88,7 @@ module.exports = { ...@@ -88,7 +88,7 @@ module.exports = {
* @return {Boolean} True if valid * @return {Boolean} True if valid
*/ */
validateUploadsFolder (folderName) { 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 return (f) ? path.resolve(this._uploadsPath, folderName) : false
}) })
}, },
...@@ -101,7 +101,7 @@ module.exports = { ...@@ -101,7 +101,7 @@ module.exports = {
*/ */
addUploadsFiles (arrFiles) { addUploadsFiles (arrFiles) {
if (_.isArray(arrFiles) || _.isPlainObject(arrFiles)) { if (_.isArray(arrFiles) || _.isPlainObject(arrFiles)) {
// this._uploadsDb.Files.insert(arrFiles); // this._uploadswiki.Db.Files.insert(arrFiles);
} }
}, },
...@@ -113,7 +113,7 @@ module.exports = { ...@@ -113,7 +113,7 @@ module.exports = {
* @return {Array<Object>} The files matching the query * @return {Array<Object>} The files matching the query
*/ */
getUploadsFiles (cat, fld) { getUploadsFiles (cat, fld) {
return db.UplFile.find({ return wiki.db.UplFile.find({
category: cat, category: cat,
folder: 'f:' + fld folder: 'f:' + fld
}).sort('filename').exec() }).sort('filename').exec()
...@@ -128,7 +128,7 @@ module.exports = { ...@@ -128,7 +128,7 @@ module.exports = {
deleteUploadsFile (uid) { deleteUploadsFile (uid) {
let self = this let self = this
return db.UplFile.findOneAndRemove({ _id: uid }).then((f) => { return wiki.db.UplFile.findOneAndRemove({ _id: uid }).then((f) => {
if (f) { if (f) {
return self.deleteUploadsFileTry(f, 0) return self.deleteUploadsFileTry(f, 0)
} }
...@@ -150,7 +150,7 @@ module.exports = { ...@@ -150,7 +150,7 @@ module.exports = {
return self.deleteUploadsFileTry(f, attempt + 1) return self.deleteUploadsFileTry(f, attempt + 1)
}) })
} else { } 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 return true
} }
}) })
...@@ -168,12 +168,12 @@ module.exports = { ...@@ -168,12 +168,12 @@ module.exports = {
let fUrlFilename = _.last(_.split(fUrlObj.pathname, '/')) let fUrlFilename = _.last(_.split(fUrlObj.pathname, '/'))
let destFolder = _.chain(fFolder).trim().toLower().value() let destFolder = _.chain(fFolder).trim().toLower().value()
return upl.validateUploadsFolder(destFolder).then((destFolderPath) => { return wiki.upl.validateUploadsFolder(destFolder).then((destFolderPath) => {
if (!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) let destFilePath = path.resolve(destFolderPath, destFilename)
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
...@@ -194,7 +194,7 @@ module.exports = { ...@@ -194,7 +194,7 @@ module.exports = {
rq.abort() rq.abort()
destFileStream.destroy() destFileStream.destroy()
fs.remove(destFilePath) fs.remove(destFilePath)
reject(new Error(lang.t('errors:remotetoolarge'))) reject(new Error(wiki.lang.t('errors:remotetoolarge')))
} }
}).on('error', (err) => { }).on('error', (err) => {
destFileStream.destroy() destFileStream.destroy()
...@@ -223,15 +223,15 @@ module.exports = { ...@@ -223,15 +223,15 @@ module.exports = {
moveUploadsFile (uid, fld, nFilename) { moveUploadsFile (uid, fld, nFilename) {
let self = this let self = this
return db.UplFolder.findById('f:' + fld).then((folder) => { return wiki.db.UplFolder.finwiki.dById('f:' + fld).then((folder) => {
if (folder) { if (folder) {
return db.UplFile.findById(uid).then((originFile) => { return wiki.db.UplFile.finwiki.dById(uid).then((originFile) => {
// -> Check if rename is valid // -> Check if rename is valid
let nameCheck = null let nameCheck = null
if (nFilename) { if (nFilename) {
let originFileObj = path.parse(originFile.filename) let originFileObj = path.parse(originFile.filename)
nameCheck = lcdata.validateUploadsFilename(nFilename + originFileObj.ext, folder.name) nameCheck = wiki.disk.validateUploadsFilename(nFilename + originFileObj.ext, folder.name)
} else { } else {
nameCheck = Promise.resolve(originFile.filename) nameCheck = Promise.resolve(originFile.filename)
} }
...@@ -245,12 +245,12 @@ module.exports = { ...@@ -245,12 +245,12 @@ module.exports = {
// -> Check for invalid operations // -> Check for invalid operations
if (sourceFilePath === destFilePath) { 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 // -> Move thumbnail ahead to avoid re-generation
...@@ -273,7 +273,7 @@ module.exports = { ...@@ -273,7 +273,7 @@ module.exports = {
}) })
}) })
} else { } else {
return Promise.reject(new Error(lang.t('errors:invaliddestfolder'))) return Promise.reject(new Error(wiki.lang.t('errors:invaliddestfolder')))
} }
}) })
} }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
// =========================================== // ===========================================
// Wiki.js // Wiki.js
// 1.0.0 // 1.0.1
// Licensed under AGPLv3 // Licensed under AGPLv3
// =========================================== // ===========================================
......
This diff was suppressed by a .gitattributes entry.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment