Jelajahi Sumber

feat: editor create page mode

NGPixel 2 tahun lalu
induk
melakukan
9a92789d13

+ 347 - 357
server/controllers/common.js

@@ -106,20 +106,6 @@ router.get('/_thumb/:id.webp', async (req, res, next) => {
   }
 })
 
-/**
- * New v3 vue app
- */
-router.get([
-  '/_admin',
-  '/_admin/*',
-  '/_profile',
-  '/_profile/*',
-  '/_error',
-  '/_error/*',
-  '/_welcome'
-], (req, res, next) => {
-  res.sendFile(path.join(WIKI.ROOTPATH, 'assets/index.html'))
-})
 // router.get(['/_admin', '/_admin/*'], (req, res, next) => {
 //   if (!WIKI.auth.checkAccess(req.user, [
 //     'manage:system',
@@ -140,297 +126,297 @@ router.get([
 
 // })
 
-/**
- * Download Page / Version
- */
-router.get(['/d', '/d/*'], 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.db.pages.getPageFromDb({
-    path: pageArgs.path,
-    locale: pageArgs.locale,
-    userId: req.user.id,
-    isPrivate: false
-  })
-
-  pageArgs.tags = _.get(page, 'tags', [])
-
-  if (versionId > 0) {
-    if (!WIKI.auth.checkAccess(req.user, ['read:history'], pageArgs)) {
-      _.set(res.locals, 'pageMeta.title', 'Unauthorized')
-      return res.render('unauthorized', { action: 'downloadVersion' })
-    }
-  } else {
-    if (!WIKI.auth.checkAccess(req.user, ['read:source'], pageArgs)) {
-      _.set(res.locals, 'pageMeta.title', 'Unauthorized')
-      return res.render('unauthorized', { action: 'download' })
-    }
-  }
-
-  if (page) {
-    const fileName = _.last(page.path.split('/')) + '.' + pageHelper.getFileExtension(page.contentType)
-    res.attachment(fileName)
-    if (versionId > 0) {
-      const pageVersion = await WIKI.db.pageHistory.getVersion({ pageId: page.id, versionId })
-      res.send(pageHelper.injectPageMetadata(pageVersion))
-    } else {
-      res.send(pageHelper.injectPageMetadata(page))
-    }
-  } else {
-    res.status(404).end()
-  }
-})
-
-/**
- * Create/Edit document
- */
-router.get(['/_edit', '/_edit/*'], async (req, res, next) => {
-  const pageArgs = pageHelper.parsePath(req.path, { stripExt: true })
-  const site = await WIKI.db.sites.getSiteByHostname({ hostname: req.hostname })
-
-  if (!site) {
-    throw new Error('INVALID_SITE')
-  }
-
-  if (pageArgs.path === '') {
-    return res.redirect(`/_edit/home`)
-  }
-
-  // if (WIKI.config.lang.namespacing && !pageArgs.explicitLocale) {
-  //   return res.redirect(`/_edit/${pageArgs.locale}/${pageArgs.path}`)
-  // }
+// /**
+//  * Download Page / Version
+//  */
+// router.get(['/d', '/d/*'], 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.db.pages.getPageFromDb({
+//     path: pageArgs.path,
+//     locale: pageArgs.locale,
+//     userId: req.user.id,
+//     isPrivate: false
+//   })
+
+//   pageArgs.tags = _.get(page, 'tags', [])
+
+//   if (versionId > 0) {
+//     if (!WIKI.auth.checkAccess(req.user, ['read:history'], pageArgs)) {
+//       _.set(res.locals, 'pageMeta.title', 'Unauthorized')
+//       return res.render('unauthorized', { action: 'downloadVersion' })
+//     }
+//   } else {
+//     if (!WIKI.auth.checkAccess(req.user, ['read:source'], pageArgs)) {
+//       _.set(res.locals, 'pageMeta.title', 'Unauthorized')
+//       return res.render('unauthorized', { action: 'download' })
+//     }
+//   }
 
-  // req.i18n.changeLanguage(pageArgs.locale)
+//   if (page) {
+//     const fileName = _.last(page.path.split('/')) + '.' + pageHelper.getFileExtension(page.contentType)
+//     res.attachment(fileName)
+//     if (versionId > 0) {
+//       const pageVersion = await WIKI.db.pageHistory.getVersion({ pageId: page.id, versionId })
+//       res.send(pageHelper.injectPageMetadata(pageVersion))
+//     } else {
+//       res.send(pageHelper.injectPageMetadata(page))
+//     }
+//   } else {
+//     res.status(404).end()
+//   }
+// })
 
-  // -> Set Editor Lang
-  _.set(res, 'locals.siteConfig.lang', pageArgs.locale)
-  // _.set(res, 'locals.siteConfig.rtl', req.i18n.dir() === 'rtl')
+// /**
+//  * Create/Edit document
+//  */
+// router.get(['/_edit', '/_edit/*'], async (req, res, next) => {
+//   const pageArgs = pageHelper.parsePath(req.path, { stripExt: true })
+//   const site = await WIKI.db.sites.getSiteByHostname({ hostname: req.hostname })
 
-  // -> Check for reserved path
-  if (pageHelper.isReservedPath(pageArgs.path)) {
-    return next(new Error('Cannot create this page because it starts with a system reserved path.'))
-  }
+//   if (!site) {
+//     throw new Error('INVALID_SITE')
+//   }
 
-  // -> Get page data from DB
-  let page = await WIKI.db.pages.getPageFromDb({
-    siteId: site.id,
-    path: pageArgs.path,
-    locale: pageArgs.locale,
-    userId: req.user.id
-  })
+//   if (pageArgs.path === '') {
+//     return res.redirect(`/_edit/home`)
+//   }
 
-  pageArgs.tags = _.get(page, 'tags', [])
+//   // if (WIKI.config.lang.namespacing && !pageArgs.explicitLocale) {
+//   //   return res.redirect(`/_edit/${pageArgs.locale}/${pageArgs.path}`)
+//   // }
 
-  // -> Effective Permissions
-  const effectivePermissions = WIKI.auth.getEffectivePermissions(req, pageArgs)
+//   // req.i18n.changeLanguage(pageArgs.locale)
 
-  const injectCode = {
-    css: '', // WIKI.config.theming.injectCSS,
-    head: '', // WIKI.config.theming.injectHead,
-    body: '' // WIKI.config.theming.injectBody
-  }
+//   // -> Set Editor Lang
+//   _.set(res, 'locals.siteConfig.lang', pageArgs.locale)
+//   // _.set(res, 'locals.siteConfig.rtl', req.i18n.dir() === 'rtl')
 
-  if (page) {
-    // -> EDIT MODE
-    if (!(effectivePermissions.pages.write || effectivePermissions.pages.manage)) {
-      _.set(res.locals, 'pageMeta.title', 'Unauthorized')
-      return res.render('unauthorized', { action: 'edit' })
-    }
+//   // -> Check for reserved path
+//   if (pageHelper.isReservedPath(pageArgs.path)) {
+//     return next(new Error('Cannot create this page because it starts with a system reserved path.'))
+//   }
 
-    // -> Get page tags
-    await page.$relatedQuery('tags')
-    page.tags = _.map(page.tags, 'tag')
+//   // -> Get page data from DB
+//   let page = await WIKI.db.pages.getPageFromDb({
+//     siteId: site.id,
+//     path: pageArgs.path,
+//     locale: pageArgs.locale,
+//     userId: req.user.id
+//   })
 
-    // Handle missing extra field
-    page.extra = page.extra || { css: '', js: '' }
+//   pageArgs.tags = _.get(page, 'tags', [])
 
-    // -> Beautify Script CSS
-    if (!_.isEmpty(page.extra.css)) {
-      page.extra.css = new CleanCSS({ format: 'beautify' }).minify(page.extra.css).styles
-    }
+//   // -> Effective Permissions
+//   const effectivePermissions = WIKI.auth.getEffectivePermissions(req, pageArgs)
 
-    _.set(res.locals, 'pageMeta.title', `Edit ${page.title}`)
-    _.set(res.locals, 'pageMeta.description', page.description)
-    page.mode = 'update'
-    page.isPublished = (page.isPublished === true || page.isPublished === 1) ? 'true' : 'false'
-    page.content = Buffer.from(page.content).toString('base64')
-  } else {
-    // -> CREATE MODE
-    if (!effectivePermissions.pages.write) {
-      _.set(res.locals, 'pageMeta.title', 'Unauthorized')
-      return res.render('unauthorized', { action: 'create' })
-    }
-
-    _.set(res.locals, 'pageMeta.title', `New Page`)
-    page = {
-      path: pageArgs.path,
-      localeCode: pageArgs.locale,
-      editorKey: null,
-      mode: 'create',
-      content: null,
-      title: null,
-      description: null,
-      updatedAt: new Date().toISOString(),
-      extra: {
-        css: '',
-        js: ''
-      }
-    }
-  }
+//   const injectCode = {
+//     css: '', // WIKI.config.theming.injectCSS,
+//     head: '', // WIKI.config.theming.injectHead,
+//     body: '' // WIKI.config.theming.injectBody
+//   }
 
-  res.render('editor', { page, injectCode, effectivePermissions })
-})
+//   if (page) {
+//     // -> EDIT MODE
+//     if (!(effectivePermissions.pages.write || effectivePermissions.pages.manage)) {
+//       _.set(res.locals, 'pageMeta.title', 'Unauthorized')
+//       return res.render('unauthorized', { action: 'edit' })
+//     }
+
+//     // -> Get page tags
+//     await page.$relatedQuery('tags')
+//     page.tags = _.map(page.tags, 'tag')
+
+//     // Handle missing extra field
+//     page.extra = page.extra || { css: '', js: '' }
+
+//     // -> Beautify Script CSS
+//     if (!_.isEmpty(page.extra.css)) {
+//       page.extra.css = new CleanCSS({ format: 'beautify' }).minify(page.extra.css).styles
+//     }
+
+//     _.set(res.locals, 'pageMeta.title', `Edit ${page.title}`)
+//     _.set(res.locals, 'pageMeta.description', page.description)
+//     page.mode = 'update'
+//     page.isPublished = (page.isPublished === true || page.isPublished === 1) ? 'true' : 'false'
+//     page.content = Buffer.from(page.content).toString('base64')
+//   } else {
+//     // -> CREATE MODE
+//     if (!effectivePermissions.pages.write) {
+//       _.set(res.locals, 'pageMeta.title', 'Unauthorized')
+//       return res.render('unauthorized', { action: 'create' })
+//     }
+
+//     _.set(res.locals, 'pageMeta.title', `New Page`)
+//     page = {
+//       path: pageArgs.path,
+//       localeCode: pageArgs.locale,
+//       editorKey: null,
+//       mode: 'create',
+//       content: null,
+//       title: null,
+//       description: null,
+//       updatedAt: new Date().toISOString(),
+//       extra: {
+//         css: '',
+//         js: ''
+//       }
+//     }
+//   }
 
-/**
- * History
- */
-router.get(['/h', '/h/*'], async (req, res, next) => {
-  const pageArgs = pageHelper.parsePath(req.path, { stripExt: true })
+//   res.render('editor', { page, injectCode, effectivePermissions })
+// })
 
-  if (WIKI.config.lang.namespacing && !pageArgs.explicitLocale) {
-    return res.redirect(`/h/${pageArgs.locale}/${pageArgs.path}`)
-  }
+// /**
+//  * History
+//  */
+// router.get(['/h', '/h/*'], async (req, res, next) => {
+//   const pageArgs = pageHelper.parsePath(req.path, { stripExt: true })
 
-  req.i18n.changeLanguage(pageArgs.locale)
+//   if (WIKI.config.lang.namespacing && !pageArgs.explicitLocale) {
+//     return res.redirect(`/h/${pageArgs.locale}/${pageArgs.path}`)
+//   }
 
-  _.set(res, 'locals.siteConfig.lang', pageArgs.locale)
-  _.set(res, 'locals.siteConfig.rtl', req.i18n.dir() === 'rtl')
+//   req.i18n.changeLanguage(pageArgs.locale)
 
-  const page = await WIKI.db.pages.getPageFromDb({
-    path: pageArgs.path,
-    locale: pageArgs.locale,
-    userId: req.user.id,
-    isPrivate: false
-  })
+//   _.set(res, 'locals.siteConfig.lang', pageArgs.locale)
+//   _.set(res, 'locals.siteConfig.rtl', req.i18n.dir() === 'rtl')
 
-  if (!page) {
-    _.set(res.locals, 'pageMeta.title', 'Page Not Found')
-    return res.status(404).render('notfound', { action: 'history' })
-  }
+//   const page = await WIKI.db.pages.getPageFromDb({
+//     path: pageArgs.path,
+//     locale: pageArgs.locale,
+//     userId: req.user.id,
+//     isPrivate: false
+//   })
 
-  pageArgs.tags = _.get(page, 'tags', [])
+//   if (!page) {
+//     _.set(res.locals, 'pageMeta.title', 'Page Not Found')
+//     return res.status(404).render('notfound', { action: 'history' })
+//   }
 
-  const effectivePermissions = WIKI.auth.getEffectivePermissions(req, pageArgs)
+//   pageArgs.tags = _.get(page, 'tags', [])
 
-  if (!effectivePermissions.history.read) {
-    _.set(res.locals, 'pageMeta.title', 'Unauthorized')
-    return res.render('unauthorized', { action: 'history' })
-  }
+//   const effectivePermissions = WIKI.auth.getEffectivePermissions(req, pageArgs)
 
-  if (page) {
-    _.set(res.locals, 'pageMeta.title', page.title)
-    _.set(res.locals, 'pageMeta.description', page.description)
+//   if (!effectivePermissions.history.read) {
+//     _.set(res.locals, 'pageMeta.title', 'Unauthorized')
+//     return res.render('unauthorized', { action: 'history' })
+//   }
 
-    res.render('history', { page, effectivePermissions })
-  } else {
-    res.redirect(`/${pageArgs.path}`)
-  }
-})
+//   if (page) {
+//     _.set(res.locals, 'pageMeta.title', page.title)
+//     _.set(res.locals, 'pageMeta.description', page.description)
 
-/**
- * Page ID redirection
- */
-router.get(['/i', '/i/:id'], async (req, res, next) => {
-  const pageId = _.toSafeInteger(req.params.id)
-  if (pageId <= 0) {
-    return res.redirect('/')
-  }
+//     res.render('history', { page, effectivePermissions })
+//   } else {
+//     res.redirect(`/${pageArgs.path}`)
+//   }
+// })
 
-  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' })
-  }
+// /**
+//  * Page ID redirection
+//  */
+// router.get(['/i', '/i/:id'], async (req, res, next) => {
+//   const pageId = _.toSafeInteger(req.params.id)
+//   if (pageId <= 0) {
+//     return res.redirect('/')
+//   }
 
-  if (!WIKI.auth.checkAccess(req.user, ['read:pages'], {
-    locale: page.localeCode,
-    path: page.path,
-    private: page.isPrivate,
-    privateNS: page.privateNS,
-    explicitLocale: false,
-    tags: page.tags
-  })) {
-    _.set(res.locals, 'pageMeta.title', 'Unauthorized')
-    return res.render('unauthorized', { action: 'view' })
-  }
+//   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' })
+//   }
 
-  if (WIKI.config.lang.namespacing) {
-    return res.redirect(`/${page.localeCode}/${page.path}`)
-  } else {
-    return res.redirect(`/${page.path}`)
-  }
-})
+//   if (!WIKI.auth.checkAccess(req.user, ['read:pages'], {
+//     locale: page.localeCode,
+//     path: page.path,
+//     private: page.isPrivate,
+//     privateNS: page.privateNS,
+//     explicitLocale: false,
+//     tags: page.tags
+//   })) {
+//     _.set(res.locals, 'pageMeta.title', 'Unauthorized')
+//     return res.render('unauthorized', { action: 'view' })
+//   }
 
