Browse Source

chore: DB ref refactor + add scheduler db model + remove search modules (#5699)

Nicolas Giard 2 years ago
parent
commit
10cc2ef4b9
100 changed files with 519 additions and 2063 deletions
  1. 2 3
      config.sample.yml
  2. 1 0
      server/app/data.yml
  3. 11 11
      server/controllers/auth.js
  4. 15 17
      server/controllers/common.js
  5. 0 2
      server/controllers/ssl.js
  6. 2 4
      server/controllers/upload.js
  7. 0 2
      server/controllers/ws.js
  8. 0 2
      server/core/asar.js
  9. 10 12
      server/core/auth.js
  10. 14 8
      server/core/config.js
  11. 7 13
      server/core/db.js
  12. 0 2
      server/core/extensions.js
  13. 14 16
      server/core/kernel.js
  14. 0 2
      server/core/letsencrypt.js
  15. 0 2
      server/core/logger.js
  16. 0 2
      server/core/mail.js
  17. 36 41
      server/core/scheduler.js
  18. 0 2
      server/core/servers.js
  19. 3 5
      server/core/sideloader.js
  20. 0 2
      server/core/system.js
  21. 0 2
      server/db/legacy/index.js
  22. 44 2
      server/db/migrations/3.0.0.js
  23. 0 2
      server/db/migrator-source.js
  24. 0 2
      server/graph/index.js
  25. 2 4
      server/graph/resolvers/analytics.js
  26. 16 18
      server/graph/resolvers/asset.js
  27. 16 18
      server/graph/resolvers/authentication.js
  28. 9 11
      server/graph/resolvers/comment.js
  29. 11 13
      server/graph/resolvers/group.js
  30. 6 8
      server/graph/resolvers/hooks.js
  31. 2 4
      server/graph/resolvers/localization.js
  32. 0 2
      server/graph/resolvers/mail.js
  33. 2 4
      server/graph/resolvers/navigation.js
  34. 33 35
      server/graph/resolvers/page.js
  35. 2 4
      server/graph/resolvers/rendering.js
  36. 0 2
      server/graph/resolvers/search.js
  37. 23 25
      server/graph/resolvers/site.js
  38. 10 12
      server/graph/resolvers/storage.js
  39. 4 6
      server/graph/resolvers/system.js
  40. 18 20
      server/graph/resolvers/user.js
  41. 0 2
      server/helpers/page.js
  42. 0 1
      server/index.js
  43. 0 2
      server/middlewares/seo.js
  44. 2 4
      server/models/analytics.js
  45. 2 2
      server/models/apiKeys.js
  46. 3 5
      server/models/assetFolders.js
  47. 14 14
      server/models/assets.js
  48. 2 4
      server/models/authentication.js
  49. 3 5
      server/models/commentProviders.js
  50. 3 5
      server/models/comments.js
  51. 1 3
      server/models/editors.js
  52. 3 5
      server/models/hooks.js
  53. 1 3
      server/models/locales.js
  54. 3 5
      server/models/navigation.js
  55. 5 7
      server/models/pageHistory.js
  56. 64 66
      server/models/pages.js
  57. 4 6
      server/models/renderers.js
  58. 1 3
      server/models/settings.js
  59. 7 9
      server/models/sites.js
  60. 4 6
      server/models/storage.js
  61. 3 5
      server/models/tags.js
  62. 4 4
      server/models/userKeys.js
  63. 46 46
      server/models/users.js
  64. 1 1
      server/modules/authentication/auth0/authentication.js
  65. 1 3
      server/modules/authentication/azure/authentication.js
  66. 1 1
      server/modules/authentication/cas/authentication.js
  67. 1 1
      server/modules/authentication/discord/authentication.js
  68. 1 1
      server/modules/authentication/dropbox/authentication.js
  69. 1 1
      server/modules/authentication/facebook/authentication.js
  70. 1 1
      server/modules/authentication/github/authentication.js
  71. 1 1
      server/modules/authentication/gitlab/authentication.js
  72. 1 1
      server/modules/authentication/google/authentication.js
  73. 1 3
      server/modules/authentication/keycloak/authentication.js
  74. 1 1
      server/modules/authentication/ldap/authentication.js
  75. 1 1
      server/modules/authentication/local/authentication.js
  76. 1 1
      server/modules/authentication/microsoft/authentication.js
  77. 1 3
      server/modules/authentication/oauth2/authentication.js
  78. 1 3
      server/modules/authentication/oidc/authentication.js
  79. 1 1
      server/modules/authentication/okta/authentication.js
  80. 1 3
      server/modules/authentication/rocketchat/authentication.js
  81. 1 3
      server/modules/authentication/saml/authentication.js
  82. 1 1
      server/modules/authentication/slack/authentication.js
  83. 1 1
      server/modules/authentication/twitch/authentication.js
  84. 7 9
      server/modules/comments/default/comment.js
  85. 0 2
      server/modules/extensions/puppeteer/ext.js
  86. 0 2
      server/modules/extensions/sharp/ext.js
  87. 4 6
      server/modules/rendering/html-core/renderer.js
  88. 0 2
      server/modules/rendering/markdown-katex/renderer.js
  89. 0 2
      server/modules/rendering/markdown-mathjax/renderer.js
  90. 0 24
      server/modules/search/algolia/definition.yml
  91. 0 203
      server/modules/search/algolia/engine.js
  92. 0 88
      server/modules/search/aws/definition.yml
  93. 0 370
      server/modules/search/aws/engine.js
  94. 0 24
      server/modules/search/azure/definition.yml
  95. 0 235
      server/modules/search/azure/engine.js
  96. 0 8
      server/modules/search/db/definition.yml
  97. 0 94
      server/modules/search/db/engine.js
  98. 0 47
      server/modules/search/elasticsearch/definition.yml
  99. 0 353
      server/modules/search/elasticsearch/engine.js
  100. 0 8
      server/modules/search/manticore/definition.yml

+ 2 - 3
config.sample.yml

@@ -129,6 +129,5 @@ bodyParserLimit: 5mb
 
 scheduler:
   # Maximum number of workers to run background cpu-intensive jobs.
-  # Make sure your PostgreSQL server can handle an extra connection
-  # for each worker!
-  workers: 3
+  # Leave 'auto' to use number of CPU cores as maximum.
+  workers: auto

+ 1 - 0
server/app/data.yml

@@ -80,6 +80,7 @@ defaults:
     maintainerEmail: security@requarks.io
 jobs:
   - task: background
+    identifier: purge-uploads
     pattern: '*/15 * * * *'
     payload:
       name: purgeUploads

+ 11 - 11
server/controllers/auth.js

@@ -10,7 +10,7 @@ const path = require('path')
 
 const bruteforce = new ExpressBrute(new BruteKnex({
   createTable: true,
-  knex: WIKI.models.knex
+  knex: WIKI.db.knex
 }), {
   freeRetries: 5,
   minWait: 5 * 60 * 1000, // 5 minutes
@@ -26,7 +26,7 @@ const bruteforce = new ExpressBrute(new BruteKnex({
 router.get('/login', async (req, res, next) => {
   // -> Bypass Login
   if (WIKI.config.auth.autoLogin && !req.query.all) {
-    const stg = await WIKI.models.authentication.query().orderBy('order').first()
+    const stg = await WIKI.db.authentication.query().orderBy('order').first()
     const stgInfo = _.find(WIKI.data.authentication, ['key', stg.strategyKey])
     if (!stgInfo.useForm) {
       return res.redirect(`/login/${stg.key}`)
@@ -41,7 +41,7 @@ router.get('/login', async (req, res, next) => {
  */
 router.get('/login/:strategy', async (req, res, next) => {
   try {
-    await WIKI.models.users.login({
+    await WIKI.db.users.login({
       strategy: req.params.strategy
     }, { req, res })
   } catch (err) {
@@ -56,7 +56,7 @@ router.all('/login/:strategy/callback', async (req, res, next) => {
   if (req.method !== 'GET' && req.method !== 'POST') { return next() }
 
   try {
-    const authResult = await WIKI.models.users.login({
+    const authResult = await WIKI.db.users.login({
       strategy: req.params.strategy
     }, { req, res })
     res.cookie('jwt', authResult.jwt, { expires: moment().add(1, 'y').toDate() })
@@ -82,7 +82,7 @@ router.all('/login/:strategy/callback', async (req, res, next) => {
  * Logout
  */
 router.get('/logout', async (req, res, next) => {
-  const redirURL = await WIKI.models.users.logout({ req, res })
+  const redirURL = await WIKI.db.users.logout({ req, res })
   req.logout((err) => {
     if (err) { return next(err) }
     res.clearCookie('jwt')
@@ -95,7 +95,7 @@ router.get('/logout', async (req, res, next) => {
  */
 router.get('/register', async (req, res, next) => {
   _.set(res.locals, 'pageMeta.title', 'Register')
-  const localStrg = await WIKI.models.authentication.getStrategy('local')
+  const localStrg = await WIKI.db.authentication.getStrategy('local')
   if (localStrg.selfRegistration) {
     res.sendFile(path.join(WIKI.ROOTPATH, 'assets/index.html'))
   } else {
@@ -108,13 +108,13 @@ router.get('/register', async (req, res, next) => {
  */
 router.get('/verify/:token', bruteforce.prevent, async (req, res, next) => {
   try {
-    const usr = await WIKI.models.userKeys.validateToken({ kind: 'verify', token: req.params.token })
-    await WIKI.models.users.query().patch({ isVerified: true }).where('id', usr.id)
+    const usr = await WIKI.db.userKeys.validateToken({ kind: 'verify', token: req.params.token })
+    await WIKI.db.users.query().patch({ isVerified: true }).where('id', usr.id)
     req.brute.reset()
     if (WIKI.config.auth.enforce2FA) {
       res.redirect('/login')
     } else {
-      const result = await WIKI.models.users.refreshToken(usr)
+      const result = await WIKI.db.users.refreshToken(usr)
       res.cookie('jwt', result.token, { expires: moment().add(1, 'years').toDate() })
       res.redirect('/')
     }
@@ -128,13 +128,13 @@ router.get('/verify/:token', bruteforce.prevent, async (req, res, next) => {
  */
 router.get('/login-reset/:token', bruteforce.prevent, async (req, res, next) => {
   try {
-    const usr = await WIKI.models.userKeys.validateToken({ kind: 'resetPwd', token: req.params.token })
+    const usr = await WIKI.db.userKeys.validateToken({ kind: 'resetPwd', token: req.params.token })
     if (!usr) {
       throw new Error('Invalid Token')
     }
     req.brute.reset()
 
-    const changePwdContinuationToken = await WIKI.models.userKeys.generateToken({
+    const changePwdContinuationToken = await WIKI.db.userKeys.generateToken({
       userId: usr.id,
       kind: 'changePwd'
     })

+ 15 - 17
server/controllers/common.js

@@ -6,8 +6,6 @@ const CleanCSS = require('clean-css')
 const moment = require('moment')
 const path = require('path')
 
-/* global WIKI */
-
 const tmplCreateRegex = /^[0-9]+(,[0-9]+)?$/
 const siteAssetsPath = path.resolve(WIKI.ROOTPATH, WIKI.config.dataPath, 'assets')
 
@@ -27,7 +25,7 @@ router.get('/robots.txt', (req, res, next) => {
  * Health Endpoint
  */
 router.get('/healthz', (req, res, next) => {
-  if (WIKI.models.knex.client.pool.numFree() < 1 && WIKI.models.knex.client.pool.numUsed() < 1) {
+  if (WIKI.db.knex.client.pool.numFree() < 1 && WIKI.db.knex.client.pool.numUsed() < 1) {
     res.status(503).json({ ok: false }).end()
   } else {
     res.status(200).json({ ok: true }).end()
@@ -38,7 +36,7 @@ router.get('/healthz', (req, res, next) => {
  * Site Asset
  */
 router.get('/_site/:siteId?/:resource', async (req, res, next) => {
-  const site = req.params.siteId ? WIKI.sites[req.params.siteId] : await WIKI.models.sites.getSiteByHostname({ hostname: req.hostname })
+  const site = req.params.siteId ? WIKI.sites[req.params.siteId] : await WIKI.db.sites.getSiteByHostname({ hostname: req.hostname })
   if (!site) {
     return res.status(404).send('Site Not Found')
   }
@@ -115,7 +113,7 @@ router.get(['/d', '/d/*'], async (req, res, next) => {
 
   const versionId = (req.query.v) ? _.toSafeInteger(req.query.v) : 0
 
-  const page = await WIKI.models.pages.getPageFromDb({
+  const page = await WIKI.db.pages.getPageFromDb({
     path: pageArgs.path,
     locale: pageArgs.locale,
     userId: req.user.id,
@@ -140,7 +138,7 @@ router.get(['/d', '/d/*'], async (req, res, next) => {
     const fileName = _.last(page.path.split('/')) + '.' + pageHelper.getFileExtension(page.contentType)
     res.attachment(fileName)
     if (versionId > 0) {
-      const pageVersion = await WIKI.models.pageHistory.getVersion({ pageId: page.id, versionId })
+      const pageVersion = await WIKI.db.pageHistory.getVersion({ pageId: page.id, versionId })
       res.send(pageHelper.injectPageMetadata(pageVersion))
     } else {
       res.send(pageHelper.injectPageMetadata(page))
@@ -176,7 +174,7 @@ router.get(['/_edit', '/_edit/*'], async (req, res, next) => {
   }
 
   // -> Get page data from DB
-  let page = await WIKI.models.pages.getPageFromDb({
+  let page = await WIKI.db.pages.getPageFromDb({
     path: pageArgs.path,
     locale: pageArgs.locale,
     userId: req.user.id,
@@ -255,7 +253,7 @@ router.get(['/_edit', '/_edit/*'], async (req, res, next) => {
 
       if (tmplVersionId > 0) {
         // -> From Page Version
-        const pageVersion = await WIKI.models.pageHistory.getVersion({ pageId: tmplPageId, versionId: tmplVersionId })
+        const pageVersion = await WIKI.db.pageHistory.getVersion({ pageId: tmplPageId, versionId: tmplVersionId })
         if (!pageVersion) {
           _.set(res.locals, 'pageMeta.title', 'Page Not Found')
           return res.status(404).render('notfound', { action: 'template' })
@@ -270,7 +268,7 @@ router.get(['/_edit', '/_edit/*'], async (req, res, next) => {
         page.description = pageVersion.description
       } else {
         // -> From Page Live
-        const pageOriginal = await WIKI.models.pages.query().findById(tmplPageId)
+        const pageOriginal = await WIKI.db.pages.query().findById(tmplPageId)
         if (!pageOriginal) {
           _.set(res.locals, 'pageMeta.title', 'Page Not Found')
           return res.status(404).render('notfound', { action: 'template' })
@@ -305,7 +303,7 @@ router.get(['/h', '/h/*'], async (req, res, next) => {
   _.set(res, 'locals.siteConfig.lang', pageArgs.locale)
   _.set(res, 'locals.siteConfig.rtl', req.i18n.dir() === 'rtl')
 
-  const page = await WIKI.models.pages.getPageFromDb({
+  const page = await WIKI.db.pages.getPageFromDb({
     path: pageArgs.path,
     locale: pageArgs.locale,
     userId: req.user.id,
@@ -345,7 +343,7 @@ router.get(['/i', '/i/:id'], async (req, res, next) => {
     return res.redirect('/')
   }
 
-  const page = await WIKI.models.pages.query().column(['path', 'localeCode', 'isPrivate', 'privateNS']).findById(pageId)
+  const page = await WIKI.db.pages.query().column(['path', 'localeCode', 'isPrivate', 'privateNS']).findById(pageId)
   if (!page) {
     _.set(res.locals, 'pageMeta.title', 'Page Not Found')
     return res.status(404).render('notfound', { action: 'view' })
@@ -377,7 +375,7 @@ router.get(['/s', '/s/*'], async (req, res, next) => {
   const pageArgs = pageHelper.parsePath(req.path, { stripExt: true })
   const versionId = (req.query.v) ? _.toSafeInteger(req.query.v) : 0
 
-  const page = await WIKI.models.pages.getPageFromDb({
+  const page = await WIKI.db.pages.getPageFromDb({
     path: pageArgs.path,
     locale: pageArgs.locale,
     userId: req.user.id,
@@ -410,7 +408,7 @@ router.get(['/s', '/s/*'], async (req, res, next) => {
 
   if (page) {
     if (versionId > 0) {
-      const pageVersion = await WIKI.models.pageHistory.getVersion({ pageId: page.id, versionId })
+      const pageVersion = await WIKI.db.pageHistory.getVersion({ pageId: page.id, versionId })
       _.set(res.locals, 'pageMeta.title', pageVersion.title)
       _.set(res.locals, 'pageMeta.description', pageVersion.description)
       res.render('source', {
@@ -446,7 +444,7 @@ router.get('/_userav/:uid', async (req, res, next) => {
   if (!WIKI.auth.checkAccess(req.user, ['read:pages'])) {
     return res.sendStatus(403)
   }
-  const av = await WIKI.models.users.getUserAvatarData(req.params.uid)
+  const av = await WIKI.db.users.getUserAvatarData(req.params.uid)
   if (av) {
     res.set('Content-Type', 'image/jpeg')
     res.send(av)
@@ -472,7 +470,7 @@ router.get('/*', async (req, res, next) => {
 
     try {
       // -> Get Page from cache
-      const page = await WIKI.models.pages.getPage({
+      const page = await WIKI.db.pages.getPage({
         path: pageArgs.path,
         locale: pageArgs.locale,
         userId: req.user.id
@@ -519,7 +517,7 @@ router.get('/*', async (req, res, next) => {
 
         // -> Build sidebar navigation
         let sdi = 1
-        const sidebar = (await WIKI.models.navigation.getTree({ cache: true, locale: pageArgs.locale, groups: req.user.groups })).map(n => ({
+        const sidebar = (await WIKI.db.navigation.getTree({ cache: true, locale: pageArgs.locale, groups: req.user.groups })).map(n => ({
           i: `sdi-${sdi++}`,
           k: n.kind,
           l: n.label,
@@ -595,7 +593,7 @@ router.get('/*', async (req, res, next) => {
       return res.sendStatus(403)
     }
 
-    await WIKI.models.assets.getAsset(pageArgs.path, res)
+    await WIKI.db.assets.getAsset(pageArgs.path, res)
   }
 })
 

+ 0 - 2
server/controllers/ssl.js

@@ -3,8 +3,6 @@ const router = express.Router()
 const _ = require('lodash')
 const qs = require('querystring')
 
-/* global WIKI */
-
 /**
  * Let's Encrypt Challenge
  */

+ 2 - 4
server/controllers/upload.js

@@ -5,8 +5,6 @@ const multer = require('multer')
 const path = require('path')
 const sanitize = require('sanitize-filename')
 
-/* global WIKI */
-
 /**
  * Upload files
  */
@@ -66,7 +64,7 @@ router.post('/u', (req, res, next) => {
   let hierarchy = []
   if (folderId) {
     try {
-      hierarchy = await WIKI.models.assetFolders.getHierarchy(folderId)
+      hierarchy = await WIKI.db.assetFolders.getHierarchy(folderId)
     } catch (err) {
       return res.status(400).json({
         succeeded: false,
@@ -88,7 +86,7 @@ router.post('/u', (req, res, next) => {
   }
 
   // Process upload file
-  await WIKI.models.assets.upload({
+  await WIKI.db.assets.upload({
     ...fileMeta,
     mode: 'upload',
     folderId: folderId,

+ 0 - 2
server/controllers/ws.js

@@ -1,8 +1,6 @@
 const chalk = require('chalk')
 const os = require('node:os')
 
-/* global WIKI */
-
 module.exports = () => {
   WIKI.servers.ws.on('connection', (socket) => {
     // TODO: Validate token + permissions

+ 0 - 2
server/core/asar.js

@@ -3,8 +3,6 @@ const path = require('path')
 const UINT64 = require('cuint').UINT64
 const fs = require('fs')
 
-/* global WIKI */
-
 /**
  * Based of express-serve-asar (https://github.com/toyobayashi/express-serve-asar)
  * by Fenglin Li (https://github.com/toyobayashi)

+ 10 - 12
server/core/auth.js

@@ -10,8 +10,6 @@ const pem2jwk = require('pem-jwk').pem2jwk
 
 const securityHelper = require('../helpers/security')
 
-/* global WIKI */
-
 module.exports = {
   strategies: {},
   guest: {
@@ -33,7 +31,7 @@ module.exports = {
 
     passport.deserializeUser(async (id, done) => {
       try {
-        const user = await WIKI.models.users.query().findById(id).withGraphFetched('groups').modifyGraph('groups', builder => {
+        const user = await WIKI.db.users.query().findById(id).withGraphFetched('groups').modifyGraph('groups', builder => {
           builder.select('groups.id', 'permissions')
         })
         if (user) {
@@ -75,7 +73,7 @@ module.exports = {
       }))
 
       // Load enabled strategies
-      const enabledStrategies = await WIKI.models.authentication.getStrategies({ enabledOnly: true })
+      const enabledStrategies = await WIKI.db.authentication.getStrategies({ enabledOnly: true })
       for (const stg of enabledStrategies) {
         try {
           const strategy = require(`../modules/authentication/${stg.module}/authentication.js`)
@@ -144,7 +142,7 @@ module.exports = {
       if (mustRevalidate) {
         const jwtPayload = jwt.decode(securityHelper.extractJWT(req))
         try {
-          const newToken = await WIKI.models.users.refreshToken(jwtPayload.id, jwtPayload.pvd)
+          const newToken = await WIKI.db.users.refreshToken(jwtPayload.id, jwtPayload.pvd)
           user = newToken.user
           user.permissions = user.getPermissions()
           user.groups = user.getGroups()
@@ -162,7 +160,7 @@ module.exports = {
           return next()
         }
       } else if (user) {
-        user = await WIKI.models.users.getById(user.id)
+        user = await WIKI.db.users.getById(user.id)
         user.permissions = user.getPermissions()
         user.groups = user.getGroups()
         user.strategyId = strategyId
@@ -170,7 +168,7 @@ module.exports = {
       } else {
         // JWT is NOT valid, set as guest
         if (WIKI.auth.guest.cacheExpiration <= DateTime.utc()) {
-          WIKI.auth.guest = await WIKI.models.users.getGuestUser()
+          WIKI.auth.guest = await WIKI.db.users.getGuestUser()
           WIKI.auth.guest.cacheExpiration = DateTime.utc().plus({ minutes: 1 })
         }
         req.user = WIKI.auth.guest
@@ -349,7 +347,7 @@ module.exports = {
    * Reload Groups from DB
    */
   async reloadGroups () {
-    const groupsArray = await WIKI.models.groups.query()
+    const groupsArray = await WIKI.db.groups.query()
     this.groups = _.keyBy(groupsArray, 'id')
     WIKI.auth.guest.cacheExpiration = DateTime.utc().minus({ days: 1 })
   },
@@ -358,7 +356,7 @@ module.exports = {
    * Reload valid API Keys from DB
    */
   async reloadApiKeys () {
-    const keys = await WIKI.models.apiKeys.query().select('id').where('isRevoked', false).andWhere('expiration', '>', DateTime.utc().toISO())
+    const keys = await WIKI.db.apiKeys.query().select('id').where('isRevoked', false).andWhere('expiration', '>', DateTime.utc().toISO())
     this.validApiKeys = _.map(keys, 'id')
   },
 
@@ -405,14 +403,14 @@ module.exports = {
    */
   async resetGuestUser() {
     WIKI.logger.info('Resetting guest account...')
-    const guestGroup = await WIKI.models.groups.query().where('id', 2).first()
+    const guestGroup = await WIKI.db.groups.query().where('id', 2).first()
 
-    await WIKI.models.users.query().delete().where({
+    await WIKI.db.users.query().delete().where({
       providerKey: 'local',
       email: 'guest@example.com'
     }).orWhere('id', 2)
 
-    const guestUser = await WIKI.models.users.query().insert({
+    const guestUser = await WIKI.db.users.query().insert({
       id: 2,
       provider: 'local',
       email: 'guest@example.com',

+ 14 - 8
server/core/config.js

@@ -5,8 +5,6 @@ const fs = require('fs')
 const path = require('path')
 const yaml = require('js-yaml')
 
-/* global WIKI */
-
 module.exports = {
   /**
    * Load root config from disk
@@ -52,10 +50,18 @@ module.exports = {
 
     appconfig = _.defaultsDeep(appconfig, appdata.defaults.config)
 
+    // Override port
+
     if (appconfig.port < 1 || process.env.HEROKU) {
       appconfig.port = process.env.PORT || 80
     }
 
+    if (process.env.WIKI_PORT) {
+      appconfig.port = process.env.WIKI_PORT || 80
+    }
+
+    // Load package info
+
     const packageInfo = require(path.join(WIKI.ROOTPATH, 'package.json'))
 
     // Load DB Password from Docker Secret File
@@ -81,12 +87,12 @@ module.exports = {
    * Load config from DB
    */
   async loadFromDb() {
-    let conf = await WIKI.models.settings.getConfig()
+    let conf = await WIKI.db.settings.getConfig()
     if (conf) {
       WIKI.config = _.defaultsDeep(conf, WIKI.config)
     } else {
-      WIKI.logger.warn('DB Configuration is empty or incomplete. Switching to Setup mode...')
-      WIKI.config.setup = true
+      WIKI.logger.warn('Missing DB Configuration!')
+      process.exit(1)
     }
   },
   /**
@@ -102,9 +108,9 @@ module.exports = {
         if (!_.isPlainObject(value)) {
           value = { v: value }
         }
-        let affectedRows = await WIKI.models.settings.query().patch({ value }).where('key', key)
+        let affectedRows = await WIKI.db.settings.query().patch({ value }).where('key', key)
         if (affectedRows === 0 && value) {
-          await WIKI.models.settings.query().insert({ key, value })
+          await WIKI.db.settings.query().insert({ key, value })
         }
       }
       if (propagate) {
@@ -121,7 +127,7 @@ module.exports = {
    * Apply Dev Flags
    */
   async applyFlags() {
-    WIKI.models.knex.client.config.debug = WIKI.config.flags.sqllog
+    WIKI.db.knex.client.config.debug = WIKI.config.flags.sqllog
   },
 
   /**

+ 7 - 13
server/core/db.js

@@ -9,8 +9,6 @@ const Objection = require('objection')
 const migrationSource = require('../db/migrator-source')
 const migrateFromLegacy = require('../db/legacy')
 
-/* global WIKI */
-
 /**
  * ORM DB module
  */
@@ -144,17 +142,13 @@ module.exports = {
       }
     }
 
-    let initTasksQueue = (WIKI.IS_MASTER) ? [
-      initTasks.connect,
-      initTasks.migrateFromLegacy,
-      initTasks.syncSchemas
-    ] : [
-      () => { return Promise.resolve() }
-    ]
-
     // Perform init tasks
 
-    this.onReady = Promise.each(initTasksQueue, t => t()).return(true)
+    this.onReady = (async () => {
+      await initTasks.connect()
+      await initTasks.migrateFromLegacy()
+      await initTasks.syncSchemas()
+    })()
 
     return {
       ...this,
@@ -187,7 +181,7 @@ module.exports = {
 
     WIKI.auth.subscribeToEvents()
     WIKI.configSvc.subscribeToEvents()
-    WIKI.models.pages.subscribeToEvents()
+    WIKI.db.pages.subscribeToEvents()
 
     WIKI.logger.info(`PG PubSub Listener initialized successfully: [ OK ]`)
   },
@@ -208,7 +202,7 @@ module.exports = {
    * @param {object} value Payload of the event
    */
   notifyViaDB (event, value) {
-    WIKI.models.listener.publish('wiki', {
+    WIKI.db.listener.publish('wiki', {
       source: WIKI.INSTANCE_ID,
       event,
       value

+ 0 - 2
server/core/extensions.js

@@ -1,8 +1,6 @@
 const fs = require('fs-extra')
 const path = require('path')
 
-/* global WIKI */
-
 module.exports = {
   ext: {},
   async init () {

+ 14 - 16
server/core/kernel.js

@@ -3,8 +3,6 @@ const EventEmitter = require('eventemitter2').EventEmitter2
 
 let isShuttingDown = false
 
-/* global WIKI */
-
 module.exports = {
   async init() {
     WIKI.logger.info('=======================================')
@@ -12,10 +10,10 @@ module.exports = {
     WIKI.logger.info('=======================================')
     WIKI.logger.info('Initializing...')
 
-    WIKI.models = require('./db').init()
+    WIKI.db = require('./db').init()
 
     try {
-      await WIKI.models.onReady
+      await WIKI.db.onReady
       await WIKI.configSvc.loadFromDb()
       await WIKI.configSvc.applyFlags()
     } catch (err) {
@@ -64,21 +62,21 @@ module.exports = {
    * Post-Web Boot Sequence
    */
   async postBootWeb() {
-    await WIKI.models.analytics.refreshProvidersFromDisk()
-    await WIKI.models.authentication.refreshStrategiesFromDisk()
-    await WIKI.models.commentProviders.refreshProvidersFromDisk()
-    await WIKI.models.renderers.refreshRenderersFromDisk()
-    await WIKI.models.storage.refreshTargetsFromDisk()
+    await WIKI.db.analytics.refreshProvidersFromDisk()
+    await WIKI.db.authentication.refreshStrategiesFromDisk()
+    await WIKI.db.commentProviders.refreshProvidersFromDisk()
+    await WIKI.db.renderers.refreshRenderersFromDisk()
+    await WIKI.db.storage.refreshTargetsFromDisk()
 
     await WIKI.extensions.init()
 
     await WIKI.auth.activateStrategies()
-    await WIKI.models.commentProviders.initProvider()
-    await WIKI.models.sites.reloadCache()
-    await WIKI.models.storage.initTargets()
+    await WIKI.db.commentProviders.initProvider()
+    await WIKI.db.sites.reloadCache()
+    await WIKI.db.storage.initTargets()
     await WIKI.scheduler.start()
 
-    await WIKI.models.subscribeToNotifications()
+    await WIKI.db.subscribeToNotifications()
   },
   /**
    * Graceful shutdown
@@ -93,9 +91,9 @@ module.exports = {
       await WIKI.scheduler.stop()
     }
     if (WIKI.models) {
-      await WIKI.models.unsubscribeToNotifications()
-      if (WIKI.models.knex) {
-        await WIKI.models.knex.destroy()
+      await WIKI.db.unsubscribeToNotifications()
+      if (WIKI.db.knex) {
+        await WIKI.db.knex.destroy()
       }
     }
     if (WIKI.asar) {

+ 0 - 2
server/core/letsencrypt.js

@@ -6,8 +6,6 @@ const CSR = require('@root/csr')
 const PEM = require('@root/pem')
 const punycode = require('punycode/')
 
-/* global WIKI */
-
 module.exports = {
   apiDirectory: WIKI.dev ? 'https://acme-staging-v02.api.letsencrypt.org/directory' : 'https://acme-v02.api.letsencrypt.org/directory',
   acme: null,

+ 0 - 2
server/core/logger.js

@@ -1,8 +1,6 @@
 const chalk = require('chalk')
 const EventEmitter = require('events')
 
-/* global WIKI */
-
 const LEVELS = ['error', 'warn', 'info', 'debug']
 const LEVELSIGNORED = ['verbose', 'silly']
 const LEVELCOLORS = {

+ 0 - 2
server/core/mail.js

@@ -3,8 +3,6 @@ const _ = require('lodash')
 const fs = require('fs-extra')
 const path = require('path')
 
-/* global WIKI */
-
 module.exports = {
   transport: null,
   templates: {},

+ 36 - 41
server/core/scheduler.js

@@ -1,5 +1,3 @@
-const { run, parseCronItems, Logger } = require('graphile-worker')
-const { Pool } = require('pg')
 const { DynamicThreadPool } = require('poolifier')
 const { v4: uuid } = require('uuid')
 const os = require('node:os')
@@ -21,49 +19,46 @@ module.exports = {
   },
   async start () {
     WIKI.logger.info('Starting Scheduler...')
-    this.runner = await run({
-      pgPool: new Pool({
-        ...(typeof WIKI.models.config === 'string') ? {
-          connectionString: WIKI.models.config
-        } : WIKI.models.config,
-        max: this.maxWorkers + 2
-      }),
-      schema: WIKI.config.db.schemas.scheduler,
-      concurrency: this.maxWorkers,
-      noHandleSignals: true,
-      logger: new Logger(scope => {
-        return (level, message, meta) => {
-          const prefix = (scope?.workerId) ? `[${scope.workerId}] ` : ''
-          WIKI.logger[level](`${prefix}${message}`, meta)
-        }
-      }),
-      parsedCronItems: parseCronItems(WIKI.data.jobs.map(j => ({
-        ...j,
-        identifier: uuid()
-      }))),
-      taskList: {
-        simple: async (payload, helpers) => {
-          // TODO: Handle task
-        },
-        background: async (payload, helpers) => {
-          try {
-            await this.pool.execute({
-              id: helpers.job.id,
-              name: payload.name,
-              data: payload.data
-            })
-          } catch (err) {
-            helpers.logger.warn(`Failed job: ${err.message}`)
-            throw err
-          }
-        }
-      }
-    })
+    // this.runner = await run({
+    //   pgPool: new Pool({
+    //     ...(typeof WIKI.db.config === 'string') ? {
+    //       connectionString: WIKI.db.config
+    //     } : WIKI.db.config,
+    //     max: this.maxWorkers + 2
+    //   }),
+    //   schema: WIKI.config.db.schemas.scheduler,
+    //   concurrency: this.maxWorkers,
+    //   noHandleSignals: true,
+    //   logger: new Logger(scope => {
+    //     return (level, message, meta) => {
+    //       const prefix = (scope?.workerId) ? `[${scope.workerId}] ` : ''
+    //       WIKI.logger[level](`${prefix}${message}`, meta)
+    //     }
+    //   }),
+    //   parsedCronItems: parseCronItems(WIKI.data.jobs),
+    //   taskList: {
+    //     simple: async (payload, helpers) => {
+    //       // TODO: Handle task
+    //     },
+    //     background: async (payload, helpers) => {
+    //       try {
+    //         await this.pool.execute({
+    //           id: helpers.job.id,
+    //           name: payload.name,
+    //           data: payload.data
+    //         })
+    //       } catch (err) {
+    //         helpers.logger.warn(`Failed job: ${err.message}`)
+    //         throw err
+    //       }
+    //     }
+    //   }
+    // })
     WIKI.logger.info('Scheduler: [ STARTED ]')
   },
   async stop () {
     WIKI.logger.info('Stopping Scheduler...')
-    await this.runner.stop()
+    // await this.runner.stop()
     WIKI.logger.info('Scheduler: [ STOPPED ]')
   }
 }

+ 0 - 2
server/core/servers.js

@@ -8,8 +8,6 @@ const io = require('socket.io')
 const { ApolloServerPluginLandingPageGraphQLPlayground, ApolloServerPluginLandingPageProductionDefault } = require('apollo-server-core')
 const { graphqlUploadExpress } = require('graphql-upload')
 
-/* global WIKI */
-
 module.exports = {
   graph: null,
   http: null,

+ 3 - 5
server/core/sideloader.js

@@ -2,8 +2,6 @@ const fs = require('fs-extra')
 const path = require('path')
 const _ = require('lodash')
 
-/* global WIKI */
-
 module.exports = {
   async init () {
     if (!WIKI.config.offline) {
@@ -45,9 +43,9 @@ module.exports = {
                 _.set(lcObj, key.replace(':', '.'), value)
               })
 
-              const localeDbExists = await WIKI.models.locales.query().select('code').where('code', locale.code).first()
+              const localeDbExists = await WIKI.db.locales.query().select('code').where('code', locale.code).first()
               if (localeDbExists) {
-                await WIKI.models.locales.query().update({
+                await WIKI.db.locales.query().update({
                   code: locale.code,
                   strings: lcObj,
                   isRTL: locale.isRTL,
@@ -55,7 +53,7 @@ module.exports = {
                   nativeName: locale.nativeName
                 }).where('code', locale.code)
               } else {
-                await WIKI.models.locales.query().insert({
+                await WIKI.db.locales.query().insert({
                   code: locale.code,
                   strings: lcObj,
                   isRTL: locale.isRTL,

+ 0 - 2
server/core/system.js

@@ -1,8 +1,6 @@
 const fs = require('fs-extra')
 const path = require('path')
 
-/* global WIKI */
-
 module.exports = {
   updates: {
     channel: 'BETA',

+ 0 - 2
server/db/legacy/index.js

@@ -1,7 +1,5 @@
 const _ = require('lodash')
 
-/* global WIKI */
-
 module.exports = {
   async migrate (knex) {
     const migrationsTableExists = await knex.schema.hasTable('migrations')

+ 44 - 2
server/db/migrations/3.0.0.js

@@ -3,8 +3,6 @@ const bcrypt = require('bcryptjs-then')
 const crypto = require('crypto')
 const pem2jwk = require('pem-jwk').pem2jwk
 
-/* global WIKI */
-
 exports.up = async knex => {
   WIKI.logger.info('Running 3.0.0 database migration...')
 
@@ -122,6 +120,35 @@ exports.up = async knex => {
       table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
       table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
     })
+    // JOB SCHEDULE ------------------------
+    .createTable('jobSchedule', table => {
+      table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
+      table.string('task').notNullable()
+      table.string('cron').notNullable()
+      table.string('type').notNullable().defaultTo('system')
+      table.jsonb('payload')
+      table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
+      table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
+    })
+    // JOB HISTORY -------------------------
+    .createTable('jobHistory', table => {
+      table.uuid('id').notNullable().primary()
+      table.string('task').notNullable()
+      table.string('state').notNullable()
+      table.jsonb('payload')
+      table.string('lastErrorMessage')
+      table.timestamp('createdAt').notNullable()
+      table.timestamp('startedAt').notNullable()
+      table.timestamp('completedAt').notNullable().defaultTo(knex.fn.now())
+    })
+    // JOBS --------------------------------
+    .createTable('jobs', table => {
+      table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
+      table.string('task').notNullable()
+      table.jsonb('payload')
+      table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
+      table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
+    })
     // LOCALES -----------------------------
     .createTable('locales', table => {
       table.string('code', 5).notNullable().primary()
@@ -636,6 +663,21 @@ exports.up = async knex => {
     }
   })
 
+  // -> SCHEDULED JOBS
+
+  await knex('jobSchedule').insert([
+    {
+      task: 'update-locales',
+      cron: '0 0 * * *',
+      type: 'system'
+    },
+    {
+      task: 'check-version',
+      cron: '0 0 * * *',
+      type: 'system'
+    }
+  ])
+
   WIKI.logger.info('Completed 3.0.0 database migration.')
 }
 

+ 0 - 2
server/db/migrator-source.js

@@ -4,8 +4,6 @@ const semver = require('semver')
 
 const baseMigrationPath = path.join(WIKI.SERVERPATH, 'db/migrations')
 
-/* global WIKI */
-
 module.exports = {
   /**
    * Gets the migration names

+ 0 - 2
server/graph/index.js

@@ -6,8 +6,6 @@ const { makeExecutableSchema } = require('@graphql-tools/schema')
 const { defaultKeyGenerator, rateLimitDirective } = require('graphql-rate-limit-directive')
 const { GraphQLUpload } = require('graphql-upload')
 
-/* global WIKI */
-
 // Rate Limiter
 
 const { rateLimitDirectiveTypeDefs, rateLimitDirectiveTransformer } = rateLimitDirective({

+ 2 - 4
server/graph/resolvers/analytics.js

@@ -1,12 +1,10 @@
 const _ = require('lodash')
 const graphHelper = require('../../helpers/graph')
 
-/* global WIKI */
-
 module.exports = {
   Query: {
     async analyticsProviders(obj, args, context, info) {
-      let providers = await WIKI.models.analytics.getProviders(args.isEnabled)
+      let providers = await WIKI.db.analytics.getProviders(args.isEnabled)
       providers = providers.map(stg => {
         const providerInfo = _.find(WIKI.data.analytics, ['key', stg.key]) || {}
         return {
@@ -31,7 +29,7 @@ module.exports = {
     async updateAnalyticsProviders(obj, args, context) {
       try {
         for (let str of args.providers) {
-          await WIKI.models.analytics.query().patch({
+          await WIKI.db.analytics.query().patch({
             isEnabled: str.isEnabled,
             config: _.reduce(str.config, (result, value, key) => {
               _.set(result, `${value.key}`, _.get(JSON.parse(value.value), 'v', null))

+ 16 - 18
server/graph/resolvers/asset.js

@@ -3,8 +3,6 @@ const sanitize = require('sanitize-filename')
 const graphHelper = require('../../helpers/graph')
 const assetHelper = require('../../helpers/asset')
 
-/* global WIKI */
-
 module.exports = {
   Query: {
     async assets(obj, args, context) {
@@ -14,9 +12,9 @@ module.exports = {
       if (args.kind !== 'ALL') {
         cond.kind = args.kind.toLowerCase()
       }
-      const folderHierarchy = await WIKI.models.assetFolders.getHierarchy(args.folderId)
+      const folderHierarchy = await WIKI.db.assetFolders.getHierarchy(args.folderId)
       const folderPath = folderHierarchy.map(h => h.slug).join('/')
-      const results = await WIKI.models.assets.query().where(cond)
+      const results = await WIKI.db.assets.query().where(cond)
       return _.filter(results, r => {
         const path = folderPath ? `${folderPath}/${r.filename}` : r.filename
         return WIKI.auth.checkAccess(context.req.user, ['read:assets'], { path })
@@ -26,10 +24,10 @@ module.exports = {
       }))
     },
     async assetsFolders(obj, args, context) {
-      const results = await WIKI.models.assetFolders.query().where({
+      const results = await WIKI.db.assetFolders.query().where({
         parentId: args.parentFolderId === 0 ? null : args.parentFolderId
       })
-      const parentHierarchy = await WIKI.models.assetFolders.getHierarchy(args.parentFolderId)
+      const parentHierarchy = await WIKI.db.assetFolders.getHierarchy(args.parentFolderId)
       const parentPath = parentHierarchy.map(h => h.slug).join('/')
       return _.filter(results, r => {
         const path = parentPath ? `${parentPath}/${r.slug}` : r.slug
@@ -45,12 +43,12 @@ module.exports = {
       try {
         const folderSlug = sanitize(args.slug).toLowerCase()
         const parentFolderId = args.parentFolderId === 0 ? null : args.parentFolderId
-        const result = await WIKI.models.assetFolders.query().where({
+        const result = await WIKI.db.assetFolders.query().where({
           parentId: parentFolderId,
           slug: folderSlug
         }).first()
         if (!result) {
-          await WIKI.models.assetFolders.query().insert({
+          await WIKI.db.assetFolders.query().insert({
             slug: folderSlug,
             name: folderSlug,
             parentId: parentFolderId
@@ -72,7 +70,7 @@ module.exports = {
       try {
         const filename = sanitize(args.filename).toLowerCase()
 
-        const asset = await WIKI.models.assets.query().findById(args.id)
+        const asset = await WIKI.db.assets.query().findById(args.id)
         if (asset) {
           // Check for extension mismatch
           if (!_.endsWith(filename, asset.ext)) {
@@ -85,7 +83,7 @@ module.exports = {
           }
 
           // Check for collision
-          const assetCollision = await WIKI.models.assets.query().where({
+          const assetCollision = await WIKI.db.assets.query().where({
             filename,
             folderId: asset.folderId
           }).first()
@@ -96,7 +94,7 @@ module.exports = {
           // Get asset folder path
           let hierarchy = []
           if (asset.folderId) {
-            hierarchy = await WIKI.models.assetFolders.getHierarchy(asset.folderId)
+            hierarchy = await WIKI.db.assetFolders.getHierarchy(asset.folderId)
           }
 
           // Check source asset permissions
@@ -113,7 +111,7 @@ module.exports = {
 
           // Update filename + hash
           const fileHash = assetHelper.generateHash(assetTargetPath)
-          await WIKI.models.assets.query().patch({
+          await WIKI.db.assets.query().patch({
             filename: filename,
             hash: fileHash
           }).findById(args.id)
@@ -122,7 +120,7 @@ module.exports = {
           await asset.deleteAssetCache()
 
           // Rename in Storage
-          await WIKI.models.storage.assetEvent({
+          await WIKI.db.storage.assetEvent({
             event: 'renamed',
             asset: {
               ...asset,
@@ -149,7 +147,7 @@ module.exports = {
      */
     async deleteAsset(obj, args, context) {
       try {
-        const asset = await WIKI.models.assets.query().findById(args.id)
+        const asset = await WIKI.db.assets.query().findById(args.id)
         if (asset) {
           // Check permissions
           const assetPath = await asset.getAssetPath()
@@ -157,12 +155,12 @@ module.exports = {
             throw new WIKI.Error.AssetDeleteForbidden()
           }
 
-          await WIKI.models.knex('assetData').where('id', args.id).del()
-          await WIKI.models.assets.query().deleteById(args.id)
+          await WIKI.db.knex('assetData').where('id', args.id).del()
+          await WIKI.db.assets.query().deleteById(args.id)
           await asset.deleteAssetCache()
 
           // Delete from Storage
-          await WIKI.models.storage.assetEvent({
+          await WIKI.db.storage.assetEvent({
             event: 'deleted',
             asset: {
               ...asset,
@@ -188,7 +186,7 @@ module.exports = {
      */
     async flushTempUploads(obj, args, context) {
       try {
-        await WIKI.models.assets.flushTempUploads()
+        await WIKI.db.assets.flushTempUploads()
         return {
           responseResult: graphHelper.generateSuccess('Temporary Uploads have been flushed successfully.')
         }

+ 16 - 18
server/graph/resolvers/authentication.js

@@ -1,15 +1,13 @@
 const _ = require('lodash')
 const graphHelper = require('../../helpers/graph')
 
-/* global WIKI */
-
 module.exports = {
   Query: {
     /**
      * List of API Keys
      */
     async apiKeys (obj, args, context) {
-      const keys = await WIKI.models.apiKeys.query().orderBy(['isRevoked', 'name'])
+      const keys = await WIKI.db.apiKeys.query().orderBy(['isRevoked', 'name'])
       return keys.map(k => ({
         id: k.id,
         name: k.name,
@@ -39,14 +37,14 @@ module.exports = {
      * Fetch active authentication strategies
      */
     async authActiveStrategies (obj, args, context) {
-      return WIKI.models.authentication.getStrategies({ enabledOnly: args.enabledOnly })
+      return WIKI.db.authentication.getStrategies({ enabledOnly: args.enabledOnly })
     },
     /**
      * Fetch site authentication strategies
      */
     async authSiteStrategies (obj, args, context, info) {
-      const site = await WIKI.models.sites.query().findById(args.siteId)
-      const activeStrategies = await WIKI.models.authentication.getStrategies({ enabledOnly: true })
+      const site = await WIKI.db.sites.query().findById(args.siteId)
+      const activeStrategies = await WIKI.db.authentication.getStrategies({ enabledOnly: true })
       return activeStrategies.map(str => {
         const siteAuth = _.find(site.config.authStrategies, ['id', str.id]) || {}
         return {
@@ -64,7 +62,7 @@ module.exports = {
      */
     async createApiKey (obj, args, context) {
       try {
-        const key = await WIKI.models.apiKeys.createNewKey(args)
+        const key = await WIKI.db.apiKeys.createNewKey(args)
         await WIKI.auth.reloadApiKeys()
         WIKI.events.outbound.emit('reloadApiKeys')
         return {
@@ -81,7 +79,7 @@ module.exports = {
      */
     async login (obj, args, context) {
       try {
-        const authResult = await WIKI.models.users.login(args, context)
+        const authResult = await WIKI.db.users.login(args, context)
         return {
           ...authResult,
           operation: graphHelper.generateSuccess('Login success')
@@ -101,7 +99,7 @@ module.exports = {
      */
     async loginTFA (obj, args, context) {
       try {
-        const authResult = await WIKI.models.users.loginTFA(args, context)
+        const authResult = await WIKI.db.users.loginTFA(args, context)
         return {
           ...authResult,
           responseResult: graphHelper.generateSuccess('TFA success')
@@ -115,7 +113,7 @@ module.exports = {
      */
     async changePassword (obj, args, context) {
       try {
-        const authResult = await WIKI.models.users.loginChangePassword(args, context)
+        const authResult = await WIKI.db.users.loginChangePassword(args, context)
         return {
           ...authResult,
           responseResult: graphHelper.generateSuccess('Password changed successfully')
@@ -129,7 +127,7 @@ module.exports = {
      */
     async forgotPassword (obj, args, context) {
       try {
-        await WIKI.models.users.loginForgotPassword(args, context)
+        await WIKI.db.users.loginForgotPassword(args, context)
         return {
           responseResult: graphHelper.generateSuccess('Password reset request processed.')
         }
@@ -142,7 +140,7 @@ module.exports = {
      */
     async register (obj, args, context) {
       try {
-        await WIKI.models.users.register({ ...args, verify: true }, context)
+        await WIKI.db.users.register({ ...args, verify: true }, context)
         return {
           responseResult: graphHelper.generateSuccess('Registration success')
         }
@@ -169,7 +167,7 @@ module.exports = {
      */
     async revokeApiKey (obj, args, context) {
       try {
-        await WIKI.models.apiKeys.query().findById(args.id).patch({
+        await WIKI.db.apiKeys.query().findById(args.id).patch({
           isRevoked: true
         })
         await WIKI.auth.reloadApiKeys()
@@ -186,7 +184,7 @@ module.exports = {
      */
     async updateAuthStrategies (obj, args, context) {
       try {
-        const previousStrategies = await WIKI.models.authentication.getStrategies()
+        const previousStrategies = await WIKI.db.authentication.getStrategies()
         for (const str of args.strategies) {
           const newStr = {
             displayName: str.displayName,
@@ -202,13 +200,13 @@ module.exports = {
           }
 
           if (_.some(previousStrategies, ['key', str.key])) {
-            await WIKI.models.authentication.query().patch({
+            await WIKI.db.authentication.query().patch({
               key: str.key,
               strategyKey: str.strategyKey,
               ...newStr
             }).where('key', str.key)
           } else {
-            await WIKI.models.authentication.query().insert({
+            await WIKI.db.authentication.query().insert({
               key: str.key,
               strategyKey: str.strategyKey,
               ...newStr
@@ -217,11 +215,11 @@ module.exports = {
         }
 
         for (const str of _.differenceBy(previousStrategies, args.strategies, 'key')) {
-          const hasUsers = await WIKI.models.users.query().count('* as total').where({ providerKey: str.key }).first()
+          const hasUsers = await WIKI.db.users.query().count('* as total').where({ providerKey: str.key }).first()
           if (_.toSafeInteger(hasUsers.total) > 0) {
             throw new Error(`Cannot delete ${str.displayName} as 1 or more users are still using it.`)
           } else {
-            await WIKI.models.authentication.query().delete().where('key', str.key)
+            await WIKI.db.authentication.query().delete().where('key', str.key)
           }
         }
 

+ 9 - 11
server/graph/resolvers/comment.js

@@ -1,15 +1,13 @@
 const _ = require('lodash')
 const graphHelper = require('../../helpers/graph')
 
-/* global WIKI */
-
 module.exports = {
   Query: {
     /**
      * Fetch list of Comments Providers
      */
     async commentsProviders(obj, args, context, info) {
-      const providers = await WIKI.models.commentProviders.getProviders()
+      const providers = await WIKI.db.commentProviders.getProviders()
       return providers.map(provider => {
         const providerInfo = _.find(WIKI.data.commentProviders, ['key', provider.key]) || {}
         return {
@@ -34,10 +32,10 @@ module.exports = {
      * Fetch list of comments for a page
      */
     async comments (obj, args, context) {
-      const page = await WIKI.models.pages.query().select('id').findOne({ localeCode: args.locale, path: args.path })
+      const page = await WIKI.db.pages.query().select('id').findOne({ localeCode: args.locale, path: args.path })
       if (page) {
         if (WIKI.auth.checkAccess(context.req.user, ['read:comments'], args)) {
-          const comments = await WIKI.models.comments.query().where('pageId', page.id).orderBy('createdAt')
+          const comments = await WIKI.db.comments.query().where('pageId', page.id).orderBy('createdAt')
           return comments.map(c => ({
             ...c,
             authorName: c.name,
@@ -59,7 +57,7 @@ module.exports = {
       if (!cm || !cm.pageId) {
         throw new WIKI.Error.CommentNotFound()
       }
-      const page = await WIKI.models.pages.query().select('localeCode', 'path').findById(cm.pageId)
+      const page = await WIKI.db.pages.query().select('localeCode', 'path').findById(cm.pageId)
       if (page) {
         if (WIKI.auth.checkAccess(context.req.user, ['read:comments'], {
           path: page.path,
@@ -86,7 +84,7 @@ module.exports = {
      */
     async createComment (obj, args, context) {
       try {
-        const cmId = await WIKI.models.comments.postNewComment({
+        const cmId = await WIKI.db.comments.postNewComment({
           ...args,
           user: context.req.user,
           ip: context.req.ip
@@ -104,7 +102,7 @@ module.exports = {
      */
     async updateComment (obj, args, context) {
       try {
-        const cmRender = await WIKI.models.comments.updateComment({
+        const cmRender = await WIKI.db.comments.updateComment({
           ...args,
           user: context.req.user,
           ip: context.req.ip
@@ -122,7 +120,7 @@ module.exports = {
      */
     async deleteComment (obj, args, context) {
       try {
-        await WIKI.models.comments.deleteComment({
+        await WIKI.db.comments.deleteComment({
           id: args.id,
           user: context.req.user,
           ip: context.req.ip
@@ -140,7 +138,7 @@ module.exports = {
     async updateCommentsProviders(obj, args, context) {
       try {
         for (let provider of args.providers) {
-          await WIKI.models.commentProviders.query().patch({
+          await WIKI.db.commentProviders.query().patch({
             isEnabled: provider.isEnabled,
             config: _.reduce(provider.config, (result, value, key) => {
               _.set(result, `${value.key}`, _.get(JSON.parse(value.value), 'v', null))
@@ -148,7 +146,7 @@ module.exports = {
             }, {})
           }).where('key', provider.key)
         }
-        await WIKI.models.commentProviders.initProvider()
+        await WIKI.db.commentProviders.initProvider()
         return {
           responseResult: graphHelper.generateSuccess('Comment Providers updated successfully')
         }

+ 11 - 13
server/graph/resolvers/group.js

@@ -3,24 +3,22 @@ const safeRegex = require('safe-regex')
 const _ = require('lodash')
 const { v4: uuid } = require('uuid')
 
-/* global WIKI */
-
 module.exports = {
   Query: {
     /**
      * FETCH ALL GROUPS
      */
     async groups () {
-      return WIKI.models.groups.query().select(
+      return WIKI.db.groups.query().select(
         'groups.*',
-        WIKI.models.groups.relatedQuery('users').count().as('userCount')
+        WIKI.db.groups.relatedQuery('users').count().as('userCount')
       )
     },
     /**
      * FETCH A SINGLE GROUP
      */
     async groupById(obj, args) {
-      return WIKI.models.groups.query().findById(args.id)
+      return WIKI.db.groups.query().findById(args.id)
     }
   },
   Mutation: {
@@ -34,7 +32,7 @@ module.exports = {
       }
 
       // Check for valid group
-      const grp = await WIKI.models.groups.query().findById(args.groupId)
+      const grp = await WIKI.db.groups.query().findById(args.groupId)
       if (!grp) {
         throw new Error('Invalid Group ID')
       }
@@ -51,13 +49,13 @@ module.exports = {
       }
 
       // Check for valid user
-      const usr = await WIKI.models.users.query().findById(args.userId)
+      const usr = await WIKI.db.users.query().findById(args.userId)
       if (!usr) {
         throw new Error('Invalid User ID')
       }
 
       // Check for existing relation
-      const relExist = await WIKI.models.knex('userGroups').where({
+      const relExist = await WIKI.db.knex('userGroups').where({
         userId: args.userId,
         groupId: args.groupId
       }).first()
@@ -80,7 +78,7 @@ module.exports = {
      * CREATE NEW GROUP
      */
     async createGroup (obj, args, { req }) {
-      const group = await WIKI.models.groups.query().insertAndFetch({
+      const group = await WIKI.db.groups.query().insertAndFetch({
         name: args.name,
         permissions: JSON.stringify(WIKI.data.groups.defaultPermissions),
         rules: JSON.stringify(WIKI.data.groups.defaultRules.map(r => ({
@@ -104,7 +102,7 @@ module.exports = {
         throw new Error('Cannot delete this group.')
       }
 
-      await WIKI.models.groups.query().deleteById(args.id)
+      await WIKI.db.groups.query().deleteById(args.id)
 
       WIKI.auth.revokeUserTokens({ id: args.id, kind: 'g' })
       WIKI.events.outbound.emit('addAuthRevoke', { id: args.id, kind: 'g' })
@@ -126,11 +124,11 @@ module.exports = {
       if (args.userId === 1 && args.groupId === 1) {
         throw new Error('Cannot unassign Administrator user from Administrators group.')
       }
-      const grp = await WIKI.models.groups.query().findById(args.groupId)
+      const grp = await WIKI.db.groups.query().findById(args.groupId)
       if (!grp) {
         throw new Error('Invalid Group ID')
       }
-      const usr = await WIKI.models.users.query().findById(args.userId)
+      const usr = await WIKI.db.users.query().findById(args.userId)
       if (!usr) {
         throw new Error('Invalid User ID')
       }
@@ -179,7 +177,7 @@ module.exports = {
       }
 
       // Update group
-      await WIKI.models.groups.query().patch({
+      await WIKI.db.groups.query().patch({
         name: args.name,
         redirectOnLogin: args.redirectOnLogin,
         permissions: JSON.stringify(args.permissions),

+ 6 - 8
server/graph/resolvers/hooks.js

@@ -1,15 +1,13 @@
 const graphHelper = require('../../helpers/graph')
 const _ = require('lodash')
 
-/* global WIKI */
-
 module.exports = {
   Query: {
     async hooks () {
-      return WIKI.models.hooks.query().orderBy('name')
+      return WIKI.db.hooks.query().orderBy('name')
     },
     async hookById (obj, args) {
-      return WIKI.models.hooks.query().findById(args.id)
+      return WIKI.db.hooks.query().findById(args.id)
     }
   },
   Mutation: {
@@ -29,7 +27,7 @@ module.exports = {
           throw new WIKI.Error.Custom('HookCreateInvalidURL', 'Invalid Hook URL')
         }
         // -> Create hook
-        const newHook = await WIKI.models.hooks.createHook(args)
+        const newHook = await WIKI.db.hooks.createHook(args)
         WIKI.logger.debug(`New Hook ${newHook.id} created successfully.`)
 
         return {
@@ -46,7 +44,7 @@ module.exports = {
     async updateHook (obj, args) {
       try {
         // -> Load hook
-        const hook = await WIKI.models.hooks.query().findById(args.id)
+        const hook = await WIKI.db.hooks.query().findById(args.id)
         if (!hook) {
           throw new WIKI.Error.Custom('HookInvalidId', 'Invalid Hook ID')
         }
@@ -61,7 +59,7 @@ module.exports = {
           throw new WIKI.Error.Custom('HookInvalidURL', 'URL is invalid.')
         }
         // -> Update hook
-        await WIKI.models.hooks.query().findById(args.id).patch(args.patch)
+        await WIKI.db.hooks.query().findById(args.id).patch(args.patch)
         WIKI.logger.debug(`Hook ${args.id} updated successfully.`)
 
         return {
@@ -76,7 +74,7 @@ module.exports = {
      */
     async deleteHook (obj, args) {
       try {
-        await WIKI.models.hooks.deleteHook(args.id)
+        await WIKI.db.hooks.deleteHook(args.id)
         WIKI.logger.debug(`Hook ${args.id} deleted successfully.`)
         return {
           operation: graphHelper.generateSuccess('Hook deleted successfully')

+ 2 - 4
server/graph/resolvers/localization.js

@@ -1,13 +1,11 @@
 const graphHelper = require('../../helpers/graph')
 const _ = require('lodash')
 
-/* global WIKI */
-
 module.exports = {
   Query: {
     async locales(obj, args, context, info) {
       let remoteLocales = await WIKI.cache.get('locales')
-      let localLocales = await WIKI.models.locales.query().select('code', 'isRTL', 'name', 'nativeName', 'createdAt', 'updatedAt', 'availability')
+      let localLocales = await WIKI.db.locales.query().select('code', 'isRTL', 'name', 'nativeName', 'createdAt', 'updatedAt', 'availability')
       remoteLocales = remoteLocales || localLocales
       return _.map(remoteLocales, rl => {
         let isInstalled = _.some(localLocales, ['code', rl.code])
@@ -44,7 +42,7 @@ module.exports = {
         WIKI.config.lang.namespacing = args.namespacing
         WIKI.config.lang.namespaces = _.union(args.namespaces, [args.locale])
 
-        const newLocale = await WIKI.models.locales.query().select('isRTL').where('code', args.locale).first()
+        const newLocale = await WIKI.db.locales.query().select('isRTL').where('code', args.locale).first()
         WIKI.config.lang.rtl = newLocale.isRTL
 
         await WIKI.configSvc.saveToDb(['lang'])

+ 0 - 2
server/graph/resolvers/mail.js

@@ -1,8 +1,6 @@
 const _ = require('lodash')
 const graphHelper = require('../../helpers/graph')
 
-/* global WIKI */
-
 module.exports = {
   Query: {
     async mailConfig(obj, args, context, info) {

+ 2 - 4
server/graph/resolvers/navigation.js

@@ -1,11 +1,9 @@
 const graphHelper = require('../../helpers/graph')
 
-/* global WIKI */
-
 module.exports = {
   Query: {
     async navigationTree (obj, args, context, info) {
-      return WIKI.models.navigation.getTree({ cache: false, locale: 'all', bypassAuth: true })
+      return WIKI.db.navigation.getTree({ cache: false, locale: 'all', bypassAuth: true })
     },
     navigationConfig (obj, args, context, info) {
       return WIKI.config.nav
@@ -14,7 +12,7 @@ module.exports = {
   Mutation: {
     async updateNavigationTree (obj, args, context) {
       try {
-        await WIKI.models.navigation.query().patch({
+        await WIKI.db.navigation.query().patch({
           config: args.tree
         }).where('key', 'site')
         for (const tree of args.tree) {

+ 33 - 35
server/graph/resolvers/page.js

@@ -1,20 +1,18 @@
 const _ = require('lodash')
 const graphHelper = require('../../helpers/graph')
 
-/* global WIKI */
-
 module.exports = {
   Query: {
     /**
      * PAGE HISTORY
      */
     async pageHistoryById (obj, args, context, info) {
-      const page = await WIKI.models.pages.query().select('path', 'localeCode').findById(args.id)
+      const page = await WIKI.db.pages.query().select('path', 'localeCode').findById(args.id)
       if (WIKI.auth.checkAccess(context.req.user, ['read:history'], {
         path: page.path,
         locale: page.localeCode
       })) {
-        return WIKI.models.pageHistory.getHistory({
+        return WIKI.db.pageHistory.getHistory({
           pageId: args.id,
           offsetPage: args.offsetPage || 0,
           offsetSize: args.offsetSize || 100
@@ -27,12 +25,12 @@ module.exports = {
      * PAGE VERSION
      */
     async pageVersionById (obj, args, context, info) {
-      const page = await WIKI.models.pages.query().select('path', 'localeCode').findById(args.pageId)
+      const page = await WIKI.db.pages.query().select('path', 'localeCode').findById(args.pageId)
       if (WIKI.auth.checkAccess(context.req.user, ['read:history'], {
         path: page.path,
         locale: page.localeCode
       })) {
-        return WIKI.models.pageHistory.getVersion({
+        return WIKI.db.pageHistory.getVersion({
           pageId: args.pageId,
           versionId: args.versionId
         })
@@ -68,7 +66,7 @@ module.exports = {
      * LIST PAGES
      */
     async pages (obj, args, context, info) {
-      let results = await WIKI.models.pages.query().column([
+      let results = await WIKI.db.pages.query().column([
         'pages.id',
         'path',
         { locale: 'localeCode' },
@@ -144,7 +142,7 @@ module.exports = {
      * FETCH SINGLE PAGE
      */
     async pageById (obj, args, context, info) {
-      let page = await WIKI.models.pages.getPageFromDb(args.id)
+      let page = await WIKI.db.pages.getPageFromDb(args.id)
       if (page) {
         if (WIKI.auth.checkAccess(context.req.user, ['manage:pages', 'delete:pages'], {
           path: page.path,
@@ -166,7 +164,7 @@ module.exports = {
      * FETCH TAGS
      */
     async tags (obj, args, context, info) {
-      const pages = await WIKI.models.pages.query()
+      const pages = await WIKI.db.pages.query()
         .column([
           'path',
           { locale: 'localeCode' }
@@ -185,7 +183,7 @@ module.exports = {
      */
     async searchTags (obj, args, context, info) {
       const query = _.trim(args.query)
-      const pages = await WIKI.models.pages.query()
+      const pages = await WIKI.db.pages.query()
         .column([
           'path',
           { locale: 'localeCode' }
@@ -220,7 +218,7 @@ module.exports = {
       if (!args.locale) { args.locale = WIKI.config.lang.code }
 
       if (args.path && !args.parent) {
-        curPage = await WIKI.models.knex('pageTree').first('parent', 'ancestors').where({
+        curPage = await WIKI.db.knex('pageTree').first('parent', 'ancestors').where({
           path: args.path,
           localeCode: args.locale
         })
@@ -231,7 +229,7 @@ module.exports = {
         }
       }
 
-      const results = await WIKI.models.knex('pageTree').where(builder => {
+      const results = await WIKI.db.knex('pageTree').where(builder => {
         builder.where('localeCode', args.locale)
         switch (args.mode) {
           case 'FOLDERS':
@@ -268,14 +266,14 @@ module.exports = {
       let results
 
       if (WIKI.config.db.type === 'mysql' || WIKI.config.db.type === 'mariadb' || WIKI.config.db.type === 'sqlite') {
-        results = await WIKI.models.knex('pages')
+        results = await WIKI.db.knex('pages')
           .column({ id: 'pages.id' }, { path: 'pages.path' }, 'title', { link: 'pageLinks.path' }, { locale: 'pageLinks.localeCode' })
           .leftJoin('pageLinks', 'pages.id', 'pageLinks.pageId')
           .where({
             'pages.localeCode': args.locale
           })
           .unionAll(
-            WIKI.models.knex('pageLinks')
+            WIKI.db.knex('pageLinks')
               .column({ id: 'pages.id' }, { path: 'pages.path' }, 'title', { link: 'pageLinks.path' }, { locale: 'pageLinks.localeCode' })
               .leftJoin('pages', 'pageLinks.pageId', 'pages.id')
               .where({
@@ -283,7 +281,7 @@ module.exports = {
               })
           )
       } else {
-        results = await WIKI.models.knex('pages')
+        results = await WIKI.db.knex('pages')
           .column({ id: 'pages.id' }, { path: 'pages.path' }, 'title', { link: 'pageLinks.path' }, { locale: 'pageLinks.localeCode' })
           .fullOuterJoin('pageLinks', 'pages.id', 'pageLinks.pageId')
           .where({
@@ -320,7 +318,7 @@ module.exports = {
      * CHECK FOR EDITING CONFLICT
      */
     async checkConflicts (obj, args, context, info) {
-      let page = await WIKI.models.pages.query().select('path', 'localeCode', 'updatedAt').findById(args.id)
+      let page = await WIKI.db.pages.query().select('path', 'localeCode', 'updatedAt').findById(args.id)
       if (page) {
         if (WIKI.auth.checkAccess(context.req.user, ['write:pages', 'manage:pages'], {
           path: page.path,
@@ -338,7 +336,7 @@ module.exports = {
      * FETCH LATEST VERSION FOR CONFLICT COMPARISON
      */
     async checkConflictsLatest (obj, args, context, info) {
-      let page = await WIKI.models.pages.getPageFromDb(args.id)
+      let page = await WIKI.db.pages.getPageFromDb(args.id)
       if (page) {
         if (WIKI.auth.checkAccess(context.req.user, ['write:pages', 'manage:pages'], {
           path: page.path,
@@ -363,7 +361,7 @@ module.exports = {
      */
     async createPage(obj, args, context) {
       try {
-        const page = await WIKI.models.pages.createPage({
+        const page = await WIKI.db.pages.createPage({
           ...args,
           user: context.req.user
         })
@@ -380,7 +378,7 @@ module.exports = {
      */
     async updatePage(obj, args, context) {
       try {
-        const page = await WIKI.models.pages.updatePage({
+        const page = await WIKI.db.pages.updatePage({
           ...args,
           user: context.req.user
         })
@@ -397,7 +395,7 @@ module.exports = {
      */
     async convertPage(obj, args, context) {
       try {
-        await WIKI.models.pages.convertPage({
+        await WIKI.db.pages.convertPage({
           ...args,
           user: context.req.user
         })
@@ -413,7 +411,7 @@ module.exports = {
      */
     async renamePage(obj, args, context) {
       try {
-        await WIKI.models.pages.movePage({
+        await WIKI.db.pages.movePage({
           ...args,
           user: context.req.user
         })
@@ -429,7 +427,7 @@ module.exports = {
      */
     async deletePage(obj, args, context) {
       try {
-        await WIKI.models.pages.deletePage({
+        await WIKI.db.pages.deletePage({
           ...args,
           user: context.req.user
         })
@@ -445,10 +443,10 @@ module.exports = {
      */
     async deleteTag (obj, args, context) {
       try {
-        const tagToDel = await WIKI.models.tags.query().findById(args.id)
+        const tagToDel = await WIKI.db.tags.query().findById(args.id)
         if (tagToDel) {
           await tagToDel.$relatedQuery('pages').unrelate()
-          await WIKI.models.tags.query().deleteById(args.id)
+          await WIKI.db.tags.query().deleteById(args.id)
         } else {
           throw new Error('This tag does not exist.')
         }
@@ -464,7 +462,7 @@ module.exports = {
      */
     async updateTag (obj, args, context) {
       try {
-        const affectedRows = await WIKI.models.tags.query()
+        const affectedRows = await WIKI.db.tags.query()
           .findById(args.id)
           .patch({
             tag: _.trim(args.tag).toLowerCase(),
@@ -485,7 +483,7 @@ module.exports = {
      */
     async flushCache(obj, args, context) {
       try {
-        await WIKI.models.pages.flushCache()
+        await WIKI.db.pages.flushCache()
         WIKI.events.outbound.emit('flushCache')
         return {
           responseResult: graphHelper.generateSuccess('Pages Cache has been flushed successfully.')
@@ -499,7 +497,7 @@ module.exports = {
      */
     async migrateToLocale(obj, args, context) {
       try {
-        const count = await WIKI.models.pages.migrateToLocale(args)
+        const count = await WIKI.db.pages.migrateToLocale(args)
         return {
           responseResult: graphHelper.generateSuccess('Migrated content to target locale successfully.'),
           count
@@ -513,7 +511,7 @@ module.exports = {
      */
     async rebuildPageTree(obj, args, context) {
       try {
-        await WIKI.models.pages.rebuildTree()
+        await WIKI.db.pages.rebuildTree()
         return {
           responseResult: graphHelper.generateSuccess('Page tree rebuilt successfully.')
         }
@@ -526,11 +524,11 @@ module.exports = {
      */
     async renderPage (obj, args, context) {
       try {
-        const page = await WIKI.models.pages.query().findById(args.id)
+        const page = await WIKI.db.pages.query().findById(args.id)
         if (!page) {
           throw new WIKI.Error.PageNotFound()
         }
-        await WIKI.models.pages.renderPage(page)
+        await WIKI.db.pages.renderPage(page)
         return {
           responseResult: graphHelper.generateSuccess('Page rendered successfully.')
         }
@@ -543,7 +541,7 @@ module.exports = {
      */
     async restorePage (obj, args, context) {
       try {
-        const page = await WIKI.models.pages.query().select('path', 'localeCode').findById(args.pageId)
+        const page = await WIKI.db.pages.query().select('path', 'localeCode').findById(args.pageId)
         if (!page) {
           throw new WIKI.Error.PageNotFound()
         }
@@ -555,12 +553,12 @@ module.exports = {
           throw new WIKI.Error.PageRestoreForbidden()
         }
 
-        const targetVersion = await WIKI.models.pageHistory.getVersion({ pageId: args.pageId, versionId: args.versionId })
+        const targetVersion = await WIKI.db.pageHistory.getVersion({ pageId: args.pageId, versionId: args.versionId })
         if (!targetVersion) {
           throw new WIKI.Error.PageNotFound()
         }
 
-        await WIKI.models.pages.updatePage({
+        await WIKI.db.pages.updatePage({
           ...targetVersion,
           id: targetVersion.pageId,
           user: context.req.user,
@@ -579,7 +577,7 @@ module.exports = {
      */
     async purgePagesHistory (obj, args, context) {
       try {
-        await WIKI.models.pageHistory.purge(args.olderThan)
+        await WIKI.db.pageHistory.purge(args.olderThan)
         return {
           responseResult: graphHelper.generateSuccess('Page history purged successfully.')
         }
@@ -590,7 +588,7 @@ module.exports = {
   },
   Page: {
     async tags (obj) {
-      return WIKI.models.pages.relatedQuery('tags').for(obj.id)
+      return WIKI.db.pages.relatedQuery('tags').for(obj.id)
     }
     // comments(pg) {
     //   return pg.$relatedQuery('comments')

+ 2 - 4
server/graph/resolvers/rendering.js

@@ -1,12 +1,10 @@
 const _ = require('lodash')
 const graphHelper = require('../../helpers/graph')
 
-/* global WIKI */
-
 module.exports = {
   Query: {
     async renderers(obj, args, context, info) {
-      let renderers = await WIKI.models.renderers.getRenderers()
+      let renderers = await WIKI.db.renderers.getRenderers()
       renderers = renderers.map(rdr => {
         const rendererInfo = _.find(WIKI.data.renderers, ['key', rdr.key]) || {}
         return {
@@ -35,7 +33,7 @@ module.exports = {
     async updateRenderers(obj, args, context) {
       try {
         for (let rdr of args.renderers) {
-          await WIKI.models.renderers.query().patch({
+          await WIKI.db.renderers.query().patch({
             isEnabled: rdr.isEnabled,
             config: _.reduce(rdr.config, (result, value, key) => {
               _.set(result, `${value.key}`, _.get(JSON.parse(value.value), 'v', null))

+ 0 - 2
server/graph/resolvers/search.js

@@ -1,7 +1,5 @@
 const graphHelper = require('../../helpers/graph')
 
-/* global WIKI */
-
 module.exports = {
   Mutation: {
     async rebuildSearchIndex (obj, args, context) {

+ 23 - 25
server/graph/resolvers/site.js

@@ -5,12 +5,10 @@ const path = require('path')
 const fs = require('fs-extra')
 const { v4: uuid } = require('uuid')
 
-/* global WIKI */
-
 module.exports = {
   Query: {
     async sites () {
-      const sites = await WIKI.models.sites.query().orderBy('hostname')
+      const sites = await WIKI.db.sites.query().orderBy('hostname')
       return sites.map(s => ({
         ...s.config,
         id: s.id,
@@ -20,7 +18,7 @@ module.exports = {
       }))
     },
     async siteById (obj, args) {
-      const site = await WIKI.models.sites.query().findById(args.id)
+      const site = await WIKI.db.sites.query().findById(args.id)
       return site ? {
         ...site.config,
         id: site.id,
@@ -30,11 +28,11 @@ module.exports = {
       } : null
     },
     async siteByHostname (obj, args) {
-      let site = await WIKI.models.sites.query().where({
+      let site = await WIKI.db.sites.query().where({
         hostname: args.hostname
       }).first()
       if (!site && !args.exact) {
-        site = await WIKI.models.sites.query().where({
+        site = await WIKI.db.sites.query().where({
           hostname: '*'
         }).first()
       }
@@ -62,7 +60,7 @@ module.exports = {
         }
         // -> Check for duplicate catch-all
         if (args.hostname === '*') {
-          const site = await WIKI.models.sites.query().where({
+          const site = await WIKI.db.sites.query().where({
             hostname: args.hostname
           }).first()
           if (site) {
@@ -70,7 +68,7 @@ module.exports = {
           }
         }
         // -> Create site
-        const newSite = await WIKI.models.sites.createSite(args.hostname, {
+        const newSite = await WIKI.db.sites.createSite(args.hostname, {
           title: args.title
         })
         return {
@@ -88,7 +86,7 @@ module.exports = {
     async updateSite (obj, args) {
       try {
         // -> Load site
-        const site = await WIKI.models.sites.query().findById(args.id)
+        const site = await WIKI.db.sites.query().findById(args.id)
         if (!site) {
           throw new WIKI.Error.Custom('SiteInvalidId', 'Invalid Site ID')
         }
@@ -98,7 +96,7 @@ module.exports = {
         }
         // -> Check for duplicate catch-all
         if (args.patch.hostname === '*' && site.hostname !== '*') {
-          const dupSite = await WIKI.models.sites.query().where({ hostname: '*' }).first()
+          const dupSite = await WIKI.db.sites.query().where({ hostname: '*' }).first()
           if (dupSite) {
             throw new WIKI.Error.Custom('SiteUpdateDuplicateCatchAll', `Site ${dupSite.config.title} with a catch-all hostname already exists! Cannot have 2 catch-all hostnames.`)
           }
@@ -112,7 +110,7 @@ module.exports = {
           args.patch.pageExtensions = args.patch.pageExtensions.split(',').map(ext => ext.trim().toLowerCase()).filter(ext => ext.length > 0)
         }
         // -> Update site
-        await WIKI.models.sites.updateSite(args.id, {
+        await WIKI.db.sites.updateSite(args.id, {
           hostname: args.patch.hostname ?? site.hostname,
           isEnabled: args.patch.isEnabled ?? site.isEnabled,
           config: _.defaultsDeep(_.omit(args.patch, ['hostname', 'isEnabled']), site.config)
@@ -132,12 +130,12 @@ module.exports = {
     async deleteSite (obj, args) {
       try {
         // -> Ensure site isn't last one
-        const sitesCount = await WIKI.models.sites.query().count('id').first()
+        const sitesCount = await WIKI.db.sites.query().count('id').first()
         if (sitesCount?.count && _.toNumber(sitesCount?.count) <= 1) {
           throw new WIKI.Error.Custom('SiteDeleteLastSite', 'Cannot delete the last site. At least 1 site must exists at all times.')
         }
         // -> Delete site
-        await WIKI.models.sites.deleteSite(args.id)
+        await WIKI.db.sites.deleteSite(args.id)
         return {
           operation: graphHelper.generateSuccess('Site deleted successfully')
         }
@@ -175,16 +173,16 @@ module.exports = {
           height: 72
         })
         // -> Save logo meta to DB
-        const site = await WIKI.models.sites.query().findById(args.id)
+        const site = await WIKI.db.sites.query().findById(args.id)
         if (!site.config.assets.logo) {
           site.config.assets.logo = uuid()
         }
         site.config.assets.logoExt = destFormat
-        await WIKI.models.sites.query().findById(args.id).patch({ config: site.config })
-        await WIKI.models.sites.reloadCache()
+        await WIKI.db.sites.query().findById(args.id).patch({ config: site.config })
+        await WIKI.db.sites.reloadCache()
         // -> Save image data to DB
         const imgBuffer = await fs.readFile(destPath)
-        await WIKI.models.knex('assetData').insert({
+        await WIKI.db.knex('assetData').insert({
           id: site.config.assets.logo,
           data: imgBuffer
         }).onConflict('id').merge()
@@ -227,16 +225,16 @@ module.exports = {
           height: 64
         })
         // -> Save favicon meta to DB
-        const site = await WIKI.models.sites.query().findById(args.id)
+        const site = await WIKI.db.sites.query().findById(args.id)
         if (!site.config.assets.favicon) {
           site.config.assets.favicon = uuid()
         }
         site.config.assets.faviconExt = destFormat
-        await WIKI.models.sites.query().findById(args.id).patch({ config: site.config })
-        await WIKI.models.sites.reloadCache()
+        await WIKI.db.sites.query().findById(args.id).patch({ config: site.config })
+        await WIKI.db.sites.reloadCache()
         // -> Save image data to DB
         const imgBuffer = await fs.readFile(destPath)
-        await WIKI.models.knex('assetData').insert({
+        await WIKI.db.knex('assetData').insert({
           id: site.config.assets.favicon,
           data: imgBuffer
         }).onConflict('id').merge()
@@ -277,15 +275,15 @@ module.exports = {
           width: 1920
         })
         // -> Save login bg meta to DB
-        const site = await WIKI.models.sites.query().findById(args.id)
+        const site = await WIKI.db.sites.query().findById(args.id)
         if (!site.config.assets.loginBg) {
           site.config.assets.loginBg = uuid()
-          await WIKI.models.sites.query().findById(args.id).patch({ config: site.config })
-          await WIKI.models.sites.reloadCache()
+          await WIKI.db.sites.query().findById(args.id).patch({ config: site.config })
+          await WIKI.db.sites.reloadCache()
         }
         // -> Save image data to DB
         const imgBuffer = await fs.readFile(destPath)
-        await WIKI.models.knex('assetData').insert({
+        await WIKI.db.knex('assetData').insert({
           id: site.config.assets.loginBg,
           data: imgBuffer
         }).onConflict('id').merge()

+ 10 - 12
server/graph/resolvers/storage.js

@@ -2,12 +2,10 @@ const _ = require('lodash')
 const graphHelper = require('../../helpers/graph')
 const { v4: uuid } = require('uuid')
 
-/* global WIKI */
-
 module.exports = {
   Query: {
     async storageTargets (obj, args, context, info) {
-      const dbTargets = await WIKI.models.storage.getTargets({ siteId: args.siteId })
+      const dbTargets = await WIKI.db.storage.getTargets({ siteId: args.siteId })
       // targets = _.sortBy(targets.map(tgt => {
       //   const targetInfo = _.find(WIKI.data.storage, ['module', tgt.key]) || {}
       //   return {
@@ -101,7 +99,7 @@ module.exports = {
     async updateStorageTargets (obj, args, context) {
       WIKI.logger.debug(`Updating storage targets for site ${args.siteId}...`)
       try {
-        const dbTargets = await WIKI.models.storage.getTargets({ siteId: args.siteId })
+        const dbTargets = await WIKI.db.storage.getTargets({ siteId: args.siteId })
         for (const tgt of args.targets) {
           const md = _.find(WIKI.storage.defs, ['key', tgt.module])
           if (!md) {
@@ -124,7 +122,7 @@ module.exports = {
           // -> Target doesn't exist yet in the DB, let's create it
           if (!dbTarget) {
             WIKI.logger.debug(`No existing DB configuration for module ${tgt.module}. Creating a new one...`)
-            await WIKI.models.storage.query().insert({
+            await WIKI.db.storage.query().insert({
               id: tgt.id,
               module: tgt.module,
               siteId: args.siteId,
@@ -147,7 +145,7 @@ module.exports = {
             })
           } else {
             WIKI.logger.debug(`Updating DB configuration for module ${tgt.module}...`)
-            await WIKI.models.storage.query().patch({
+            await WIKI.db.storage.query().patch({
               isEnabled: tgt.isEnabled ?? dbTarget.isEnabled ?? false,
               contentTypes: {
                 activeTypes: tgt.contentTypes ?? dbTarget?.contentTypes?.activeTypes ?? [],
@@ -164,7 +162,7 @@ module.exports = {
             }).where('id', tgt.id)
           }
         }
-        // await WIKI.models.storage.initTargets()
+        // await WIKI.db.storage.initTargets()
         return {
           status: graphHelper.generateSuccess('Storage targets updated successfully')
         }
@@ -174,7 +172,7 @@ module.exports = {
     },
     async setupStorageTarget (obj, args, context) {
       try {
-        const tgt = await WIKI.models.storage.query().findById(args.targetId)
+        const tgt = await WIKI.db.storage.query().findById(args.targetId)
         if (!tgt) {
           throw new Error('Not storage target matching this ID')
         }
@@ -182,7 +180,7 @@ module.exports = {
         if (!md) {
           throw new Error('No matching storage module installed.')
         }
-        if (!await WIKI.models.storage.ensureModule(md.key)) {
+        if (!await WIKI.db.storage.ensureModule(md.key)) {
           throw new Error('Failed to load storage module. Check logs for details.')
         }
         const result = await WIKI.storage.modules[md.key].setup(args.targetId, args.state)
@@ -197,7 +195,7 @@ module.exports = {
     },
     async destroyStorageTargetSetup (obj, args, context) {
       try {
-        const tgt = await WIKI.models.storage.query().findById(args.targetId)
+        const tgt = await WIKI.db.storage.query().findById(args.targetId)
         if (!tgt) {
           throw new Error('Not storage target matching this ID')
         }
@@ -205,7 +203,7 @@ module.exports = {
         if (!md) {
           throw new Error('No matching storage module installed.')
         }
-        if (!await WIKI.models.storage.ensureModule(md.key)) {
+        if (!await WIKI.db.storage.ensureModule(md.key)) {
           throw new Error('Failed to load storage module. Check logs for details.')
         }
         await WIKI.storage.modules[md.key].setupDestroy(args.targetId)
@@ -219,7 +217,7 @@ module.exports = {
     },
     async executeStorageAction (obj, args, context) {
       try {
-        await WIKI.models.storage.executeAction(args.targetKey, args.handler)
+        await WIKI.db.storage.executeAction(args.targetKey, args.handler)
         return {
           status: graphHelper.generateSuccess('Action completed.')
         }

+ 4 - 6
server/graph/resolvers/system.js

@@ -9,8 +9,6 @@ const { DateTime } = require('luxon')
 const graphHelper = require('../../helpers/graph')
 const cronParser = require('cron-parser')
 
-/* global WIKI */
-
 module.exports = {
   Query: {
     systemFlags () {
@@ -183,19 +181,19 @@ module.exports = {
       return process.cwd()
     },
     async groupsTotal () {
-      const total = await WIKI.models.groups.query().count('* as total').first()
+      const total = await WIKI.db.groups.query().count('* as total').first()
       return _.toSafeInteger(total.total)
     },
     async pagesTotal () {
-      const total = await WIKI.models.pages.query().count('* as total').first()
+      const total = await WIKI.db.pages.query().count('* as total').first()
       return _.toSafeInteger(total.total)
     },
     async usersTotal () {
-      const total = await WIKI.models.users.query().count('* as total').first()
+      const total = await WIKI.db.users.query().count('* as total').first()
       return _.toSafeInteger(total.total)
     },
     async tagsTotal () {
-      const total = await WIKI.models.tags.query().count('* as total').first()
+      const total = await WIKI.db.tags.query().count('* as total').first()
       return _.toSafeInteger(total.total)
     }
   }

+ 18 - 20
server/graph/resolvers/user.js

@@ -1,8 +1,6 @@
 const graphHelper = require('../../helpers/graph')
 const _ = require('lodash')
 
-/* global WIKI */
-
 module.exports = {
   Query: {
     /**
@@ -22,7 +20,7 @@ module.exports = {
       }
 
       // -> Fetch Users
-      return WIKI.models.users.query()
+      return WIKI.db.users.query()
         .select('id', 'email', 'name', 'isSystem', 'isActive', 'createdAt', 'lastLoginAt')
         .where(builder => {
           if (args.filter) {
@@ -38,7 +36,7 @@ module.exports = {
      * FETCH A SINGLE USER
      */
     async userById (obj, args, context, info) {
-      const usr = await WIKI.models.users.query().findById(args.id)
+      const usr = await WIKI.db.users.query().findById(args.id)
 
       if (!usr) {
         throw new Error('Invalid User')
@@ -64,7 +62,7 @@ module.exports = {
     //   if (!context.req.user || context.req.user.id < 1 || context.req.user.id === 2) {
     //     throw new WIKI.Error.AuthRequired()
     //   }
-    //   const usr = await WIKI.models.users.query().findById(context.req.user.id)
+    //   const usr = await WIKI.db.users.query().findById(context.req.user.id)
     //   if (!usr.isActive) {
     //     throw new WIKI.Error.AuthAccountBanned()
     //   }
@@ -80,7 +78,7 @@ module.exports = {
     //   return usr
     // },
     async lastLogins (obj, args, context, info) {
-      return WIKI.models.users.query()
+      return WIKI.db.users.query()
         .select('id', 'name', 'lastLoginAt')
         .whereNotNull('lastLoginAt')
         .orderBy('lastLoginAt', 'desc')
@@ -90,7 +88,7 @@ module.exports = {
   Mutation: {
     async createUser (obj, args) {
       try {
-        await WIKI.models.users.createNewUser({ ...args, passwordRaw: args.password, isVerified: true })
+        await WIKI.db.users.createNewUser({ ...args, passwordRaw: args.password, isVerified: true })
 
         return {
           operation: graphHelper.generateSuccess('User created successfully')
@@ -104,7 +102,7 @@ module.exports = {
         if (args.id <= 2) {
           throw new WIKI.Error.UserDeleteProtected()
         }
-        await WIKI.models.users.deleteUser(args.id, args.replaceId)
+        await WIKI.db.users.deleteUser(args.id, args.replaceId)
 
         WIKI.auth.revokeUserTokens({ id: args.id, kind: 'u' })
         WIKI.events.outbound.emit('addAuthRevoke', { id: args.id, kind: 'u' })
@@ -122,7 +120,7 @@ module.exports = {
     },
     async updateUser (obj, args) {
       try {
-        await WIKI.models.users.updateUser(args.id, args.patch)
+        await WIKI.db.users.updateUser(args.id, args.patch)
 
         return {
           operation: graphHelper.generateSuccess('User updated successfully')
@@ -133,7 +131,7 @@ module.exports = {
     },
     async verifyUser (obj, args) {
       try {
-        await WIKI.models.users.query().patch({ isVerified: true }).findById(args.id)
+        await WIKI.db.users.query().patch({ isVerified: true }).findById(args.id)
 
         return {
           operation: graphHelper.generateSuccess('User verified successfully')
@@ -144,7 +142,7 @@ module.exports = {
     },
     async activateUser (obj, args) {
       try {
-        await WIKI.models.users.query().patch({ isActive: true }).findById(args.id)
+        await WIKI.db.users.query().patch({ isActive: true }).findById(args.id)
 
         return {
           operation: graphHelper.generateSuccess('User activated successfully')
@@ -158,7 +156,7 @@ module.exports = {
         if (args.id <= 2) {
           throw new Error('Cannot deactivate system accounts.')
         }
-        await WIKI.models.users.query().patch({ isActive: false }).findById(args.id)
+        await WIKI.db.users.query().patch({ isActive: false }).findById(args.id)
 
         WIKI.auth.revokeUserTokens({ id: args.id, kind: 'u' })
         WIKI.events.outbound.emit('addAuthRevoke', { id: args.id, kind: 'u' })
@@ -172,7 +170,7 @@ module.exports = {
     },
     async enableUserTFA (obj, args) {
       try {
-        await WIKI.models.users.query().patch({ tfaIsActive: true, tfaSecret: null }).findById(args.id)
+        await WIKI.db.users.query().patch({ tfaIsActive: true, tfaSecret: null }).findById(args.id)
 
         return {
           operation: graphHelper.generateSuccess('User 2FA enabled successfully')
@@ -183,7 +181,7 @@ module.exports = {
     },
     async disableUserTFA (obj, args) {
       try {
-        await WIKI.models.users.query().patch({ tfaIsActive: false, tfaSecret: null }).findById(args.id)
+        await WIKI.db.users.query().patch({ tfaIsActive: false, tfaSecret: null }).findById(args.id)
 
         return {
           operation: graphHelper.generateSuccess('User 2FA disabled successfully')
@@ -200,7 +198,7 @@ module.exports = {
         if (!context.req.user || context.req.user.id === WIKI.auth.guest.id) {
           throw new WIKI.Error.AuthRequired()
         }
-        const usr = await WIKI.models.users.query().findById(context.req.user.id)
+        const usr = await WIKI.db.users.query().findById(context.req.user.id)
         if (!usr.isActive) {
           throw new WIKI.Error.AuthAccountBanned()
         }
@@ -216,7 +214,7 @@ module.exports = {
           throw new WIKI.Error.InputInvalid()
         }
 
-        await WIKI.models.users.query().findById(usr.id).patch({
+        await WIKI.db.users.query().findById(usr.id).patch({
           name: args.name?.trim() ?? usr.name,
           meta: {
             ...usr.meta,
@@ -245,7 +243,7 @@ module.exports = {
         if (!context.req.user || context.req.user.id < 1 || context.req.user.id === 2) {
           throw new WIKI.Error.AuthRequired()
         }
-        const usr = await WIKI.models.users.query().findById(context.req.user.id)
+        const usr = await WIKI.db.users.query().findById(context.req.user.id)
         if (!usr.isActive) {
           throw new WIKI.Error.AuthAccountBanned()
         }
@@ -261,12 +259,12 @@ module.exports = {
           throw new WIKI.Error.AuthPasswordInvalid()
         }
 
-        await WIKI.models.users.updateUser({
+        await WIKI.db.users.updateUser({
           id: usr.id,
           newPassword: args.new
         })
 
-        const newToken = await WIKI.models.users.refreshToken(usr)
+        const newToken = await WIKI.db.users.refreshToken(usr)
 
         return {
           responseResult: graphHelper.generateSuccess('Password changed successfully'),
@@ -288,7 +286,7 @@ module.exports = {
   //     return usrGroups.map(g => g.name)
   //   },
   //   async pagesTotal (usr) {
-  //     const result = await WIKI.models.pages.query().count('* as total').where('creatorId', usr.id).first()
+  //     const result = await WIKI.db.pages.query().count('* as total').where('creatorId', usr.id).first()
   //     return _.toSafeInteger(result.total)
   //   }
   // }

+ 0 - 2
server/helpers/page.js

@@ -14,8 +14,6 @@ const contentToExt = {
 }
 const extToContent = _.invert(contentToExt)
 
-/* global WIKI */
-
 module.exports = {
   /**
    * Parse raw url path and make it safe

+ 0 - 1
server/index.js

@@ -15,7 +15,6 @@ if (!semver.satisfies(process.version, '>=18')) {
 
 let WIKI = {
   IS_DEBUG: process.env.NODE_ENV === 'development',
-  IS_MASTER: true,
   ROOTPATH: process.cwd(),
   INSTANCE_ID: nanoid(10),
   SERVERPATH: path.join(process.cwd(), 'server'),

+ 0 - 2
server/middlewares/seo.js

@@ -1,7 +1,5 @@
 const _ = require('lodash')
 
-/* global WIKI */
-
 /**
  * SEO Middleware
  *

+ 2 - 4
server/models/analytics.js

@@ -5,8 +5,6 @@ const _ = require('lodash')
 const yaml = require('js-yaml')
 const commonHelper = require('../helpers/common')
 
-/* global WIKI */
-
 /**
  * Analytics model
  */
@@ -31,7 +29,7 @@ module.exports = class Analytics extends Model {
   }
 
   static async getProviders(isEnabled) {
-    const providers = await WIKI.models.analytics.query().where(_.isBoolean(isEnabled) ? { isEnabled } : {})
+    const providers = await WIKI.db.analytics.query().where(_.isBoolean(isEnabled) ? { isEnabled } : {})
     return _.sortBy(providers, ['module'])
   }
 
@@ -69,7 +67,7 @@ module.exports = class Analytics extends Model {
         bodyStart: '',
         bodyEnd: ''
       }
-      const providers = await WIKI.models.analytics.getProviders(true)
+      const providers = await WIKI.db.analytics.getProviders(true)
 
       for (let provider of providers) {
         const def = await fs.readFile(path.join(WIKI.SERVERPATH, 'modules/analytics', provider.key, 'code.yml'), 'utf8')

+ 2 - 2
server/models/apiKeys.js

@@ -43,7 +43,7 @@ module.exports = class ApiKey extends Model {
   static async createNewKey ({ name, expiration, groups }) {
     console.info(DateTime.utc().plus(ms(expiration)).toISO())
 
-    const entry = await WIKI.models.apiKeys.query().insert({
+    const entry = await WIKI.db.apiKeys.query().insert({
       name,
       key: 'pending',
       expiration: DateTime.utc().plus(ms(expiration)).toISO(),
@@ -65,7 +65,7 @@ module.exports = class ApiKey extends Model {
       issuer: 'urn:wiki.js'
     })
 
-    await WIKI.models.apiKeys.query().findById(entry.id).patch({
+    await WIKI.db.apiKeys.query().findById(entry.id).patch({
       key,
       isRevoked: false
     })

+ 3 - 5
server/models/assetFolders.js

@@ -1,8 +1,6 @@
 const Model = require('objection').Model
 const _ = require('lodash')
 
-/* global WIKI */
-
 /**
  * Users model
  */
@@ -42,13 +40,13 @@ module.exports = class AssetFolder extends Model {
   static async getHierarchy (folderId) {
     let hier
     if (WIKI.config.db.type === 'mssql') {
-      hier = await WIKI.models.knex.with('ancestors', qb => {
+      hier = await WIKI.db.knex.with('ancestors', qb => {
         qb.select('id', 'name', 'slug', 'parentId').from('assetFolders').where('id', folderId).unionAll(sqb => {
           sqb.select('a.id', 'a.name', 'a.slug', 'a.parentId').from('assetFolders AS a').join('ancestors', 'ancestors.parentId', 'a.id')
         })
       }).select('*').from('ancestors')
     } else {
-      hier = await WIKI.models.knex.withRecursive('ancestors', qb => {
+      hier = await WIKI.db.knex.withRecursive('ancestors', qb => {
         qb.select('id', 'name', 'slug', 'parentId').from('assetFolders').where('id', folderId).union(sqb => {
           sqb.select('a.id', 'a.name', 'a.slug', 'a.parentId').from('assetFolders AS a').join('ancestors', 'ancestors.parentId', 'a.id')
         })
@@ -62,7 +60,7 @@ module.exports = class AssetFolder extends Model {
    * Get full folder paths
    */
   static async getAllPaths () {
-    const all = await WIKI.models.assetFolders.query()
+    const all = await WIKI.db.assetFolders.query()
     let folders = {}
     all.forEach(fld => {
       _.set(folders, fld.id, fld.slug)

+ 14 - 14
server/models/assets.js

@@ -69,7 +69,7 @@ module.exports = class Asset extends Model {
   async getAssetPath() {
     let hierarchy = []
     if (this.folderId) {
-      hierarchy = await WIKI.models.assetFolders.getHierarchy(this.folderId)
+      hierarchy = await WIKI.db.assetFolders.getHierarchy(this.folderId)
     }
     return (this.folderId) ? hierarchy.map(h => h.slug).join('/') + `/${this.filename}` : this.filename
   }
@@ -83,7 +83,7 @@ module.exports = class Asset extends Model {
     const fileHash = assetHelper.generateHash(opts.assetPath)
 
     // Check for existing asset
-    let asset = await WIKI.models.assets.query().where({
+    let asset = await WIKI.db.assets.query().where({
       hash: fileHash,
       folderId: opts.folderId
     }).first()
@@ -124,8 +124,8 @@ module.exports = class Asset extends Model {
         if (opts.mode === 'upload') {
           assetRow.authorId = opts.user.id
         }
-        await WIKI.models.assets.query().patch(assetRow).findById(asset.id)
-        await WIKI.models.knex('assetData').where({
+        await WIKI.db.assets.query().patch(assetRow).findById(asset.id)
+        await WIKI.db.knex('assetData').where({
           id: asset.id
         }).update({
           data: fileBuffer
@@ -133,8 +133,8 @@ module.exports = class Asset extends Model {
       } else {
         // Create asset entry
         assetRow.authorId = opts.user.id
-        asset = await WIKI.models.assets.query().insert(assetRow)
-        await WIKI.models.knex('assetData').insert({
+        asset = await WIKI.db.assets.query().insert(assetRow)
+        await WIKI.db.knex('assetData').insert({
           id: asset.id,
           data: fileBuffer
         })
@@ -149,7 +149,7 @@ module.exports = class Asset extends Model {
 
       // Add to Storage
       if (!opts.skipStorage) {
-        await WIKI.models.storage.assetEvent({
+        await WIKI.db.storage.assetEvent({
           event: 'uploaded',
           asset: {
             ...asset,
@@ -177,13 +177,13 @@ module.exports = class Asset extends Model {
         res.set('Content-disposition', 'attachment; filename=' + encodeURIComponent(fileInfo.base))
       }
 
-      if (await WIKI.models.assets.getAssetFromCache(assetPath, cachePath, res)) {
+      if (await WIKI.db.assets.getAssetFromCache(assetPath, cachePath, res)) {
         return
       }
-      if (await WIKI.models.assets.getAssetFromStorage(assetPath, res)) {
+      if (await WIKI.db.assets.getAssetFromStorage(assetPath, res)) {
         return
       }
-      await WIKI.models.assets.getAssetFromDb(assetPath, fileHash, cachePath, res)
+      await WIKI.db.assets.getAssetFromDb(assetPath, fileHash, cachePath, res)
     } catch (err) {
       if (err.code === `ECONNABORTED` || err.code === `EPIPE`) {
         return
@@ -206,13 +206,13 @@ module.exports = class Asset extends Model {
   }
 
   static async getAssetFromStorage(assetPath, res) {
-    const localLocations = await WIKI.models.storage.getLocalLocations({
+    const localLocations = await WIKI.db.storage.getLocalLocations({
       asset: {
         path: assetPath
       }
     })
     for (let location of _.filter(localLocations, location => Boolean(location.path))) {
-      const assetExists = await WIKI.models.assets.getAssetFromCache(assetPath, location.path, res)
+      const assetExists = await WIKI.db.assets.getAssetFromCache(assetPath, location.path, res)
       if (assetExists) {
         return true
       }
@@ -221,9 +221,9 @@ module.exports = class Asset extends Model {
   }
 
   static async getAssetFromDb(assetPath, fileHash, cachePath, res) {
-    const asset = await WIKI.models.assets.query().where('hash', fileHash).first()
+    const asset = await WIKI.db.assets.query().where('hash', fileHash).first()
     if (asset) {
-      const assetData = await WIKI.models.knex('assetData').where('id', asset.id).first()
+      const assetData = await WIKI.db.knex('assetData').where('id', asset.id).first()
       res.type(asset.ext)
       res.send(assetData.data)
       await fs.outputFile(cachePath, assetData.data)

+ 2 - 4
server/models/authentication.js

@@ -5,8 +5,6 @@ const _ = require('lodash')
 const yaml = require('js-yaml')
 const commonHelper = require('../helpers/common')
 
-/* global WIKI */
-
 /**
  * Authentication model
  */
@@ -32,11 +30,11 @@ module.exports = class Authentication extends Model {
   }
 
   static async getStrategy(key) {
-    return WIKI.models.authentication.query().findOne({ key })
+    return WIKI.db.authentication.query().findOne({ key })
   }
 
   static async getStrategies({ enabledOnly = false } = {}) {
-    const strategies = await WIKI.models.authentication.query().where(enabledOnly ? { isEnabled: true } : {})
+    const strategies = await WIKI.db.authentication.query().where(enabledOnly ? { isEnabled: true } : {})
     return strategies.map(str => ({
       ...str,
       domainWhitelist: _.get(str.domainWhitelist, 'v', []),

+ 3 - 5
server/models/commentProviders.js

@@ -5,8 +5,6 @@ const _ = require('lodash')
 const yaml = require('js-yaml')
 const commonHelper = require('../helpers/common')
 
-/* global WIKI */
-
 /**
  * CommentProvider model
  */
@@ -31,11 +29,11 @@ module.exports = class CommentProvider extends Model {
   }
 
   static async getProvider(key) {
-    return WIKI.models.commentProviders.query().findOne({ key })
+    return WIKI.db.commentProviders.query().findOne({ key })
   }
 
   static async getProviders(isEnabled) {
-    const providers = await WIKI.models.commentProviders.query().where(_.isBoolean(isEnabled) ? { isEnabled } : {})
+    const providers = await WIKI.db.commentProviders.query().where(_.isBoolean(isEnabled) ? { isEnabled } : {})
     return _.sortBy(providers, ['module'])
   }
 
@@ -61,7 +59,7 @@ module.exports = class CommentProvider extends Model {
   }
 
   static async initProvider() {
-    const commentProvider = await WIKI.models.commentProviders.query().findOne('isEnabled', true)
+    const commentProvider = await WIKI.db.commentProviders.query().findOne('isEnabled', true)
     if (commentProvider) {
       WIKI.data.commentProvider = {
         ..._.find(WIKI.data.commentProviders, ['key', commentProvider.module]),

+ 3 - 5
server/models/comments.js

@@ -2,8 +2,6 @@ const Model = require('objection').Model
 const validate = require('validate.js')
 const _ = require('lodash')
 
-/* global WIKI */
-
 /**
  * Comments model
  */
@@ -95,7 +93,7 @@ module.exports = class Comment extends Model {
     }
 
     // -> Load Page
-    const page = await WIKI.models.pages.getPageFromDb(pageId)
+    const page = await WIKI.db.pages.getPageFromDb(pageId)
     if (page) {
       if (!WIKI.auth.checkAccess(user, ['write:comments'], {
         path: page.path,
@@ -132,7 +130,7 @@ module.exports = class Comment extends Model {
     if (!pageId) {
       throw new WIKI.Error.CommentNotFound()
     }
-    const page = await WIKI.models.pages.getPageFromDb(pageId)
+    const page = await WIKI.db.pages.getPageFromDb(pageId)
     if (page) {
       if (!WIKI.auth.checkAccess(user, ['manage:comments'], {
         path: page.path,
@@ -165,7 +163,7 @@ module.exports = class Comment extends Model {
     if (!pageId) {
       throw new WIKI.Error.CommentNotFound()
     }
-    const page = await WIKI.models.pages.getPageFromDb(pageId)
+    const page = await WIKI.db.pages.getPageFromDb(pageId)
     if (page) {
       if (!WIKI.auth.checkAccess(user, ['manage:comments'], {
         path: page.path,

+ 1 - 3
server/models/editors.js

@@ -1,7 +1,5 @@
 const Model = require('objection').Model
 
-/* global WIKI */
-
 /**
  * Editor model
  */
@@ -26,7 +24,7 @@ module.exports = class Editor extends Model {
   }
 
   static async getEditors() {
-    return WIKI.models.editors.query()
+    return WIKI.db.editors.query()
   }
 
   static async getDefaultEditor(contentType) {

+ 3 - 5
server/models/hooks.js

@@ -1,7 +1,5 @@
 const Model = require('objection').Model
 
-/* global WIKI */
-
 /**
  * Hook model
  */
@@ -17,7 +15,7 @@ module.exports = class Hook extends Model {
   }
 
   static async createHook (data) {
-    return WIKI.models.hooks.query().insertAndFetch({
+    return WIKI.db.hooks.query().insertAndFetch({
       name: data.name,
       events: data.events,
       url: data.url,
@@ -31,7 +29,7 @@ module.exports = class Hook extends Model {
   }
 
   static async updateHook (id, patch) {
-    return WIKI.models.hooks.query().findById(id).patch({
+    return WIKI.db.hooks.query().findById(id).patch({
       ...patch,
       state: 'pending',
       lastErrorMessage: null
@@ -39,6 +37,6 @@ module.exports = class Hook extends Model {
   }
 
   static async deleteHook (id) {
-    return WIKI.models.hooks.query().deleteById(id)
+    return WIKI.db.hooks.query().deleteById(id)
   }
 }

+ 1 - 3
server/models/locales.js

@@ -1,7 +1,5 @@
 const Model = require('objection').Model
 
-/* global WIKI */
-
 /**
  * Locales model
  */
@@ -50,7 +48,7 @@ module.exports = class Locale extends Model {
     //     return navLocalesCached
     //   }
     // }
-    // const navLocales = await WIKI.models.locales.query().select('code', 'nativeName AS name').whereIn('code', WIKI.config.lang.namespaces).orderBy('code')
+    // const navLocales = await WIKI.db.locales.query().select('code', 'nativeName AS name').whereIn('code', WIKI.config.lang.namespaces).orderBy('code')
     // if (navLocales) {
     //   if (cache) {
     //     await WIKI.cache.set('nav:locales', navLocales, 300)

+ 3 - 5
server/models/navigation.js

@@ -1,8 +1,6 @@
 const Model = require('objection').Model
 const _ = require('lodash')
 
-/* global WIKI */
-
 /**
  * Navigation model
  */
@@ -26,10 +24,10 @@ module.exports = class Navigation extends Model {
     if (cache) {
       const navTreeCached = await WIKI.cache.get(`nav:sidebar:${locale}`)
       if (navTreeCached) {
-        return bypassAuth ? navTreeCached : WIKI.models.navigation.getAuthorizedItems(navTreeCached, groups)
+        return bypassAuth ? navTreeCached : WIKI.db.navigation.getAuthorizedItems(navTreeCached, groups)
       }
     }
-    const navTree = await WIKI.models.navigation.query().findOne('key', `site`)
+    const navTree = await WIKI.db.navigation.query().findOne('key', `site`)
     if (navTree) {
       // Check for pre-2.3 format
       if (_.has(navTree.config[0], 'kind')) {
@@ -51,7 +49,7 @@ module.exports = class Navigation extends Model {
       if (bypassAuth) {
         return locale === 'all' ? navTree.config : WIKI.cache.get(`nav:sidebar:${locale}`)
       } else {
-        return locale === 'all' ? WIKI.models.navigation.getAuthorizedItems(navTree.config, groups) : WIKI.models.navigation.getAuthorizedItems(WIKI.cache.get(`nav:sidebar:${locale}`), groups)
+        return locale === 'all' ? WIKI.db.navigation.getAuthorizedItems(navTree.config, groups) : WIKI.db.navigation.getAuthorizedItems(WIKI.cache.get(`nav:sidebar:${locale}`), groups)
       }
     } else {
       WIKI.logger.warn('Site Navigation is missing or corrupted.')

+ 5 - 7
server/models/pageHistory.js

@@ -2,8 +2,6 @@ const Model = require('objection').Model
 const _ = require('lodash')
 const { DateTime, Duration } = require('luxon')
 
-/* global WIKI */
-
 /**
  * Page History model
  */
@@ -89,7 +87,7 @@ module.exports = class PageHistory extends Model {
    * Create Page Version
    */
   static async addVersion(opts) {
-    await WIKI.models.pageHistory.query().insert({
+    await WIKI.db.pageHistory.query().insert({
       pageId: opts.id,
       authorId: opts.authorId,
       content: opts.content,
@@ -113,7 +111,7 @@ module.exports = class PageHistory extends Model {
    * Get Page Version
    */
   static async getVersion({ pageId, versionId }) {
-    const version = await WIKI.models.pageHistory.query()
+    const version = await WIKI.db.pageHistory.query()
       .column([
         'pageHistory.path',
         'pageHistory.title',
@@ -156,7 +154,7 @@ module.exports = class PageHistory extends Model {
    * Get History Trail of a Page
    */
   static async getHistory({ pageId, offsetPage = 0, offsetSize = 100 }) {
-    const history = await WIKI.models.pageHistory.query()
+    const history = await WIKI.db.pageHistory.query()
       .column([
         'pageHistory.id',
         'pageHistory.path',
@@ -178,7 +176,7 @@ module.exports = class PageHistory extends Model {
     const upperLimit = (offsetPage + 1) * offsetSize
 
     if (history.total >= upperLimit) {
-      prevPh = await WIKI.models.pageHistory.query()
+      prevPh = await WIKI.db.pageHistory.query()
         .column([
           'pageHistory.id',
           'pageHistory.path',
@@ -238,6 +236,6 @@ module.exports = class PageHistory extends Model {
   static async purge (olderThan) {
     const dur = Duration.fromISO(olderThan)
     const olderThanISO = DateTime.utc().minus(dur)
-    await WIKI.models.pageHistory.query().where('versionDate', '<', olderThanISO.toISO()).del()
+    await WIKI.db.pageHistory.query().where('versionDate', '<', olderThanISO.toISO()).del()
   }
 }

+ 64 - 66
server/models/pages.js

@@ -13,8 +13,6 @@ const TurndownService = require('turndown')
 const turndownPluginGfm = require('@joplin/turndown-plugin-gfm').gfm
 const cheerio = require('cheerio')
 
-/* global WIKI */
-
 const frontmatterRegex = {
   html: /^(<!-{2}(?:\n|\r)([\w\W]+?)(?:\n|\r)-{2}>)?(?:\n|\r)*([\w\W]*)*/,
   legacy: /^(<!-- TITLE: ?([\w\W]+?) ?-{2}>)?(?:\n|\r)?(<!-- SUBTITLE: ?([\w\W]+?) ?-{2}>)?(?:\n|\r)*([\w\W]*)*/i,
@@ -120,7 +118,7 @@ module.exports = class Page extends Model {
    */
   static async beforeDelete({ asFindQuery }) {
     const page = await asFindQuery().select('id')
-    await WIKI.models.comments.query().delete().where('pageId', page[0].id)
+    await WIKI.db.comments.query().delete().where('pageId', page[0].id)
   }
   /**
    * Cache Schema
@@ -256,7 +254,7 @@ module.exports = class Page extends Model {
     }
 
     // -> Check for duplicate
-    const dupCheck = await WIKI.models.pages.query().select('id').where('localeCode', opts.locale).where('path', opts.path).first()
+    const dupCheck = await WIKI.db.pages.query().select('id').where('localeCode', opts.locale).where('path', opts.path).first()
     if (dupCheck) {
       throw new WIKI.Error.PageDuplicateCreate()
     }
@@ -289,7 +287,7 @@ module.exports = class Page extends Model {
     }
 
     // -> Create page
-    await WIKI.models.pages.query().insert({
+    await WIKI.db.pages.query().insert({
       authorId: opts.user.id,
       content: opts.content,
       creatorId: opts.user.id,
@@ -310,7 +308,7 @@ module.exports = class Page extends Model {
         css: scriptCss
       })
     })
-    const page = await WIKI.models.pages.getPageFromDb({
+    const page = await WIKI.db.pages.getPageFromDb({
       path: opts.path,
       locale: opts.locale,
       userId: opts.user.id
@@ -318,37 +316,37 @@ module.exports = class Page extends Model {
 
     // -> Save Tags
     if (opts.tags && opts.tags.length > 0) {
-      await WIKI.models.tags.associateTags({ tags: opts.tags, page })
+      await WIKI.db.tags.associateTags({ tags: opts.tags, page })
     }
 
     // -> Render page to HTML
-    await WIKI.models.pages.renderPage(page)
+    await WIKI.db.pages.renderPage(page)
 
     // -> Rebuild page tree
-    await WIKI.models.pages.rebuildTree()
+    await WIKI.db.pages.rebuildTree()
 
     // -> Add to Search Index
-    const pageContents = await WIKI.models.pages.query().findById(page.id).select('render')
-    page.safeContent = WIKI.models.pages.cleanHTML(pageContents.render)
+    const pageContents = await WIKI.db.pages.query().findById(page.id).select('render')
+    page.safeContent = WIKI.db.pages.cleanHTML(pageContents.render)
     await WIKI.data.searchEngine.created(page)
 
     // -> Add to Storage
     if (!opts.skipStorage) {
-      await WIKI.models.storage.pageEvent({
+      await WIKI.db.storage.pageEvent({
         event: 'created',
         page
       })
     }
 
     // -> Reconnect Links
-    await WIKI.models.pages.reconnectLinks({
+    await WIKI.db.pages.reconnectLinks({
       locale: page.localeCode,
       path: page.path,
       mode: 'create'
     })
 
     // -> Get latest updatedAt
-    page.updatedAt = await WIKI.models.pages.query().findById(page.id).select('updatedAt').then(r => r.updatedAt)
+    page.updatedAt = await WIKI.db.pages.query().findById(page.id).select('updatedAt').then(r => r.updatedAt)
 
     return page
   }
@@ -361,7 +359,7 @@ module.exports = class Page extends Model {
    */
   static async updatePage(opts) {
     // -> Fetch original page
-    const ogPage = await WIKI.models.pages.query().findById(opts.id)
+    const ogPage = await WIKI.db.pages.query().findById(opts.id)
     if (!ogPage) {
       throw new Error('Invalid Page Id')
     }
@@ -380,7 +378,7 @@ module.exports = class Page extends Model {
     }
 
     // -> Create version snapshot
-    await WIKI.models.pageHistory.addVersion({
+    await WIKI.db.pageHistory.addVersion({
       ...ogPage,
       action: opts.action ? opts.action : 'updated',
       versionDate: ogPage.updatedAt
@@ -414,7 +412,7 @@ module.exports = class Page extends Model {
     }
 
     // -> Update page
-    await WIKI.models.pages.query().patch({
+    await WIKI.db.pages.query().patch({
       authorId: opts.user.id,
       content: opts.content,
       description: opts.description,
@@ -428,23 +426,23 @@ module.exports = class Page extends Model {
         css: scriptCss
       })
     }).where('id', ogPage.id)
-    let page = await WIKI.models.pages.getPageFromDb(ogPage.id)
+    let page = await WIKI.db.pages.getPageFromDb(ogPage.id)
 
     // -> Save Tags
-    await WIKI.models.tags.associateTags({ tags: opts.tags, page })
+    await WIKI.db.tags.associateTags({ tags: opts.tags, page })
 
     // -> Render page to HTML
-    await WIKI.models.pages.renderPage(page)
+    await WIKI.db.pages.renderPage(page)
     WIKI.events.outbound.emit('deletePageFromCache', page.hash)
 
     // -> Update Search Index
-    const pageContents = await WIKI.models.pages.query().findById(page.id).select('render')
-    page.safeContent = WIKI.models.pages.cleanHTML(pageContents.render)
+    const pageContents = await WIKI.db.pages.query().findById(page.id).select('render')
+    page.safeContent = WIKI.db.pages.cleanHTML(pageContents.render)
     await WIKI.data.searchEngine.updated(page)
 
     // -> Update on Storage
     if (!opts.skipStorage) {
-      await WIKI.models.storage.pageEvent({
+      await WIKI.db.storage.pageEvent({
         event: 'updated',
         page
       })
@@ -460,7 +458,7 @@ module.exports = class Page extends Model {
         throw new WIKI.Error.PageMoveForbidden()
       }
 
-      await WIKI.models.pages.movePage({
+      await WIKI.db.pages.movePage({
         id: page.id,
         destinationLocale: opts.locale,
         destinationPath: opts.path,
@@ -468,13 +466,13 @@ module.exports = class Page extends Model {
       })
     } else {
       // -> Update title of page tree entry
-      await WIKI.models.knex.table('pageTree').where({
+      await WIKI.db.knex.table('pageTree').where({
         pageId: page.id
       }).update('title', page.title)
     }
 
     // -> Get latest updatedAt
-    page.updatedAt = await WIKI.models.pages.query().findById(page.id).select('updatedAt').then(r => r.updatedAt)
+    page.updatedAt = await WIKI.db.pages.query().findById(page.id).select('updatedAt').then(r => r.updatedAt)
 
     return page
   }
@@ -487,7 +485,7 @@ module.exports = class Page extends Model {
    */
   static async convertPage(opts) {
     // -> Fetch original page
-    const ogPage = await WIKI.models.pages.query().findById(opts.id)
+    const ogPage = await WIKI.db.pages.query().findById(opts.id)
     if (!ogPage) {
       throw new Error('Invalid Page Id')
     }
@@ -621,7 +619,7 @@ module.exports = class Page extends Model {
 
     // -> Create version snapshot
     if (shouldConvert) {
-      await WIKI.models.pageHistory.addVersion({
+      await WIKI.db.pageHistory.addVersion({
         ...ogPage,
         action: 'updated',
         versionDate: ogPage.updatedAt
@@ -629,18 +627,18 @@ module.exports = class Page extends Model {
     }
 
     // -> Update page
-    await WIKI.models.pages.query().patch({
+    await WIKI.db.pages.query().patch({
       contentType: targetContentType,
       editor: opts.editor,
       ...(convertedContent ? { content: convertedContent } : {})
     }).where('id', ogPage.id)
-    const page = await WIKI.models.pages.getPageFromDb(ogPage.id)
+    const page = await WIKI.db.pages.getPageFromDb(ogPage.id)
 
-    await WIKI.models.pages.deletePageFromCache(page.hash)
+    await WIKI.db.pages.deletePageFromCache(page.hash)
     WIKI.events.outbound.emit('deletePageFromCache', page.hash)
 
     // -> Update on Storage
-    await WIKI.models.storage.pageEvent({
+    await WIKI.db.storage.pageEvent({
       event: 'updated',
       page
     })
@@ -655,9 +653,9 @@ module.exports = class Page extends Model {
   static async movePage(opts) {
     let page
     if (_.has(opts, 'id')) {
-      page = await WIKI.models.pages.query().findById(opts.id)
+      page = await WIKI.db.pages.query().findById(opts.id)
     } else {
-      page = await WIKI.models.pages.query().findOne({
+      page = await WIKI.db.pages.query().findOne({
         path: opts.path,
         localeCode: opts.locale
       })
@@ -697,7 +695,7 @@ module.exports = class Page extends Model {
     }
 
     // -> Check for existing page at destination path
-    const destPage = await WIKI.models.pages.query().findOne({
+    const destPage = await WIKI.db.pages.query().findOne({
       path: opts.destinationPath,
       localeCode: opts.destinationLocale
     })
@@ -706,7 +704,7 @@ module.exports = class Page extends Model {
     }
 
     // -> Create version snapshot
-    await WIKI.models.pageHistory.addVersion({
+    await WIKI.db.pageHistory.addVersion({
       ...page,
       action: 'moved',
       versionDate: page.updatedAt
@@ -716,21 +714,21 @@ module.exports = class Page extends Model {
 
     // -> Move page
     const destinationTitle = (page.title === page.path ? opts.destinationPath : page.title)
-    await WIKI.models.pages.query().patch({
+    await WIKI.db.pages.query().patch({
       path: opts.destinationPath,
       localeCode: opts.destinationLocale,
       title: destinationTitle,
       hash: destinationHash
     }).findById(page.id)
-    await WIKI.models.pages.deletePageFromCache(page.hash)
+    await WIKI.db.pages.deletePageFromCache(page.hash)
     WIKI.events.outbound.emit('deletePageFromCache', page.hash)
 
     // -> Rebuild page tree
-    await WIKI.models.pages.rebuildTree()
+    await WIKI.db.pages.rebuildTree()
 
     // -> Rename in Search Index
-    const pageContents = await WIKI.models.pages.query().findById(page.id).select('render')
-    page.safeContent = WIKI.models.pages.cleanHTML(pageContents.render)
+    const pageContents = await WIKI.db.pages.query().findById(page.id).select('render')
+    page.safeContent = WIKI.db.pages.cleanHTML(pageContents.render)
     await WIKI.data.searchEngine.renamed({
       ...page,
       destinationPath: opts.destinationPath,
@@ -740,7 +738,7 @@ module.exports = class Page extends Model {
 
     // -> Rename in Storage
     if (!opts.skipStorage) {
-      await WIKI.models.storage.pageEvent({
+      await WIKI.db.storage.pageEvent({
         event: 'renamed',
         page: {
           ...page,
@@ -755,7 +753,7 @@ module.exports = class Page extends Model {
     }
 
     // -> Reconnect Links : Changing old links to the new path
-    await WIKI.models.pages.reconnectLinks({
+    await WIKI.db.pages.reconnectLinks({
       sourceLocale: page.localeCode,
       sourcePath: page.path,
       locale: opts.destinationLocale,
@@ -764,7 +762,7 @@ module.exports = class Page extends Model {
     })
 
     // -> Reconnect Links : Validate invalid links to the new path
-    await WIKI.models.pages.reconnectLinks({
+    await WIKI.db.pages.reconnectLinks({
       locale: opts.destinationLocale,
       path: opts.destinationPath,
       mode: 'create'
@@ -778,7 +776,7 @@ module.exports = class Page extends Model {
    * @returns {Promise} Promise with no value
    */
   static async deletePage(opts) {
-    const page = await WIKI.models.pages.getPageFromDb(_.has(opts, 'id') ? opts.id : opts)
+    const page = await WIKI.db.pages.getPageFromDb(_.has(opts, 'id') ? opts.id : opts)
     if (!page) {
       throw new WIKI.Error.PageNotFound()
     }
@@ -792,33 +790,33 @@ module.exports = class Page extends Model {
     }
 
     // -> Create version snapshot
-    await WIKI.models.pageHistory.addVersion({
+    await WIKI.db.pageHistory.addVersion({
       ...page,
       action: 'deleted',
       versionDate: page.updatedAt
     })
 
     // -> Delete page
-    await WIKI.models.pages.query().delete().where('id', page.id)
-    await WIKI.models.pages.deletePageFromCache(page.hash)
+    await WIKI.db.pages.query().delete().where('id', page.id)
+    await WIKI.db.pages.deletePageFromCache(page.hash)
     WIKI.events.outbound.emit('deletePageFromCache', page.hash)
 
     // -> Rebuild page tree
-    await WIKI.models.pages.rebuildTree()
+    await WIKI.db.pages.rebuildTree()
 
     // -> Delete from Search Index
     await WIKI.data.searchEngine.deleted(page)
 
     // -> Delete from Storage
     if (!opts.skipStorage) {
-      await WIKI.models.storage.pageEvent({
+      await WIKI.db.storage.pageEvent({
         event: 'deleted',
         page
       })
     }
 
     // -> Reconnect Links
-    await WIKI.models.pages.reconnectLinks({
+    await WIKI.db.pages.reconnectLinks({
       locale: page.localeCode,
       path: page.path,
       mode: 'delete'
@@ -863,10 +861,10 @@ module.exports = class Page extends Model {
     let affectedHashes = []
     // -> Perform replace and return affected page hashes (POSTGRES only)
     if (WIKI.config.db.type === 'postgres') {
-      const qryHashes = await WIKI.models.pages.query()
+      const qryHashes = await WIKI.db.pages.query()
         .returning('hash')
         .patch({
-          render: WIKI.models.knex.raw('REPLACE(??, ?, ?)', ['render', replaceArgs.from, replaceArgs.to])
+          render: WIKI.db.knex.raw('REPLACE(??, ?, ?)', ['render', replaceArgs.from, replaceArgs.to])
         })
         .whereIn('pages.id', function () {
           this.select('pageLinks.pageId').from('pageLinks').where({
@@ -877,9 +875,9 @@ module.exports = class Page extends Model {
       affectedHashes = qryHashes.map(h => h.hash)
     } else {
       // -> Perform replace, then query affected page hashes (MYSQL, MARIADB, MSSQL, SQLITE only)
-      await WIKI.models.pages.query()
+      await WIKI.db.pages.query()
         .patch({
-          render: WIKI.models.knex.raw('REPLACE(??, ?, ?)', ['render', replaceArgs.from, replaceArgs.to])
+          render: WIKI.db.knex.raw('REPLACE(??, ?, ?)', ['render', replaceArgs.from, replaceArgs.to])
         })
         .whereIn('pages.id', function () {
           this.select('pageLinks.pageId').from('pageLinks').where({
@@ -887,7 +885,7 @@ module.exports = class Page extends Model {
             'pageLinks.localeCode': opts.locale
           })
         })
-      const qryHashes = await WIKI.models.pages.query()
+      const qryHashes = await WIKI.db.pages.query()
         .column('hash')
         .whereIn('pages.id', function () {
           this.select('pageLinks.pageId').from('pageLinks').where({
@@ -898,7 +896,7 @@ module.exports = class Page extends Model {
       affectedHashes = qryHashes.map(h => h.hash)
     }
     for (const hash of affectedHashes) {
-      await WIKI.models.pages.deletePageFromCache(hash)
+      await WIKI.db.pages.deletePageFromCache(hash)
       WIKI.events.outbound.emit('deletePageFromCache', hash)
     }
   }
@@ -940,14 +938,14 @@ module.exports = class Page extends Model {
    */
   static async getPage(opts) {
     // -> Get from cache first
-    let page = await WIKI.models.pages.getPageFromCache(opts)
+    let page = await WIKI.db.pages.getPageFromCache(opts)
     if (!page) {
       // -> Get from DB
-      page = await WIKI.models.pages.getPageFromDb(opts)
+      page = await WIKI.db.pages.getPageFromDb(opts)
       if (page) {
         if (page.render) {
           // -> Save render to cache
-          await WIKI.models.pages.savePageToCache(page)
+          await WIKI.db.pages.savePageToCache(page)
         } else {
           // -> No render? Possible duplicate issue
           /* TODO: Detect duplicate and delete */
@@ -967,7 +965,7 @@ module.exports = class Page extends Model {
   static async getPageFromDb(opts) {
     const queryModeID = _.isNumber(opts)
     try {
-      return WIKI.models.pages.query()
+      return WIKI.db.pages.query()
         .column([
           'pages.id',
           'pages.path',
@@ -1031,7 +1029,7 @@ module.exports = class Page extends Model {
    */
   static async savePageToCache(page) {
     const cachePath = path.resolve(WIKI.ROOTPATH, WIKI.config.dataPath, `cache/${page.hash}.bin`)
-    await fs.outputFile(cachePath, WIKI.models.pages.cacheSchema.encode({
+    await fs.outputFile(cachePath, WIKI.db.pages.cacheSchema.encode({
       id: page.id,
       authorId: page.authorId,
       authorName: page.authorName,
@@ -1067,7 +1065,7 @@ module.exports = class Page extends Model {
 
     try {
       const pageBuffer = await fs.readFile(cachePath)
-      let page = WIKI.models.pages.cacheSchema.decode(pageBuffer)
+      let page = WIKI.db.pages.cacheSchema.decode(pageBuffer)
       return {
         ...page,
         path: opts.path,
@@ -1108,7 +1106,7 @@ module.exports = class Page extends Model {
    * @returns {Promise} Promise with no value
    */
   static async migrateToLocale({ sourceLocale, targetLocale }) {
-    return WIKI.models.pages.query()
+    return WIKI.db.pages.query()
       .patch({
         localeCode: targetLocale
       })
@@ -1142,10 +1140,10 @@ module.exports = class Page extends Model {
    */
   static subscribeToEvents() {
     WIKI.events.inbound.on('deletePageFromCache', hash => {
-      WIKI.models.pages.deletePageFromCache(hash)
+      WIKI.db.pages.deletePageFromCache(hash)
     })
     WIKI.events.inbound.on('flushCache', () => {
-      WIKI.models.pages.flushCache()
+      WIKI.db.pages.flushCache()
     })
   }
 }

+ 4 - 6
server/models/renderers.js

@@ -6,8 +6,6 @@ const yaml = require('js-yaml')
 const DepGraph = require('dependency-graph').DepGraph
 const commonHelper = require('../helpers/common')
 
-/* global WIKI */
-
 /**
  * Renderer model
  */
@@ -32,7 +30,7 @@ module.exports = class Renderer extends Model {
   }
 
   static async getRenderers() {
-    return WIKI.models.renderers.query()
+    return WIKI.db.renderers.query()
   }
 
   static async fetchDefinitions() {
@@ -57,16 +55,16 @@ module.exports = class Renderer extends Model {
   }
 
   static async refreshRenderersFromDisk() {
-    // const dbRenderers = await WIKI.models.renderers.query()
+    // const dbRenderers = await WIKI.db.renderers.query()
 
     // -> Fetch definitions from disk
-    await WIKI.models.renderers.fetchDefinitions()
+    await WIKI.db.renderers.fetchDefinitions()
 
     // TODO: Merge existing configs with updated modules
   }
 
   static async getRenderingPipeline(contentType) {
-    const renderersDb = await WIKI.models.renderers.query().where('isEnabled', true)
+    const renderersDb = await WIKI.db.renderers.query().where('isEnabled', true)
     if (renderersDb && renderersDb.length > 0) {
       const renderers = renderersDb.map(rdr => {
         const renderer = _.find(WIKI.data.renderers, ['key', rdr.key])

+ 1 - 3
server/models/settings.js

@@ -1,8 +1,6 @@
 const Model = require('objection').Model
 const _ = require('lodash')
 
-/* global WIKI */
-
 /**
  * Settings model
  */
@@ -26,7 +24,7 @@ module.exports = class Setting extends Model {
   }
 
   static async getConfig() {
-    const settings = await WIKI.models.settings.query()
+    const settings = await WIKI.db.settings.query()
     if (settings.length > 0) {
       return _.reduce(settings, (res, val, key) => {
         _.set(res, val.key, (_.has(val.value, 'v')) ? val.value.v : val.value)

+ 7 - 9
server/models/sites.js

@@ -3,8 +3,6 @@ const crypto = require('crypto')
 const pem2jwk = require('pem-jwk').pem2jwk
 const _ = require('lodash')
 
-/* global WIKI */
-
 /**
  * Site model
  */
@@ -30,7 +28,7 @@ module.exports = class Site extends Model {
 
   static async getSiteByHostname ({ hostname, forceReload = false }) {
     if (forceReload) {
-      await WIKI.models.sites.reloadCache()
+      await WIKI.db.sites.reloadCache()
     }
     const siteId = WIKI.sitesMappings[hostname] || WIKI.sitesMappings['*']
     if (siteId) {
@@ -41,7 +39,7 @@ module.exports = class Site extends Model {
 
   static async reloadCache () {
     WIKI.logger.info('Reloading site configurations...')
-    const sites = await WIKI.models.sites.query().orderBy('id')
+    const sites = await WIKI.db.sites.query().orderBy('id')
     WIKI.sites = _.keyBy(sites, 'id')
     WIKI.sitesMappings = {}
     for (const site of sites) {
@@ -51,7 +49,7 @@ module.exports = class Site extends Model {
   }
 
   static async createSite (hostname, config) {
-    const newSite = await WIKI.models.sites.query().insertAndFetch({
+    const newSite = await WIKI.db.sites.query().insertAndFetch({
       hostname,
       isEnabled: true,
       config: _.defaultsDeep(config, {
@@ -114,7 +112,7 @@ module.exports = class Site extends Model {
 
     WIKI.logger.debug(`Creating new DB storage for site ${newSite.id}`)
 
-    await WIKI.models.storage.query().insert({
+    await WIKI.db.storage.query().insert({
       module: 'db',
       siteId: newSite.id,
       isEnabled: true,
@@ -135,11 +133,11 @@ module.exports = class Site extends Model {
   }
 
   static async updateSite (id, patch) {
-    return WIKI.models.sites.query().findById(id).patch(patch)
+    return WIKI.db.sites.query().findById(id).patch(patch)
   }
 
   static async deleteSite (id) {
-    await WIKI.models.storage.query().delete().where('siteId', id)
-    return WIKI.models.sites.query().deleteById(id)
+    await WIKI.db.storage.query().delete().where('siteId', id)
+    return WIKI.db.sites.query().deleteById(id)
   }
 }

+ 4 - 6
server/models/storage.js

@@ -5,8 +5,6 @@ const _ = require('lodash')
 const yaml = require('js-yaml')
 const commonHelper = require('../helpers/common')
 
-/* global WIKI */
-
 /**
  * Storage model
  */
@@ -31,7 +29,7 @@ module.exports = class Storage extends Model {
   }
 
   static async getTargets ({ siteId }) {
-    return WIKI.models.storage.query().where(builder => {
+    return WIKI.db.storage.query().where(builder => {
       if (siteId) {
         builder.where('siteId', siteId)
       }
@@ -85,7 +83,7 @@ module.exports = class Storage extends Model {
    * Initialize active storage targets
    */
   static async initTargets () {
-    const dbTargets = await WIKI.models.storage.query().where('isEnabled', true)
+    const dbTargets = await WIKI.db.storage.query().where('isEnabled', true)
     const activeModules = _.uniq(dbTargets.map(t => t.module))
     try {
       // -> Stop and delete existing jobs
@@ -109,7 +107,7 @@ module.exports = class Storage extends Model {
       //     await target.fn.init()
 
       //     // -> Save succeeded init state
-      //     await WIKI.models.storage.query().patch({
+      //     await WIKI.db.storage.query().patch({
       //       state: {
       //         status: 'operational',
       //         message: '',
@@ -138,7 +136,7 @@ module.exports = class Storage extends Model {
       //     }
       //   } catch (err) {
       //     // -> Save initialization error
-      //     await WIKI.models.storage.query().patch({
+      //     await WIKI.db.storage.query().patch({
       //       state: {
       //         status: 'error',
       //         message: err.message,

+ 3 - 5
server/models/tags.js

@@ -1,8 +1,6 @@
 const Model = require('objection').Model
 const _ = require('lodash')
 
-/* global WIKI */
-
 /**
  * Tags model
  */
@@ -50,7 +48,7 @@ module.exports = class Tag extends Model {
   }
 
   static async associateTags ({ tags, page }) {
-    let existingTags = await WIKI.models.tags.query().column('id', 'tag')
+    let existingTags = await WIKI.db.tags.query().column('id', 'tag')
 
     // Format tags
 
@@ -61,11 +59,11 @@ module.exports = class Tag extends Model {
     const newTags = _.filter(tags, t => !_.some(existingTags, ['tag', t])).map(t => ({ tag: t }))
     if (newTags.length > 0) {
       if (WIKI.config.db.type === 'postgres') {
-        const createdTags = await WIKI.models.tags.query().insert(newTags)
+        const createdTags = await WIKI.db.tags.query().insert(newTags)
         existingTags = _.concat(existingTags, createdTags)
       } else {
         for (const newTag of newTags) {
-          const createdTag = await WIKI.models.tags.query().insert(newTag)
+          const createdTag = await WIKI.db.tags.query().insert(newTag)
           existingTags.push(createdTag)
         }
       }

+ 4 - 4
server/models/userKeys.js

@@ -46,7 +46,7 @@ module.exports = class UserKey extends Model {
 
   static async generateToken ({ userId, kind, meta }, context) {
     const token = await nanoid()
-    await WIKI.models.userKeys.query().insert({
+    await WIKI.db.userKeys.query().insert({
       kind,
       token,
       meta,
@@ -57,10 +57,10 @@ module.exports = class UserKey extends Model {
   }
 
   static async validateToken ({ kind, token, skipDelete }, context) {
-    const res = await WIKI.models.userKeys.query().findOne({ kind, token }).withGraphJoined('user')
+    const res = await WIKI.db.userKeys.query().findOne({ kind, token }).withGraphJoined('user')
     if (res) {
       if (skipDelete !== true) {
-        await WIKI.models.userKeys.query().deleteById(res.id)
+        await WIKI.db.userKeys.query().deleteById(res.id)
       }
       if (DateTime.utc() > DateTime.fromISO(res.validUntil)) {
         throw new WIKI.Error.AuthValidationTokenInvalid()
@@ -75,6 +75,6 @@ module.exports = class UserKey extends Model {
   }
 
   static async destroyToken ({ token }) {
-    return WIKI.models.userKeys.query().findOne({ token }).delete()
+    return WIKI.db.userKeys.query().findOne({ token }).delete()
   }
 }

+ 46 - 46
server/models/users.js

@@ -90,7 +90,7 @@ module.exports = class User extends Model {
       name: WIKI.config.title,
       account: this.email
     })
-    await WIKI.models.users.query().findById(this.id).patch({
+    await WIKI.db.users.query().findById(this.id).patch({
       tfaIsActive: false,
       tfaSecret: tfaInfo.secret
     })
@@ -99,7 +99,7 @@ module.exports = class User extends Model {
   }
 
   async enableTFA() {
-    return WIKI.models.users.query().findById(this.id).patch({
+    return WIKI.db.users.query().findById(this.id).patch({
       tfaIsActive: true
     })
   }
@@ -129,7 +129,7 @@ module.exports = class User extends Model {
   // ------------------------------------------------
 
   static async getById(id) {
-    return WIKI.models.users.query().findById(id).withGraphFetched('groups').modifyGraph('groups', builder => {
+    return WIKI.db.users.query().findById(id).withGraphFetched('groups').modifyGraph('groups', builder => {
       builder.select('groups.id', 'permissions')
     })
   }
@@ -139,7 +139,7 @@ module.exports = class User extends Model {
     provider.info = _.find(WIKI.data.authentication, ['key', provider.stategyKey])
 
     // Find existing user
-    let user = await WIKI.models.users.query().findOne({
+    let user = await WIKI.db.users.query().findOne({
       providerId: _.toString(profile.id),
       providerKey
     })
@@ -164,7 +164,7 @@ module.exports = class User extends Model {
 
     // Find pending social user
     if (!user) {
-      user = await WIKI.models.users.query().findOne({
+      user = await WIKI.db.users.query().findOne({
         email: primaryEmail,
         providerId: null,
         providerKey
@@ -213,7 +213,7 @@ module.exports = class User extends Model {
       })
 
       if (pictureUrl === 'internal') {
-        await WIKI.models.users.updateUserAvatarData(user.id, profile.picture)
+        await WIKI.db.users.updateUserAvatarData(user.id, profile.picture)
       }
 
       return user
@@ -230,7 +230,7 @@ module.exports = class User extends Model {
       }
 
       // Create account
-      user = await WIKI.models.users.query().insertAndFetch({
+      user = await WIKI.db.users.query().insertAndFetch({
         providerKey: providerKey,
         providerId: _.toString(profile.id),
         email: primaryEmail,
@@ -250,7 +250,7 @@ module.exports = class User extends Model {
       }
 
       if (pictureUrl === 'internal') {
-        await WIKI.models.users.updateUserAvatarData(user.id, profile.picture)
+        await WIKI.db.users.updateUserAvatarData(user.id, profile.picture)
       }
 
       return user
@@ -288,7 +288,7 @@ module.exports = class User extends Model {
           if (!user) { return reject(new WIKI.Error.AuthLoginFailed()) }
 
           try {
-            const resp = await WIKI.models.users.afterLoginChecks(user, selStrategy.id, context, {
+            const resp = await WIKI.db.users.afterLoginChecks(user, selStrategy.id, context, {
               skipTFA: !strInfo.useForm,
               skipChangePwd: !strInfo.useForm
             })
@@ -326,7 +326,7 @@ module.exports = class User extends Model {
     if (!skipTFA) {
       if (authStr.tfaRequired && authStr.tfaSecret) {
         try {
-          const tfaToken = await WIKI.models.userKeys.generateToken({
+          const tfaToken = await WIKI.db.userKeys.generateToken({
             kind: 'tfa',
             userId: user.id
           })
@@ -342,7 +342,7 @@ module.exports = class User extends Model {
       } else if (WIKI.config.auth.enforce2FA || (authStr.tfaIsActive && !authStr.tfaSecret)) {
         try {
           const tfaQRImage = await user.generateTFA()
-          const tfaToken = await WIKI.models.userKeys.generateToken({
+          const tfaToken = await WIKI.db.userKeys.generateToken({
             kind: 'tfaSetup',
             userId: user.id
           })
@@ -362,7 +362,7 @@ module.exports = class User extends Model {
     // Must Change Password?
     if (!skipChangePwd && authStr.mustChangePwd) {
       try {
-        const pwdChangeToken = await WIKI.models.userKeys.generateToken({
+        const pwdChangeToken = await WIKI.db.userKeys.generateToken({
           kind: 'changePwd',
           userId: user.id
         })
@@ -381,7 +381,7 @@ module.exports = class User extends Model {
     return new Promise((resolve, reject) => {
       context.req.login(user, { session: false }, async errc => {
         if (errc) { return reject(errc) }
-        const jwtToken = await WIKI.models.users.refreshToken(user, strategyId)
+        const jwtToken = await WIKI.db.users.refreshToken(user, strategyId)
         resolve({ jwt: jwtToken.token, redirect })
       })
     })
@@ -392,7 +392,7 @@ module.exports = class User extends Model {
    */
   static async refreshToken(user, provider) {
     if (_.isString(user)) {
-      user = await WIKI.models.users.query().findById(user).withGraphFetched('groups').modifyGraph('groups', builder => {
+      user = await WIKI.db.users.query().findById(user).withGraphFetched('groups').modifyGraph('groups', builder => {
         builder.select('groups.id', 'permissions')
       })
       if (!user) {
@@ -409,7 +409,7 @@ module.exports = class User extends Model {
 
     // Update Last Login Date
     // -> Bypass Objection.js to avoid updating the updatedAt field
-    await WIKI.models.knex('users').where('id', user.id).update({ lastLoginAt: new Date().toISOString() })
+    await WIKI.db.knex('users').where('id', user.id).update({ lastLoginAt: new Date().toISOString() })
 
     return {
       token: jwt.sign({
@@ -435,7 +435,7 @@ module.exports = class User extends Model {
    */
   static async loginTFA ({ securityCode, continuationToken, setup }, context) {
     if (securityCode.length === 6 && continuationToken.length > 1) {
-      const user = await WIKI.models.userKeys.validateToken({
+      const user = await WIKI.db.userKeys.validateToken({
         kind: setup ? 'tfaSetup' : 'tfa',
         token: continuationToken,
         skipDelete: setup
@@ -445,7 +445,7 @@ module.exports = class User extends Model {
           if (setup) {
             await user.enableTFA()
           }
-          return WIKI.models.users.afterLoginChecks(user, context, { skipTFA: true })
+          return WIKI.db.users.afterLoginChecks(user, context, { skipTFA: true })
         } else {
           throw new WIKI.Error.AuthTFAFailed()
         }
@@ -461,13 +461,13 @@ module.exports = class User extends Model {
     if (!newPassword || newPassword.length < 6) {
       throw new WIKI.Error.InputInvalid('Password must be at least 6 characters!')
     }
-    const usr = await WIKI.models.userKeys.validateToken({
+    const usr = await WIKI.db.userKeys.validateToken({
       kind: 'changePwd',
       token: continuationToken
     })
 
     if (usr) {
-      await WIKI.models.users.query().patch({
+      await WIKI.db.users.query().patch({
         password: newPassword,
         mustChangePwd: false
       }).findById(usr.id)
@@ -475,7 +475,7 @@ module.exports = class User extends Model {
       return new Promise((resolve, reject) => {
         context.req.logIn(usr, { session: false }, async err => {
           if (err) { return reject(err) }
-          const jwtToken = await WIKI.models.users.refreshToken(usr)
+          const jwtToken = await WIKI.db.users.refreshToken(usr)
           resolve({ jwt: jwtToken.token })
         })
       })
@@ -488,7 +488,7 @@ module.exports = class User extends Model {
    * Send a password reset request
    */
   static async loginForgotPassword ({ email }, context) {
-    const usr = await WIKI.models.users.query().where({
+    const usr = await WIKI.db.users.query().where({
       email,
       providerKey: 'local'
     }).first()
@@ -496,7 +496,7 @@ module.exports = class User extends Model {
       WIKI.logger.debug(`Password reset attempt on nonexistant local account ${email}: [DISCARDED]`)
       return
     }
-    const resetToken = await WIKI.models.userKeys.generateToken({
+    const resetToken = await WIKI.db.userKeys.generateToken({
       userId: usr.id,
       kind: 'resetPwd'
     })
@@ -585,7 +585,7 @@ module.exports = class User extends Model {
     }
 
     // Check if email already exists
-    const usr = await WIKI.models.users.query().findOne({ email, providerKey })
+    const usr = await WIKI.db.users.query().findOne({ email, providerKey })
     if (!usr) {
       // Create the account
       let newUsrData = {
@@ -606,7 +606,7 @@ module.exports = class User extends Model {
         newUsrData.mustChangePwd = (mustChangePassword === true)
       }
 
-      const newUsr = await WIKI.models.users.query().insert(newUsrData)
+      const newUsr = await WIKI.db.users.query().insert(newUsrData)
 
       // Assign to group(s)
       if (groups.length > 0) {
@@ -640,11 +640,11 @@ module.exports = class User extends Model {
    * @param {Object} param0 User ID and fields to update
    */
   static async updateUser ({ id, email, name, newPassword, groups, location, jobTitle, timezone, dateFormat, appearance }) {
-    const usr = await WIKI.models.users.query().findById(id)
+    const usr = await WIKI.db.users.query().findById(id)
     if (usr) {
       let usrData = {}
       if (!_.isEmpty(email) && email !== usr.email) {
-        const dupUsr = await WIKI.models.users.query().select('id').where({
+        const dupUsr = await WIKI.db.users.query().select('id').where({
           email,
           providerKey: usr.providerKey
         }).first()
@@ -691,7 +691,7 @@ module.exports = class User extends Model {
       if (!_.isNil(appearance) && appearance !== usr.appearance) {
         usrData.appearance = appearance
       }
-      await WIKI.models.users.query().patch(usrData).findById(id)
+      await WIKI.db.users.query().patch(usrData).findById(id)
     } else {
       throw new WIKI.Error.UserNotFound()
     }
@@ -703,16 +703,16 @@ module.exports = class User extends Model {
    * @param {*} id User ID
    */
   static async deleteUser (id, replaceId) {
-    const usr = await WIKI.models.users.query().findById(id)
+    const usr = await WIKI.db.users.query().findById(id)
     if (usr) {
-      await WIKI.models.assets.query().patch({ authorId: replaceId }).where('authorId', id)
-      await WIKI.models.comments.query().patch({ authorId: replaceId }).where('authorId', id)
-      await WIKI.models.pageHistory.query().patch({ authorId: replaceId }).where('authorId', id)
-      await WIKI.models.pages.query().patch({ authorId: replaceId }).where('authorId', id)
-      await WIKI.models.pages.query().patch({ creatorId: replaceId }).where('creatorId', id)
-
-      await WIKI.models.userKeys.query().delete().where('userId', id)
-      await WIKI.models.users.query().deleteById(id)
+      await WIKI.db.assets.query().patch({ authorId: replaceId }).where('authorId', id)
+      await WIKI.db.comments.query().patch({ authorId: replaceId }).where('authorId', id)
+      await WIKI.db.pageHistory.query().patch({ authorId: replaceId }).where('authorId', id)
+      await WIKI.db.pages.query().patch({ authorId: replaceId }).where('authorId', id)
+      await WIKI.db.pages.query().patch({ creatorId: replaceId }).where('creatorId', id)
+
+      await WIKI.db.userKeys.query().delete().where('userId', id)
+      await WIKI.db.users.query().deleteById(id)
     } else {
       throw new WIKI.Error.UserNotFound()
     }
@@ -725,7 +725,7 @@ module.exports = class User extends Model {
    * @param {Object} context GraphQL Context
    */
   static async register ({ email, password, name, verify = false, bypassChecks = false }, context) {
-    const localStrg = await WIKI.models.authentication.getStrategy('local')
+    const localStrg = await WIKI.db.authentication.getStrategy('local')
     // Check if self-registration is enabled
     if (localStrg.selfRegistration || bypassChecks) {
       // Input sanitization
@@ -773,10 +773,10 @@ module.exports = class User extends Model {
         }
       }
       // Check if email already exists
-      const usr = await WIKI.models.users.query().findOne({ email, providerKey: 'local' })
+      const usr = await WIKI.db.users.query().findOne({ email, providerKey: 'local' })
       if (!usr) {
         // Create the account
-        const newUsr = await WIKI.models.users.query().insert({
+        const newUsr = await WIKI.db.users.query().insert({
           provider: 'local',
           email,
           name,
@@ -796,7 +796,7 @@ module.exports = class User extends Model {
 
         if (verify) {
           // Create verification token
-          const verificationToken = await WIKI.models.userKeys.generateToken({
+          const verificationToken = await WIKI.db.userKeys.generateToken({
             kind: 'verify',
             userId: newUsr.id
           })
@@ -846,7 +846,7 @@ module.exports = class User extends Model {
   }
 
   static async getGuestUser () {
-    const user = await WIKI.models.users.query().findById(WIKI.config.auth.guestUserId).withGraphJoined('groups').modifyGraph('groups', builder => {
+    const user = await WIKI.db.users.query().findById(WIKI.config.auth.guestUserId).withGraphJoined('groups').modifyGraph('groups', builder => {
       builder.select('groups.id', 'permissions')
     })
     if (!user) {
@@ -858,7 +858,7 @@ module.exports = class User extends Model {
   }
 
   static async getRootUser () {
-    let user = await WIKI.models.users.query().findById(WIKI.config.auth.rootAdminUserId)
+    let user = await WIKI.db.users.query().findById(WIKI.config.auth.rootAdminUserId)
     if (!user) {
       WIKI.logger.error('CRITICAL ERROR: Root Administrator user is missing!')
       process.exit(1)
@@ -876,15 +876,15 @@ module.exports = class User extends Model {
       if (data.length > 1024 * 1024) {
         throw new Error('Avatar image filesize is too large. 1MB max.')
       }
-      const existing = await WIKI.models.knex('userAvatars').select('id').where('id', userId).first()
+      const existing = await WIKI.db.knex('userAvatars').select('id').where('id', userId).first()
       if (existing) {
-        await WIKI.models.knex('userAvatars').where({
+        await WIKI.db.knex('userAvatars').where({
           id: userId
         }).update({
           data
         })
       } else {
-        await WIKI.models.knex('userAvatars').insert({
+        await WIKI.db.knex('userAvatars').insert({
           id: userId,
           data
         })
@@ -896,7 +896,7 @@ module.exports = class User extends Model {
 
   static async getUserAvatarData (userId) {
     try {
-      const usrData = await WIKI.models.knex('userAvatars').where('id', userId).first()
+      const usrData = await WIKI.db.knex('userAvatars').where('id', userId).first()
       if (usrData) {
         return usrData.data
       } else {

+ 1 - 1
server/modules/authentication/auth0/authentication.js

@@ -17,7 +17,7 @@ module.exports = {
         passReqToCallback: true
       }, async (req, accessToken, refreshToken, extraParams, profile, cb) => {
         try {
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile
           })

+ 1 - 3
server/modules/authentication/azure/authentication.js

@@ -1,7 +1,5 @@
 const _ = require('lodash')
 
-/* global WIKI */
-
 // ------------------------------------
 // Azure AD Account
 // ------------------------------------
@@ -39,7 +37,7 @@ module.exports = {
       }, async (req, iss, sub, profile, cb) => {
         const usrEmail = _.get(profile, '_json.email', null) || _.get(profile, '_json.preferred_username')
         try {
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile: {
               id: profile.oid,

+ 1 - 1
server/modules/authentication/cas/authentication.js

@@ -15,7 +15,7 @@ module.exports = {
         passReqToCallback: true
       }, async (req, profile, cb) => {
         try {
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile
           })

+ 1 - 1
server/modules/authentication/discord/authentication.js

@@ -22,7 +22,7 @@ module.exports = {
           if (conf.guildId && !_.some(profile.guilds, { id: conf.guildId })) {
             throw new WIKI.Error.AuthLoginFailed()
           }
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile: {
               ...profile,

+ 1 - 1
server/modules/authentication/dropbox/authentication.js

@@ -18,7 +18,7 @@ module.exports = {
         passReqToCallback: true
       }, async (req, accessToken, refreshToken, profile, cb) => {
         try {
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile: {
               ...profile,

+ 1 - 1
server/modules/authentication/facebook/authentication.js

@@ -19,7 +19,7 @@ module.exports = {
         passReqToCallback: true
       }, async (req, accessToken, refreshToken, profile, cb) => {
         try {
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile: {
               ...profile,

+ 1 - 1
server/modules/authentication/github/authentication.js

@@ -27,7 +27,7 @@ module.exports = {
     passport.use(conf.key,
       new GitHubStrategy(githubConfig, async (req, accessToken, refreshToken, profile, cb) => {
         try {
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile: {
               ...profile,

+ 1 - 1
server/modules/authentication/gitlab/authentication.js

@@ -19,7 +19,7 @@ module.exports = {
         passReqToCallback: true
       }, async (req, accessToken, refreshToken, profile, cb) => {
         try {
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile: {
               ...profile,

+ 1 - 1
server/modules/authentication/google/authentication.js

@@ -19,7 +19,7 @@ module.exports = {
         if (conf.hostedDomain && conf.hostedDomain != profile._json.hd) {
           throw new Error('Google authentication should have been performed with domain ' + conf.hostedDomain)
         }
-        const user = await WIKI.models.users.processProfile({
+        const user = await WIKI.db.users.processProfile({
           providerKey: req.params.strategy,
           profile: {
             ...profile,

+ 1 - 3
server/modules/authentication/keycloak/authentication.js

@@ -1,7 +1,5 @@
 const _ = require('lodash')
 
-/* global WIKI */
-
 // ------------------------------------
 // Keycloak Account
 // ------------------------------------
@@ -27,7 +25,7 @@ module.exports = {
           displayName = profile.fullName
         }
         try {
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile: {
               id: profile.keycloakId,

+ 1 - 1
server/modules/authentication/ldap/authentication.js

@@ -31,7 +31,7 @@ module.exports = {
             throw new Error('Invalid Unique ID field mapping!')
           }
 
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile: {
               id: userId,

+ 1 - 1
server/modules/authentication/local/authentication.js

@@ -15,7 +15,7 @@ module.exports = {
         passwordField: 'password'
       }, async (uEmail, uPassword, done) => {
         try {
-          const user = await WIKI.models.users.query().findOne({
+          const user = await WIKI.db.users.query().findOne({
             email: uEmail.toLowerCase()
           })
           if (user) {

+ 1 - 1
server/modules/authentication/microsoft/authentication.js

@@ -18,7 +18,7 @@ module.exports = {
         passReqToCallback: true
       }, async (req, accessToken, refreshToken, profile, cb) => {
         try {
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile: {
               ...profile,

+ 1 - 3
server/modules/authentication/oauth2/authentication.js

@@ -1,7 +1,5 @@
 const _ = require('lodash')
 
-/* global WIKI */
-
 // ------------------------------------
 // OAuth2 Account
 // ------------------------------------
@@ -21,7 +19,7 @@ module.exports = {
       scope: conf.scope
     }, async (req, accessToken, refreshToken, profile, cb) => {
       try {
-        const user = await WIKI.models.users.processProfile({
+        const user = await WIKI.db.users.processProfile({
           providerKey: req.params.strategy,
           profile: {
             ...profile,

+ 1 - 3
server/modules/authentication/oidc/authentication.js

@@ -1,7 +1,5 @@
 const _ = require('lodash')
 
-/* global WIKI */
-
 // ------------------------------------
 // OpenID Connect Account
 // ------------------------------------
@@ -22,7 +20,7 @@ module.exports = {
         passReqToCallback: true
       }, async (req, iss, sub, profile, cb) => {
         try {
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile: {
               ...profile,

+ 1 - 1
server/modules/authentication/okta/authentication.js

@@ -20,7 +20,7 @@ module.exports = {
         passReqToCallback: true
       }, async (req, accessToken, refreshToken, profile, cb) => {
         try {
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile: {
               ...profile,

+ 1 - 3
server/modules/authentication/rocketchat/authentication.js

@@ -1,7 +1,5 @@
 const _ = require('lodash')
 
-/* global WIKI */
-
 // ------------------------------------
 // Rocket.chat Account
 // ------------------------------------
@@ -43,7 +41,7 @@ module.exports = {
         passReqToCallback: true
       }, async (req, accessToken, refreshToken, profile, cb) => {
         try {
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile
           })

+ 1 - 3
server/modules/authentication/saml/authentication.js

@@ -1,7 +1,5 @@
 const _ = require('lodash')
 
-/* global WIKI */
-
 // ------------------------------------
 // SAML Account
 // ------------------------------------
@@ -47,7 +45,7 @@ module.exports = {
             throw new Error('Invalid or Missing Unique ID field!')
           }
 
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile: {
               id: userId,

+ 1 - 1
server/modules/authentication/slack/authentication.js

@@ -19,7 +19,7 @@ module.exports = {
         passReqToCallback: true
       }, async (req, accessToken, refreshToken, { user: userProfile }, cb) => {
         try {
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile: {
               ...userProfile,

+ 1 - 1
server/modules/authentication/twitch/authentication.js

@@ -17,7 +17,7 @@ module.exports = {
         passReqToCallback: true
       }, async (req, accessToken, refreshToken, profile, cb) => {
         try {
-          const user = await WIKI.models.users.processProfile({
+          const user = await WIKI.db.users.processProfile({
             providerKey: req.params.strategy,
             profile: {
               ...profile,

+ 7 - 9
server/modules/comments/default/comment.js

@@ -6,8 +6,6 @@ const _ = require('lodash')
 const { AkismetClient } = require('akismet-api')
 const moment = require('moment')
 
-/* global WIKI */
-
 const window = new JSDOM('').window
 const DOMPurify = createDOMPurify(window)
 
@@ -108,14 +106,14 @@ module.exports = {
 
     // -> Check for minimum delay between posts
     if (WIKI.data.commentProvider.config.minDelay > 0) {
-      const lastComment = await WIKI.models.comments.query().select('updatedAt').findOne('authorId', user.id).orderBy('updatedAt', 'desc')
+      const lastComment = await WIKI.db.comments.query().select('updatedAt').findOne('authorId', user.id).orderBy('updatedAt', 'desc')
       if (lastComment && moment().subtract(WIKI.data.commentProvider.config.minDelay, 'seconds').isBefore(lastComment.updatedAt)) {
         throw new Error('Your administrator has set a time limit before you can post another comment. Try again later.')
       }
     }
 
     // -> Save Comment to DB
-    const cm = await WIKI.models.comments.query().insert(newComment)
+    const cm = await WIKI.db.comments.query().insert(newComment)
 
     // -> Return Comment ID
     return cm.id
@@ -125,7 +123,7 @@ module.exports = {
    */
   async update ({ id, content, user }) {
     const renderedContent = DOMPurify.sanitize(mkdown.render(content))
-    await WIKI.models.comments.query().findById(id).patch({
+    await WIKI.db.comments.query().findById(id).patch({
       render: renderedContent
     })
     return renderedContent
@@ -134,26 +132,26 @@ module.exports = {
    * Delete an existing comment by ID
    */
   async remove ({ id, user }) {
-    return WIKI.models.comments.query().findById(id).delete()
+    return WIKI.db.comments.query().findById(id).delete()
   },
   /**
    * Get the page ID from a comment ID
    */
   async getPageIdFromCommentId (id) {
-    const result = await WIKI.models.comments.query().select('pageId').findById(id)
+    const result = await WIKI.db.comments.query().select('pageId').findById(id)
     return (result) ? result.pageId : false
   },
   /**
    * Get a comment by ID
    */
   async getCommentById (id) {
-    return WIKI.models.comments.query().findById(id)
+    return WIKI.db.comments.query().findById(id)
   },
   /**
    * Get the total comments count for a page ID
    */
   async count (pageId) {
-    const result = await WIKI.models.comments.query().count('* as total').where('pageId', pageId).first()
+    const result = await WIKI.db.comments.query().count('* as total').where('pageId', pageId).first()
     return _.toSafeInteger(result.total)
   }
 }

+ 0 - 2
server/modules/extensions/puppeteer/ext.js

@@ -4,8 +4,6 @@ const util = require('util')
 const exec = util.promisify(require('child_process').exec)
 const fs = require('fs-extra')
 
-/* global WIKI */
-
 module.exports = {
   key: 'puppeteer',
   title: 'Puppeteer',

+ 0 - 2
server/modules/extensions/sharp/ext.js

@@ -5,8 +5,6 @@ const util = require('util')
 const exec = util.promisify(require('child_process').exec)
 const { pipeline } = require('stream/promises')
 
-/* global WIKI */
-
 module.exports = {
   key: 'sharp',
   title: 'Sharp',

+ 4 - 6
server/modules/rendering/html-core/renderer.js

@@ -6,8 +6,6 @@ const URL = require('url').URL
 
 const mustacheRegExp = /(\{|&#x7b;?){2}(.+?)(\}|&#x7d;?){2}/i
 
-/* global WIKI */
-
 module.exports = {
   async render() {
     const $ = cheerio.load(this.input, {
@@ -133,7 +131,7 @@ module.exports = {
 
     if (internalRefs.length > 0) {
       // -> Find matching pages
-      const results = await WIKI.models.pages.query().column('id', 'path', 'localeCode').where(builder => {
+      const results = await WIKI.db.pages.query().column('id', 'path', 'localeCode').where(builder => {
         internalRefs.forEach((ref, idx) => {
           if (idx < 1) {
             builder.where(ref)
@@ -168,14 +166,14 @@ module.exports = {
       })
       if (missingLinks.length > 0) {
         if (WIKI.config.db.type === 'postgres') {
-          await WIKI.models.pageLinks.query().insert(missingLinks.map(lnk => ({
+          await WIKI.db.pageLinks.query().insert(missingLinks.map(lnk => ({
             pageId: this.page.id,
             path: lnk.path,
             localeCode: lnk.localeCode
           })))
         } else {
           for (const lnk of missingLinks) {
-            await WIKI.models.pageLinks.query().insert({
+            await WIKI.db.pageLinks.query().insert({
               pageId: this.page.id,
               path: lnk.path,
               localeCode: lnk.localeCode
@@ -191,7 +189,7 @@ module.exports = {
         return nLink.localeCode === pLink.localeCode && nLink.path === pLink.path
       })
       if (outdatedLinks.length > 0) {
-        await WIKI.models.pageLinks.query().delete().whereIn('id', _.map(outdatedLinks, 'id'))
+        await WIKI.db.pageLinks.query().delete().whereIn('id', _.map(outdatedLinks, 'id'))
       }
     }
 

+ 0 - 2
server/modules/rendering/markdown-katex/renderer.js

@@ -1,8 +1,6 @@
 const katex = require('katex')
 const chemParse = require('./mhchem')
 
-/* global WIKI */
-
 // ------------------------------------
 // Markdown - KaTeX Renderer
 // ------------------------------------

+ 0 - 2
server/modules/rendering/markdown-mathjax/renderer.js

@@ -1,7 +1,5 @@
 const mjax = require('mathjax')
 
-/* global WIKI */
-
 // ------------------------------------
 // Markdown - MathJax Renderer
 // ------------------------------------

+ 0 - 24
server/modules/search/algolia/definition.yml

@@ -1,24 +0,0 @@
-key: algolia
-title: Algolia
-description: Algolia is a powerful search-as-a-service solution, made easy to use with API clients, UI libraries, and pre-built integrations.
-author: requarks.io
-logo: https://static.requarks.io/logo/algolia.svg
-website: https://www.algolia.com/
-isAvailable: true
-props:
-  appId:
-    type: String
-    title: App ID
-    hint: Your Algolia Application ID, found under API Keys
-    order: 1
-  apiKey:
-    type: String
-    title: Admin API Key
-    hint: Your Algolia Admin API Key, found under API Keys.
-    order: 2
-  indexName:
-    type: String
-    title: Index Name
-    hint: The name of the index you created under Indices.
-    default: wiki
-    order: 3

+ 0 - 203
server/modules/search/algolia/engine.js

@@ -1,203 +0,0 @@
-const _ = require('lodash')
-const algoliasearch = require('algoliasearch')
-const stream = require('stream')
-const Promise = require('bluebird')
-const pipeline = Promise.promisify(stream.pipeline)
-
-/* global WIKI */
-
-module.exports = {
-  async activate() {
-    // not used
-  },
-  async deactivate() {
-    // not used
-  },
-  /**
-   * INIT
-   */
-  async init() {
-    WIKI.logger.info(`(SEARCH/ALGOLIA) Initializing...`)
-    this.client = algoliasearch(this.config.appId, this.config.apiKey)
-    this.index = this.client.initIndex(this.config.indexName)
-
-    // -> Create Search Index
-    WIKI.logger.info(`(SEARCH/ALGOLIA) Setting index configuration...`)
-    await this.index.setSettings({
-      searchableAttributes: [
-        'title',
-        'description',
-        'content'
-      ],
-      attributesToRetrieve: [
-        'locale',
-        'path',
-        'title',
-        'description'
-      ],
-      advancedSyntax: true
-    })
-    WIKI.logger.info(`(SEARCH/ALGOLIA) Initialization completed.`)
-  },
-  /**
-   * QUERY
-   *
-   * @param {String} q Query
-   * @param {Object} opts Additional options
-   */
-  async query(q, opts) {
-    try {
-      const results = await this.index.search(q, {
-        hitsPerPage: 50
-      })
-      return {
-        results: _.map(results.hits, r => ({
-          id: r.objectID,
-          locale: r.locale,
-          path: r.path,
-          title: r.title,
-          description: r.description
-        })),
-        suggestions: [],
-        totalHits: results.nbHits
-      }
-    } catch (err) {
-      WIKI.logger.warn('Search Engine Error:')
-      WIKI.logger.warn(err)
-    }
-  },
-  /**
-   * CREATE
-   *
-   * @param {Object} page Page to create
-   */
-  async created(page) {
-    await this.index.saveObject({
-      objectID: page.hash,
-      locale: page.localeCode,
-      path: page.path,
-      title: page.title,
-      description: page.description,
-      content: page.safeContent
-    })
-  },
-  /**
-   * UPDATE
-   *
-   * @param {Object} page Page to update
-   */
-  async updated(page) {
-    await this.index.partialUpdateObject({
-      objectID: page.hash,
-      title: page.title,
-      description: page.description,
-      content: page.safeContent
-    })
-  },
-  /**
-   * DELETE
-   *
-   * @param {Object} page Page to delete
-   */
-  async deleted(page) {
-    await this.index.deleteObject(page.hash)
-  },
-  /**
-   * RENAME
-   *
-   * @param {Object} page Page to rename
-   */
-  async renamed(page) {
-    await this.index.deleteObject(page.hash)
-    await this.index.saveObject({
-      objectID: page.destinationHash,
-      locale: page.destinationLocaleCode,
-      path: page.destinationPath,
-      title: page.title,
-      description: page.description,
-      content: page.safeContent
-    })
-  },
-  /**
-   * REBUILD INDEX
-   */
-  async rebuild() {
-    WIKI.logger.info(`(SEARCH/ALGOLIA) Rebuilding Index...`)
-    await this.index.clearObjects()
-
-    const MAX_DOCUMENT_BYTES = 10 * Math.pow(2, 10) // 10 KB
-    const MAX_INDEXING_BYTES = 10 * Math.pow(2, 20) - Buffer.from('[').byteLength - Buffer.from(']').byteLength // 10 MB
-    const MAX_INDEXING_COUNT = 1000
-    const COMMA_BYTES = Buffer.from(',').byteLength
-
-    let chunks = []
-    let bytes = 0
-
-    const processDocument = async (cb, doc) => {
-      try {
-        if (doc) {
-          const docBytes = Buffer.from(JSON.stringify(doc)).byteLength
-          // -> Document too large
-          if (docBytes >= MAX_DOCUMENT_BYTES) {
-            throw new Error('Document exceeds maximum size allowed by Algolia.')
-          }
-
-          // -> Current batch exceeds size hard limit, flush
-          if (docBytes + COMMA_BYTES + bytes >= MAX_INDEXING_BYTES) {
-            await flushBuffer()
-          }
-
-          if (chunks.length > 0) {
-            bytes += COMMA_BYTES
-          }
-          bytes += docBytes
-          chunks.push(doc)
-
-          // -> Current batch exceeds count soft limit, flush
-          if (chunks.length >= MAX_INDEXING_COUNT) {
-            await flushBuffer()
-          }
-        } else {
-          // -> End of stream, flush
-          await flushBuffer()
-        }
-        cb()
-      } catch (err) {
-        cb(err)
-      }
-    }
-
-    const flushBuffer = async () => {
-      WIKI.logger.info(`(SEARCH/ALGOLIA) Sending batch of ${chunks.length}...`)
-      try {
-        await this.index.saveObjects(
-          _.map(chunks, doc => ({
-            objectID: doc.id,
-            locale: doc.locale,
-            path: doc.path,
-            title: doc.title,
-            description: doc.description,
-            content: WIKI.models.pages.cleanHTML(doc.render)
-          }))
-        )
-      } catch (err) {
-        WIKI.logger.warn('(SEARCH/ALGOLIA) Failed to send batch to Algolia: ', err)
-      }
-      chunks.length = 0
-      bytes = 0
-    }
-
-    await pipeline(
-      WIKI.models.knex.column({ id: 'hash' }, 'path', { locale: 'localeCode' }, 'title', 'description', 'render').select().from('pages').where({
-        isPublished: true,
-        isPrivate: false
-      }).stream(),
-      new stream.Transform({
-        objectMode: true,
-        transform: async (chunk, enc, cb) => processDocument(cb, chunk),
-        flush: async (cb) => processDocument(cb)
-      })
-    )
-    WIKI.logger.info(`(SEARCH/ALGOLIA) Index rebuilt successfully.`)
-  }
-}

+ 0 - 88
server/modules/search/aws/definition.yml

@@ -1,88 +0,0 @@
-key: aws
-title: AWS CloudSearch
-description: Amazon CloudSearch is a managed service in the AWS Cloud that makes it simple and cost-effective to set up, manage, and scale a search solution for your website or application.
-author: requarks.io
-logo: https://static.requarks.io/logo/aws-cloudsearch.svg
-website: https://aws.amazon.com/cloudsearch/
-isAvailable: true
-props:
-  domain:
-    type: String
-    title: Search Domain
-    hint: The name of your CloudSearch service.
-    order: 1
-  endpoint:
-    type: String
-    title: Document Endpoint
-    hint: The Document Endpoint specified in the domain AWS console dashboard.
-    order: 2
-  region:
-    type: String
-    title: Region
-    hint: The AWS datacenter region where the instance was created.
-    default: us-east-1
-    enum:
-      - ap-northeast-1
-      - ap-northeast-2
-      - ap-southeast-1
-      - ap-southeast-2
-      - eu-central-1
-      - eu-west-1
-      - sa-east-1
-      - us-east-1
-      - us-west-1
-      - us-west-2
-    order: 3
-  accessKeyId:
-    type: String
-    title: Access Key ID
-    hint: The Access Key ID with CloudSearchFullAccess role access to the CloudSearch instance.
-    order: 4
-  secretAccessKey :
-    type: String
-    title: Secret Access Key
-    hint: The Secret Access Key for the Access Key ID provided above.
-    order: 5
-  AnalysisSchemeLang:
-    type: String
-    title: Analysis Scheme Language
-    hint: The language used to analyse content.
-    default: en
-    enum:
-      - 'ar'
-      - 'bg'
-      - 'ca'
-      - 'cs'
-      - 'da'
-      - 'de'
-      - 'el'
-      - 'en'
-      - 'es'
-      - 'eu'
-      - 'fa'
-      - 'fi'
-      - 'fr'
-      - 'ga'
-      - 'gl'
-      - 'he'
-      - 'hi'
-      - 'hu'
-      - 'hy'
-      - 'id'
-      - 'it'
-      - 'ja'
-      - 'ko'
-      - 'lv'
-      - 'mul'
-      - 'nl'
-      - 'no'
-      - 'pt'
-      - 'ro'
-      - 'ru'
-      - 'sv'
-      - 'th'
-      - 'tr'
-      - 'zh-Hans'
-      - 'zh-Hant'
-    order: 6
-

+ 0 - 370
server/modules/search/aws/engine.js

@@ -1,370 +0,0 @@
-const _ = require('lodash')
-const AWS = require('aws-sdk')
-const stream = require('stream')
-const Promise = require('bluebird')
-const pipeline = Promise.promisify(stream.pipeline)
-
-/* global WIKI */
-
-module.exports = {
-  async activate() {
-    // not used
-  },
-  async deactivate() {
-    // not used
-  },
-  /**
-   * INIT
-   */
-  async init() {
-    WIKI.logger.info(`(SEARCH/AWS) Initializing...`)
-    this.client = new AWS.CloudSearch({
-      apiVersion: '2013-01-01',
-      accessKeyId: this.config.accessKeyId,
-      secretAccessKey: this.config.secretAccessKey,
-      region: this.config.region
-    })
-    this.clientDomain = new AWS.CloudSearchDomain({
-      apiVersion: '2013-01-01',
-      endpoint: this.config.endpoint,
-      accessKeyId: this.config.accessKeyId,
-      secretAccessKey: this.config.secretAccessKey,
-      region: this.config.region
-    })
-
-    let rebuildIndex = false
-
-    // -> Define Analysis Schemes
-    const schemes = await this.client.describeAnalysisSchemes({
-      DomainName: this.config.domain,
-      AnalysisSchemeNames: ['default_anlscheme']
-    }).promise()
-    if (_.get(schemes, 'AnalysisSchemes', []).length < 1) {
-      WIKI.logger.info(`(SEARCH/AWS) Defining Analysis Scheme...`)
-      await this.client.defineAnalysisScheme({
-        DomainName: this.config.domain,
-        AnalysisScheme: {
-          AnalysisSchemeLanguage: this.config.AnalysisSchemeLang,
-          AnalysisSchemeName: 'default_anlscheme'
-        }
-      }).promise()
-      rebuildIndex = true
-    }
-
-    // -> Define Index Fields
-    const fields = await this.client.describeIndexFields({
-      DomainName: this.config.domain
-    }).promise()
-    if (_.get(fields, 'IndexFields', []).length < 1) {
-      WIKI.logger.info(`(SEARCH/AWS) Defining Index Fields...`)
-      await this.client.defineIndexField({
-        DomainName: this.config.domain,
-        IndexField: {
-          IndexFieldName: 'id',
-          IndexFieldType: 'literal'
-        }
-      }).promise()
-      await this.client.defineIndexField({
-        DomainName: this.config.domain,
-        IndexField: {
-          IndexFieldName: 'path',
-          IndexFieldType: 'literal'
-        }
-      }).promise()
-      await this.client.defineIndexField({
-        DomainName: this.config.domain,
-        IndexField: {
-          IndexFieldName: 'locale',
-          IndexFieldType: 'literal'
-        }
-      }).promise()
-      await this.client.defineIndexField({
-        DomainName: this.config.domain,
-        IndexField: {
-          IndexFieldName: 'title',
-          IndexFieldType: 'text',
-          TextOptions: {
-            ReturnEnabled: true,
-            AnalysisScheme: 'default_anlscheme'
-          }
-        }
-      }).promise()
-      await this.client.defineIndexField({
-        DomainName: this.config.domain,
-        IndexField: {
-          IndexFieldName: 'description',
-          IndexFieldType: 'text',
-          TextOptions: {
-            ReturnEnabled: true,
-            AnalysisScheme: 'default_anlscheme'
-          }
-        }
-      }).promise()
-      await this.client.defineIndexField({
-        DomainName: this.config.domain,
-        IndexField: {
-          IndexFieldName: 'content',
-          IndexFieldType: 'text',
-          TextOptions: {
-            ReturnEnabled: false,
-            AnalysisScheme: 'default_anlscheme'
-          }
-        }
-      }).promise()
-      rebuildIndex = true
-    }
-
-    // -> Define suggester
-    const suggesters = await this.client.describeSuggesters({
-      DomainName: this.config.domain,
-      SuggesterNames: ['default_suggester']
-    }).promise()
-    if (_.get(suggesters, 'Suggesters', []).length < 1) {
-      WIKI.logger.info(`(SEARCH/AWS) Defining Suggester...`)
-      await this.client.defineSuggester({
-        DomainName: this.config.domain,
-        Suggester: {
-          SuggesterName: 'default_suggester',
-          DocumentSuggesterOptions: {
-            SourceField: 'title',
-            FuzzyMatching: 'high'
-          }
-        }
-      }).promise()
-      rebuildIndex = true
-    }
-
-    // -> Rebuild Index
-    if (rebuildIndex) {
-      WIKI.logger.info(`(SEARCH/AWS) Requesting Index Rebuild...`)
-      await this.client.indexDocuments({
-        DomainName: this.config.domain
-      }).promise()
-    }
-
-    WIKI.logger.info(`(SEARCH/AWS) Initialization completed.`)
-  },
-  /**
-   * QUERY
-   *
-   * @param {String} q Query
-   * @param {Object} opts Additional options
-   */
-  async query(q, opts) {
-    try {
-      let suggestions = []
-      const results = await this.clientDomain.search({
-        query: q,
-        partial: true,
-        size: 50
-      }).promise()
-      if (results.hits.found < 5) {
-        const suggestResults = await this.clientDomain.suggest({
-          query: q,
-          suggester: 'default_suggester',
-          size: 5
-        }).promise()
-        suggestions = suggestResults.suggest.suggestions.map(s => s.suggestion)
-      }
-      return {
-        results: _.map(results.hits.hit, r => ({
-          id: r.id,
-          path: _.head(r.fields.path),
-          locale: _.head(r.fields.locale),
-          title: _.head(r.fields.title) || '',
-          description: _.head(r.fields.description) || ''
-        })),
-        suggestions: suggestions,
-        totalHits: results.hits.found
-      }
-    } catch (err) {
-      WIKI.logger.warn('Search Engine Error:')
-      WIKI.logger.warn(err)
-    }
-  },
-  /**
-   * CREATE
-   *
-   * @param {Object} page Page to create
-   */
-  async created(page) {
-    await this.clientDomain.uploadDocuments({
-      contentType: 'application/json',
-      documents: JSON.stringify([
-        {
-          type: 'add',
-          id: page.hash,
-          fields: {
-            locale: page.localeCode,
-            path: page.path,
-            title: page.title,
-            description: page.description,
-            content: page.safeContent
-          }
-        }
-      ])
-    }).promise()
-  },
-  /**
-   * UPDATE
-   *
-   * @param {Object} page Page to update
-   */
-  async updated(page) {
-    await this.clientDomain.uploadDocuments({
-      contentType: 'application/json',
-      documents: JSON.stringify([
-        {
-          type: 'add',
-          id: page.hash,
-          fields: {
-            locale: page.localeCode,
-            path: page.path,
-            title: page.title,
-            description: page.description,
-            content: page.safeContent
-          }
-        }
-      ])
-    }).promise()
-  },
-  /**
-   * DELETE
-   *
-   * @param {Object} page Page to delete
-   */
-  async deleted(page) {
-    await this.clientDomain.uploadDocuments({
-      contentType: 'application/json',
-      documents: JSON.stringify([
-        {
-          type: 'delete',
-          id: page.hash
-        }
-      ])
-    }).promise()
-  },
-  /**
-   * RENAME
-   *
-   * @param {Object} page Page to rename
-   */
-  async renamed(page) {
-    await this.clientDomain.uploadDocuments({
-      contentType: 'application/json',
-      documents: JSON.stringify([
-        {
-          type: 'delete',
-          id: page.hash
-        }
-      ])
-    }).promise()
-    await this.clientDomain.uploadDocuments({
-      contentType: 'application/json',
-      documents: JSON.stringify([
-        {
-          type: 'add',
-          id: page.destinationHash,
-          fields: {
-            locale: page.destinationLocaleCode,
-            path: page.destinationPath,
-            title: page.title,
-            description: page.description,
-            content: page.safeContent
-          }
-        }
-      ])
-    }).promise()
-  },
-  /**
-   * REBUILD INDEX
-   */
-  async rebuild() {
-    WIKI.logger.info(`(SEARCH/AWS) Rebuilding Index...`)
-
-    const MAX_DOCUMENT_BYTES = Math.pow(2, 20)
-    const MAX_INDEXING_BYTES = 5 * Math.pow(2, 20) - Buffer.from('[').byteLength - Buffer.from(']').byteLength
-    const MAX_INDEXING_COUNT = 1000
-    const COMMA_BYTES = Buffer.from(',').byteLength
-
-    let chunks = []
-    let bytes = 0
-
-    const processDocument = async (cb, doc) => {
-      try {
-        if (doc) {
-          const docBytes = Buffer.from(JSON.stringify(doc)).byteLength
-          // -> Document too large
-          if (docBytes >= MAX_DOCUMENT_BYTES) {
-            throw new Error('Document exceeds maximum size allowed by AWS CloudSearch.')
-          }
-
-          // -> Current batch exceeds size hard limit, flush
-          if (docBytes + COMMA_BYTES + bytes >= MAX_INDEXING_BYTES) {
-            await flushBuffer()
-          }
-
-          if (chunks.length > 0) {
-            bytes += COMMA_BYTES
-          }
-          bytes += docBytes
-          chunks.push(doc)
-
-          // -> Current batch exceeds count soft limit, flush
-          if (chunks.length >= MAX_INDEXING_COUNT) {
-            await flushBuffer()
-          }
-        } else {
-          // -> End of stream, flush
-          await flushBuffer()
-        }
-        cb()
-      } catch (err) {
-        cb(err)
-      }
-    }
-
-    const flushBuffer = async () => {
-      WIKI.logger.info(`(SEARCH/AWS) Sending batch of ${chunks.length}...`)
-      try {
-        await this.clientDomain.uploadDocuments({
-          contentType: 'application/json',
-          documents: JSON.stringify(_.map(chunks, doc => ({
-            type: 'add',
-            id: doc.id,
-            fields: {
-              locale: doc.locale,
-              path: doc.path,
-              title: doc.title,
-              description: doc.description,
-              content: WIKI.models.pages.cleanHTML(doc.render)
-            }
-          })))
-        }).promise()
-      } catch (err) {
-        WIKI.logger.warn('(SEARCH/AWS) Failed to send batch to AWS CloudSearch: ', err)
-      }
-      chunks.length = 0
-      bytes = 0
-    }
-
-    await pipeline(
-      WIKI.models.knex.column({ id: 'hash' }, 'path', { locale: 'localeCode' }, 'title', 'description', 'render').select().from('pages').where({
-        isPublished: true,
-        isPrivate: false
-      }).stream(),
-      new stream.Transform({
-        objectMode: true,
-        transform: async (chunk, enc, cb) => processDocument(cb, chunk),
-        flush: async (cb) => processDocument(cb)
-      })
-    )
-
-    WIKI.logger.info(`(SEARCH/AWS) Requesting Index Rebuild...`)
-    await this.client.indexDocuments({
-      DomainName: this.config.domain
-    }).promise()
-
-    WIKI.logger.info(`(SEARCH/AWS) Index rebuilt successfully.`)
-  }
-}

+ 0 - 24
server/modules/search/azure/definition.yml

@@ -1,24 +0,0 @@
-key: azure
-title: Azure Search
-description: AI-Powered cloud search service for web and mobile app development.
-author: requarks.io
-logo: https://static.requarks.io/logo/azure.svg
-website: https://azure.microsoft.com/services/search/
-isAvailable: true
-props:
-  serviceName:
-    type: String
-    title: Service Name
-    hint: The name of the Azure Search Service. Found under Properties.
-    order: 1
-  adminKey:
-    type: String
-    title: Admin API Key
-    hint: Either the primary or secondary admin key. Found under Keys.
-    order: 2
-  indexName:
-    type: String
-    title: Index Name
-    hint: 'Name to use when creating the index. (default: wiki)'
-    default: wiki
-    order: 3

+ 0 - 235
server/modules/search/azure/engine.js

@@ -1,235 +0,0 @@
-const _ = require('lodash')
-const { SearchService, QueryType } = require('azure-search-client')
-const request = require('request-promise')
-const stream = require('stream')
-const Promise = require('bluebird')
-const pipeline = Promise.promisify(stream.pipeline)
-
-/* global WIKI */
-
-module.exports = {
-  async activate() {
-    // not used
-  },
-  async deactivate() {
-    // not used
-  },
-  /**
-   * INIT
-   */
-  async init() {
-    WIKI.logger.info(`(SEARCH/AZURE) Initializing...`)
-    this.client = new SearchService(this.config.serviceName, this.config.adminKey)
-
-    // -> Create Search Index
-    const indexes = await this.client.indexes.list()
-    if (!_.find(_.get(indexes, 'result.value', []), ['name', this.config.indexName])) {
-      WIKI.logger.info(`(SEARCH/AZURE) Creating index...`)
-      await this.client.indexes.create({
-        name: this.config.indexName,
-        fields: [
-          {
-            name: 'id',
-            type: 'Edm.String',
-            key: true,
-            searchable: false
-          },
-          {
-            name: 'locale',
-            type: 'Edm.String',
-            searchable: false
-          },
-          {
-            name: 'path',
-            type: 'Edm.String',
-            searchable: false
-          },
-          {
-            name: 'title',
-            type: 'Edm.String',
-            searchable: true
-          },
-          {
-            name: 'description',
-            type: 'Edm.String',
-            searchable: true
-          },
-          {
-            name: 'content',
-            type: 'Edm.String',
-            searchable: true
-          }
-        ],
-        scoringProfiles: [
-          {
-            name: 'fieldWeights',
-            text: {
-              weights: {
-                title: 4,
-                description: 3,
-                content: 1
-              }
-            }
-          }
-        ],
-        suggesters: [
-          {
-            name: 'suggestions',
-            searchMode: 'analyzingInfixMatching',
-            sourceFields: ['title', 'description', 'content']
-          }
-        ]
-      })
-    }
-    WIKI.logger.info(`(SEARCH/AZURE) Initialization completed.`)
-  },
-  /**
-   * QUERY
-   *
-   * @param {String} q Query
-   * @param {Object} opts Additional options
-   */
-  async query(q, opts) {
-    try {
-      let suggestions = []
-      const results = await this.client.indexes.use(this.config.indexName).search({
-        count: true,
-        scoringProfile: 'fieldWeights',
-        search: q,
-        select: 'id, locale, path, title, description',
-        queryType: QueryType.simple,
-        top: 50
-      })
-      if (results.result.value.length < 5) {
-        // Using plain request, not yet available in library...
-        try {
-          const suggestResults = await request({
-            uri: `https://${this.config.serviceName}.search.windows.net/indexes/${this.config.indexName}/docs/autocomplete`,
-            method: 'post',
-            qs: {
-              'api-version': '2017-11-11-Preview'
-            },
-            headers: {
-              'api-key': this.config.adminKey,
-              'Content-Type': 'application/json'
-            },
-            json: true,
-            body: {
-              autocompleteMode: 'oneTermWithContext',
-              search: q,
-              suggesterName: 'suggestions'
-            }
-          })
-          suggestions = suggestResults.value.map(s => s.queryPlusText)
-        } catch (err) {
-          WIKI.logger.warn('Search Engine suggestion failure: ', err)
-        }
-      }
-      return {
-        results: results.result.value,
-        suggestions,
-        totalHits: results.result['@odata.count']
-      }
-    } catch (err) {
-      WIKI.logger.warn('Search Engine Error:')
-      WIKI.logger.warn(err)
-    }
-  },
-  /**
-   * CREATE
-   *
-   * @param {Object} page Page to create
-   */
-  async created(page) {
-    await this.client.indexes.use(this.config.indexName).index([
-      {
-        id: page.hash,
-        locale: page.localeCode,
-        path: page.path,
-        title: page.title,
-        description: page.description,
-        content: page.safeContent
-      }
-    ])
-  },
-  /**
-   * UPDATE
-   *
-   * @param {Object} page Page to update
-   */
-  async updated(page) {
-    await this.client.indexes.use(this.config.indexName).index([
-      {
-        id: page.hash,
-        locale: page.localeCode,
-        path: page.path,
-        title: page.title,
-        description: page.description,
-        content: page.safeContent
-      }
-    ])
-  },
-  /**
-   * DELETE
-   *
-   * @param {Object} page Page to delete
-   */
-  async deleted(page) {
-    await this.client.indexes.use(this.config.indexName).index([
-      {
-        '@search.action': 'delete',
-        id: page.hash
-      }
-    ])
-  },
-  /**
-   * RENAME
-   *
-   * @param {Object} page Page to rename
-   */
-  async renamed(page) {
-    await this.client.indexes.use(this.config.indexName).index([
-      {
-        '@search.action': 'delete',
-        id: page.hash
-      }
-    ])
-    await this.client.indexes.use(this.config.indexName).index([
-      {
-        id: page.destinationHash,
-        locale: page.destinationLocaleCode,
-        path: page.destinationPath,
-        title: page.title,
-        description: page.description,
-        content: page.safeContent
-      }
-    ])
-  },
-  /**
-   * REBUILD INDEX
-   */
-  async rebuild() {
-    WIKI.logger.info(`(SEARCH/AZURE) Rebuilding Index...`)
-    await pipeline(
-      WIKI.models.knex.column({ id: 'hash' }, 'path', { locale: 'localeCode' }, 'title', 'description', 'render').select().from('pages').where({
-        isPublished: true,
-        isPrivate: false
-      }).stream(),
-      new stream.Transform({
-        objectMode: true,
-        transform: (chunk, enc, cb) => {
-          cb(null, {
-            id: chunk.id,
-            path: chunk.path,
-            locale: chunk.locale,
-            title: chunk.title,
-            description: chunk.description,
-            content: WIKI.models.pages.cleanHTML(chunk.render)
-          })
-        }
-      }),
-      this.client.indexes.use(this.config.indexName).createIndexingStream()
-    )
-    WIKI.logger.info(`(SEARCH/AZURE) Index rebuilt successfully.`)
-  }
-}

+ 0 - 8
server/modules/search/db/definition.yml

@@ -1,8 +0,0 @@
-key: db
-title: Database - Basic
-description: Default basic database-based search engine.
-author: requarks.io
-logo: https://static.requarks.io/logo/database.svg
-website: https://www.requarks.io/
-isAvailable: true
-props: {}

+ 0 - 94
server/modules/search/db/engine.js

@@ -1,94 +0,0 @@
-/* global WIKI */
-
-module.exports = {
-  activate() {
-    // not used
-  },
-  deactivate() {
-    // not used
-  },
-  /**
-   * INIT
-   */
-  init() {
-    // not used
-  },
-  /**
-   * QUERY
-   *
-   * @param {String} q Query
-   * @param {Object} opts Additional options
-   */
-  async query(q, opts) {
-    const results = await WIKI.models.pages.query()
-      .column('pages.id', 'title', 'description', 'path', 'localeCode as locale')
-      .withGraphJoined('tags') // Adding page tags since they can be used to check resource access permissions
-      .modifyGraph('tags', builder => {
-        builder.select('tag')
-      })
-      .where(builder => {
-        builder.where('isPublished', true)
-        if (opts.locale) {
-          builder.andWhere('localeCode', opts.locale)
-        }
-        if (opts.path) {
-          builder.andWhere('path', 'like', `${opts.path}%`)
-        }
-        builder.andWhere(builderSub => {
-          if (WIKI.config.db.type === 'postgres') {
-            builderSub.where('title', 'ILIKE', `%${q}%`)
-            builderSub.orWhere('description', 'ILIKE', `%${q}%`)
-            builderSub.orWhere('path', 'ILIKE', `%${q.toLowerCase()}%`)
-          } else {
-            builderSub.where('title', 'LIKE', `%${q}%`)
-            builderSub.orWhere('description', 'LIKE', `%${q}%`)
-            builderSub.orWhere('path', 'LIKE', `%${q.toLowerCase()}%`)
-          }
-        })
-      })
-      .limit(WIKI.config.search.maxHits)
-    return {
-      results,
-      suggestions: [],
-      totalHits: results.length
-    }
-  },
-  /**
-   * CREATE
-   *
-   * @param {Object} page Page to create
-   */
-  async created(page) {
-    // not used
-  },
-  /**
-   * UPDATE
-   *
-   * @param {Object} page Page to update
-   */
-  async updated(page) {
-    // not used
-  },
-  /**
-   * DELETE
-   *
-   * @param {Object} page Page to delete
-   */
-  async deleted(page) {
-    // not used
-  },
-  /**
-   * RENAME
-   *
-   * @param {Object} page Page to rename
-   */
-  async renamed(page) {
-    // not used
-  },
-  /**
-   * REBUILD INDEX
-   */
-  async rebuild() {
-    // not used
-  }
-}

+ 0 - 47
server/modules/search/elasticsearch/definition.yml

@@ -1,47 +0,0 @@
-key: elasticsearch
-title: Elasticsearch
-description: Elasticsearch is a distributed, RESTful search and analytics engine capable of solving a growing number of use cases.
-author: requarks.io
-logo: https://static.requarks.io/logo/elasticsearch.svg
-website: https://www.elastic.co/products/elasticsearch
-isAvailable: true
-props:
-  apiVersion:
-    type: String
-    title: Elasticsearch Version
-    hint: Should match the version of the Elasticsearch nodes you are connecting to
-    order: 1
-    enum:
-      - '7.x'
-      - '6.x'
-    default: '6.x'
-  hosts:
-    type: String
-    title: Host(s)
-    hint: Comma-separated list of Elasticsearch hosts to connect to, including the port, username and password if necessary. (e.g. http://localhost:9200, https://user:pass@es1.example.com:9200)
-    order: 2
-  indexName:
-    type: String
-    title: Index Name
-    hint: The index name to use during creation
-    default: wiki
-    order: 3
-  analyzer:
-    type: String
-    title: Analyzer
-    hint: 'The token analyzer in elasticsearch'
-    default: simple
-    order: 4
-  sniffOnStart:
-    type: Boolean
-    title: Sniff on start
-    hint: 'Should Wiki.js attempt to detect the rest of the cluster on first connect? (Default: off)'
-    default: false
-    order: 5
-  sniffInterval:
-    type: Number
-    title: Sniff Interval
-    hint: '0 = disabled, Interval in seconds to check for updated list of nodes in cluster. (Default: 0)'
-    default: 0
-    order: 6
-

+ 0 - 353
server/modules/search/elasticsearch/engine.js

@@ -1,353 +0,0 @@
-const _ = require('lodash')
-const stream = require('stream')
-const Promise = require('bluebird')
-const pipeline = Promise.promisify(stream.pipeline)
-
-/* global WIKI */
-
-module.exports = {
-  async activate() {
-    // not used
-  },
-  async deactivate() {
-    // not used
-  },
-  /**
-   * INIT
-   */
-  async init() {
-    WIKI.logger.info(`(SEARCH/ELASTICSEARCH) Initializing...`)
-    switch (this.config.apiVersion) {
-      case '7.x':
-        const { Client: Client7 } = require('elasticsearch7')
-        this.client = new Client7({
-          nodes: this.config.hosts.split(',').map(_.trim),
-          sniffOnStart: this.config.sniffOnStart,
-          sniffInterval: (this.config.sniffInterval > 0) ? this.config.sniffInterval : false,
-          name: 'wiki-js'
-        })
-        break
-      case '6.x':
-        const { Client: Client6 } = require('elasticsearch6')
-        this.client = new Client6({
-          nodes: this.config.hosts.split(',').map(_.trim),
-          sniffOnStart: this.config.sniffOnStart,
-          sniffInterval: (this.config.sniffInterval > 0) ? this.config.sniffInterval : false,
-          name: 'wiki-js'
-        })
-        break
-      default:
-        throw new Error('Unsupported version of elasticsearch! Update your settings in the Administration Area.')
-    }
-
-    // -> Create Search Index
-    await this.createIndex()
-
-    WIKI.logger.info(`(SEARCH/ELASTICSEARCH) Initialization completed.`)
-  },
-  /**
-   * Create Index
-   */
-  async createIndex() {
-    try {
-      const indexExists = await this.client.indices.exists({ index: this.config.indexName })
-      if (!indexExists.body) {
-        WIKI.logger.info(`(SEARCH/ELASTICSEARCH) Creating index...`)
-        try {
-          const idxBody = {
-            properties: {
-              suggest: { type: 'completion' },
-              title: { type: 'text', boost: 10.0 },
-              description: { type: 'text', boost: 3.0 },
-              content: { type: 'text', boost: 1.0 },
-              locale: { type: 'keyword' },
-              path: { type: 'text' },
-              tags: { type: 'text', boost: 8.0 }
-            }
-          }
-          await this.client.indices.create({
-            index: this.config.indexName,
-            body: {
-              mappings: (this.config.apiVersion === '6.x') ? {
-                _doc: idxBody
-              } : idxBody,
-              settings: {
-                analysis: {
-                  analyzer: {
-                    default: {
-                      type: this.config.analyzer
-                    }
-                  }
-                }
-              }
-            }
-          })
-        } catch (err) {
-          WIKI.logger.error(`(SEARCH/ELASTICSEARCH) Create Index Error: `, _.get(err, 'meta.body.error', err))
-        }
-      }
-    } catch (err) {
-      WIKI.logger.error(`(SEARCH/ELASTICSEARCH) Index Check Error: `, _.get(err, 'meta.body.error', err))
-    }
-  },
-  /**
-   * QUERY
-   *
-   * @param {String} q Query
-   * @param {Object} opts Additional options
-   */
-  async query(q, opts) {
-    try {
-      const results = await this.client.search({
-        index: this.config.indexName,
-        body: {
-          query: {
-            simple_query_string: {
-              query: `*${q}*`,
-              fields: ['title^20', 'description^3', 'tags^8', 'content^1'],
-              default_operator: 'and',
-              analyze_wildcard: true
-            }
-          },
-          from: 0,
-          size: 50,
-          _source: ['title', 'description', 'path', 'locale'],
-          suggest: {
-            suggestions: {
-              text: q,
-              completion: {
-                field: 'suggest',
-                size: 5,
-                skip_duplicates: true,
-                fuzzy: true
-              }
-            }
-          }
-        }
-      })
-      return {
-        results: _.get(results, 'body.hits.hits', []).map(r => ({
-          id: r._id,
-          locale: r._source.locale,
-          path: r._source.path,
-          title: r._source.title,
-          description: r._source.description
-        })),
-        suggestions: _.reject(_.get(results, 'suggest.suggestions', []).map(s => _.get(s, 'options[0].text', false)), s => !s),
-        totalHits: _.get(results, 'body.hits.total.value', _.get(results, 'body.hits.total', 0))
-      }
-    } catch (err) {
-      WIKI.logger.warn('Search Engine Error: ', _.get(err, 'meta.body.error', err))
-    }
-  },
-
-  /**
-   * Build tags field
-   * @param id
-   * @returns {Promise<*|*[]>}
-   */
-  async buildTags(id) {
-    const tags = await WIKI.models.pages.query().findById(id).select('*').withGraphJoined('tags')
-    return (tags.tags && tags.tags.length > 0) ? tags.tags.map(function (tag) {
-      return tag.title
-    }) : []
-  },
-  /**
-   * Build suggest field
-   */
-  buildSuggest(page) {
-    return _.reject(_.uniq(_.concat(
-      page.title.split(' ').map(s => ({
-        input: s,
-        weight: 10
-      })),
-      page.description.split(' ').map(s => ({
-        input: s,
-        weight: 3
-      })),
-      page.safeContent.split(' ').map(s => ({
-        input: s,
-        weight: 1
-      }))
-    )), ['input', ''])
-  },
-  /**
-   * CREATE
-   *
-   * @param {Object} page Page to create
-   */
-  async created(page) {
-    await this.client.index({
-      index: this.config.indexName,
-      type: '_doc',
-      id: page.hash,
-      body: {
-        suggest: this.buildSuggest(page),
-        locale: page.localeCode,
-        path: page.path,
-        title: page.title,
-        description: page.description,
-        content: page.safeContent,
-        tags: await this.buildTags(page.id)
-      },
-      refresh: true
-    })
-  },
-  /**
-   * UPDATE
-   *
-   * @param {Object} page Page to update
-   */
-  async updated(page) {
-    await this.client.index({
-      index: this.config.indexName,
-      type: '_doc',
-      id: page.hash,
-      body: {
-        suggest: this.buildSuggest(page),
-        locale: page.localeCode,
-        path: page.path,
-        title: page.title,
-        description: page.description,
-        content: page.safeContent,
-        tags: await this.buildTags(page.id)
-      },
-      refresh: true
-    })
-  },
-  /**
-   * DELETE
-   *
-   * @param {Object} page Page to delete
-   */
-  async deleted(page) {
-    await this.client.delete({
-      index: this.config.indexName,
-      type: '_doc',
-      id: page.hash,
-      refresh: true
-    })
-  },
-  /**
-   * RENAME
-   *
-   * @param {Object} page Page to rename
-   */
-  async renamed(page) {
-    await this.client.delete({
-      index: this.config.indexName,
-      type: '_doc',
-      id: page.hash,
-      refresh: true
-    })
-    await this.client.index({
-      index: this.config.indexName,
-      type: '_doc',
-      id: page.destinationHash,
-      body: {
-        suggest: this.buildSuggest(page),
-        locale: page.destinationLocaleCode,
-        path: page.destinationPath,
-        title: page.title,
-        description: page.description,
-        content: page.safeContent,
-        tags: await this.buildTags(page.id)
-      },
-      refresh: true
-    })
-  },
-  /**
-   * REBUILD INDEX
-   */
-  async rebuild() {
-    WIKI.logger.info(`(SEARCH/ELASTICSEARCH) Rebuilding Index...`)
-    await this.client.indices.delete({ index: this.config.indexName })
-    await this.createIndex()
-
-    const MAX_INDEXING_BYTES = 10 * Math.pow(2, 20) - Buffer.from('[').byteLength - Buffer.from(']').byteLength // 10 MB
-    const MAX_INDEXING_COUNT = 1000
-    const COMMA_BYTES = Buffer.from(',').byteLength
-
-    let chunks = []
-    let bytes = 0
-
-    const processDocument = async (cb, doc) => {
-      try {
-        if (doc) {
-          const docBytes = Buffer.from(JSON.stringify(doc)).byteLength
-
-          doc['tags'] = await this.buildTags(doc.realId)
-          // -> Current batch exceeds size limit, flush
-          if (docBytes + COMMA_BYTES + bytes >= MAX_INDEXING_BYTES) {
-            await flushBuffer()
-          }
-
-          if (chunks.length > 0) {
-            bytes += COMMA_BYTES
-          }
-          bytes += docBytes
-          chunks.push(doc)
-
-          // -> Current batch exceeds count limit, flush
-          if (chunks.length >= MAX_INDEXING_COUNT) {
-            await flushBuffer()
-          }
-        } else {
-          // -> End of stream, flush
-          await flushBuffer()
-        }
-        cb()
-      } catch (err) {
-        cb(err)
-      }
-    }
-
-    const flushBuffer = async () => {
-      WIKI.logger.info(`(SEARCH/ELASTICSEARCH) Sending batch of ${chunks.length}...`)
-      try {
-        await this.client.bulk({
-          index: this.config.indexName,
-          body: _.reduce(chunks, (result, doc) => {
-            result.push({
-              index: {
-                _index: this.config.indexName,
-                _type: '_doc',
-                _id: doc.id
-              }
-            })
-            doc.safeContent = WIKI.models.pages.cleanHTML(doc.render)
-            result.push({
-              suggest: this.buildSuggest(doc),
-              tags: doc.tags,
-              locale: doc.locale,
-              path: doc.path,
-              title: doc.title,
-              description: doc.description,
-              content: doc.safeContent
-            })
-            return result
-          }, []),
-          refresh: true
-        })
-      } catch (err) {
-        WIKI.logger.warn('(SEARCH/ELASTICSEARCH) Failed to send batch to elasticsearch: ', err)
-      }
-      chunks.length = 0
-      bytes = 0
-    }
-
-    // Added real id in order to fetch page tags from the query
-    await pipeline(
-      WIKI.models.knex.column({ id: 'hash' }, 'path', { locale: 'localeCode' }, 'title', 'description', 'render', { realId: 'id' }).select().from('pages').where({
-        isPublished: true,
-        isPrivate: false
-      }).stream(),
-      new stream.Transform({
-        objectMode: true,
-        transform: async (chunk, enc, cb) => processDocument(cb, chunk),
-        flush: async (cb) => processDocument(cb)
-      })
-    )
-    WIKI.logger.info(`(SEARCH/ELASTICSEARCH) Index rebuilt successfully.`)
-  }
-}

+ 0 - 8
server/modules/search/manticore/definition.yml

@@ -1,8 +0,0 @@
-key: manticore
-title: Manticore Search
-description: High performance full-text search engine with SQL and JSON support.
-author: requarks.io
-logo: https://static.requarks.io/logo/manticore.svg
-website: https://manticoresearch.com/
-isAvailable: false
-props: {}

Some files were not shown because too many files changed in this diff