|
@@ -1,6 +1,7 @@
|
|
import { Model } from 'objection'
|
|
import { Model } from 'objection'
|
|
import { find, get, has, initial, isEmpty, isString, last, pick } from 'lodash-es'
|
|
import { find, get, has, initial, isEmpty, isString, last, pick } from 'lodash-es'
|
|
import { Type as JSBinType } from 'js-binary'
|
|
import { Type as JSBinType } from 'js-binary'
|
|
|
|
+import { getDictNameFromLocale } from '../helpers/common.mjs'
|
|
import { generateHash, getFileExtension, injectPageMetadata } from '../helpers/page.mjs'
|
|
import { generateHash, getFileExtension, injectPageMetadata } from '../helpers/page.mjs'
|
|
import path from 'node:path'
|
|
import path from 'node:path'
|
|
import fse from 'fs-extra'
|
|
import fse from 'fs-extra'
|
|
@@ -27,9 +28,6 @@ const frontmatterRegex = {
|
|
markdown: /^(-{3}(?:\n|\r)([\w\W]+?)(?:\n|\r)-{3})?(?:\n|\r)*([\w\W]*)*/
|
|
markdown: /^(-{3}(?:\n|\r)([\w\W]+?)(?:\n|\r)-{3})?(?:\n|\r)*([\w\W]*)*/
|
|
}
|
|
}
|
|
|
|
|
|
-const punctuationRegex = /[!,:;/\\_+\-=()&#@<>$~%^*[\]{}"'|]+|(\.\s)|(\s\.)/ig
|
|
|
|
-// const htmlEntitiesRegex = /(&#[0-9]{3};)|(&#x[a-zA-Z0-9]{2};)/ig
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* Pages model
|
|
* Pages model
|
|
*/
|
|
*/
|
|
@@ -66,18 +64,18 @@ export class Page extends Model {
|
|
|
|
|
|
static get relationMappings() {
|
|
static get relationMappings() {
|
|
return {
|
|
return {
|
|
- tags: {
|
|
|
|
- relation: Model.ManyToManyRelation,
|
|
|
|
- modelClass: Tag,
|
|
|
|
- join: {
|
|
|
|
- from: 'pages.id',
|
|
|
|
- through: {
|
|
|
|
- from: 'pageTags.pageId',
|
|
|
|
- to: 'pageTags.tagId'
|
|
|
|
- },
|
|
|
|
- to: 'tags.id'
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
|
|
+ // tags: {
|
|
|
|
+ // relation: Model.ManyToManyRelation,
|
|
|
|
+ // modelClass: Tag,
|
|
|
|
+ // join: {
|
|
|
|
+ // from: 'pages.id',
|
|
|
|
+ // through: {
|
|
|
|
+ // from: 'pageTags.pageId',
|
|
|
|
+ // to: 'pageTags.tagId'
|
|
|
|
+ // },
|
|
|
|
+ // to: 'tags.id'
|
|
|
|
+ // }
|
|
|
|
+ // },
|
|
links: {
|
|
links: {
|
|
relation: Model.HasManyRelation,
|
|
relation: Model.HasManyRelation,
|
|
modelClass: PageLink,
|
|
modelClass: PageLink,
|
|
@@ -319,6 +317,12 @@ export class Page extends Model {
|
|
scriptJsUnload = opts.scriptJsUnload || ''
|
|
scriptJsUnload = opts.scriptJsUnload || ''
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // -> Get Tags
|
|
|
|
+ let tags = []
|
|
|
|
+ if (opts.tags && opts.tags.length > 0) {
|
|
|
|
+ tags = await WIKI.db.tags.fetchIds({ tags: opts.tags, siteId: opts.siteId })
|
|
|
|
+ }
|
|
|
|
+
|
|
// -> Create page
|
|
// -> Create page
|
|
const page = await WIKI.db.pages.query().insert({
|
|
const page = await WIKI.db.pages.query().insert({
|
|
alias: opts.alias,
|
|
alias: opts.alias,
|
|
@@ -348,6 +352,7 @@ export class Page extends Model {
|
|
publishStartDate: opts.publishStartDate?.toISO(),
|
|
publishStartDate: opts.publishStartDate?.toISO(),
|
|
relations: opts.relations ?? [],
|
|
relations: opts.relations ?? [],
|
|
siteId: opts.siteId,
|
|
siteId: opts.siteId,
|
|
|
|
+ tags,
|
|
title: opts.title,
|
|
title: opts.title,
|
|
toc: '[]',
|
|
toc: '[]',
|
|
scripts: JSON.stringify({
|
|
scripts: JSON.stringify({
|
|
@@ -357,11 +362,6 @@ export class Page extends Model {
|
|
})
|
|
})
|
|
}).returning('*')
|
|
}).returning('*')
|
|
|
|
|
|
- // -> Save Tags
|
|
|
|
- if (opts.tags && opts.tags.length > 0) {
|
|
|
|
- await WIKI.db.tags.associateTags({ tags: opts.tags, page })
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
// -> Render page to HTML
|
|
// -> Render page to HTML
|
|
await WIKI.db.pages.renderPage(page)
|
|
await WIKI.db.pages.renderPage(page)
|
|
|
|
|
|
@@ -387,31 +387,23 @@ export class Page extends Model {
|
|
siteId: page.siteId
|
|
siteId: page.siteId
|
|
})
|
|
})
|
|
|
|
|
|
- return page
|
|
|
|
- // TODO: Handle remaining flow
|
|
|
|
-
|
|
|
|
- // -> Rebuild page tree
|
|
|
|
- await WIKI.db.pages.rebuildTree()
|
|
|
|
|
|
+ // -> Update search vector
|
|
|
|
+ WIKI.db.pages.updatePageSearchVector(page.id)
|
|
|
|
|
|
- // -> Add to Search Index
|
|
|
|
- const pageContents = await WIKI.db.pages.query().findById(page.id).select('render')
|
|
|
|
- page.safeContent = WIKI.db.pages.cleanHTML(pageContents.render)
|
|
|
|
- await WIKI.data.searchEngine.created(page)
|
|
|
|
-
|
|
|
|
- // -> Add to Storage
|
|
|
|
- if (!opts.skipStorage) {
|
|
|
|
- await WIKI.db.storage.pageEvent({
|
|
|
|
- event: 'created',
|
|
|
|
- page
|
|
|
|
- })
|
|
|
|
- }
|
|
|
|
|
|
+ // // -> Add to Storage
|
|
|
|
+ // if (!opts.skipStorage) {
|
|
|
|
+ // await WIKI.db.storage.pageEvent({
|
|
|
|
+ // event: 'created',
|
|
|
|
+ // page
|
|
|
|
+ // })
|
|
|
|
+ // }
|
|
|
|
|
|
- // -> Reconnect Links
|
|
|
|
- await WIKI.db.pages.reconnectLinks({
|
|
|
|
- locale: page.localeCode,
|
|
|
|
- path: page.path,
|
|
|
|
- mode: 'create'
|
|
|
|
- })
|
|
|
|
|
|
+ // // -> Reconnect Links
|
|
|
|
+ // await WIKI.db.pages.reconnectLinks({
|
|
|
|
+ // locale: page.localeCode,
|
|
|
|
+ // path: page.path,
|
|
|
|
+ // mode: 'create'
|
|
|
|
+ // })
|
|
|
|
|
|
// -> Get latest updatedAt
|
|
// -> Get latest updatedAt
|
|
page.updatedAt = await WIKI.db.pages.query().findById(page.id).select('updatedAt').then(r => r.updatedAt)
|
|
page.updatedAt = await WIKI.db.pages.query().findById(page.id).select('updatedAt').then(r => r.updatedAt)
|
|
@@ -445,6 +437,7 @@ export class Page extends Model {
|
|
action: 'updated',
|
|
action: 'updated',
|
|
affectedFields: []
|
|
affectedFields: []
|
|
}
|
|
}
|
|
|
|
+ let shouldUpdateSearch = false
|
|
|
|
|
|
// -> Create version snapshot
|
|
// -> Create version snapshot
|
|
await WIKI.db.pageHistory.addVersion(ogPage)
|
|
await WIKI.db.pageHistory.addVersion(ogPage)
|
|
@@ -453,6 +446,7 @@ export class Page extends Model {
|
|
if ('title' in opts.patch) {
|
|
if ('title' in opts.patch) {
|
|
patch.title = opts.patch.title.trim()
|
|
patch.title = opts.patch.title.trim()
|
|
historyData.affectedFields.push('title')
|
|
historyData.affectedFields.push('title')
|
|
|
|
+ shouldUpdateSearch = true
|
|
|
|
|
|
if (patch.title.length < 1) {
|
|
if (patch.title.length < 1) {
|
|
throw new Error('ERR_PAGE_TITLE_MISSING')
|
|
throw new Error('ERR_PAGE_TITLE_MISSING')
|
|
@@ -462,6 +456,7 @@ export class Page extends Model {
|
|
if ('description' in opts.patch) {
|
|
if ('description' in opts.patch) {
|
|
patch.description = opts.patch.description.trim()
|
|
patch.description = opts.patch.description.trim()
|
|
historyData.affectedFields.push('description')
|
|
historyData.affectedFields.push('description')
|
|
|
|
+ shouldUpdateSearch = true
|
|
}
|
|
}
|
|
|
|
|
|
if ('icon' in opts.patch) {
|
|
if ('icon' in opts.patch) {
|
|
@@ -488,9 +483,10 @@ export class Page extends Model {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if ('content' in opts.patch) {
|
|
|
|
|
|
+ if ('content' in opts.patch && opts.patch.content) {
|
|
patch.content = opts.patch.content
|
|
patch.content = opts.patch.content
|
|
historyData.affectedFields.push('content')
|
|
historyData.affectedFields.push('content')
|
|
|
|
+ shouldUpdateSearch = true
|
|
}
|
|
}
|
|
|
|
|
|
// -> Publish State
|
|
// -> Publish State
|
|
@@ -674,10 +670,10 @@ export class Page extends Model {
|
|
updatedAt: page.updatedAt
|
|
updatedAt: page.updatedAt
|
|
})
|
|
})
|
|
|
|
|
|
- // // -> Update Search Index
|
|
|
|
- // const pageContents = await WIKI.db.pages.query().findById(page.id).select('render')
|
|
|
|
- // page.safeContent = WIKI.db.pages.cleanHTML(pageContents.render)
|
|
|
|
- // await WIKI.data.searchEngine.updated(page)
|
|
|
|
|
|
+ // -> Update search vector
|
|
|
|
+ if (shouldUpdateSearch) {
|
|
|
|
+ WIKI.db.pages.updatePageSearchVector(page.id)
|
|
|
|
+ }
|
|
|
|
|
|
// -> Update on Storage
|
|
// -> Update on Storage
|
|
// if (!opts.skipStorage) {
|
|
// if (!opts.skipStorage) {
|
|
@@ -711,6 +707,24 @@ export class Page extends Model {
|
|
return page
|
|
return page
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Update a page text search vector value
|
|
|
|
+ *
|
|
|
|
+ * @param {String} id Page UUID
|
|
|
|
+ */
|
|
|
|
+ static async updatePageSearchVector (id) {
|
|
|
|
+ const page = await WIKI.db.pages.query().findById(id).select('localeCode', 'render')
|
|
|
|
+ const safeContent = WIKI.db.pages.cleanHTML(page.render)
|
|
|
|
+ const dictName = getDictNameFromLocale(page.localeCode)
|
|
|
|
+ return WIKI.db.knex('pages').where('id', id).update({
|
|
|
|
+ searchContent: safeContent,
|
|
|
|
+ ts: WIKI.db.knex.raw(`
|
|
|
|
+ setweight(to_tsvector('${dictName}', coalesce(title,'')), 'A') ||
|
|
|
|
+ setweight(to_tsvector('${dictName}', coalesce(description,'')), 'B') ||
|
|
|
|
+ setweight(to_tsvector('${dictName}', coalesce(?,'')), 'C')`, [safeContent])
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Convert an Existing Page
|
|
* Convert an Existing Page
|
|
*
|
|
*
|
|
@@ -1214,10 +1228,10 @@ export class Page extends Model {
|
|
])
|
|
])
|
|
.joinRelated('author')
|
|
.joinRelated('author')
|
|
.joinRelated('creator')
|
|
.joinRelated('creator')
|
|
- .withGraphJoined('tags')
|
|
|
|
- .modifyGraph('tags', builder => {
|
|
|
|
- builder.select('tag')
|
|
|
|
- })
|
|
|
|
|
|
+ // .withGraphJoined('tags')
|
|
|
|
+ // .modifyGraph('tags', builder => {
|
|
|
|
+ // builder.select('tag')
|
|
|
|
+ // })
|
|
.where(queryModeID ? {
|
|
.where(queryModeID ? {
|
|
'pages.id': opts
|
|
'pages.id': opts
|
|
} : {
|
|
} : {
|
|
@@ -1346,14 +1360,11 @@ export class Page extends Model {
|
|
* @returns {string} Cleaned Content Text
|
|
* @returns {string} Cleaned Content Text
|
|
*/
|
|
*/
|
|
static cleanHTML(rawHTML = '') {
|
|
static cleanHTML(rawHTML = '') {
|
|
- let data = striptags(rawHTML || '', [], ' ')
|
|
|
|
|
|
+ const data = striptags(rawHTML || '', [], ' ')
|
|
.replace(emojiRegex(), '')
|
|
.replace(emojiRegex(), '')
|
|
- // .replace(htmlEntitiesRegex, '')
|
|
|
|
return he.decode(data)
|
|
return he.decode(data)
|
|
- .replace(punctuationRegex, ' ')
|
|
|
|
.replace(/(\r\n|\n|\r)/gm, ' ')
|
|
.replace(/(\r\n|\n|\r)/gm, ' ')
|
|
.replace(/\s\s+/g, ' ')
|
|
.replace(/\s\s+/g, ' ')
|
|
- .split(' ').filter(w => w.length > 1).join(' ').toLowerCase()
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|