-/**
- * Source
- */
-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.db.pages.getPageFromDb({
-    path: pageArgs.path,
-    locale: pageArgs.locale,
-    userId: req.user.id,
-    isPrivate: false
-  })
+//   if (WIKI.config.lang.namespacing) {
+//     return res.redirect(`/${page.localeCode}/${page.path}`)
+//   } else {
+//     return res.redirect(`/${page.path}`)
+//   }
+// })
 
-  pageArgs.tags = _.get(page, 'tags', [])
+// /**
+//  * Source
+//  */
+// 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
 
-  if (WIKI.config.lang.namespacing && !pageArgs.explicitLocale) {
-    return res.redirect(`/s/${pageArgs.locale}/${pageArgs.path}`)
-  }
+//   const page = await WIKI.db.pages.getPageFromDb({
+//     path: pageArgs.path,
+//     locale: pageArgs.locale,
+//     userId: req.user.id,
+//     isPrivate: false
+//   })
 
-  // -> Effective Permissions
-  const effectivePermissions = WIKI.auth.getEffectivePermissions(req, pageArgs)
+//   pageArgs.tags = _.get(page, 'tags', [])
 
-  _.set(res, 'locals.siteConfig.lang', pageArgs.locale)
-  _.set(res, 'locals.siteConfig.rtl', req.i18n.dir() === 'rtl')
+//   if (WIKI.config.lang.namespacing && !pageArgs.explicitLocale) {
+//     return res.redirect(`/s/${pageArgs.locale}/${pageArgs.path}`)
+//   }
 
