feat: new page UI + db fixes + installer improvements

This commit is contained in:
Nicolas Giard
2018-08-19 01:22:59 -04:00
parent 04c972c1d0
commit 4bb522f9d9
21 changed files with 357 additions and 182 deletions

View File

@@ -66,6 +66,10 @@ jobs:
onInit: true
cron: '*/15 * * * *'
concurrency: 0
renderPage:
onInit: false
cron: false
concurrency: 1
syncGraphLocales:
onInit: true
cron: '0 0 * * *'

View File

@@ -1,5 +1,8 @@
const express = require('express')
const router = express.Router()
const pageHelper = require('../helpers/page')
/* global WIKI */
/**
* Create/Edit document
@@ -25,15 +28,20 @@ router.get(['/p', '/p/*'], (req, res, next) => {
/**
* View document
*/
router.get('/', (req, res, next) => {
res.render('welcome')
})
/**
* View document
*/
router.get('/*', (req, res, next) => {
res.render('page')
router.get('/*', async (req, res, next) => {
const pageArgs = pageHelper.parsePath(req.path)
const page = await WIKI.models.pages.getPage({
path: pageArgs.path,
locale: pageArgs.locale,
userId: req.user.id
})
if (page) {
res.render('page')
} else if (pageArgs.path === 'home') {
res.render('welcome')
} else {
res.render('new')
}
})
module.exports = router

View File

@@ -87,6 +87,7 @@ exports.up = knex => {
table.string('description')
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isPublished').notNullable().defaultTo(false)
table.string('privateNS')
table.string('publishStartDate')
table.string('publishEndDate')
table.text('content')

View File

@@ -1,60 +0,0 @@
/* global appdata, ROOTPATH */
const crypto = require('crypto')
const path = require('path')
const qs = require('querystring')
const _ = require('lodash')
module.exports = {
/**
* Parse raw url path and make it safe
*
* @param {String} urlPath The url path
* @return {String} Safe entry path
*/
parsePath (urlPath) {
urlPath = qs.unescape(urlPath)
let wlist = new RegExp('[^a-z0-9' + appdata.regex.cjk + appdata.regex.arabic + '/-]', 'g')
urlPath = _.toLower(urlPath).replace(wlist, '')
if (urlPath === '/') {
urlPath = 'home'
}
let urlParts = _.filter(_.split(urlPath, '/'), (p) => { return !_.isEmpty(p) })
return _.join(urlParts, '/')
},
/**
* Gets the full original path of a document.
*
* @param {String} entryPath The entry path
* @return {String} The full path.
*/
getFullPath (entryPath) {
return path.join(appdata.repoPath, entryPath + '.md')
},
/**
* Gets the full cache path of a document.
*
* @param {String} entryPath The entry path
* @return {String} The full cache path.
*/
getCachePath (entryPath) {
return path.join(appdata.cachePath, crypto.createHash('md5').update(entryPath).digest('hex') + '.json')
},
/**
* Gets the entry path from full path.
*
* @param {String} fullPath The full path
* @return {String} The entry path
*/
getEntryPathFromFullPath (fullPath) {
let absRepoPath = path.resolve(ROOTPATH, appdata.repoPath)
return _.chain(fullPath).replace(absRepoPath, '').replace('.md', '').replace(new RegExp('\\\\', 'g'), '/').value()
}
}

30
server/helpers/page.js Normal file
View File

@@ -0,0 +1,30 @@
const qs = require('querystring')
const _ = require('lodash')
module.exports = {
/**
* Parse raw url path and make it safe
*/
parsePath (rawPath) {
let pathObj = {
locale: 'en',
path: 'home',
private: false,
privateNS: ''
}
// Clean Path
rawPath = _.trim(qs.unescape(rawPath))
if (_.startsWith(rawPath, '/')) { rawPath = rawPath.substring(1) }
if (rawPath === '') { rawPath = 'home' }
// Extract Info
let pathParts = _.filter(_.split(rawPath, '/'), p => !_.isEmpty(p))
if (pathParts[0].length === 2) {
pathObj = pathParts[0]
pathParts.shift()
}
pathObj.path = _.join(pathParts, '/')
return pathObj
}
}

View File

@@ -6,7 +6,6 @@ module.exports = async (job) => {
WIKI.logger.info(`Rendering page ${job.data.path}...`)
try {
WIKI.logger.info(`Rendering page ${job.data.path}: [ COMPLETED ]`)
} catch (err) {
WIKI.logger.error(`Rendering page ${job.data.path}: [ FAILED ]`)

View File

@@ -1,4 +1,5 @@
const Model = require('objection').Model
const _ = require('lodash')
/* global WIKI */
@@ -19,6 +20,7 @@ module.exports = class Page extends Model {
title: {type: 'string'},
description: {type: 'string'},
isPublished: {type: 'boolean'},
privateNS: {type: 'string'},
publishStartDate: {type: 'string'},
publishEndDate: {type: 'string'},
content: {type: 'string'},
@@ -87,6 +89,27 @@ module.exports = class Page extends Model {
this.updatedAt = new Date().toISOString()
}
static async getPage(opts) {
const page = await WIKI.models.pages.query().where({
path: opts.path,
localeCode: opts.locale
}).andWhere(builder => {
builder.where({
isPublished: true
}).orWhere({
isPublished: false,
authorId: opts.userId
})
}).andWhere(builder => {
if (opts.private) {
builder.where({ isPrivate: true, privateNS: opts.privateNS })
} else {
builder.where({ isPrivate: false })
}
}).first()
return page
}
static async createPage(opts) {
await WIKI.models.pages.renderPage(opts)
const page = await WIKI.models.pages.query().insertAndFetch({

16
server/views/new.pug Normal file
View File

@@ -0,0 +1,16 @@
extends master.pug
block body
#root.is-fullscreen
v-app
.newpage
.newpage-content
img.animated.fadeIn(src='/svg/henry-thinking.svg', alt='Henry')
.headline= t('newpage.title')
.subheading.mt-3= t('newpage.subtitle')
v-btn.mt-5(href='/e/home', large)
v-icon(left) add
span= t('newpage.create')
v-btn.mt-2(color='blue lighten-4', href='javascript:window.history.go(-1);', large, outline)
v-icon(left) arrow_back
span= t('newpage.goback')

View File

@@ -4,9 +4,10 @@ block body
#root.is-fullscreen
v-app
.onboarding
img.animated.fadeIn(src='/svg/logo-wikijs.svg', alt='Wiki.js')
.headline= t('welcome.title')
.subheading.mt-3= t('welcome.subtitle')
v-btn.mt-5(color='primary', href='/e/home', large)
v-icon(left) add
span= t('welcome.createhome')
.onboarding-content
img.animated.fadeIn(src='/svg/logo-wikijs.svg', alt='Wiki.js')
.headline= t('welcome.title')
.subheading.mt-3= t('welcome.subtitle')
v-btn.mt-5(color='primary', href='/e/home', large)
v-icon(left) add
span= t('welcome.createhome')