2
0
Эх сурвалжийг харах

fix: file manager rename + ltree path encode/decode + various improvements

NGPixel 2 жил өмнө
parent
commit
7fde587a6c

+ 66 - 50
server/core/db.mjs

@@ -1,10 +1,12 @@
-import { get, has, isEmpty, isPlainObject } from 'lodash-es'
+import { create, get, has, isEmpty, isPlainObject } from 'lodash-es'
 import path from 'node:path'
 import knex from 'knex'
 import fs from 'node:fs/promises'
 import Objection from 'objection'
 import PGPubSub from 'pg-pubsub'
+import semver from 'semver'
 
+import { createDeferred } from '../helpers/common.mjs'
 import migrationSource from '../db/migrator-source.mjs'
 // const migrateFromLegacy = require('../db/legacy')
 import { setTimeout } from 'node:timers/promises'
@@ -17,12 +19,14 @@ export default {
   knex: null,
   listener: null,
   config: null,
+  VERSION: null,
+  LEGACY: false,
+  onReady: createDeferred(),
+  connectAttempts: 0,
   /**
    * Initialize DB
    */
   async init (workerMode = false) {
-    let self = this
-
     WIKI.logger.info('Checking DB configuration...')
 
     // Fetch DB Config
@@ -101,58 +105,28 @@ export default {
     Objection.Model.knex(this.knex)
 
     // Load DB Models
-
     WIKI.logger.info('Loading DB models...')
     const models = (await import(path.join(WIKI.SERVERPATH, 'models/index.mjs'))).default
 
-    // Set init tasks
-    let conAttempts = 0
-    const initTasks = {
-      // -> Attempt initial connection
-      async connect () {
-        try {
-          WIKI.logger.info('Connecting to database...')
-          await self.knex.raw('SELECT 1 + 1;')
-          WIKI.logger.info('Database Connection Successful [ OK ]')
-        } catch (err) {
-          if (conAttempts < 10) {
-            if (err.code) {
-              WIKI.logger.error(`Database Connection Error: ${err.code} ${err.address}:${err.port}`)
-            } else {
-              WIKI.logger.error(`Database Connection Error: ${err.message}`)
-            }
-            WIKI.logger.warn(`Will retry in 3 seconds... [Attempt ${++conAttempts} of 10]`)
-            await setTimeout(3000)
-            await initTasks.connect()
-          } else {
-            throw err
-          }
-        }
-      },
-      // -> Migrate DB Schemas
-      async syncSchemas () {
-        WIKI.logger.info('Ensuring DB schema exists...')
-        await self.knex.raw(`CREATE SCHEMA IF NOT EXISTS ${WIKI.config.db.schemas.wiki}`)
-        WIKI.logger.info('Ensuring DB migrations have been applied...')
-        return self.knex.migrate.latest({
-          tableName: 'migrations',
-          migrationSource,
-          schemaName: WIKI.config.db.schemas.wiki
-        })
-      },
-      // -> Migrate DB Schemas from 2.x
-      async migrateFromLegacy () {
-        // return migrateFromLegacy.migrate(self.knex)
-      }
+    // Connect
+    await this.connect()
+
+    // Check DB Version
+    const resVersion = await this.knex.raw('SHOW server_version;')
+    const dbVersion = semver.coerce(resVersion.rows[0].server_version, { loose: true })
+    this.VERSION = dbVersion.version
+    this.LEGACY = dbVersion.major < 16
+    if (dbVersion.major < 11) {
+      WIKI.logger.error('Your PostgreSQL database version is too old and unsupported by Wiki.js. Exiting...')
+      process.exit(1)
     }
+    WIKI.logger.info(`PostgreSQL ${dbVersion.version} [ ${this.LEGACY ? 'LEGACY MODE' : 'OK'} ]`)
 
-    // Perform init tasks
-
-    this.onReady = workerMode ? Promise.resolve() : (async () => {
-      await initTasks.connect()
-      await initTasks.migrateFromLegacy()
-      await initTasks.syncSchemas()
-    })()
+    // Run Migrations
+    if (!workerMode) {
+      await this.migrateFromLegacy()
+      await this.syncSchemas()
+    }
 
     return {
       ...this,
@@ -220,5 +194,47 @@ export default {
       event,
       value
     })
+  },
+  /**
+   * Attempt initial connection
+   */
+  async connect () {
+    try {
+      WIKI.logger.info('Connecting to database...')
+      await this.knex.raw('SELECT 1 + 1;')
+      WIKI.logger.info('Database Connection Successful [ OK ]')
+    } catch (err) {
+      if (this.connectAttempts < 10) {
+        if (err.code) {
+          WIKI.logger.error(`Database Connection Error: ${err.code} ${err.address}:${err.port}`)
+        } else {
+          WIKI.logger.error(`Database Connection Error: ${err.message}`)
+        }
+        WIKI.logger.warn(`Will retry in 3 seconds... [Attempt ${++this.connectAttempts} of 10]`)
+        await setTimeout(3000)
+        await this.connect()
+      } else {
+        throw err
+      }
+    }
+  },
+  /**
+   * Migrate DB Schemas
+   */
+  async syncSchemas () {
+    WIKI.logger.info('Ensuring DB schema exists...')
+    await this.knex.raw(`CREATE SCHEMA IF NOT EXISTS ${WIKI.config.db.schemas.wiki}`)
+    WIKI.logger.info('Ensuring DB migrations have been applied...')
+    return this.knex.migrate.latest({
+      tableName: 'migrations',
+      migrationSource,
+      schemaName: WIKI.config.db.schemas.wiki
+    })
+  },
+  /**
+   * Migrate DB Schemas from 2.x
+   */
+  async migrateFromLegacy () {
+    // return migrateFromLegacy.migrate(self.knex)
   }
 }

+ 0 - 1
server/core/kernel.mjs

@@ -21,7 +21,6 @@ export default {
     WIKI.db = await db.init()
 
     try {
-      await WIKI.db.onReady
       await WIKI.configSvc.loadFromDb()
       await WIKI.configSvc.applyFlags()
     } catch (err) {

+ 1 - 1
server/graph/resolvers/system.mjs

@@ -202,7 +202,7 @@ export default {
       return WIKI.config.db.host
     },
     dbVersion () {
-      return _.get(WIKI.db, 'knex.client.version', 'Unknown Version')
+      return WIKI.db.VERSION
     },
     hostname () {
       return os.hostname()

+ 18 - 7
server/graph/resolvers/tree.mjs

@@ -1,4 +1,10 @@
 import _ from 'lodash-es'
+import {
+  decodeFolderPath,
+  encodeFolderPath,
+  decodeTreePath,
+  encodeTreePath
+} from '../../helpers/common.mjs'
 import { generateError, generateSuccess } from '../../helpers/graph.mjs'
 
 const typeResolvers = {
@@ -44,12 +50,12 @@ export default {
       if (args.parentId) {
         const parent = await WIKI.db.knex('tree').where('id', args.parentId).first()
         if (parent) {
-          parentPath = (parent.folderPath ? `${parent.folderPath}.${parent.fileName}` : parent.fileName).replaceAll('-', '_')
+          parentPath = (parent.folderPath ? `${decodeFolderPath(parent.folderPath)}.${parent.fileName}` : parent.fileName)
         }
       } else if (args.parentPath) {
-        parentPath = args.parentPath.replaceAll('/', '.').replaceAll('-', '_').toLowerCase()
+        parentPath = encodeTreePath(args.parentPath)
       }
-      const folderPathCondition = parentPath ? `${parentPath}.${depthCondition}` : depthCondition
+      const folderPathCondition = parentPath ? `${encodeFolderPath(parentPath)}.${depthCondition}` : depthCondition
 
       // Fetch Items
       const items = await WIKI.db.knex('tree')
@@ -59,9 +65,14 @@ export default {
           // -> Include ancestors
           if (args.includeAncestors) {
             const parentPathParts = parentPath.split('.')
-            for (let i = 1; i <= parentPathParts.length; i++) {
+            for (let i = 0; i <= parentPathParts.length; i++) {
+              console.info({
+                folderPath: encodeFolderPath(_.dropRight(parentPathParts, i).join('.')),
+                fileName: _.nth(parentPathParts, i * -1),
+                type: 'folder'
+              })
               builder.orWhere({
-                folderPath: _.dropRight(parentPathParts, i).join('.'),
+                folderPath: encodeFolderPath(_.dropRight(parentPathParts, i).join('.')),
                 fileName: _.nth(parentPathParts, i * -1),
                 type: 'folder'
               })
@@ -92,14 +103,14 @@ export default {
         id: item.id,
         depth: item.depth,
         type: item.type,
-        folderPath: item.folderPath.replaceAll('.', '/').replaceAll('_', '-'),
+        folderPath: decodeTreePath(decodeFolderPath(item.folderPath)),
         fileName: item.fileName,
         title: item.title,
         createdAt: item.createdAt,
         updatedAt: item.updatedAt,
         ...(item.type === 'folder') && {
           childrenCount: item.meta?.children || 0,
-          isAncestor: item.folderPath.length < parentPath.length
+          isAncestor: item.folderPath.length < parentPath.length || (parentPath !== '' && item.folderPath === parentPath)
         },
         ...(item.type === 'asset') && {
           fileSize: item.meta?.fileSize || 0,

+ 22 - 2
server/helpers/common.mjs

@@ -37,7 +37,7 @@ export function createDeferred () {
  * @returns Decoded tree path
  */
 export function decodeTreePath (str) {
-  return str.replaceAll('_', '-').replaceAll('.', '/')
+  return str?.replaceAll('.', '/')
 }
 
 /**
@@ -47,7 +47,27 @@ export function decodeTreePath (str) {
  * @returns Encoded tree path
  */
 export function encodeTreePath (str) {
-  return str?.toLowerCase()?.replaceAll('-', '_')?.replaceAll('/', '.') || ''
+  return str?.toLowerCase()?.replaceAll('/', '.') || ''
+}
+
+/**
+ * Encode a folder path (to support legacy PostgresSQL ltree)
+ *
+ * @param {string} val String to encode
+ * @returns Encoded folder path
+ */
+export function encodeFolderPath (val) {
+  return WIKI.db.LEGACY ? val?.replaceAll('-', '_') : val
+}
+
+/**
+ * Decode a folder path (to support legacy PostgresSQL ltree)
+ *
+ * @param {string} val String to decode
+ * @returns Decoded folder path
+ */
+export function decodeFolderPath (val) {
+  return WIKI.db.LEGACY ? val?.replaceAll('_', '-') : val
 }
 
 /**

+ 22 - 17
server/models/tree.mjs

@@ -1,6 +1,12 @@
 import { Model } from 'objection'
 import { differenceWith, dropRight, last, nth } from 'lodash-es'
-import { decodeTreePath, encodeTreePath, generateHash } from '../helpers/common.mjs'
+import {
+  decodeFolderPath,
+  decodeTreePath,
+  encodeFolderPath,
+  encodeTreePath,
+  generateHash
+} from '../helpers/common.mjs'
 
 import { Locale } from './locales.mjs'
 import { Site } from './sites.mjs'
@@ -87,7 +93,7 @@ export class Tree extends Model {
       const parentPath = encodeTreePath(path)
       const parentPathParts = parentPath.split('.')
       const parentFilter = {
-        folderPath: dropRight(parentPathParts).join('.'),
+        folderPath: encodeFolderPath(dropRight(parentPathParts).join('.')),
         fileName: last(parentPathParts)
       }
       const parent = await WIKI.db.knex('tree').where({
@@ -135,14 +141,14 @@ export class Tree extends Model {
       folderPath: '',
       fileName: ''
     }
-    const folderPath = decodeTreePath(folder.folderPath ? `${folder.folderPath}.${folder.fileName}` : folder.fileName)
+    const folderPath = folder.folderPath ? `${folder.folderPath}.${folder.fileName}` : folder.fileName
     const fullPath = folderPath ? `${folderPath}/${fileName}` : fileName
 
     WIKI.logger.debug(`Adding page ${fullPath} to tree...`)
 
     const pageEntry = await WIKI.db.knex('tree').insert({
       id,
-      folderPath,
+      folderPath: encodeFolderPath(folderPath),
       fileName,
       type: 'page',
       title: title,
@@ -179,14 +185,13 @@ export class Tree extends Model {
       fileName: ''
     }
     const folderPath = folder.folderPath ? `${folder.folderPath}.${folder.fileName}` : folder.fileName
-    const decodedFolderPath = decodeTreePath(folderPath)
-    const fullPath = decodedFolderPath ? `${decodedFolderPath}/${fileName}` : fileName
+    const fullPath = folderPath ? `${folderPath}/${fileName}` : fileName
 
     WIKI.logger.debug(`Adding asset ${fullPath} to tree...`)
 
     const assetEntry = await WIKI.db.knex('tree').insert({
       id,
-      folderPath,
+      folderPath: encodeFolderPath(folderPath),
       fileName,
       type: 'asset',
       title: title,
@@ -225,7 +230,7 @@ export class Tree extends Model {
     WIKI.logger.debug(`Creating new folder ${pathName}...`)
     const parentPathParts = parentPath.split('.')
     const parentFilter = {
-      folderPath: dropRight(parentPathParts).join('.'),
+      folderPath: encodeFolderPath(dropRight(parentPathParts).join('.')),
       fileName: last(parentPathParts)
     }
 
@@ -236,7 +241,7 @@ export class Tree extends Model {
       if (!parent) {
         throw new Error('ERR_NONEXISTING_PARENT_ID')
       }
-      parentPath = parent.folderPath ? `${parent.folderPath}.${parent.fileName}` : parent.fileName
+      parentPath = parent.folderPath ? `${decodeFolderPath(parent.folderPath)}.${parent.fileName}` : parent.fileName
     } else if (parentPath) {
       parent = await WIKI.db.knex('tree').where(parentFilter).first()
     } else {
@@ -247,7 +252,7 @@ export class Tree extends Model {
     const existingFolder = await WIKI.db.knex('tree').select('id').where({
       siteId: siteId,
       localeCode: locale,
-      folderPath: encodeTreePath(parentPath),
+      folderPath: encodeFolderPath(parentPath),
       fileName: pathName
     }).first()
     if (existingFolder) {
@@ -261,7 +266,7 @@ export class Tree extends Model {
         const parentPathParts = parentPath.split('.')
         for (let i = 1; i <= parentPathParts.length; i++) {
           const ancestor = {
-            folderPath: encodeTreePath(dropRight(parentPathParts, i).join('.')),
+            folderPath: encodeFolderPath(dropRight(parentPathParts, i).join('.')),
             fileName: nth(parentPathParts, i * -1)
           }
           expectedAncestors.push(ancestor)
@@ -296,7 +301,7 @@ export class Tree extends Model {
     // Create folder
     const fullPath = parentPath ? `${decodeTreePath(parentPath)}/${pathName}` : pathName
     const folder = await WIKI.db.knex('tree').insert({
-      folderPath: encodeTreePath(parentPath),
+      folderPath: encodeFolderPath(parentPath),
       fileName: pathName,
       type: 'folder',
       title: title,
@@ -364,8 +369,8 @@ export class Tree extends Model {
       }
 
       // Build new paths
-      const oldFolderPath = (folder.folderPath ? `${folder.folderPath}.${folder.fileName}` : folder.fileName).replaceAll('-', '_')
-      const newFolderPath = (folder.folderPath ? `${folder.folderPath}.${pathName}` : pathName).replaceAll('-', '_')
+      const oldFolderPath = encodeFolderPath(folder.folderPath ? `${folder.folderPath}.${folder.fileName}` : folder.fileName)
+      const newFolderPath = encodeFolderPath(folder.folderPath ? `${folder.folderPath}.${pathName}` : pathName)
 
       // Update children nodes
       WIKI.logger.debug(`Updating parent path of children nodes from ${oldFolderPath} to ${newFolderPath} ...`)
@@ -377,7 +382,7 @@ export class Tree extends Model {
       })
 
       // Rename the folder itself
-      const fullPath = folder.folderPath ? `${decodeTreePath(folder.folderPath)}/${pathName}` : pathName
+      const fullPath = folder.folderPath ? `${decodeFolderPath(folder.folderPath)}/${pathName}` : pathName
       await WIKI.db.knex('tree').where('id', folder.id).update({
         fileName: pathName,
         title: title,
@@ -408,7 +413,7 @@ export class Tree extends Model {
     WIKI.logger.debug(`Deleting folder ${folder.id} at path ${folderPath}...`)
 
     // Delete all children
-    const deletedNodes = await WIKI.db.knex('tree').where('folderPath', '<@', folderPath).del().returning(['id', 'type'])
+    const deletedNodes = await WIKI.db.knex('tree').where('folderPath', '<@', encodeFolderPath(folderPath)).del().returning(['id', 'type'])
 
     // Delete folders
     const deletedFolders = deletedNodes.filter(n => n.type === 'folder').map(n => n.id)
@@ -439,7 +444,7 @@ export class Tree extends Model {
     if (folder.folderPath) {
       const parentPathParts = folder.folderPath.split('.')
       const parent = await WIKI.db.knex('tree').where({
-        folderPath: dropRight(parentPathParts).join('.'),
+        folderPath: encodeFolderPath(dropRight(parentPathParts).join('.')),
         fileName: last(parentPathParts)
       }).first()
       await WIKI.db.knex('tree').where('id', parent.id).update({

+ 182 - 185
server/package-lock.json

@@ -9,18 +9,18 @@
       "version": "3.0.0",
       "license": "AGPL-3.0",
       "dependencies": {
-        "@apollo/server": "4.7.1",
+        "@apollo/server": "4.7.3",
         "@azure/storage-blob": "12.14.0",
         "@exlinc/keycloak-passport": "1.0.2",
         "@graphql-tools/schema": "10.0.0",
-        "@graphql-tools/utils": "10.0.0",
+        "@graphql-tools/utils": "10.0.1",
         "@joplin/turndown-plugin-gfm": "1.0.47",
         "@root/csr": "0.8.1",
         "@root/keypairs": "0.10.3",
         "@root/pem": "1.0.4",
         "acme": "3.0.3",
         "akismet-api": "6.0.0",
-        "aws-sdk": "2.1386.0",
+        "aws-sdk": "2.1395.0",
         "bcryptjs": "2.4.3",
         "body-parser": "1.20.2",
         "chalk": "5.2.0",
@@ -46,7 +46,7 @@
         "express": "4.18.2",
         "express-brute": "1.0.1",
         "express-session": "1.17.3",
-        "file-type": "18.4.0",
+        "file-type": "18.5.0",
         "filesize": "10.0.7",
         "fs-extra": "11.1.1",
         "getos": "3.2.1",
@@ -57,7 +57,7 @@
         "graphql-upload": "16.0.2",
         "he": "1.2.0",
         "highlight.js": "11.8.0",
-        "i18next": "22.5.0",
+        "i18next": "22.5.1",
         "i18next-node-fs-backend": "2.1.3",
         "image-size": "1.0.2",
         "js-base64": "3.7.5",
@@ -91,7 +91,7 @@
         "nanoid": "4.0.2",
         "node-2fa": "2.0.3",
         "node-cache": "5.1.2",
-        "nodemailer": "6.9.2",
+        "nodemailer": "6.9.3",
         "objection": "3.0.1",
         "passport": "0.6.0",
         "passport-auth0": "1.4.3",
@@ -111,7 +111,7 @@
         "passport-okta-oauth": "0.0.1",
         "passport-openidconnect": "0.1.1",
         "passport-saml": "3.2.1",
-        "passport-slack-oauth2": "1.1.1",
+        "passport-slack-oauth2": "1.2.0",
         "passport-twitch-strategy": "2.2.0",
         "pem-jwk": "2.0.0",
         "pg": "8.11.0",
@@ -119,9 +119,9 @@
         "pg-pubsub": "0.8.1",
         "pg-query-stream": "4.5.0",
         "pg-tsquery": "8.4.1",
-        "poolifier": "2.4.14",
+        "poolifier": "2.6.2",
         "punycode": "2.3.0",
-        "puppeteer-core": "20.4.0",
+        "puppeteer-core": "20.5.0",
         "qr-image": "3.2.0",
         "rate-limiter-flexible": "2.4.1",
         "remove-markdown": "0.5.0",
@@ -134,7 +134,7 @@
         "serve-favicon": "2.5.0",
         "sharp": "0.32.1",
         "simple-git": "3.19.0",
-        "socket.io": "4.6.1",
+        "socket.io": "4.6.2",
         "striptags": "3.2.0",
         "tar-fs": "2.1.1",
         "turndown": "7.1.2",
@@ -146,9 +146,9 @@
         "yargs": "17.7.2"
       },
       "devDependencies": {
-        "eslint": "8.41.0",
+        "eslint": "8.42.0",
         "eslint-config-requarks": "1.0.7",
-        "eslint-config-standard": "17.0.0",
+        "eslint-config-standard": "17.1.0",
         "eslint-plugin-import": "2.27.5",
         "eslint-plugin-node": "11.1.0",
         "eslint-plugin-promise": "6.1.1",
@@ -229,9 +229,9 @@
       }
     },
     "node_modules/@apollo/server": {
-      "version": "4.7.1",
-      "resolved": "https://registry.npmjs.org/@apollo/server/-/server-4.7.1.tgz",
-      "integrity": "sha512-rFxd8jsMlqEYzmhuxATaDAPoRH905R56FKP4TnZWaiDYJtjhHe3hxZOWl24V7s0dB52DIp6S/x+zjQX8fwD37w==",
+      "version": "4.7.3",
+      "resolved": "https://registry.npmjs.org/@apollo/server/-/server-4.7.3.tgz",
+      "integrity": "sha512-eFCzHHheNHfVALjYJjIghV7kSgO49ZFr8+4g2CKOLShoDmLplQ3blyL5NsONyC0Z5l8kqm62V8yXGoxy2eNGfw==",
       "dependencies": {
         "@apollo/cache-control-types": "^1.0.2",
         "@apollo/server-gateway-interface": "^1.1.0",
@@ -241,7 +241,7 @@
         "@apollo/utils.isnodelike": "^2.0.0",
         "@apollo/utils.keyvaluecache": "^2.1.0",
         "@apollo/utils.logger": "^2.0.0",
-        "@apollo/utils.usagereporting": "^2.0.0",
+        "@apollo/utils.usagereporting": "^2.1.0",
         "@apollo/utils.withrequired": "^2.0.0",
         "@graphql-tools/schema": "^9.0.0",
         "@josephg/resolvable": "^1.0.0",
@@ -309,17 +309,6 @@
         "node": ">=12"
       }
     },
-    "node_modules/@apollo/server/node_modules/@apollo/utils.dropunuseddefinitions": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/@apollo/utils.dropunuseddefinitions/-/utils.dropunuseddefinitions-2.0.1.tgz",
-      "integrity": "sha512-EsPIBqsSt2BwDsv8Wu76LK5R1KtsVkNoO4b0M5aK0hx+dGg9xJXuqlr7Fo34Dl+y83jmzn+UvEW+t1/GP2melA==",
-      "engines": {
-        "node": ">=14"
-      },
-      "peerDependencies": {
-        "graphql": "14.x || 15.x || 16.x"
-      }
-    },
     "node_modules/@apollo/server/node_modules/@apollo/utils.keyvaluecache": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/@apollo/utils.keyvaluecache/-/utils.keyvaluecache-2.1.1.tgz",
@@ -340,72 +329,6 @@
         "node": ">=14"
       }
     },
-    "node_modules/@apollo/server/node_modules/@apollo/utils.printwithreducedwhitespace": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/@apollo/utils.printwithreducedwhitespace/-/utils.printwithreducedwhitespace-2.0.1.tgz",
-      "integrity": "sha512-9M4LUXV/fQBh8vZWlLvb/HyyhjJ77/I5ZKu+NBWV/BmYGyRmoEP9EVAy7LCVoY3t8BDcyCAGfxJaLFCSuQkPUg==",
-      "engines": {
-        "node": ">=14"
-      },
-      "peerDependencies": {
-        "graphql": "14.x || 15.x || 16.x"
-      }
-    },
-    "node_modules/@apollo/server/node_modules/@apollo/utils.removealiases": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/@apollo/utils.removealiases/-/utils.removealiases-2.0.1.tgz",
-      "integrity": "sha512-0joRc2HBO4u594Op1nev+mUF6yRnxoUH64xw8x3bX7n8QBDYdeYgY4tF0vJReTy+zdn2xv6fMsquATSgC722FA==",
-      "engines": {
-        "node": ">=14"
-      },
-      "peerDependencies": {
-        "graphql": "14.x || 15.x || 16.x"
-      }
-    },
-    "node_modules/@apollo/server/node_modules/@apollo/utils.sortast": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/@apollo/utils.sortast/-/utils.sortast-2.0.1.tgz",
-      "integrity": "sha512-eciIavsWpJ09za1pn37wpsCGrQNXUhM0TktnZmHwO+Zy9O4fu/WdB4+5BvVhFiZYOXvfjzJUcc+hsIV8RUOtMw==",
-      "dependencies": {
-        "lodash.sortby": "^4.7.0"
-      },
-      "engines": {
-        "node": ">=14"
-      },
-      "peerDependencies": {
-        "graphql": "14.x || 15.x || 16.x"
-      }
-    },
-    "node_modules/@apollo/server/node_modules/@apollo/utils.stripsensitiveliterals": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/@apollo/utils.stripsensitiveliterals/-/utils.stripsensitiveliterals-2.0.1.tgz",
-      "integrity": "sha512-QJs7HtzXS/JIPMKWimFnUMK7VjkGQTzqD9bKD1h3iuPAqLsxd0mUNVbkYOPTsDhUKgcvUOfOqOJWYohAKMvcSA==",
-      "engines": {
-        "node": ">=14"
-      },
-      "peerDependencies": {
-        "graphql": "14.x || 15.x || 16.x"
-      }
-    },
-    "node_modules/@apollo/server/node_modules/@apollo/utils.usagereporting": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/@apollo/utils.usagereporting/-/utils.usagereporting-2.0.1.tgz",
-      "integrity": "sha512-18smkNfiSfu5yj2mpCIfSzmpDNh90a4PQ6t8kSwGKcPRD3KD83TfK7fF37fSRdnvO93dBkGreWisLXnCpqfWXg==",
-      "dependencies": {
-        "@apollo/usage-reporting-protobuf": "^4.0.0",
-        "@apollo/utils.dropunuseddefinitions": "^2.0.1",
-        "@apollo/utils.printwithreducedwhitespace": "^2.0.1",
-        "@apollo/utils.removealiases": "2.0.1",
-        "@apollo/utils.sortast": "^2.0.1",
-        "@apollo/utils.stripsensitiveliterals": "^2.0.1"
-      },
-      "engines": {
-        "node": ">=14"
-      },
-      "peerDependencies": {
-        "graphql": "14.x || 15.x || 16.x"
-      }
-    },
     "node_modules/@apollo/server/node_modules/@graphql-tools/merge": {
       "version": "8.4.2",
       "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.4.2.tgz",
@@ -471,6 +394,17 @@
         "node": ">=14"
       }
     },
+    "node_modules/@apollo/utils.dropunuseddefinitions": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@apollo/utils.dropunuseddefinitions/-/utils.dropunuseddefinitions-2.0.1.tgz",
+      "integrity": "sha512-EsPIBqsSt2BwDsv8Wu76LK5R1KtsVkNoO4b0M5aK0hx+dGg9xJXuqlr7Fo34Dl+y83jmzn+UvEW+t1/GP2melA==",
+      "engines": {
+        "node": ">=14"
+      },
+      "peerDependencies": {
+        "graphql": "14.x || 15.x || 16.x"
+      }
+    },
     "node_modules/@apollo/utils.fetcher": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/@apollo/utils.fetcher/-/utils.fetcher-2.0.1.tgz",
@@ -487,6 +421,72 @@
         "node": ">=14"
       }
     },
+    "node_modules/@apollo/utils.printwithreducedwhitespace": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@apollo/utils.printwithreducedwhitespace/-/utils.printwithreducedwhitespace-2.0.1.tgz",
+      "integrity": "sha512-9M4LUXV/fQBh8vZWlLvb/HyyhjJ77/I5ZKu+NBWV/BmYGyRmoEP9EVAy7LCVoY3t8BDcyCAGfxJaLFCSuQkPUg==",
+      "engines": {
+        "node": ">=14"
+      },
+      "peerDependencies": {
+        "graphql": "14.x || 15.x || 16.x"
+      }
+    },
+    "node_modules/@apollo/utils.removealiases": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@apollo/utils.removealiases/-/utils.removealiases-2.0.1.tgz",
+      "integrity": "sha512-0joRc2HBO4u594Op1nev+mUF6yRnxoUH64xw8x3bX7n8QBDYdeYgY4tF0vJReTy+zdn2xv6fMsquATSgC722FA==",
+      "engines": {
+        "node": ">=14"
+      },
+      "peerDependencies": {
+        "graphql": "14.x || 15.x || 16.x"
+      }
+    },
+    "node_modules/@apollo/utils.sortast": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@apollo/utils.sortast/-/utils.sortast-2.0.1.tgz",
+      "integrity": "sha512-eciIavsWpJ09za1pn37wpsCGrQNXUhM0TktnZmHwO+Zy9O4fu/WdB4+5BvVhFiZYOXvfjzJUcc+hsIV8RUOtMw==",
+      "dependencies": {
+        "lodash.sortby": "^4.7.0"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "peerDependencies": {
+        "graphql": "14.x || 15.x || 16.x"
+      }
+    },
+    "node_modules/@apollo/utils.stripsensitiveliterals": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@apollo/utils.stripsensitiveliterals/-/utils.stripsensitiveliterals-2.0.1.tgz",
+      "integrity": "sha512-QJs7HtzXS/JIPMKWimFnUMK7VjkGQTzqD9bKD1h3iuPAqLsxd0mUNVbkYOPTsDhUKgcvUOfOqOJWYohAKMvcSA==",
+      "engines": {
+        "node": ">=14"
+      },
+      "peerDependencies": {
+        "graphql": "14.x || 15.x || 16.x"
+      }
+    },
+    "node_modules/@apollo/utils.usagereporting": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@apollo/utils.usagereporting/-/utils.usagereporting-2.1.0.tgz",
+      "integrity": "sha512-LPSlBrn+S17oBy5eWkrRSGb98sWmnEzo3DPTZgp8IQc8sJe0prDgDuppGq4NeQlpoqEHz0hQeYHAOA0Z3aQsxQ==",
+      "dependencies": {
+        "@apollo/usage-reporting-protobuf": "^4.1.0",
+        "@apollo/utils.dropunuseddefinitions": "^2.0.1",
+        "@apollo/utils.printwithreducedwhitespace": "^2.0.1",
+        "@apollo/utils.removealiases": "2.0.1",
+        "@apollo/utils.sortast": "^2.0.1",
+        "@apollo/utils.stripsensitiveliterals": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "peerDependencies": {
+        "graphql": "14.x || 15.x || 16.x"
+      }
+    },
     "node_modules/@apollo/utils.withrequired": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/@apollo/utils.withrequired/-/utils.withrequired-2.0.1.tgz",
@@ -709,9 +709,9 @@
       "dev": true
     },
     "node_modules/@eslint/js": {
-      "version": "8.41.0",
-      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz",
-      "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==",
+      "version": "8.42.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz",
+      "integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==",
       "dev": true,
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -758,9 +758,9 @@
       }
     },
     "node_modules/@graphql-tools/utils": {
-      "version": "10.0.0",
-      "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.0.0.tgz",
-      "integrity": "sha512-ndBPc6zgR+eGU/jHLpuojrs61kYN3Z89JyMLwK3GCRkPv4EQn9EOr1UWqF1JO0iM+/jAVHY0mvfUxyrFFN9DUQ==",
+      "version": "10.0.1",
+      "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.0.1.tgz",
+      "integrity": "sha512-i1FozbDGHgdsFA47V/JvQZ0FE8NAy0Eiz7HGCJO2MkNdZAKNnwei66gOq0JWYVFztwpwbVQ09GkKhq7Kjcq5Cw==",
       "dependencies": {
         "@graphql-typed-document-node/core": "^3.1.1",
         "tslib": "^2.4.0"
@@ -781,9 +781,9 @@
       }
     },
     "node_modules/@humanwhocodes/config-array": {
-      "version": "0.11.8",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
-      "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+      "version": "0.11.10",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
+      "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==",
       "dev": true,
       "dependencies": {
         "@humanwhocodes/object-schema": "^1.2.1",
@@ -978,14 +978,14 @@
       "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
     },
     "node_modules/@puppeteer/browsers": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.0.tgz",
-      "integrity": "sha512-HiRpoc15NhFwoR1IjN3MkMsqeAfRQKNzbhWVV+0BfvybEhjWSyRNQMC0ohMhkFhzoGnFoS59WlrJCGLPky/89g==",
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.1.tgz",
+      "integrity": "sha512-H43VosMzywHCcYcgv0GXXopvwnV21Ud9g2aXbPlQUJj1Xcz9V0wBwHeFz6saFhx/3VKisZfI1GEKEOhQCau7Vw==",
       "dependencies": {
         "debug": "4.3.4",
         "extract-zip": "2.0.1",
         "progress": "2.0.3",
-        "proxy-agent": "6.2.0",
+        "proxy-agent": "6.2.1",
         "tar-fs": "2.1.1",
         "unbzip2-stream": "1.4.3",
         "yargs": "17.7.1"
@@ -994,7 +994,7 @@
         "browsers": "lib/cjs/main-cli.js"
       },
       "engines": {
-        "node": ">=16.0.0"
+        "node": ">=16.3.0"
       },
       "peerDependencies": {
         "typescript": ">= 4.7.4"
@@ -1158,9 +1158,12 @@
       "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
     },
     "node_modules/@types/cors": {
-      "version": "2.8.12",
-      "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz",
-      "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw=="
+      "version": "2.8.13",
+      "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz",
+      "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==",
+      "dependencies": {
+        "@types/node": "*"
+      }
     },
     "node_modules/@types/express": {
       "version": "4.17.13",
@@ -1666,9 +1669,9 @@
       }
     },
     "node_modules/aws-sdk": {
-      "version": "2.1386.0",
-      "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1386.0.tgz",
-      "integrity": "sha512-bmUvpNRR4x1YvTaAm7WK/2lSNVPrNuiYlleU47GA5Xskh8PKaWedGHvGinH2YwhC720hM0Qc4f4/snUPGJ0eYg==",
+      "version": "2.1395.0",
+      "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1395.0.tgz",
+      "integrity": "sha512-e/Ovw2dyBCsUfAxhdKanSMAmLL9/SIpKCC++xWEMe/3OfETz/B5FisjQQNnnVfe5eGJjiLbFKts1V8ZPCelUHw==",
       "dependencies": {
         "buffer": "4.9.2",
         "events": "1.1.1",
@@ -2139,9 +2142,9 @@
       "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
     },
     "node_modules/chromium-bidi": {
-      "version": "0.4.10",
-      "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.10.tgz",
-      "integrity": "sha512-ngdRIq/f5G3nIOz1M0MtCABCTezr79MBCrJ09K2xRk+hTZQGTH8JIeFbgQmVvNPBMQblh7ROfJnSzsE07YpFfg==",
+      "version": "0.4.11",
+      "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.11.tgz",
+      "integrity": "sha512-p03ajLhlQ5gebw3cmbDBFmBc2wnJM5dnXS8Phu6mblGn/KQd76yOVL5VwE0VAisa7oazNfKGTaXlIZ8Q5Bb9OA==",
       "dependencies": {
         "mitt": "3.0.0"
       },
@@ -2857,9 +2860,9 @@
       }
     },
     "node_modules/engine.io": {
-      "version": "6.4.1",
-      "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.1.tgz",
-      "integrity": "sha512-JFYQurD/nbsA5BSPmbaOSLa3tSVj8L6o4srSwXXY3NqE+gGUNmmPTbhn8tjzcCtSqhFgIeqef81ngny8JM25hw==",
+      "version": "6.4.2",
+      "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.2.tgz",
+      "integrity": "sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==",
       "dependencies": {
         "@types/cookie": "^0.4.1",
         "@types/cors": "^2.8.12",
@@ -2877,9 +2880,9 @@
       }
     },
     "node_modules/engine.io-parser": {
-      "version": "5.0.6",
-      "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.6.tgz",
-      "integrity": "sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==",
+      "version": "5.0.7",
+      "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.7.tgz",
+      "integrity": "sha512-P+jDFbvK6lE3n1OL+q9KuzdOFWkkZ/cMV9gol/SbVfpyqfvrfrFTOFJ6fQm2VC3PZHlU3QPhVwmbsCnauHF2MQ==",
       "engines": {
         "node": ">=10.0.0"
       }
@@ -3131,16 +3134,16 @@
       }
     },
     "node_modules/eslint": {
-      "version": "8.41.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz",
-      "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==",
+      "version": "8.42.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz",
+      "integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.2.0",
         "@eslint-community/regexpp": "^4.4.0",
         "@eslint/eslintrc": "^2.0.3",
-        "@eslint/js": "8.41.0",
-        "@humanwhocodes/config-array": "^0.11.8",
+        "@eslint/js": "8.42.0",
+        "@humanwhocodes/config-array": "^0.11.10",
         "@humanwhocodes/module-importer": "^1.0.1",
         "@nodelib/fs.walk": "^1.2.8",
         "ajv": "^6.10.0",
@@ -3200,9 +3203,9 @@
       }
     },
     "node_modules/eslint-config-standard": {
-      "version": "17.0.0",
-      "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz",
-      "integrity": "sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==",
+      "version": "17.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz",
+      "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==",
       "dev": true,
       "funding": [
         {
@@ -3218,10 +3221,13 @@
           "url": "https://feross.org/support"
         }
       ],
+      "engines": {
+        "node": ">=12.0.0"
+      },
       "peerDependencies": {
         "eslint": "^8.0.1",
         "eslint-plugin-import": "^2.25.2",
-        "eslint-plugin-n": "^15.0.0",
+        "eslint-plugin-n": "^15.0.0 || ^16.0.0 ",
         "eslint-plugin-promise": "^6.0.0"
       }
     },
@@ -3989,9 +3995,9 @@
       }
     },
     "node_modules/file-type": {
-      "version": "18.4.0",
-      "resolved": "https://registry.npmjs.org/file-type/-/file-type-18.4.0.tgz",
-      "integrity": "sha512-o6MQrZKTAK6WpvmQk3jqTVUmqxYBxW5bloUfrdH1ZnRFDvvAPNr+l+rgOxM3nkqWT+3khaj3FRMDydWe0xhu+w==",
+      "version": "18.5.0",
+      "resolved": "https://registry.npmjs.org/file-type/-/file-type-18.5.0.tgz",
+      "integrity": "sha512-yvpl5U868+V6PqXHMmsESpg6unQ5GfnPssl4dxdJudBrr9qy7Fddt7EVX1VLlddFfe8Gj9N7goCZH22FXuSQXQ==",
       "dependencies": {
         "readable-web-to-node-stream": "^3.0.2",
         "strtok3": "^7.0.0",
@@ -4821,9 +4827,9 @@
       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
     },
     "node_modules/i18next": {
-      "version": "22.5.0",
-      "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.5.0.tgz",
-      "integrity": "sha512-sqWuJFj+wJAKQP2qBQ+b7STzxZNUmnSxrehBCCj9vDOW9RDYPfqCaK1Hbh2frNYQuPziz6O2CGoJPwtzY3vAYA==",
+      "version": "22.5.1",
+      "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.5.1.tgz",
+      "integrity": "sha512-8TGPgM3pAD+VRsMtUMNknRz3kzqwp/gPALrWMsDnmC1mKqJwpWyooQRLMcbTwq8z8YwSmuj+ZYvc+xCuEpkssA==",
       "funding": [
         {
           "type": "individual",
@@ -6358,9 +6364,9 @@
       "deprecated": "Use uuid module instead"
     },
     "node_modules/nodemailer": {
-      "version": "6.9.2",
-      "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.2.tgz",
-      "integrity": "sha512-4+TYaa/e1nIxQfyw/WzNPYTEZ5OvHIDEnmjs4LPmIfccPQN+2CYKmGHjWixn/chzD3bmUTu5FMfpltizMxqzdg==",
+      "version": "6.9.3",
+      "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.3.tgz",
+      "integrity": "sha512-fy9v3NgTzBngrMFkDsKEj0r02U7jm6XfC3b52eoNV+GCrGj+s8pt5OqhiJdWKuw51zCTdiNR/IUD1z33LIIGpg==",
       "engines": {
         "node": ">=6.0.0"
       }
@@ -7160,20 +7166,11 @@
       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
     },
     "node_modules/passport-slack-oauth2": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/passport-slack-oauth2/-/passport-slack-oauth2-1.1.1.tgz",
-      "integrity": "sha512-xC+yMKFXximP5TzSNt4lr9TP78MMos5B+acC7bJNCxBAVNyL9e02AEpVpVtyMIqHv4nNZnv1vyoOb50J8VCcZQ==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/passport-slack-oauth2/-/passport-slack-oauth2-1.2.0.tgz",
+      "integrity": "sha512-SeQl8uPoi4ajhzgIvwQM7gW/6yPrKH0hPFjxcP/426SOZ0M9ZNDOfSa32q3NTw7KcwYOTjyWX/2xdJndQE7Rkg==",
       "dependencies": {
-        "passport-oauth2": "^1.5.0",
-        "pkginfo": "^0.4.1"
-      }
-    },
-    "node_modules/passport-slack-oauth2/node_modules/pkginfo": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.1.tgz",
-      "integrity": "sha512-8xCNE/aT/EXKenuMDZ+xTVwkT8gsoHN2z/Q29l80u0ppGEXVvsKRzNMbtKhg8LS8k1tJLAHHylf6p4VFmP6XUQ==",
-      "engines": {
-        "node": ">= 0.4.0"
+        "passport-oauth2": "^1.7.0"
       }
     },
     "node_modules/passport-strategy": {
@@ -7452,9 +7449,9 @@
       }
     },
     "node_modules/poolifier": {
-      "version": "2.4.14",
-      "resolved": "https://registry.npmjs.org/poolifier/-/poolifier-2.4.14.tgz",
-      "integrity": "sha512-22cWUpyV/2B+e/UXUbf+rvr9s7EHsDrjpuIr8I4MO9JBru4gADIlxEUSEpzj4U2eAhayyMo6Xt4kINKdiGGETg==",
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/poolifier/-/poolifier-2.6.2.tgz",
+      "integrity": "sha512-3/bYzHdoFwJ+LCWlgVELuD9kEN1jho3RH4kG/YOo+2IX0ASVQD9SogGJ2YEW7+y9GD6vMuv9rcCkoTf2LxgaoQ==",
       "funding": [
         {
           "type": "opencollective",
@@ -7467,8 +7464,8 @@
       ],
       "hasInstallScript": true,
       "engines": {
-        "node": ">=16.0.0",
-        "pnpm": ">=8.0.0"
+        "node": ">=16.14.0",
+        "pnpm": ">=8.6.0"
       }
     },
     "node_modules/postgres-array": {
@@ -7612,16 +7609,16 @@
       }
     },
     "node_modules/proxy-agent": {
-      "version": "6.2.0",
-      "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.2.0.tgz",
-      "integrity": "sha512-g3rBHXPhEa0Z1nxZkirj0+US1SCcA67SnjpxbdZf7BloLdULEUCzbQozsq+wFwhmMeZegeZISDZjPFN/Ct9DaQ==",
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.2.1.tgz",
+      "integrity": "sha512-OIbBKlRAT+ycCm6wAYIzMwPejzRtjy8F3QiDX0eKOA3e4pe3U9F/IvzcHP42bmgQxVv97juG+J8/gx+JIeCX/Q==",
       "dependencies": {
-        "agent-base": "^7.0.1",
+        "agent-base": "^7.0.2",
         "debug": "^4.3.4",
-        "http-proxy-agent": "^6.0.1",
-        "https-proxy-agent": "^6.1.0",
+        "http-proxy-agent": "^7.0.0",
+        "https-proxy-agent": "^7.0.0",
         "lru-cache": "^7.14.1",
-        "pac-proxy-agent": "^6.0.2",
+        "pac-proxy-agent": "^6.0.3",
         "proxy-from-env": "^1.1.0",
         "socks-proxy-agent": "^8.0.1"
       },
@@ -7657,9 +7654,9 @@
       }
     },
     "node_modules/proxy-agent/node_modules/http-proxy-agent": {
-      "version": "6.1.1",
-      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-6.1.1.tgz",
-      "integrity": "sha512-JRCz+4Whs6yrrIoIlrH+ZTmhrRwtMnmOHsHn8GFEn9O2sVfSE+DAZ3oyyGIKF8tjJEeSJmP89j7aTjVsSqsU0g==",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz",
+      "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==",
       "dependencies": {
         "agent-base": "^7.1.0",
         "debug": "^4.3.4"
@@ -7669,9 +7666,9 @@
       }
     },
     "node_modules/proxy-agent/node_modules/https-proxy-agent": {
-      "version": "6.2.1",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-6.2.1.tgz",
-      "integrity": "sha512-ONsE3+yfZF2caH5+bJlcddtWqNI3Gvs5A38+ngvljxaBiRXRswym2c7yf8UAeFpRFKjFNHIFEHqR/OLAWJzyiA==",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz",
+      "integrity": "sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==",
       "dependencies": {
         "agent-base": "^7.0.2",
         "debug": "4"
@@ -7727,19 +7724,19 @@
       }
     },
     "node_modules/puppeteer-core": {
-      "version": "20.4.0",
-      "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.4.0.tgz",
-      "integrity": "sha512-fcL2fYQLFZEuIIDbMhvf6WF5rAcKXetsrjOxu6Br6FEAet7kEtJlCcrKmnz3pfqkwAIlihjuzwT5ys7jMWEx8A==",
+      "version": "20.5.0",
+      "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.5.0.tgz",
+      "integrity": "sha512-9ddHXUQ7jpliGei87zYTuEZYQvFj6Lzk5R8w4vT4gMmNArkEqC5CX72TnVIJiTUbiTpOXJkvMQaXIHYopjdUtQ==",
       "dependencies": {
-        "@puppeteer/browsers": "1.4.0",
-        "chromium-bidi": "0.4.10",
+        "@puppeteer/browsers": "1.4.1",
+        "chromium-bidi": "0.4.11",
         "cross-fetch": "3.1.6",
         "debug": "4.3.4",
         "devtools-protocol": "0.0.1120988",
         "ws": "8.13.0"
       },
       "engines": {
-        "node": ">=16.0.0"
+        "node": ">=16.3.0"
       },
       "peerDependencies": {
         "typescript": ">= 4.7.4"
@@ -8582,16 +8579,16 @@
       }
     },
     "node_modules/socket.io": {
-      "version": "4.6.1",
-      "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.1.tgz",
-      "integrity": "sha512-KMcaAi4l/8+xEjkRICl6ak8ySoxsYG+gG6/XfRCPJPQ/haCRIJBTL4wIl8YCsmtaBovcAXGLOShyVWQ/FG8GZA==",
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.2.tgz",
+      "integrity": "sha512-Vp+lSks5k0dewYTfwgPT9UeGGd+ht7sCpB7p0e83VgO4X/AHYWhXITMrNk/pg8syY2bpx23ptClCQuHhqi2BgQ==",
       "dependencies": {
         "accepts": "~1.3.4",
         "base64id": "~2.0.0",
         "debug": "~4.3.2",
-        "engine.io": "~6.4.1",
+        "engine.io": "~6.4.2",
         "socket.io-adapter": "~2.5.2",
-        "socket.io-parser": "~4.2.1"
+        "socket.io-parser": "~4.2.4"
       },
       "engines": {
         "node": ">=10.0.0"
@@ -8626,9 +8623,9 @@
       }
     },
     "node_modules/socket.io-parser": {
-      "version": "4.2.2",
-      "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz",
-      "integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==",
+      "version": "4.2.4",
+      "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
+      "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
       "dependencies": {
         "@socket.io/component-emitter": "~3.1.0",
         "debug": "~4.3.1"

+ 13 - 13
server/package.json

@@ -34,18 +34,18 @@
     "node": ">=18.0"
   },
   "dependencies": {
-    "@apollo/server": "4.7.1",
+    "@apollo/server": "4.7.3",
     "@azure/storage-blob": "12.14.0",
     "@exlinc/keycloak-passport": "1.0.2",
     "@graphql-tools/schema": "10.0.0",
-    "@graphql-tools/utils": "10.0.0",
+    "@graphql-tools/utils": "10.0.1",
     "@joplin/turndown-plugin-gfm": "1.0.47",
     "@root/csr": "0.8.1",
     "@root/keypairs": "0.10.3",
     "@root/pem": "1.0.4",
     "acme": "3.0.3",
     "akismet-api": "6.0.0",
-    "aws-sdk": "2.1386.0",
+    "aws-sdk": "2.1395.0",
     "bcryptjs": "2.4.3",
     "body-parser": "1.20.2",
     "chalk": "5.2.0",
@@ -71,7 +71,7 @@
     "express": "4.18.2",
     "express-brute": "1.0.1",
     "express-session": "1.17.3",
-    "file-type": "18.4.0",
+    "file-type": "18.5.0",
     "filesize": "10.0.7",
     "fs-extra": "11.1.1",
     "getos": "3.2.1",
@@ -82,7 +82,7 @@
     "graphql-upload": "16.0.2",
     "he": "1.2.0",
     "highlight.js": "11.8.0",
-    "i18next": "22.5.0",
+    "i18next": "22.5.1",
     "i18next-node-fs-backend": "2.1.3",
     "image-size": "1.0.2",
     "js-base64": "3.7.5",
@@ -116,7 +116,7 @@
     "nanoid": "4.0.2",
     "node-2fa": "2.0.3",
     "node-cache": "5.1.2",
-    "nodemailer": "6.9.2",
+    "nodemailer": "6.9.3",
     "objection": "3.0.1",
     "passport": "0.6.0",
     "passport-auth0": "1.4.3",
@@ -136,7 +136,7 @@
     "passport-okta-oauth": "0.0.1",
     "passport-openidconnect": "0.1.1",
     "passport-saml": "3.2.1",
-    "passport-slack-oauth2": "1.1.1",
+    "passport-slack-oauth2": "1.2.0",
     "passport-twitch-strategy": "2.2.0",
     "pem-jwk": "2.0.0",
     "pg": "8.11.0",
@@ -144,9 +144,9 @@
     "pg-pubsub": "0.8.1",
     "pg-query-stream": "4.5.0",
     "pg-tsquery": "8.4.1",
-    "poolifier": "2.4.14",
+    "poolifier": "2.6.2",
     "punycode": "2.3.0",
-    "puppeteer-core": "20.4.0",
+    "puppeteer-core": "20.5.0",
     "qr-image": "3.2.0",
     "rate-limiter-flexible": "2.4.1",
     "remove-markdown": "0.5.0",
@@ -159,7 +159,7 @@
     "serve-favicon": "2.5.0",
     "sharp": "0.32.1",
     "simple-git": "3.19.0",
-    "socket.io": "4.6.1",
+    "socket.io": "4.6.2",
     "striptags": "3.2.0",
     "tar-fs": "2.1.1",
     "turndown": "7.1.2",
@@ -171,9 +171,9 @@
     "yargs": "17.7.2"
   },
   "devDependencies": {
-    "eslint": "8.41.0",
+    "eslint": "8.42.0",
     "eslint-config-requarks": "1.0.7",
-    "eslint-config-standard": "17.0.0",
+    "eslint-config-standard": "17.1.0",
     "eslint-plugin-import": "2.27.5",
     "eslint-plugin-node": "11.1.0",
     "eslint-plugin-promise": "6.1.1",
@@ -181,7 +181,7 @@
     "nodemon": "2.0.22"
   },
   "overrides": {
-    "@graphql-tools/utils": "10.0.0"
+    "@graphql-tools/utils": "10.0.1"
   },
   "collective": {
     "type": "opencollective",

+ 2 - 1
server/tasks/simple/check-version.mjs

@@ -10,11 +10,12 @@ export async function task (payload) {
       version: strictVersion,
       versionDate: resp.published_at
     }
-    await WIKI.config.saveToDb(['update'])
+    await WIKI.configSvc.saveToDb(['update'])
 
     WIKI.logger.info('Checked for latest version: [ COMPLETED ]')
   } catch (err) {
     WIKI.logger.error('Checking for latest version: [ FAILED ]')
     WIKI.logger.error(err.message)
+    throw err
   }
 }

+ 1 - 0
server/tasks/simple/clean-job-history.mjs

@@ -13,5 +13,6 @@ export async function task (payload) {
   } catch (err) {
     WIKI.logger.error('Cleaning scheduler job history: [ FAILED ]')
     WIKI.logger.error(err.message)
+    throw err
   }
 }

+ 1 - 0
server/tasks/simple/update-locales.mjs

@@ -48,5 +48,6 @@ export async function task (payload) {
   } catch (err) {
     WIKI.logger.error('Fetching latest localization data: [ FAILED ]')
     WIKI.logger.error(err.message)
+    throw err
   }
 }

+ 95 - 138
ux/package-lock.json

@@ -8,8 +8,8 @@
       "name": "wiki-ux",
       "version": "3.0.0",
       "dependencies": {
-        "@apollo/client": "3.7.14",
-        "@lezer/common": "1.0.2",
+        "@apollo/client": "3.7.15",
+        "@lezer/common": "1.0.3",
         "@mdi/font": "7.2.96",
         "@quasar/extras": "1.16.4",
         "@tiptap/core": "2.0.3",
@@ -69,21 +69,21 @@
         "markdown-it-sup": "1.0.0",
         "markdown-it-task-lists": "2.1.1",
         "mitt": "3.0.0",
-        "monaco-editor": "0.38.0",
+        "monaco-editor": "0.39.0",
         "pako": "2.1.0",
         "pinia": "2.1.3",
         "prosemirror-commands": "1.5.2",
         "prosemirror-history": "1.3.2",
         "prosemirror-keymap": "1.2.2",
         "prosemirror-model": "1.19.2",
-        "prosemirror-schema-list": "1.2.3",
+        "prosemirror-schema-list": "1.3.0",
         "prosemirror-state": "1.4.3",
-        "prosemirror-transform": "1.7.2",
-        "prosemirror-view": "1.31.3",
+        "prosemirror-transform": "1.7.3",
+        "prosemirror-view": "1.31.4",
         "pug": "3.0.2",
         "quasar": "2.12.0",
         "slugify": "1.6.6",
-        "socket.io-client": "4.6.1",
+        "socket.io-client": "4.6.2",
         "tabulator-tables": "5.5.0",
         "tippy.js": "6.3.7",
         "twemoji": "14.0.2",
@@ -91,10 +91,10 @@
         "v-network-graph": "0.9.3",
         "vue": "3.3.4",
         "vue-i18n": "9.2.2",
-        "vue-router": "4.2.1",
+        "vue-router": "4.2.2",
         "vue3-otp-input": "0.4.1",
         "vuedraggable": "4.1.0",
-        "xterm": "5.1.0",
+        "xterm": "5.2.1",
         "zxcvbn": "4.4.2"
       },
       "devDependencies": {
@@ -104,10 +104,10 @@
         "@volar/vue-language-plugin-pug": "1.6.5",
         "autoprefixer": "10.4.14",
         "browserlist": "latest",
-        "eslint": "8.41.0",
-        "eslint-config-standard": "17.0.0",
+        "eslint": "8.42.0",
+        "eslint-config-standard": "17.1.0",
         "eslint-plugin-import": "2.27.5",
-        "eslint-plugin-n": "15.7.0",
+        "eslint-plugin-n": "16.0.0",
         "eslint-plugin-promise": "6.1.1",
         "eslint-plugin-vue": "9.14.1"
       },
@@ -117,14 +117,14 @@
       }
     },
     "node_modules/@apollo/client": {
-      "version": "3.7.14",
-      "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.7.14.tgz",
-      "integrity": "sha512-BRvdkwq5PAXBkjXjboO12uksDm3nrZEqDi4xF97Fk3Mnaa0zDOEfJa7hoKTY9b9KA1EkeWv9BL3i7hSd4SfGBg==",
+      "version": "3.7.15",
+      "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.7.15.tgz",
+      "integrity": "sha512-pLScjo4GAQRWKWyEg2J3FlQr9fbUAuADT0EI2+JlLf2BjaU9I7WUaZVD9w+0qNPE8BZqs53MRQq0OCm1QCW+eg==",
       "dependencies": {
         "@graphql-typed-document-node/core": "^3.1.1",
         "@wry/context": "^0.7.0",
         "@wry/equality": "^0.5.0",
-        "@wry/trie": "^0.3.0",
+        "@wry/trie": "^0.4.0",
         "graphql-tag": "^2.12.6",
         "hoist-non-react-statics": "^3.3.2",
         "optimism": "^0.16.2",
@@ -157,6 +157,17 @@
         }
       }
     },
+    "node_modules/@apollo/client/node_modules/@wry/trie": {
+      "version": "0.4.3",
+      "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.4.3.tgz",
+      "integrity": "sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w==",
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/@babel/helper-validator-identifier": {
       "version": "7.16.7",
       "license": "MIT",
@@ -249,9 +260,9 @@
       }
     },
     "node_modules/@eslint/js": {
-      "version": "8.41.0",
-      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz",
-      "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==",
+      "version": "8.42.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz",
+      "integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==",
       "dev": true,
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -265,9 +276,10 @@
       }
     },
     "node_modules/@humanwhocodes/config-array": {
-      "version": "0.11.8",
+      "version": "0.11.10",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
+      "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==",
       "dev": true,
-      "license": "Apache-2.0",
       "dependencies": {
         "@humanwhocodes/object-schema": "^1.2.1",
         "debug": "^4.1.1",
@@ -291,8 +303,9 @@
     },
     "node_modules/@humanwhocodes/object-schema": {
       "version": "1.2.1",
-      "dev": true,
-      "license": "BSD-3-Clause"
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+      "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+      "dev": true
     },
     "node_modules/@intlify/bundle-utils": {
       "version": "6.0.1",
@@ -484,8 +497,9 @@
       "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
     },
     "node_modules/@lezer/common": {
-      "version": "1.0.2",
-      "license": "MIT"
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.3.tgz",
+      "integrity": "sha512-JH4wAXCgUOcCGNekQPLhVeUtIqjH0yPBs7vvUdSjyQama9618IOKFJwkv2kcqdhF0my8hQEgCTEJU0GIgnahvA=="
     },
     "node_modules/@linaria/core": {
       "version": "3.0.0-beta.13",
@@ -3251,16 +3265,16 @@
       }
     },
     "node_modules/eslint": {
-      "version": "8.41.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz",
-      "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==",
+      "version": "8.42.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz",
+      "integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.2.0",
         "@eslint-community/regexpp": "^4.4.0",
         "@eslint/eslintrc": "^2.0.3",
-        "@eslint/js": "8.41.0",
-        "@humanwhocodes/config-array": "^0.11.8",
+        "@eslint/js": "8.42.0",
+        "@humanwhocodes/config-array": "^0.11.10",
         "@humanwhocodes/module-importer": "^1.0.1",
         "@nodelib/fs.walk": "^1.2.8",
         "ajv": "^6.10.0",
@@ -3307,7 +3321,9 @@
       }
     },
     "node_modules/eslint-config-standard": {
-      "version": "17.0.0",
+      "version": "17.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz",
+      "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==",
       "dev": true,
       "funding": [
         {
@@ -3323,11 +3339,13 @@
           "url": "https://feross.org/support"
         }
       ],
-      "license": "MIT",
+      "engines": {
+        "node": ">=12.0.0"
+      },
       "peerDependencies": {
         "eslint": "^8.0.1",
         "eslint-plugin-import": "^2.25.2",
-        "eslint-plugin-n": "^15.0.0",
+        "eslint-plugin-n": "^15.0.0 || ^16.0.0 ",
         "eslint-plugin-promise": "^6.0.0"
       }
     },
@@ -3373,47 +3391,23 @@
         "ms": "^2.1.1"
       }
     },
-    "node_modules/eslint-plugin-es": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz",
-      "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==",
+    "node_modules/eslint-plugin-es-x": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-6.2.1.tgz",
+      "integrity": "sha512-uR34zUhZ9EBoiSD2DdV5kHLpydVEvwWqjteUr9sXRgJknwbKZJZhdJ7uFnaTtd+Nr/2G3ceJHnHXrFhJ67n3Tw==",
       "dev": true,
       "dependencies": {
-        "eslint-utils": "^2.0.0",
-        "regexpp": "^3.0.0"
+        "@eslint-community/eslint-utils": "^4.1.2",
+        "@eslint-community/regexpp": "^4.5.0"
       },
       "engines": {
-        "node": ">=8.10.0"
+        "node": "^14.18.0 || >=16.0.0"
       },
       "funding": {
-        "url": "https://github.com/sponsors/mysticatea"
+        "url": "https://github.com/sponsors/ota-meshi"
       },
       "peerDependencies": {
-        "eslint": ">=4.19.1"
-      }
-    },
-    "node_modules/eslint-plugin-es/node_modules/eslint-utils": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
-      "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
-      "dev": true,
-      "dependencies": {
-        "eslint-visitor-keys": "^1.1.0"
-      },
-      "engines": {
-        "node": ">=6"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/mysticatea"
-      }
-    },
-    "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
-      "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
-      "dev": true,
-      "engines": {
-        "node": ">=4"
+        "eslint": ">=8"
       }
     },
     "node_modules/eslint-plugin-import": {
@@ -3472,22 +3466,22 @@
       }
     },
     "node_modules/eslint-plugin-n": {
-      "version": "15.7.0",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz",
-      "integrity": "sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==",
+      "version": "16.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.0.0.tgz",
+      "integrity": "sha512-akkZTE3hsHBrq6CwmGuYCzQREbVUrA855kzcHqe6i0FLBkeY7Y/6tThCVkjUnjhvRBAlc+8lILcSe5QvvDpeZQ==",
       "dev": true,
       "dependencies": {
+        "@eslint-community/eslint-utils": "^4.4.0",
         "builtins": "^5.0.1",
-        "eslint-plugin-es": "^4.1.0",
-        "eslint-utils": "^3.0.0",
+        "eslint-plugin-es-x": "^6.1.0",
         "ignore": "^5.1.1",
-        "is-core-module": "^2.11.0",
+        "is-core-module": "^2.12.0",
         "minimatch": "^3.1.2",
-        "resolve": "^1.22.1",
-        "semver": "^7.3.8"
+        "resolve": "^1.22.2",
+        "semver": "^7.5.0"
       },
       "engines": {
-        "node": ">=12.22.0"
+        "node": ">=16.0.0"
       },
       "funding": {
         "url": "https://github.com/sponsors/mysticatea"
@@ -3544,33 +3538,6 @@
         "url": "https://opencollective.com/eslint"
       }
     },
-    "node_modules/eslint-utils": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
-      "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
-      "dev": true,
-      "dependencies": {
-        "eslint-visitor-keys": "^2.0.0"
-      },
-      "engines": {
-        "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/mysticatea"
-      },
-      "peerDependencies": {
-        "eslint": ">=5"
-      }
-    },
-    "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
-      "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
-      "dev": true,
-      "engines": {
-        "node": ">=10"
-      }
-    },
     "node_modules/eslint-visitor-keys": {
       "version": "3.4.1",
       "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz",
@@ -5498,9 +5465,9 @@
       }
     },
     "node_modules/monaco-editor": {
-      "version": "0.38.0",
-      "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.38.0.tgz",
-      "integrity": "sha512-11Fkh6yzEmwx7O0YoLxeae0qEGFwmyPRlVxpg7oF9czOOCB/iCjdJrG5I67da5WiXK3YJCxoz9TJFE8Tfq/v9A=="
+      "version": "0.39.0",
+      "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.39.0.tgz",
+      "integrity": "sha512-zhbZ2Nx93tLR8aJmL2zI1mhJpsl87HMebNBM6R8z4pLfs8pj604pIVIVwyF1TivcfNtIPpMXL+nb3DsBmE/x6Q=="
     },
     "node_modules/ms": {
       "version": "2.1.3",
@@ -6160,13 +6127,13 @@
       }
     },
     "node_modules/prosemirror-schema-list": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.2.3.tgz",
-      "integrity": "sha512-HD8yjDOusz7JB3oBFCaMOpEN9Z9DZttLr6tcASjnvKMc0qTyX5xgAN8YiMFFEcwyhF7WZrZ2YQkAwzsn8ICVbQ==",
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.3.0.tgz",
+      "integrity": "sha512-Hz/7gM4skaaYfRPNgr421CU4GSwotmEwBVvJh5ltGiffUJwm7C8GfN/Bc6DR1EKEp5pDKhODmdXXyi9uIsZl5A==",
       "dependencies": {
         "prosemirror-model": "^1.0.0",
         "prosemirror-state": "^1.0.0",
-        "prosemirror-transform": "^1.0.0"
+        "prosemirror-transform": "^1.7.3"
       }
     },
     "node_modules/prosemirror-state": {
@@ -6219,17 +6186,17 @@
       }
     },
     "node_modules/prosemirror-transform": {
-      "version": "1.7.2",
-      "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.7.2.tgz",
-      "integrity": "sha512-b94lVUdA9NyaYRb2WuGSgb5YANiITa05dtew9eSK+KkYu64BCnU27WhJPE95gAWAnhV57CM3FabWXM23gri8Kg==",
+      "version": "1.7.3",
+      "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.7.3.tgz",
+      "integrity": "sha512-qDapyx5lqYfxVeUWEw0xTGgeP2S8346QtE7DxkalsXlX89lpzkY6GZfulgfHyk1n4tf74sZ7CcXgcaCcGjsUtA==",
       "dependencies": {
         "prosemirror-model": "^1.0.0"
       }
     },
     "node_modules/prosemirror-view": {
-      "version": "1.31.3",
-      "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.31.3.tgz",
-      "integrity": "sha512-UYDa8WxRFZm0xQLXiPJUVTl6H08Fn0IUVDootA7ZlQwzooqVWnBOXLovJyyTKgws1nprfsPhhlvWgt2jo4ZA6g==",
+      "version": "1.31.4",
+      "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.31.4.tgz",
+      "integrity": "sha512-nJzH2LpYbonSTYFqQ1BUdEhbd1WPN/rp/K9T9qxBEYpgg3jK3BvEUCR45Ymc9IHpO0m3nBJwPm19RBxZdoBVuw==",
       "dependencies": {
         "prosemirror-model": "^1.16.0",
         "prosemirror-state": "^1.0.0",
@@ -6506,18 +6473,6 @@
         "node": ">= 0.4"
       }
     },
-    "node_modules/regexpp": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
-      "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
-      "dev": true,
-      "engines": {
-        "node": ">=8"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/mysticatea"
-      }
-    },
     "node_modules/register-service-worker": {
       "version": "1.7.2",
       "dev": true,
@@ -6925,22 +6880,23 @@
       }
     },
     "node_modules/socket.io-client": {
-      "version": "4.6.1",
-      "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.6.1.tgz",
-      "integrity": "sha512-5UswCV6hpaRsNg5kkEHVcbBIXEYoVbMQaHJBXJCyEQ+CiFPV1NIOY0XOFWG4XR4GZcB8Kn6AsRs/9cy9TbqVMQ==",
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.6.2.tgz",
+      "integrity": "sha512-OwWrMbbA8wSqhBAR0yoPK6EdQLERQAYjXb3A0zLpgxfM1ZGLKoxHx8gVmCHA6pcclRX5oA/zvQf7bghAS11jRA==",
       "dependencies": {
         "@socket.io/component-emitter": "~3.1.0",
         "debug": "~4.3.2",
         "engine.io-client": "~6.4.0",
-        "socket.io-parser": "~4.2.1"
+        "socket.io-parser": "~4.2.4"
       },
       "engines": {
         "node": ">=10.0.0"
       }
     },
     "node_modules/socket.io-parser": {
-      "version": "4.2.2",
-      "license": "MIT",
+      "version": "4.2.4",
+      "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
+      "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
       "dependencies": {
         "@socket.io/component-emitter": "~3.1.0",
         "debug": "~4.3.1"
@@ -7725,9 +7681,9 @@
       }
     },
     "node_modules/vue-router": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.1.tgz",
-      "integrity": "sha512-nW28EeifEp8Abc5AfmAShy5ZKGsGzjcnZ3L1yc2DYUo+MqbBClrRP9yda3dIekM4I50/KnEwo1wkBLf7kHH5Cw==",
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.2.tgz",
+      "integrity": "sha512-cChBPPmAflgBGmy3tBsjeoe3f3VOSG6naKyY5pjtrqLGbNEXdzCigFUHgBvp9e3ysAtFtEx7OLqcSDh/1Cq2TQ==",
       "dependencies": {
         "@vue/devtools-api": "^6.5.0"
       },
@@ -7927,8 +7883,9 @@
       }
     },
     "node_modules/xterm": {
-      "version": "5.1.0",
-      "license": "MIT"
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.2.1.tgz",
+      "integrity": "sha512-cs5Y1fFevgcdoh2hJROMVIWwoBHD80P1fIP79gopLHJIE4kTzzblanoivxTiQ4+92YM9IxS36H1q0MxIJXQBcA=="
     },
     "node_modules/y18n": {
       "version": "5.0.8",

+ 12 - 12
ux/package.json

@@ -13,8 +13,8 @@
     "ncu-u": "ncu -u -x codemirror,codemirror-asciidoc"
   },
   "dependencies": {
-    "@apollo/client": "3.7.14",
-    "@lezer/common": "1.0.2",
+    "@apollo/client": "3.7.15",
+    "@lezer/common": "1.0.3",
     "@mdi/font": "7.2.96",
     "@quasar/extras": "1.16.4",
     "@tiptap/core": "2.0.3",
@@ -74,21 +74,21 @@
     "markdown-it-sup": "1.0.0",
     "markdown-it-task-lists": "2.1.1",
     "mitt": "3.0.0",
-    "monaco-editor": "0.38.0",
+    "monaco-editor": "0.39.0",
     "pako": "2.1.0",
     "pinia": "2.1.3",
     "prosemirror-commands": "1.5.2",
     "prosemirror-history": "1.3.2",
     "prosemirror-keymap": "1.2.2",
     "prosemirror-model": "1.19.2",
-    "prosemirror-schema-list": "1.2.3",
+    "prosemirror-schema-list": "1.3.0",
     "prosemirror-state": "1.4.3",
-    "prosemirror-transform": "1.7.2",
-    "prosemirror-view": "1.31.3",
+    "prosemirror-transform": "1.7.3",
+    "prosemirror-view": "1.31.4",
     "pug": "3.0.2",
     "quasar": "2.12.0",
     "slugify": "1.6.6",
-    "socket.io-client": "4.6.1",
+    "socket.io-client": "4.6.2",
     "tabulator-tables": "5.5.0",
     "tippy.js": "6.3.7",
     "twemoji": "14.0.2",
@@ -96,10 +96,10 @@
     "v-network-graph": "0.9.3",
     "vue": "3.3.4",
     "vue-i18n": "9.2.2",
-    "vue-router": "4.2.1",
+    "vue-router": "4.2.2",
     "vue3-otp-input": "0.4.1",
     "vuedraggable": "4.1.0",
-    "xterm": "5.1.0",
+    "xterm": "5.2.1",
     "zxcvbn": "4.4.2"
   },
   "devDependencies": {
@@ -109,10 +109,10 @@
     "@volar/vue-language-plugin-pug": "1.6.5",
     "autoprefixer": "10.4.14",
     "browserlist": "latest",
-    "eslint": "8.41.0",
-    "eslint-config-standard": "17.0.0",
+    "eslint": "8.42.0",
+    "eslint-config-standard": "17.1.0",
     "eslint-plugin-import": "2.27.5",
-    "eslint-plugin-n": "15.7.0",
+    "eslint-plugin-n": "16.0.0",
     "eslint-plugin-promise": "6.1.1",
     "eslint-plugin-vue": "9.14.1"
   },

+ 14 - 3
ux/src/components/FileManager.vue

@@ -615,7 +615,7 @@ async function loadTree ({ parentId = null, parentPath = null, types, initLoad =
 
             // -> Set Ancestors / Tree Roots
             if (item.folderPath) {
-              if (!state.treeNodes[parentId].children.includes(item.id)) {
+              if (item.id !== parentId && !state.treeNodes[parentId].children.includes(item.id)) {
                 state.treeNodes[parentId].children.push(item.id)
               }
             } else {
@@ -725,9 +725,20 @@ function renameFolder (folderId) {
     componentProps: {
       folderId
     }
-  }).onOk(() => {
+  }).onOk(async () => {
     treeComp.value.resetLoaded()
-    loadTree({ parentId: folderId, initLoad: true })
+    // // -> Delete current folder and children from cache
+    // const fPath = [state.treeNodes[folderId].folderPath, state.treeNodes[folderId].fileName].filter(p => !!p).join('/')
+    // delete state.treeNodes[folderId]
+    // for (const [nodeId, node] of Object.entries(state.treeNodes)) {
+    //   if (node.folderPath.startsWith(fPath)) {
+    //     delete state.treeNodes[nodeId]
+    //   }
+    // }
+    // -> Reload tree
+    await loadTree({ parentId: folderId, types: ['folder'], initLoad: true }) // Update tree
+    // -> Reload current view (in case current folder is included)
+    await loadTree({ parentId: state.currentFolderId })
   })
 }
 

+ 1 - 0
ux/src/components/FolderRenameDialog.vue

@@ -204,6 +204,7 @@ onMounted(async () => {
           }
         }
       `,
+      fetchPolicy: 'network-only',
       variables: {
         id: props.folderId
       }

+ 1 - 1
ux/src/components/LocaleSelectorMenu.vue

@@ -1,7 +1,7 @@
 <template lang="pug">
 q-menu.translucent-menu(
   auto-close
-  anchor='top right'
+  anchor='bottom middle'
   self='top left'
   )
   q-list(padding, style='min-width: 200px;')

+ 5 - 0
ux/src/css/page-contents.scss

@@ -249,6 +249,11 @@
         border-color: $green-5;
       }
     }
+
+    .codeblock > code {
+      background-color: inherit;
+      color: inherit;
+    }
   }
 
   // ---------------------------------