feat: local disk import all action + v1 import content (#1100)
This commit is contained in:
parent
334d0a754e
commit
cffd32dee0
@ -1,7 +1,6 @@
|
|||||||
const passport = require('passport')
|
const passport = require('passport')
|
||||||
const passportJWT = require('passport-jwt')
|
const passportJWT = require('passport-jwt')
|
||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const path = require('path')
|
|
||||||
const jwt = require('jsonwebtoken')
|
const jwt = require('jsonwebtoken')
|
||||||
const moment = require('moment')
|
const moment = require('moment')
|
||||||
const Promise = require('bluebird')
|
const Promise = require('bluebird')
|
||||||
|
@ -4,6 +4,13 @@ const crypto = require('crypto')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
const localeSegmentRegex = /^[A-Z]{2}(-[A-Z]{2})?$/i
|
const localeSegmentRegex = /^[A-Z]{2}(-[A-Z]{2})?$/i
|
||||||
|
const localeFolderRegex = /^([a-z]{2}(?:-[a-z]{2})?\/)?(.*)/i
|
||||||
|
|
||||||
|
const contentToExt = {
|
||||||
|
markdown: 'md',
|
||||||
|
html: 'html'
|
||||||
|
}
|
||||||
|
const extToContent = _.invert(contentToExt)
|
||||||
|
|
||||||
/* global WIKI */
|
/* global WIKI */
|
||||||
|
|
||||||
@ -94,13 +101,34 @@ module.exports = {
|
|||||||
* Get file extension from content type
|
* Get file extension from content type
|
||||||
*/
|
*/
|
||||||
getFileExtension(contentType) {
|
getFileExtension(contentType) {
|
||||||
switch (contentType) {
|
_.get(contentToExt, contentType, 'txt')
|
||||||
case 'markdown':
|
},
|
||||||
return 'md'
|
/**
|
||||||
case 'html':
|
* Get content type from file extension
|
||||||
return 'html'
|
*/
|
||||||
default:
|
getContentType (filePath) {
|
||||||
return 'txt'
|
const ext = _.last(filePath.split('.'))
|
||||||
|
return _.get(extToContent, ext, false)
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Get Page Meta object from disk path
|
||||||
|
*/
|
||||||
|
getPagePath (filePath) {
|
||||||
|
let fpath = filePath
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
fpath = filePath.replace(/\\/g, '/')
|
||||||
}
|
}
|
||||||
|
let meta = {
|
||||||
|
locale: WIKI.config.lang.code,
|
||||||
|
path: _.initial(fpath.split('.')).join('')
|
||||||
|
}
|
||||||
|
const result = localeFolderRegex.exec(meta.path)
|
||||||
|
if (result[1]) {
|
||||||
|
meta = {
|
||||||
|
locale: result[1],
|
||||||
|
path: result[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return meta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,6 +99,8 @@ module.exports = class Editor extends Model {
|
|||||||
switch (contentType) {
|
switch (contentType) {
|
||||||
case 'markdown':
|
case 'markdown':
|
||||||
return 'markdown'
|
return 'markdown'
|
||||||
|
case 'html':
|
||||||
|
return 'ckeditor'
|
||||||
default:
|
default:
|
||||||
return 'code'
|
return 'code'
|
||||||
}
|
}
|
||||||
|
@ -366,7 +366,7 @@ module.exports = class Page extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// -> Perform move?
|
// -> Perform move?
|
||||||
if (opts.locale !== page.localeCode || opts.path !== page.path) {
|
if ((opts.locale && opts.locale !== page.localeCode) || (opts.path && opts.path !== page.path)) {
|
||||||
await WIKI.models.pages.movePage({
|
await WIKI.models.pages.movePage({
|
||||||
id: page.id,
|
id: page.id,
|
||||||
destinationLocale: opts.locale,
|
destinationLocale: opts.locale,
|
||||||
|
@ -712,4 +712,14 @@ module.exports = class User extends Model {
|
|||||||
user.permissions = user.getGlobalPermissions()
|
user.permissions = user.getGlobalPermissions()
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async getRootUser () {
|
||||||
|
let user = await WIKI.models.users.query().findById(1)
|
||||||
|
if (!user) {
|
||||||
|
WIKI.logger.error('CRITICAL ERROR: Root Administrator user is missing!')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
user.permissions = ['manage:system']
|
||||||
|
return user
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,3 +29,6 @@ actions:
|
|||||||
- handler: backup
|
- handler: backup
|
||||||
label: Create Backup
|
label: Create Backup
|
||||||
hint: Will create a manual backup archive at this point in time, in a subfolder named _manual, from the contents currently on disk.
|
hint: Will create a manual backup archive at this point in time, in a subfolder named _manual, from the contents currently on disk.
|
||||||
|
- handler: importAll
|
||||||
|
label: Import Everything
|
||||||
|
hint: Will import all content currently in the local disk folder.
|
||||||
|
@ -3,8 +3,10 @@ const path = require('path')
|
|||||||
const tar = require('tar-fs')
|
const tar = require('tar-fs')
|
||||||
const zlib = require('zlib')
|
const zlib = require('zlib')
|
||||||
const stream = require('stream')
|
const stream = require('stream')
|
||||||
|
const _ = require('lodash')
|
||||||
const Promise = require('bluebird')
|
const Promise = require('bluebird')
|
||||||
const pipeline = Promise.promisify(stream.pipeline)
|
const pipeline = Promise.promisify(stream.pipeline)
|
||||||
|
const klaw = require('klaw')
|
||||||
const pageHelper = require('../../../helpers/page.js')
|
const pageHelper = require('../../../helpers/page.js')
|
||||||
const moment = require('moment')
|
const moment = require('moment')
|
||||||
|
|
||||||
@ -113,5 +115,77 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
async backup() {
|
async backup() {
|
||||||
return this.sync({ manual: true })
|
return this.sync({ manual: true })
|
||||||
|
},
|
||||||
|
async importAll() {
|
||||||
|
WIKI.logger.info(`(STORAGE/DISK) Importing all content from local disk folder to the DB...`)
|
||||||
|
|
||||||
|
const rootUser = await WIKI.models.users.getRootUser()
|
||||||
|
|
||||||
|
await pipeline(
|
||||||
|
klaw(this.config.path, {
|
||||||
|
filter: (f) => {
|
||||||
|
return !_.includes(f, '.git')
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
new stream.Transform({
|
||||||
|
objectMode: true,
|
||||||
|
transform: async (file, enc, cb) => {
|
||||||
|
const relPath = file.path.substr(this.config.path.length + 1)
|
||||||
|
if (relPath && relPath.length > 3) {
|
||||||
|
WIKI.logger.info(`(STORAGE/DISK) Processing ${relPath}...`)
|
||||||
|
const contentType = pageHelper.getContentType(relPath)
|
||||||
|
if (!contentType) {
|
||||||
|
return cb()
|
||||||
|
}
|
||||||
|
const contentPath = pageHelper.getPagePath(relPath)
|
||||||
|
|
||||||
|
let itemContents = ''
|
||||||
|
try {
|
||||||
|
itemContents = await fs.readFile(path.join(this.config.path, relPath), 'utf8')
|
||||||
|
const pageData = WIKI.models.pages.parseMetadata(itemContents, contentType)
|
||||||
|
const currentPage = await WIKI.models.pages.query().findOne({
|
||||||
|
path: contentPath.path,
|
||||||
|
localeCode: contentPath.locale
|
||||||
|
})
|
||||||
|
if (currentPage) {
|
||||||
|
// Already in the DB, can mark as modified
|
||||||
|
WIKI.logger.info(`(STORAGE/DISK) Page marked as modified: ${relPath}`)
|
||||||
|
await WIKI.models.pages.updatePage({
|
||||||
|
id: currentPage.id,
|
||||||
|
title: _.get(pageData, 'title', currentPage.title),
|
||||||
|
description: _.get(pageData, 'description', currentPage.description) || '',
|
||||||
|
isPublished: _.get(pageData, 'isPublished', currentPage.isPublished),
|
||||||
|
isPrivate: false,
|
||||||
|
content: pageData.content,
|
||||||
|
user: rootUser,
|
||||||
|
skipStorage: true
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// Not in the DB, can mark as new
|
||||||
|
WIKI.logger.info(`(STORAGE/DISK) Page marked as new: ${relPath}`)
|
||||||
|
const pageEditor = await WIKI.models.editors.getDefaultEditor(contentType)
|
||||||
|
await WIKI.models.pages.createPage({
|
||||||
|
path: contentPath.path,
|
||||||
|
locale: contentPath.locale,
|
||||||
|
title: _.get(pageData, 'title', _.last(contentPath.path.split('/'))),
|
||||||
|
description: _.get(pageData, 'description', '') || '',
|
||||||
|
isPublished: _.get(pageData, 'isPublished', true),
|
||||||
|
isPrivate: false,
|
||||||
|
content: pageData.content,
|
||||||
|
user: rootUser,
|
||||||
|
editor: pageEditor,
|
||||||
|
skipStorage: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
WIKI.logger.warn(`(STORAGE/DISK) Failed to process ${relPath}`)
|
||||||
|
WIKI.logger.warn(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cb()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
WIKI.logger.info('(STORAGE/DISK) Import completed.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,41 +8,8 @@ const pipeline = Promise.promisify(stream.pipeline)
|
|||||||
const klaw = require('klaw')
|
const klaw = require('klaw')
|
||||||
const pageHelper = require('../../../helpers/page.js')
|
const pageHelper = require('../../../helpers/page.js')
|
||||||
|
|
||||||
const localeFolderRegex = /^([a-z]{2}(?:-[a-z]{2})?\/)?(.*)/i
|
|
||||||
|
|
||||||
/* global WIKI */
|
/* global WIKI */
|
||||||
|
|
||||||
const getContenType = (filePath) => {
|
|
||||||
const ext = _.last(filePath.split('.'))
|
|
||||||
switch (ext) {
|
|
||||||
case 'md':
|
|
||||||
return 'markdown'
|
|
||||||
case 'html':
|
|
||||||
return 'html'
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getPagePath = (filePath) => {
|
|
||||||
let fpath = filePath
|
|
||||||
if (process.platform === 'win32') {
|
|
||||||
fpath = filePath.replace(/\\/g, '/')
|
|
||||||
}
|
|
||||||
let meta = {
|
|
||||||
locale: 'en',
|
|
||||||
path: _.initial(fpath.split('.')).join('')
|
|
||||||
}
|
|
||||||
const result = localeFolderRegex.exec(meta.path)
|
|
||||||
if (result[1]) {
|
|
||||||
meta = {
|
|
||||||
locale: result[1],
|
|
||||||
path: result[2]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
git: null,
|
git: null,
|
||||||
repoPath: path.join(process.cwd(), 'data/repo'),
|
repoPath: path.join(process.cwd(), 'data/repo'),
|
||||||
@ -145,6 +112,8 @@ module.exports = {
|
|||||||
async sync() {
|
async sync() {
|
||||||
const currentCommitLog = _.get(await this.git.log(['-n', '1', this.config.branch]), 'latest', {})
|
const currentCommitLog = _.get(await this.git.log(['-n', '1', this.config.branch]), 'latest', {})
|
||||||
|
|
||||||
|
const rootUser = await WIKI.models.users.getRootUser()
|
||||||
|
|
||||||
// Pull rebase
|
// Pull rebase
|
||||||
if (_.includes(['sync', 'pull'], this.mode)) {
|
if (_.includes(['sync', 'pull'], this.mode)) {
|
||||||
WIKI.logger.info(`(STORAGE/GIT) Performing pull rebase from origin on branch ${this.config.branch}...`)
|
WIKI.logger.info(`(STORAGE/GIT) Performing pull rebase from origin on branch ${this.config.branch}...`)
|
||||||
@ -167,7 +136,7 @@ module.exports = {
|
|||||||
|
|
||||||
const diff = await this.git.diffSummary(['-M', currentCommitLog.hash, latestCommitLog.hash])
|
const diff = await this.git.diffSummary(['-M', currentCommitLog.hash, latestCommitLog.hash])
|
||||||
if (_.get(diff, 'files', []).length > 0) {
|
if (_.get(diff, 'files', []).length > 0) {
|
||||||
await this.processFiles(diff.files)
|
await this.processFiles(diff.files, rootUser)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -176,13 +145,13 @@ module.exports = {
|
|||||||
*
|
*
|
||||||
* @param {Array<String>} files Array of files to process
|
* @param {Array<String>} files Array of files to process
|
||||||
*/
|
*/
|
||||||
async processFiles(files) {
|
async processFiles(files, user) {
|
||||||
for (const item of files) {
|
for (const item of files) {
|
||||||
const contentType = getContenType(item.file)
|
const contentType = pageHelper.getContentType(item.file)
|
||||||
if (!contentType) {
|
if (!contentType) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const contentPath = getPagePath(item.file)
|
const contentPath = pageHelper.getPagePath(item.file)
|
||||||
|
|
||||||
let itemContents = ''
|
let itemContents = ''
|
||||||
try {
|
try {
|
||||||
@ -202,7 +171,7 @@ module.exports = {
|
|||||||
isPublished: _.get(pageData, 'isPublished', currentPage.isPublished),
|
isPublished: _.get(pageData, 'isPublished', currentPage.isPublished),
|
||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
content: pageData.content,
|
content: pageData.content,
|
||||||
authorId: 1,
|
user: user,
|
||||||
skipStorage: true
|
skipStorage: true
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -217,7 +186,7 @@ module.exports = {
|
|||||||
isPublished: _.get(pageData, 'isPublished', true),
|
isPublished: _.get(pageData, 'isPublished', true),
|
||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
content: pageData.content,
|
content: pageData.content,
|
||||||
authorId: 1,
|
user: user,
|
||||||
editor: pageEditor,
|
editor: pageEditor,
|
||||||
skipStorage: true
|
skipStorage: true
|
||||||
})
|
})
|
||||||
@ -233,8 +202,7 @@ module.exports = {
|
|||||||
skipStorage: true
|
skipStorage: true
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
WIKI.logger.warn(`(STORAGE/GIT) Failed to open ${item.file}`)
|
WIKI.logger.warn(`(STORAGE/GIT) Failed to process ${item.file}`)
|
||||||
console.error(err)
|
|
||||||
WIKI.logger.warn(err)
|
WIKI.logger.warn(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -365,6 +333,9 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
async importAll() {
|
async importAll() {
|
||||||
WIKI.logger.info(`(STORAGE/GIT) Importing all content from local Git repo to the DB...`)
|
WIKI.logger.info(`(STORAGE/GIT) Importing all content from local Git repo to the DB...`)
|
||||||
|
|
||||||
|
const rootUser = await WIKI.models.users.getRootUser()
|
||||||
|
|
||||||
await pipeline(
|
await pipeline(
|
||||||
klaw(this.repoPath, {
|
klaw(this.repoPath, {
|
||||||
filter: (f) => {
|
filter: (f) => {
|
||||||
@ -378,10 +349,11 @@ module.exports = {
|
|||||||
if (relPath && relPath.length > 3) {
|
if (relPath && relPath.length > 3) {
|
||||||
WIKI.logger.info(`(STORAGE/GIT) Processing ${relPath}...`)
|
WIKI.logger.info(`(STORAGE/GIT) Processing ${relPath}...`)
|
||||||
await this.processFiles([{
|
await this.processFiles([{
|
||||||
|
user: rootUser,
|
||||||
file: relPath,
|
file: relPath,
|
||||||
deletions: 0,
|
deletions: 0,
|
||||||
insertions: 0
|
insertions: 0
|
||||||
}])
|
}], rootUser)
|
||||||
}
|
}
|
||||||
cb()
|
cb()
|
||||||
}
|
}
|
||||||
@ -391,6 +363,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
async syncUntracked() {
|
async syncUntracked() {
|
||||||
WIKI.logger.info(`(STORAGE/GIT) Adding all untracked content...`)
|
WIKI.logger.info(`(STORAGE/GIT) Adding all untracked content...`)
|
||||||
|
|
||||||
await pipeline(
|
await pipeline(
|
||||||
WIKI.models.knex.column('path', 'localeCode', 'title', 'description', 'contentType', 'content', 'isPublished', 'updatedAt').select().from('pages').where({
|
WIKI.models.knex.column('path', 'localeCode', 'title', 'description', 'contentType', 'content', 'isPublished', 'updatedAt').select().from('pages').where({
|
||||||
isPrivate: false
|
isPrivate: false
|
||||||
|
Loading…
Reference in New Issue
Block a user