-  if (versionId > 0) {
-    if (!effectivePermissions.history.read) {
-      _.set(res.locals, 'pageMeta.title', 'Unauthorized')
-      return res.render('unauthorized', { action: 'sourceVersion' })
-    }
-  } else {
-    if (!effectivePermissions.source.read) {
-      _.set(res.locals, 'pageMeta.title', 'Unauthorized')
-      return res.render('unauthorized', { action: 'source' })
-    }
-  }
+//   // -> Effective Permissions
+//   const effectivePermissions = WIKI.auth.getEffectivePermissions(req, pageArgs)
+
+//   _.set(res, 'locals.siteConfig.lang', pageArgs.locale)
+//   _.set(res, 'locals.siteConfig.rtl', req.i18n.dir() === 'rtl')
+
+//   if (versionId > 0) {
+//     if (!effectivePermissions.history.read) {
+//       _.set(res.locals, 'pageMeta.title', 'Unauthorized')
+//       return res.render('unauthorized', { action: 'sourceVersion' })
+//     }
+//   } else {
+//     if (!effectivePermissions.source.read) {
+//       _.set(res.locals, 'pageMeta.title', 'Unauthorized')
+//       return res.render('unauthorized', { action: 'source' })
+//     }
+//   }
 
-  if (page) {
-    if (versionId > 0) {
-      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', {
-        page: {
-          ...page,
-          ...pageVersion
-        },
-        effectivePermissions
-      })
-    } else {
-      _.set(res.locals, 'pageMeta.title', page.title)
-      _.set(res.locals, 'pageMeta.description', page.description)
-
-      res.render('source', { page, effectivePermissions })
-    }
-  } else {
-    res.redirect(`/${pageArgs.path}`)
-  }
-})
+//   if (page) {
+//     if (versionId > 0) {
+//       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', {
+//         page: {
+//           ...page,
+//           ...pageVersion
+//         },
+//         effectivePermissions
+//       })
+//     } else {
+//       _.set(res.locals, 'pageMeta.title', page.title)
+//       _.set(res.locals, 'pageMeta.description', page.description)
+
+//       res.render('source', { page, effectivePermissions })
+//     }
+//   } else {
+//     res.redirect(`/${pageArgs.path}`)
+//   }
+// })
 
-/**
- * Tags
- */
-router.get(['/t', '/t/*'], (req, res, next) => {
-  _.set(res.locals, 'pageMeta.title', 'Tags')
-  res.render('tags')
-})
+// /**
+//  * Tags
+//  */
+// router.get(['/t', '/t/*'], (req, res, next) => {
+//   _.set(res.locals, 'pageMeta.title', 'Tags')
+//   res.render('tags')
+// })
 
 /**
  * User Avatar
@@ -448,96 +434,100 @@ router.get('/_user/:uid/avatar', async (req, res, next) => {
   return res.sendStatus(404)
 })
 
-/**
- * View document / asset
- */
-router.get('/*', async (req, res, next) => {
-  const stripExt = _.some(WIKI.data.pageExtensions, ext => _.endsWith(req.path, `.${ext}`))
-  const pageArgs = pageHelper.parsePath(req.path, { stripExt })
-  const isPage = (stripExt || pageArgs.path.indexOf('.') === -1)
-  const site = await WIKI.db.sites.getSiteByHostname({ hostname: req.hostname })
-
-  if (!site) {
-    throw new Error('INVALID_SITE')
-  }
-
-  if (isPage) {
-    // if (WIKI.config.lang.namespacing && !pageArgs.explicitLocale) {
-    //   return res.redirect(`/${pageArgs.locale}/${pageArgs.path}`)
-    // }
-
-    // req.i18n.changeLanguage(pageArgs.locale)
-
-    try {
-      // -> Get Page from cache
-      const page = await WIKI.db.pages.getPage({
-        siteId: site.id,
-        path: pageArgs.path,
-        locale: pageArgs.locale,
-        userId: req.user.id
-      })
-      pageArgs.tags = _.get(page, 'tags', [])
-
-      // -> Effective Permissions
-      const effectivePermissions = WIKI.auth.getEffectivePermissions(req, pageArgs)
-
-      // -> Check User Access
-      if (!effectivePermissions.pages.read) {
-        if (req.user.id === WIKI.auth.guest.id) {
-          res.cookie('loginRedirect', req.path, {
-            maxAge: 15 * 60 * 1000
-          })
-        }
-        if (pageArgs.path === 'home' && req.user.id === WIKI.auth.guest.id) {
-          return res.redirect('/login')
-        }
-        return res.redirect(`/_error/unauthorized?from=${req.path}`)
-      }
+// /**
+//  * View document / asset
+//  */
+// router.get('/*', async (req, res, next) => {
+//   const stripExt = _.some(WIKI.data.pageExtensions, ext => _.endsWith(req.path, `.${ext}`))
+//   const pageArgs = pageHelper.parsePath(req.path, { stripExt })
+//   const isPage = (stripExt || pageArgs.path.indexOf('.') === -1)
+//   const site = await WIKI.db.sites.getSiteByHostname({ hostname: req.hostname })
+
+//   if (!site) {
+//     throw new Error('INVALID_SITE')
+//   }
 
-      _.set(res, 'locals.siteConfig.lang', pageArgs.locale)
-      // _.set(res, 'locals.siteConfig.rtl', req.i18n.dir() === 'rtl')
-
-      if (page) {
-        _.set(res.locals, 'pageMeta.title', page.title)
-        _.set(res.locals, 'pageMeta.description', page.description)
-
-        // -> Check Publishing State
-        let pageIsPublished = page.isPublished
-        if (pageIsPublished && !_.isEmpty(page.publishStartDate)) {
-          pageIsPublished = moment(page.publishStartDate).isSameOrBefore()
-        }
-        if (pageIsPublished && !_.isEmpty(page.publishEndDate)) {
-          pageIsPublished = moment(page.publishEndDate).isSameOrAfter()
-        }
-        if (!pageIsPublished && !effectivePermissions.pages.write) {
-          _.set(res.locals, 'pageMeta.title', 'Unauthorized')
-          return res.status(403).render('unauthorized', {
-            action: 'view'
-          })
-        }
-
-        // -> Render view
-        res.sendFile(path.join(WIKI.ROOTPATH, 'assets/index.html'))
-      } else if (pageArgs.path === 'home') {
-        res.redirect('/_welcome')
-      } else {
-        _.set(res.locals, 'pageMeta.title', 'Page Not Found')
-        if (effectivePermissions.pages.write) {
-          res.status(404).render('new', { path: pageArgs.path, locale: pageArgs.locale })
-        } else {
-          res.status(404).render('notfound', { action: 'view' })
-        }
-      }
-    } catch (err) {
-      next(err)
-    }
-  } else {
-    if (!WIKI.auth.checkAccess(req.user, ['read:assets'], pageArgs)) {
-      return res.sendStatus(403)
-    }
+//   if (isPage) {
+//     // if (WIKI.config.lang.namespacing && !pageArgs.explicitLocale) {
+//     //   return res.redirect(`/${pageArgs.locale}/${pageArgs.path}`)
+//     // }
+
+//     // req.i18n.changeLanguage(pageArgs.locale)
+
+//     try {
+//       // -> Get Page from cache
+//       const page = await WIKI.db.pages.getPage({
+//         siteId: site.id,
+//         path: pageArgs.path,
+//         locale: pageArgs.locale,
+//         userId: req.user.id
+//       })
+//       pageArgs.tags = _.get(page, 'tags', [])
+
+//       // -> Effective Permissions
+//       const effectivePermissions = WIKI.auth.getEffectivePermissions(req, pageArgs)
+
+//       // -> Check User Access
+//       if (!effectivePermissions.pages.read) {
+//         if (req.user.id === WIKI.auth.guest.id) {
+//           res.cookie('loginRedirect', req.path, {
+//             maxAge: 15 * 60 * 1000
+//           })
+//         }
+//         if (pageArgs.path === 'home' && req.user.id === WIKI.auth.guest.id) {
+//           return res.redirect('/login')
+//         }
+//         return res.redirect(`/_error/unauthorized?from=${req.path}`)
+//       }
+
+//       _.set(res, 'locals.siteConfig.lang', pageArgs.locale)
+//       // _.set(res, 'locals.siteConfig.rtl', req.i18n.dir() === 'rtl')
+
+//       if (page) {
+//         _.set(res.locals, 'pageMeta.title', page.title)
+//         _.set(res.locals, 'pageMeta.description', page.description)
+
+//         // -> Check Publishing State
+//         let pageIsPublished = page.isPublished
+//         if (pageIsPublished && !_.isEmpty(page.publishStartDate)) {
+//           pageIsPublished = moment(page.publishStartDate).isSameOrBefore()
+//         }
+//         if (pageIsPublished && !_.isEmpty(page.publishEndDate)) {
+//           pageIsPublished = moment(page.publishEndDate).isSameOrAfter()
+//         }
+//         if (!pageIsPublished && !effectivePermissions.pages.write) {
+//           _.set(res.locals, 'pageMeta.title', 'Unauthorized')
+//           return res.status(403).render('unauthorized', {
+//             action: 'view'
+//           })
+//         }
+
+//         // -> Render view
+//         res.sendFile(path.join(WIKI.ROOTPATH, 'assets/index.html'))
+//       } else if (pageArgs.path === 'home') {
+//         res.redirect('/_welcome')
+//       } else {
+//         _.set(res.locals, 'pageMeta.title', 'Page Not Found')
+//         if (effectivePermissions.pages.write) {
+//           res.status(404).render('new', { path: pageArgs.path, locale: pageArgs.locale })
+//         } else {
+//           res.status(404).render('notfound', { action: 'view' })
+//         }
+//       }
+//     } catch (err) {
+//       next(err)
+//     }
+//   } else {
+//     if (!WIKI.auth.checkAccess(req.user, ['read:assets'], pageArgs)) {
+//       return res.sendStatus(403)
+//     }
+
+//     await WIKI.db.assets.getAsset(pageArgs.path, res)
+//   }
+// })
 
-    await WIKI.db.assets.getAsset(pageArgs.path, res)
-  }
+router.get('/*', (req, res, next) => {
+  res.sendFile(path.join(WIKI.ROOTPATH, 'assets/index.html'))
 })
 
 module.exports = router

+ 1 - 5
server/web.js

@@ -74,17 +74,13 @@ module.exports = async () => {
     index: false,
     maxAge: '7d'
   }))
-  app.use('/_assets-legacy/svg/twemoji', async (req, res, next) => {
+  app.use('/_assets/svg/twemoji', async (req, res, next) => {
     try {
       WIKI.asar.serve('twemoji', req, res, next)
     } catch (err) {
       res.sendStatus(404)
     }
   })
-  app.use('/_assets-legacy', express.static(path.join(WIKI.ROOTPATH, 'assets-legacy'), {
-    index: false,
-    maxAge: '7d'
-  }))
 
   // ----------------------------------------
   // SSL Handlers

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

@@ -27,6 +27,7 @@ q-header.bg-header.text-white.site-header(
     q-toolbar.gt-sm(
       style='height: 64px;'
       dark
+      v-if='siteStore.features.search'
       )
       q-input(
         dark

+ 52 - 2
ux/src/components/PageHeader.vue

@@ -126,6 +126,17 @@
         @click='discardChanges'
       )
       q-btn.acrylic-btn(
+        v-if='editorStore.mode === `create`'
+        flat
+        icon='las la-check'
+        color='positive'
+        label='Create Page'
+        aria-label='Create Page'
+        no-caps
+        @click='createPage'
+      )
+      q-btn.acrylic-btn(
+        v-else
         flat
         icon='las la-check'
         color='positive'
@@ -246,10 +257,49 @@ async function saveChanges () {
   $q.loading.hide()
 }
 
-function editPage () {
+async function createPage () {
+  $q.dialog({
+    component: defineAsyncComponent(() => import('../components/TreeBrowserDialog.vue')),
+    componentProps: {
+      mode: 'createPage',
+      folderPath: '',
+      itemTitle: pageStore.title,
+      itemFileName: pageStore.path
+    }
+  }).onOk(async ({ path, title }) => {
+    $q.loading.show()
+    try {
+      pageStore.$patch({
+        title,
+        path
+      })
+      await pageStore.pageSave()
+      $q.notify({
+        type: 'positive',
+        message: 'Page created successfully.'
+      })
+      editorStore.$patch({
+        isActive: false
+      })
+    } catch (err) {
+      $q.notify({
+        type: 'negative',
+        message: 'Failed to create page.',
+        caption: err.message
+      })
+    }
+    $q.loading.hide()
+  })
+}
+
+async function editPage () {
+  $q.loading.show()
+  await pageStore.pageLoad({ id: pageStore.id, withContent: true })
   editorStore.$patch({
     isActive: true,
-    editor: 'markdown'
+    mode: 'edit',
+    editor: pageStore.editor
   })
+  $q.loading.hide()
 }
 </script>

+ 4 - 1
ux/src/components/TreeBrowserDialog.vue

@@ -230,7 +230,10 @@ const files = computed(() => {
 // METHODS
 
 async function save () {
-  onDialogOK()
+  onDialogOK({
+    title: state.title,
+    path: state.path
+  })
 }
 
 async function treeLazyLoad (nodeId, { done, fail }) {

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

@@ -93,7 +93,7 @@ function createHomePage (editor) {
   pageStore.pageCreate({
     editor,
     locale: 'en',
-    path: '',
+    path: 'home',
     title: t('welcome.homeDefault.title'),
     description: t('welcome.homeDefault.description'),
     content: t('welcome.homeDefault.content')

+ 1 - 6
ux/src/pages/AdminGeneral.vue

@@ -752,12 +752,7 @@ async function save () {
     })
     await adminStore.fetchSites()
     if (adminStore.currentSiteId === siteStore.id) {
-      siteStore.$patch({
-        title: state.config.title,
-        description: state.config.description,
-        company: state.config.company,
-        contentLicense: state.config.contentLicense
-      })
+      siteStore.loadSite(window.location.hostname)
     }
   } catch (err) {
     $q.notify({

+ 182 - 46
ux/src/stores/page.js

@@ -78,6 +78,34 @@ const gqlQueries = {
       }
     }
     ${pagePropsFragment}
+  `,
+  pageByIdWithContent: gql`
+    query loadPageWithContent (
+      $id: UUID!
+    ) {
+      pageById(
+        id: $id
+      ) {
+        ...PageRead,
+        content
+      }
+    }
+    ${pagePropsFragment}
+  `,
+  pageByPathWithContent: gql`
+    query loadPageWithContent (
+      $siteId: UUID!
+      $path: String!
+    ) {
+      pageByPath(
+        siteId: $siteId
+        path: $path
+      ) {
+        ...PageRead,
+        content
+      }
+    }
+    ${pagePropsFragment}
   `
 }
 
@@ -92,6 +120,7 @@ export const usePageStore = defineStore('page', {
     content: '',
     createdAt: '',
     description: '',
+    editor: '',
     icon: 'las la-file-alt',
     id: '',
     isBrowsable: true,
@@ -140,12 +169,18 @@ export const usePageStore = defineStore('page', {
     /**
      * PAGE - LOAD
      */
-    async pageLoad ({ path, id }) {
+    async pageLoad ({ path, id, withContent = false }) {
       const editorStore = useEditorStore()
       const siteStore = useSiteStore()
       try {
+        let query
+        if (withContent) {
+          query = id ? gqlQueries.pageByIdWithContent : gqlQueries.pageByPathWithContent
+        } else {
+          query = id ? gqlQueries.pageById : gqlQueries.pageByPath
+        }
         const resp = await APOLLO_CLIENT.query({
-          query: id ? gqlQueries.pageById : gqlQueries.pageByPath,
+          query,
           variables: id ? { id } : { siteId: siteStore.id, path },
           fetchPolicy: 'network-only'
         })
@@ -221,56 +256,157 @@ export const usePageStore = defineStore('page', {
      */
     async pageSave () {
       const editorStore = useEditorStore()
+      const siteStore = useSiteStore()
       try {
-        const resp = await APOLLO_CLIENT.mutate({
-          mutation: gql`
-            mutation savePage (
-              $id: UUID!
-              $patch: PageUpdateInput!
-            ) {
-              updatePage (
-                id: $id
-                patch: $patch
+        if (editorStore.mode === 'create') {
+          const resp = await APOLLO_CLIENT.mutate({
+            mutation: gql`
+              mutation createPage (
+                $allowComments: Boolean
+                $allowContributions: Boolean
+                $allowRatings: Boolean
+                $content: String!
+                $description: String!
+                $editor: String!
+                $icon: String
+                $isBrowsable: Boolean
+                $locale: String!
+                $path: String!
+                $publishState: PagePublishState!
+                $publishEndDate: Date
+                $publishStartDate: Date
+                $relations: [PageRelationInput!]
+                $scriptCss: String
+                $scriptJsLoad: String
+                $scriptJsUnload: String
+                $showSidebar: Boolean
+                $showTags: Boolean
+                $showToc: Boolean
+                $siteId: UUID!
+                $tags: [String!]
+                $title: String!
+                $tocDepth: PageTocDepthInput
               ) {
-                operation {
-                  succeeded
-                  message
+                createPage (
+                  allowComments: $allowComments
+                  allowContributions: $allowContributions
+                  allowRatings: $allowRatings
+                  content: $content
+                  description: $description
+                  editor: $editor
+                  icon: $icon
+                  isBrowsable: $isBrowsable
+                  locale: $locale
+                  path: $path
+                  publishState: $publishState
+                  publishEndDate: $publishEndDate
+                  publishStartDate: $publishStartDate
+                  relations: $relations
+                  scriptCss: $scriptCss
+                  scriptJsLoad: $scriptJsLoad
+                  scriptJsUnload: $scriptJsUnload
+                  showSidebar: $showSidebar
+                  showTags: $showTags
+                  showToc: $showToc
+                  siteId: $siteId
+                  tags: $tags
+                  title: $title
+                  tocDepth: $tocDepth
+                ) {
+                  operation {
+                    succeeded
+                    message
+                  }
                 }
               }
+              `,
+            variables: {
+              ...pick(this, [
+                'allowComments',
+                'allowContributions',
+                'allowRatings',
+                'content',
+                'description',
+                'icon',
+                'isBrowsable',
+                'locale',
+                'password',
+                'path',
+                'publishEndDate',
+                'publishStartDate',
+                'publishState',
+                'relations',
+                'scriptJsLoad',
+                'scriptJsUnload',
+                'scriptCss',
+                'showSidebar',
+                'showTags',
+                'showToc',
+                'tags',
+                'title',
+                'tocDepth'
+              ]),
+              editor: editorStore.editor,
+              siteId: siteStore.id
             }
-            `,
-          variables: {
-            id: this.id,
-            patch: pick(this, [
-              'allowComments',
-              'allowContributions',
-              'allowRatings',
-              // 'content',
-              'description',
-              'icon',
-              'isBrowsable',
-              'locale',
-              'password',
-              'path',
-              'publishEndDate',
-              'publishStartDate',
-              'publishState',
-              'relations',
-              'scriptJsLoad',
-              'scriptJsUnload',
-              'scriptCss',
-              'showSidebar',
-              'showTags',
-              'showToc',
-              'tags',
-              'title',
-              'tocDepth'
-            ])
+          })
+          const result = resp?.data?.createPage?.operation ?? {}
+          if (!result.succeeded) {
+            throw new Error(result.message)
+          }
+          this.id = resp.data.createPage.page.id
+          this.editor = editorStore.editor
+        } else {
+          const resp = await APOLLO_CLIENT.mutate({
+            mutation: gql`
+              mutation savePage (
+                $id: UUID!
+                $patch: PageUpdateInput!
+              ) {
+                updatePage (
+                  id: $id
+                  patch: $patch
+                ) {
+                  operation {
+                    succeeded
+                    message
+                  }
+                }
+              }
+              `,
+            variables: {
+              id: this.id,
+              patch: pick(this, [
+                'allowComments',
+                'allowContributions',
+                'allowRatings',
+                'content',
+                'description',
+                'icon',
+                'isBrowsable',
+                'locale',
+                'password',
+                'path',
+                'publishEndDate',
+                'publishStartDate',
+                'publishState',
+                'relations',
+                'scriptJsLoad',
+                'scriptJsUnload',
+                'scriptCss',
+                'showSidebar',
+                'showTags',
+                'showToc',
+                'tags',
+                'title',
+                'tocDepth'
+              ])
+            }
+          })
+          const result = resp?.data?.updatePage?.operation ?? {}
+          if (!result.succeeded) {
+            throw new Error(result.message)
           }
-        })
-        const result = resp?.data?.updatePage?.operation ?? {}
-        if (!result.succeeded) {
-          throw new Error(result.message)
         }
         // Update editor state timestamps
         const curDate = DateTime.utc()

+ 5 - 1
ux/src/stores/site.js

@@ -26,7 +26,9 @@ export const useSiteStore = defineStore('site', {
     showSidebar: true,
     overlay: null,
     features: {
-      ratingsMode: 'off'
+      ratingsMode: 'off',
+      reasonForChange: 'required',
+      search: false
     },
     editors: {
       asciidoc: false,
@@ -87,6 +89,8 @@ export const useSiteStore = defineStore('site', {
                 footerExtra
                 features {
                   ratingsMode
+                  reasonForChange
+                  search
                 }
                 editors {
                   asciidoc {